Connecting a client: discover, negotiate, call
Lesson 2 of 5 in Building with MCP: Servers, Clients, and the Install Review.
MCP has three roles, and mixing them up is the most common source of confused architecture diagrams.
The host is the LLM application — Claude Desktop, an IDE, your own agent runtime. It initiates connections, coordinates clients, enforces security policy, handles user authorization, and aggregates context. The client is a connector inside the host with a strict 1:1 relationship to exactly one server. The server provides context and capabilities and may be a local subprocess or a remote service.
One server, one client, one dedicated connection. Ten servers in your IDE means ten clients inside one host — which is precisely why a design principle of the protocol is that servers should not be able to read the whole conversation nor see into other servers: full conversation history stays with the host, and cross-server interaction is the host’s call, not a server’s.
One tool call, end to end, through MCP (revision 2026-07-28)
- Host starts a client for one server
For a local server the host launches a subprocess and talks over stdio; for a remote server it opens an HTTP connection to a single MCP endpoint.
- server/discover
Servers MUST implement server/discover, advertising supported protocol versions, capabilities, and identity. Clients MAY call it before any other request.
- tools/list
The server returns its tool declarations: name, description, inputSchema, optional outputSchema and annotations.
- Host puts declarations in the model’s tool definitions
This is the join: MCP declarations become the same tool definitions the model’s function-calling API already accepts. The model never learns it is talking to MCP.
- Model emits a tool call
Structured text naming a tool and its arguments. Exactly as in the agent loop from foundations — MCP changed where the definitions came from, not the loop.
- Host policy: permitted and consented?
The spec is explicit that hosts must obtain explicit user consent before invoking any tool, and that there SHOULD always be a human able to deny an invocation. MCP itself cannot enforce this — the host must.
- tools/call over stdio or Streamable HTTP
JSON-RPC 2.0, UTF-8. Over Streamable HTTP each message is a POST to the single MCP endpoint; the reply is a JSON object or a request-scoped SSE stream.
- resultType: complete, or input_required?
Under 2026-07-28 every result carries a resultType. Servers never initiate JSON-RPC requests; instead they return an InputRequiredResult carrying inputRequests.
- Client collects input, retries with inputResponses
The Multi Round-Trip Requests pattern (SEP-2322). Elicitation now travels this way rather than as a server-initiated request.
- Result appended to context
content and/or structuredContent. Execution failures arrive here too, as isError: true, so the model can retry.
- Model continues the loop
Two things in that diagram are new as of revision 2026-07-28, and both change how you write a client.
There is no handshake. The initialize / notifications/initialized exchange was removed (SEP-2575). The base protocol is now stateless: every request is self-contained and carries its protocol version and the client’s capabilities in _meta, so capability negotiation happens per request rather than once per session. In exchange, servers MUST implement server/discover so a client can still ask what it is talking to.
There is no session. Protocol-level sessions and the Mcp-Session-Id header were removed (SEP-2567). A server that genuinely needs state across calls — a cart, a browser context, a transaction — should mint an explicit handle, return it from a creation tool, and accept it as an ordinary argument on later calls. That is a real design consequence: the model is now responsible for carrying the handle forward, which means the handle must be documented in your tool descriptions like any other argument, authorized on every call, opaque, and given a documented lifetime.
Interactive sorting exercise: Ten responsibilities, three roles. Getting this boundary right is what stops you from writing a server that quietly assumes it is the host.
Interactive checkpoint quiz (2 questions) — open this page in a browser to take it.