Connect an MCP Client
Goal
Connect an MCP client by checking protocol compatibility, choosing only capabilities allowed for the current task, validating returned data, and handling remote failures without blindly trusting what a server advertises.
Start with a server that offers more than you need
Imagine a host application connects to a server and discovers these tools:
get_order_status
search_orders
refund_order
delete_order
The user only asked, “Has order 4172 shipped?” Discovery tells the host what the server offers. It does not mean the model should receive or use every offered tool.
The host already knows the current user, task, and local permission rules. It can therefore reduce the discovered list to the capability needed here—perhaps only get_order_status—and expose that smaller choice to the model-facing workflow.
This is the client-side responsibility: treat remote capability descriptions as information, then apply local policy before use. Protocol compatibility answers “Can these components communicate?” Permission answers “May this action happen for this user and task?” Those are separate questions.
The same rule applies after a call. A server response still has to match the expected result shape before the host puts it into model context or application state.
Build a versioned request
A client request should carry the pinned protocol version and the expected operation metadata. If the transport exposes method/name headers, the client should construct them consistently with the request body. Tests should detect disagreement rather than relying on whichever representation a downstream component happens to read.
discover → compatibility check → local authorization → MCP call → validate result
Before a side-effecting call, the host still performs permission and approval checks. The server will have its own checks too. Defense in depth means both sides can enforce their responsibilities without assuming the other side is enough.
Validate remote results and caching
Results are remote input. Validate the expected shape and preserve provenance. If a tool claims it returned an order status, the client should not silently accept a completely different object and feed it into later actions.
Cache behavior needs context. The 2026-07-28 release added cache hints for list and resource results. A client can use those hints, but it should also respect user scope and local sensitivity policy. A response safe to cache for one user is not automatically safe to share with another.
Map protocol errors into recovery
Network and protocol errors should map into the Level 12 retry model. An unsupported version is not a transient timeout. A malformed result usually needs investigation or fallback, not repeated identical calls. A rate limit may be retryable under a bounded policy.
Tracing should connect the host task to the protocol call. Record the endpoint identity, expected protocol version, capability name, attempt, policy result, remote latency, and validation outcome. This makes failures diagnosable even when the remote server is maintained by another team.
A robust client therefore acts as a trust adapter. It translates a remote protocol capability into local controller concepts while keeping remote descriptions, results, and errors inside explicit validation boundaries.
Predict
Run the local Lab
Run:
python3 labs/notebooks/level-13/l13-05-mcp-client.py
The Lab filters a discovered capability list through version and local role policy.
- Run it unchanged. With
role="reader", the exposed set should containget_orderbut notrefund_orderor the old-version tool. - Before editing, predict which capability will be added if the trusted local role changes to
operator. The remote catalog itself must stay fixed. - Change only
role="reader"torole="operator", then rerun. - Confirm that
refund_orderbecomes locally exposed whileold_toolremains excluded by its protocol version.
Loading lab…
Write the core logic yourself
Open:
labs/notebooks/level-13/l13-05-mcp-client-exercise.py
Implement local capability filtering using both negotiated protocol version and trusted local role. Discovery alone must not grant authority.
Run:
python3 labs/notebooks/level-13/l13-05-mcp-client-exercise.py
The starter intentionally fails at its TODO boundary. A completed implementation ends with a PASS: marker. Compare with the solved deterministic Lab only after attempting the implementation yourself.
Quick Check
Explain it back
Walk through a client connecting to a configured MCP endpoint, discovering capabilities, filtering them, calling one tool, and validating the result. Identify every trust decision.
Key Takeaways
- Clients map remote capability discovery into local policy.
- Construct version and operation metadata consistently.
- Remote results require schema and provenance validation.
- Cache hints do not override local data-scope policy.
- Protocol failures should feed typed retry and tracing behavior.
Next Lesson
Next, L13.6 — Security and Trust in MCP brings identity, endpoint trust, authorization, and least privilege together.
References
- Model Context Protocol, 2026-07-28 Specification.
- Model Context Protocol, 2026-07-28 Specification Release.
Completion is stored locally on this device.