Skip to main content

Class 2: Anatomy of MCP

Duration: ~20 minutes | Level: Beginner | Prerequisites: Class 1: Why MCP Exists


Four Actors, One Protocol

An MCP interaction involves four distinct roles, and keeping them apart matters because "client" and "server" also name things at other layers.

The arrow between client and server carries JSON-RPC 2.0 messages: small JSON objects naming a method, its parameters, and an id the reply quotes back.

1. The AI Model

The model, Claude Opus 5, GPT-5, Gemini, or any other LLM, is the reasoning engine. It doesn't know about MCP directly: what it sees is a list of available tools, described in its context window, the text it can see while it answers. When the model needs a tool, it picks one, constructs the arguments, and produces a structured tool-call output. The host then handles the actual MCP communication.

2. The Host

The host is the application the user interacts with: Claude Desktop, Cursor, a custom agent you built, or any other AI-enabled application. The host is responsible for:

  • Managing the conversation context
  • Feeding tool definitions into the model
  • Passing the model's tool calls to its MCP clients, which deliver them to the server that actually executes them
  • Managing user permissions for sensitive operations

Users interact with the host and do not see the protocol.

3. The MCP Client

The client is the MCP-protocol component embedded inside the host. It:

  • Establishes and maintains a connection to an MCP server
  • Declares its own protocol version and capabilities, meaning the optional features it supports: once in an initialize handshake through 2025-11-25, and in every request it sends from 2026-07-28
  • Learns what the server offers by calling server/discover, or by sending a request and handling the version error (see below)
  • Sends tool calls, resource reads, and prompt requests to its server
  • Returns results to the host (which passes them to the model)

One host can contain multiple MCP clients, and each client maintains a connection to one MCP server.

4. The MCP Server

The server is what you build. It's a process that:

  • Runs your business logic (querying a DB, calling an API, reading files)
  • Exposes that logic as structured MCP primitives: Tools, Resources, and Prompts
  • Handles requests from the client and returns results

The server is where you spend your implementation time; the model, the host and the client come from the AI application you're integrating with.


A Concrete Example: Database Query Tool

Suppose you build an MCP server that lets an AI query your PostgreSQL database.

What you build: An MCP server process that:

  1. Connects to PostgreSQL as a database user whose read access covers only the tables this tool needs
  2. Exposes a run_query tool with a sql string parameter
  3. On a tool call: rejects anything that is not a single SELECT, runs it with a row limit, and returns the results
  4. Limits how often the tool can be called

The model writes that sql string, and any text that reaches the model can influence what it writes, so the database connection is where the limit belongs. The MCP tools specification requires servers to validate tool inputs, apply access controls and rate limit invocations, and OWASP LLM06:2025, Excessive Agency asks for read access only, without insert, update or delete.

What happens at runtime, with the user in Cursor and your server already connected:

Steps 5 and 8 are the only MCP messages here. Everything else happens inside the host or your server.

What the user sees: An accurate, data-backed answer without copy-pasting any query results into the chat.


Server Multiplicity: One Host, Many Servers

A single host can connect to several servers at once, and each server is a separate process with its own set of capabilities.

The model sees the tools from all four servers as one list. Routing is the host's job: it passes each call to the client connected to the server that exposes that tool. A server receives only the arguments of its own call, so it cannot read the conversation or see what another server holds, which the architecture specification states as a design principle.

Each server covers one system, so it can be reused by any host that speaks MCP.


Server Lifecycle

stdio is short for standard input and output, the two byte streams a process reads from and writes to. The two deployments differ in more than where the process runs:

What you are choosingLocal stdio serverRemote HTTP server
Who starts the processthe client, as a subprocessyou, as a deployed service
How long it runsacross many unrelated requests, and not tied to one conversationas long as the service is deployed, or for a single request on a serverless platform, where a process is created for one request and then discarded
Who can reach itonly the local user's clientmany clients and many users, over the network
How it stopsthe client closes the server's standard input, waits for it to exit, then terminates ityou redeploy it or scale it down

The choice decides how the server authenticates its callers and what it costs to run. Class 5 works through both transports, the connections the messages travel over.


Statelessness: Why There Is No Session

Revision 2026-07-28 removed something most MCP material still takes for granted: the session.

What the protocol used to do. Through revision 2025-11-25, every connection had three phases.

Initialisation settled two questions once instead of on every message: which protocol version are we speaking, and which optional features does the other side support. notifications/initialized is a notification, a JSON-RPC message that does not carry an id and does not expect a reply. During operation, servers could also send requests back to the client.

What it does now. Settling those questions per connection makes the connection stateful. Such state is awkward behind a load balancer or on a serverless platform, where many identical copies of a server share the traffic and any request can go to any copy. So 2026-07-28 deleted the model. The specification's lifecycle page was replaced by one on versioning and compatibility, and the base protocol now opens with this:

The Model Context Protocol (MCP) is a stateless protocol: all the information needed to process a request is contained in the request itself. A server processes each request independently; no state should be inferred from previous requests, even those on the same connection or stream.

Protocol version and client capabilities travel in _meta, a reserved field any MCP message may carry. Both are required on every request, and io.modelcontextprotocol/clientInfo is recommended:

{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "run_query",
"arguments": { "sql": "SELECT customer_id, SUM(amount) FROM orders GROUP BY 1" },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": { "elicitation": {} },
"io.modelcontextprotocol/clientInfo": { "name": "example-client", "version": "1.0.0" }
}
}
}

A server that does not implement the requested version answers that request with UnsupportedProtocolVersionError, code -32022, listing the versions it does support:

{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32022,
"message": "Unsupported protocol version",
"data": {
"supported": ["2025-11-25"],
"requested": "2026-07-28"
}
}
}

The client picks a version from data.supported and sends the call again. Any state that has to outlive a single request must be referenced by an explicit identifier the client passes back each time. The spec is blunt about the consequence: an open connection, a running stdio process included, is not a conversation and not a session.

Servers no longer send requests back to the client either. When a server needs an answer from the user, it returns resultType: "input_required" with the questions to ask and an opaque requestState. Only prompts/get, resources/read and tools/call may return that result.

The retry is a separate request with a new JSON-RPC id, carrying the answers in inputResponses and the same requestState. That state is the server's own record of where it stopped, and the client MUST NOT read or change it.

The same pattern carries the two older ways a server could reach the client: sampling, where the server asks the host's model to generate text, and roots, where it asks which directories it may work in. 2026-07-28 deprecates both: pass directories through tool parameters or server configuration instead of roots, and call an LLM provider's API directly instead of sampling.

Servers MUST implement one new method, server/discover, which reports their supported versions, capabilities, identity and an optional instructions string for the model. Clients MAY call it first, or invoke any request cold and handle the version error. The result looks like this:

{
"jsonrpc": "2.0",
"id": "discover-1",
"result": {
"resultType": "complete",
"supportedVersions": ["2026-07-28", "2025-11-25"],
"capabilities": { "tools": {}, "resources": {} },
"instructions": "Read-only SQL access to the sales database.",
"_meta": {
"io.modelcontextprotocol/serverInfo": { "name": "db-server", "version": "1.0.0" }
}
}
}

Legacy and modern, side by side:

What the two sides have to agreeLegacy, through 2025-11-25Modern, 2026-07-28
Protocol versionsettled once in the initialize handshakedeclared in _meta on every request
Client capabilitiessent once in initializesent in _meta on every request
How the client learns what the server offersfrom the initialize responsefrom server/discover, or by sending a request and handling -32022
How a server asks the client for inputit sends its own requestit returns input_required and the client retries
What an open connection meansa sessiona byte stream carrying unrelated requests
Why you will still meet the handshake

The older revisions have not been switched off. The spec calls them legacy, calls the per-request model modern, and defines how a dual-era implementation serves both. The Java MCP SDK 2.0.0 implements 2025-11-25, which is what the Java code on this site targets. Class 6 walks through the legacy handshake in detail.


Key Takeaways

  • Host = the application users interact with (Claude Desktop, Cursor, your custom agent)
  • Client = the MCP protocol component embedded in the host
  • Server = what you build, your business logic wrapped in MCP
  • Model = the AI reasoning engine, which sees only tool definitions and results
  • One host can connect to multiple servers; each server is a separate process
  • Servers expose three kinds of primitives: Tools, Resources, and Prompts
  • Under 2026-07-28 a connection is not a session: every request carries its own protocol version and capabilities

In the next class we take each of the three primitives in turn: what each is for and when to use which.


Further Reading

  • MCP specification: Architecture: the four design principles behind the host, client and server split, and the responsibilities the specification assigns to each of them.
  • MCP specification: Base Protocol: the shape of every JSON-RPC request, result, error and notification MCP uses, and the rules for which JSON Schema dialects a tool may declare.
  • MCP specification: Versioning and Compatibility: the compatibility matrix for every pairing of legacy and modern client and server, and how a dual-era implementation works out which era it is talking to.
  • MCP specification: Discovery: when a client should call server/discover first, and why a client must not base a security decision on the serverInfo a server reports about itself.
  • MCP specification: Multi Round-Trip Requests: the full server and client requirements, including how a server has to sign requestState and give it a short lifetime so a client cannot replay it or tamper with it.
  • MCP specification: Lifecycle (2025-11-25): the initialize request and response bodies, the timeout guidance, and the shutdown sequence for each transport.
  • modelcontextprotocol/servers: the reference server implementations, including the filesystem server that appears in the diagram above.
  • Awesome MCP Servers: a community-maintained index of published MCP servers, for finding one that already covers a system you need.

Sources