Your MCP server starts successfully, yet the assistant says it cannot use the tool. Which message would you inspect first? Knowing the protocol's shape helps you find the fault without changing prompts at random.
Before you begin: Complete the MCP connection and server lessons. Know the shape of a JSON object.
Begin with the connection lifecycle
MCP uses JSON-RPC messages and a defined initialization exchange. Participants negotiate a protocol version and advertise capabilities before normal interaction. An SDK handles much of the message machinery. Understanding it still matters when a host and server disagree about supported features.
The protocol revision and package version answer different questions. The revision describes the agreed message contract. The SDK version identifies the implementation you installed. September 10, 2026's review used the July 28, 2026 specification and the Python SDK's v2 documentation.
What does a successful exchange actually prove?
A protocol success says the exchange worked at that layer. It does not automatically establish that the business operation succeeded or that the result contains useful evidence. A tool may return an explicit application error inside a successfully delivered response.
Read the request, envelope and tool content separately. Then inspect how the host turns that content into an answer. The challenge follows a timetable lookup whose transport succeeds but whose meaning is mishandled, so you can place validation at the right boundary.
A tool response reaches the host successfully, but its content reports a lookup failure.
Distinguish protocol delivery from the tool’s application-level outcome.
The assistant can report that availability could not be checked instead of claiming the timetable is empty.
Inspect discovery before execution
Tools expose callable operations. Resources expose readable content identified by URIs. Prompts expose reusable prompt templates. These are protocol concepts, not guarantees that every host presents all three in the same interface.
For a tool, discovery includes its name, description, and input schema. The host needs enough information to construct a valid call. If a tool is missing from discovery, investigate server registration, advertised capabilities, and host connection state before investigating the model's selection behavior.
The simplified request below illustrates a tools/call message after initialization. It is a protocol example, not a complete client program or a recorded network trace.
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "read_workshop",
"arguments": {"workshop_id": "W1"}
}
}
The request ID correlates a response with this request. It is not an authenticated user ID, a database key, or an idempotency guarantee for a write. Those identities may all exist in an application, but they serve different purposes.
Read success at the right layer
A successful HTTP response can contain a protocol-level result that reports a tool failure. A successful tool invocation can return a legitimate not_found business result. A successful lookup can still be paraphrased incorrectly by the model.
For example, malformed request arguments belong to validation or protocol handling. “Catalog service unavailable” is a tool execution problem. “W99 does not exist” can be a normal domain result. Preserve these distinctions so the host can offer an appropriate next step.
Tool results may carry textual content and structured content according to the supported specification and schema. Read the tool's documented output contract rather than assuming every server returns a plain string. If the contract says capacity is unknown, preserve that state instead of converting it to zero.
Trace one ambiguous failure
The transport returns HTTP 200, the tool result indicates a backend timeout, and the assistant answers “No matching workshops.” Which layer first lost meaning?
Compare the trace diagnosis
The tool correctly reported a timeout. The host or answer-generation step treated that error as an empty successful search. Preserve the failure status in the model-visible result and test the final response. HTTP success only confirms part of the exchange; it does not certify the user's task succeeded.
For practice, create three expected traces: missing tool, invalid argument, and valid request for an absent record. Write the recovery message for each. The missing tool may require connection repair; the invalid argument may require correction; the absent record may require a different question. Retrying all three identically wastes work and hides the cause.
Practice with feedback
Read an MCP exchange at the right layer
A tool call returns successfully, and the assistant tells the user the timetable is empty. The timetable is not empty.
Follow initialise, discovery, call, and result, and locate an ambiguous failure.
Check your understanding
Your task
Write the message sequence for one call and fix the ambiguous empty result.
These notes stay on this page. Download them before leaving.
What to include
- The sequence names initialise, tools/list, tools/call, and the result
- The replacement shape distinguishes no-match from failure
- Two distinct user-facing messages are given
- The logging captures which case occurred
Compare with a worked answer
Here is one way to answer. Check how it uses the information in the task.
Sequence: 1. initialize - client sends its protocol version and capabilities; server replies with its own plus server info. Nothing else is legal before this. 2. notifications/initialized - client confirms; the session is now open. 3. tools/list - server returns tool names, descriptions, and input schemas. 4. tools/call - client sends {name, arguments}; server returns content plus isError. Protocol success is isError=false; what the content says is a separate question.
The ambiguous result today: {'classes': []} whether nothing matched or the database query raised and was swallowed by a bare except.
The shape I would return instead: {'status': 'ok', 'classes': [...]} normal, possibly empty {'status': 'ok', 'classes': [], 'note': 'no classes match Wednesday'} {'status': 'error', 'reason': 'timetable database unreachable'} with isError=true, so the protocol layer agrees with the application layer.
What the assistant should say: empty match -> 'There are no classes on Wednesday.' error -> 'I could not read the timetable just now.' Never 'there are no classes', which is a false statement about the world.
What I log: the call name, arguments, status, reason, and row count, on every call. Distinguishing these two cases after the fact was impossible before, which is why the bug survived three weeks.
When you are signed in, opening the challenge carries your edited working notes into its draft in this browser. The challenge has its own completion record. Practising here does not award points or mark it complete.
Next, return to document applications and inspect the data transformations that happen behind an indexing abstraction.
Sources
MCP specification defines the lifecycle. Tools defines discovery, calls, and tool results. Architecture connects these messages to application roles.