Model Context Protocol

Sefism.

Chapter 02

Messages and lifecycle

Everything in MCP is a JSON-RPC 2.0 message. The current revision is stateless: every request carries the version and capabilities it relies on, instead of a handshake at the start of a connection.

JSON-RPC 2.0

What
A small JSON message format. Requests have an id, a method and params; responses echo the id with a result or an error; notifications have no id and get no reply.
Why
Every MCP feature, from tools/list to resources/read, is a JSON-RPC method, so reading raw messages is the fastest way to debug.
JSON
{
  "jsonrpc": "2.0", "id": 7,
  "method": "tools/call",
  "params": {
    "name": "search_notes",
    "arguments": { "query": "invoices" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

Watch out

Using null as a request id, or reusing an id that is still in flight; both are invalid.

Stateless requests and _meta

Also called _meta, per-request metadata

What
Since 2026-07-28, each request carries its protocol version and client capabilities (and usually client info) in _meta. Servers must not rely on earlier requests on the same connection.
Why
Any server instance can answer any request, so remote servers scale behind a load balancer without sticky sessions.

Watch out

Storing per-user state keyed by the connection. Return an explicit handle from a tool and accept it as an argument instead.

server/discover and version negotiation

What
Servers implement server/discover to advertise their supported versions, capabilities and identity. A request with an unsupported version gets an UnsupportedProtocolVersion error.
Why
Clients can pick a version up front, and use it as a probe to detect servers that only speak an older revision.

The initialize handshake (older revisions)

Also called initialize, notifications/initialized

What
Up to 2025-11-25, a connection began with an initialize request exchanging versions and capabilities, then an initialized notification. HTTP connections also carried an Mcp-Session-Id.
Why
Many hosts and servers still speak these revisions, so you will meet the handshake in logs, SDKs and tutorials.

Watch out

Mixing the two models in one server, for example relying on session ids while claiming the stateless revision.

Capabilities

What
Declarations of optional features each side supports, such as tools with listChanged on a server or elicitation on a client.
Why
A server must not use a client feature the client has not declared, and a client only calls methods the server advertises.
JSON
{
  "capabilities": {
    "tools": { "listChanged": true },
    "resources": {},
    "prompts": {}
  }
}

Multi round-trip requests

Also called MRTR, input_required

What
When a server needs more from the client mid-request (user input, for example), it returns a result with resultType: "input_required" and the questions. The client retries the request with the answers.
Why
It replaces server-initiated requests, so servers stay stateless and work over plain request and response.

Watch out

Retrying with the same JSON-RPC id. The retry is a new request with a new id, carrying the answers and any requestState.

Notifications and subscriptions

Also called listChanged, subscriptions/listen

What
One-way messages such as progress updates or notifications/tools/list_changed. Change notifications flow on a subscriptions/listen stream the client opens and chooses topics for.
Why
They let a client refresh its tool list or a resource when it changes, instead of polling.

Protocol errors and tool errors

What
Protocol problems (unknown tool, malformed params) are JSON-RPC errors. Failures while running a tool (bad date, API down) are normal results with isError: true and a readable message.
Why
The model sees tool errors and can fix its arguments and retry; protocol errors usually cannot be fixed by the model.

Watch out

Throwing a JSON-RPC error for a validation problem, hiding the helpful message from the model.

02 · Messages and lifecycle2 / 10