new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

MCP · Specification · all subjects

handshake & version negotiation

44 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

MCP 2026-07-28 is a stateless protocol

MCP is a stateless protocol: all information needed to process a request is contained in the request itself, and a server processes each request independently without inferring state from previous requests on the same connection or stream. Servers MUST NOT rely on prior requests over the same connection to establish context such as capabilities, protocol version, or client identity — every request supplies this metadata in its `_meta` field. Servers SHOULD be prepared to handle requests associated with multiple tasks, threads, or conversations, and SHOULD NOT require a client to reuse the same connection or process for related operations. Clients SHOULD NOT use an individual task, thread, or conversation as the lifetime boundary for the stdio process. State spanning multiple requests (e.g., long-running tasks, application-level handles) MUST be referenced by an explicit identifier the client passes on each request.

Per-request protocol fields in _meta (required vs optional)

Client requests carry protocol fields in `_meta`: `io.modelcontextprotocol/protocolVersion` (string, REQUIRED, e.g. "2026-07-28"), `io.modelcontextprotocol/clientInfo` (Implementation, optional), `io.modelcontextprotocol/clientCapabilities` (ClientCapabilities, REQUIRED), and `io.modelcontextprotocol/logLevel` (LoggingLevel, optional). Servers use these to identify the protocol version and capabilities in use without relying on prior connection state. Clients SHOULD include `io.modelcontextprotocol/clientInfo` on every request unless specifically configured not to.

Per-response _meta serverInfo field

Servers SHOULD include `io.modelcontextprotocol/serverInfo` (type `Implementation`, server name and version, not strictly required) in every result's `_meta`, unless specifically configured not to, so they identify themselves without relying on prior connection state.

Protocol version and client capabilities travel in _meta.io.modelcontextprotocol/* on every request

All protocol metadata travels in the message body: every request carries its protocol version and the client capabilities in `_meta.io.modelcontextprotocol/*` fields. There is no connection-scoped session state carrying them in the 2026-07-28 revision.

Backward compatibility with initialize-handshake era revisions

Earlier MCP protocol revisions established a connection-scoped session with an `initialize` handshake and allowed servers to initiate JSON-RPC requests. In the 2026-07-28 revision, clients and servers that interoperate with those revisions detect the counterpart's era and fall back as described in the Versioning page's 'Backward Compatibility with Initialization-Based Versions' section, which includes a compatibility matrix. Each binding page describes its transport-specific detection mechanics.

stdio request metadata lives in _meta, no headers

All request metadata for the stdio transport is carried inline in the JSON-RPC message body: the protocol version, per-request capabilities, and optional client identity live in `_meta.io.modelcontextprotocol/*`, while the method name and arguments live where JSON-RPC puts them. There is no header layer on stdio.

Probing with server/discover before initialize fallback

A client supporting both modern (per-request-metadata) MCP versions and a legacy version that requires an `initialize` handshake SHOULD probe with `server/discover` before sending any other request, setting its preferred modern version in `_meta`. Three outcomes: (a) a DiscoverResult means the server is modern — select a mutually supported version from `supportedVersions` and continue; (b) a recognized modern JSON-RPC error such as UnsupportedProtocolVersionError means the server is modern but does not support the requested version — use one of the versions in its advertised `supported` list and do NOT fall back to `initialize`; (c) any other error or no response within a reasonable timeout means the server is legacy — fall back to the `initialize` handshake.

Probing recommended even for modern-only clients

A client that only supports modern MCP versions does not need to probe with server/discover, but probing is still RECOMMENDED: some legacy servers do not validate that a request arrives after `initialize` and would process an era-ambiguous method such as `tools/call` under legacy semantics. Probing yields a deterministic failure instead.

MCP 2026-07-28 has no initialize handshake; version travels per request

In protocol revision 2026-07-28 there is no negotiation handshake. Every request declares the protocol version it uses in its `_meta` field, and the server accepts or rejects each request independently. On HTTP the version is also carried in the `MCP-Protocol-Version` header.

Client SHOULD retry with a mutually supported version

On receiving UnsupportedProtocolVersionError, the client SHOULD select a mutually supported version from the `supported` list and retry the request, or surface an error to the user if no compatible version exists.

Modern vs legacy vs dual-era protocol terminology

'Modern' protocol versions convey version, identity, and capabilities as per-request metadata (revision 2026-07-28 and later). 'Legacy' versions establish a session with an `initialize` handshake (2025-11-25 and earlier). 'Dual-era' describes an implementation supporting both modern and legacy versions.

Modern-only server SHOULD list versions in initialize error

A server that supports only modern versions SHOULD name the protocol versions it supports in any error it returns to an `initialize` request, on any transport, because legacy clients have no fall-forward mechanism and this message may be the only diagnostic they can surface to users.

Client/server era compatibility matrix outcomes

Expected outcomes by era: Modern client + modern server works (server/discover optional; mismatches surface as UnsupportedProtocolVersionError and the client retries). Modern client + legacy server fails (server may return an implementation-defined error, stay silent, or process an era-ambiguous method under legacy semantics; on stdio clients SHOULD send `server/discover` first to fail deterministically). Dual-era client + modern server works (stdio probe returns a DiscoverResult or UnsupportedProtocolVersionError; on HTTP the first modern request succeeds or returns a modern error). Dual-era client + legacy server works (stdio probe returns a non-modern error or times out and the client falls back to `initialize`; HTTP returns 4xx without a recognized modern error body and the client falls back to `initialize`, possibly further to the deprecated HTTP+SSE transport). Legacy client + modern server fails (stdio: server rejects `initialize` with an implementation-defined JSON-RPC error code since `initialize` is unknown and `_meta` fields are missing; HTTP: missing required headers gives 400 Bad Request, or a deprecated HTTP+SSE client fails at its opening GET). Legacy client + dual-era server works via `initialize`. Legacy + legacy works per the legacy revision.

initialize handshake removed in 2026-07-28 (MCP is stateless)

Revision 2026-07-28 makes MCP stateless by removing the `initialize` request and `notifications/initialized` notification entirely (SEP-2575). Instead, every request carries its protocol version and client capabilities in `_meta` under the keys `io.modelcontextprotocol/protocolVersion` and `io.modelcontextprotocol/clientCapabilities`.

_meta keys for identity: clientInfo and serverInfo

With the stateless model of 2026-07-28, clients SHOULD identify themselves on each request via the `_meta` key `io.modelcontextprotocol/clientInfo`, and servers SHOULD identify themselves in each result's `_meta` via `io.modelcontextprotocol/serverInfo`.

server/discover RPC is MUST-implement

Servers MUST implement the `server/discover` RPC, which advertises the server's supported protocol versions, capabilities, and identity. Clients MAY call it before any other request for up-front version selection, or use it as a backward-compatibility probe on STDIO (SEP-2575).

Previous revision of 2026-07-28 is 2025-11-25

MCP specification revision 2026-07-28 lists its changes relative to the previous revision 2025-11-25.

server/discover method is MUST for servers

In MCP spec version 2026-07-28, `server/discover` lets a client query a server's supported protocol versions, capabilities, and identity before sending any other requests. Servers **MUST** implement `server/discover`.

server/discover request shape

A `server/discover` request carries no body parameters beyond the standard `_meta`. Example: {"jsonrpc": "2.0", "id": "discover-1", "method": "server/discover", "params": {"_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientInfo": {"name": "ExampleClient", "version": "1.0.0"}, "io.modelcontextprotocol/clientCapabilities": {}}}}.

server/discover response (DiscoverResult) shape

The `server/discover` result contains `resultType` (e.g. "complete"), `supportedVersions` (array of protocol version strings such as ["2026-07-28"]), `capabilities` (e.g. {"tools": {}, "resources": {}}), `_meta` containing `io.modelcontextprotocol/serverInfo` with `name` and `version`, optional `instructions` (natural-language guidance for LLMs), and caching fields `ttlMs` (e.g. 3600000) and `cacheScope` (e.g. "public").

Calling server/discover is optional for clients

Clients are not required to call `server/discover`. A client may invoke any RPC inline and handle `UnsupportedProtocolVersionError` if the server does not support the requested version. Discovery is useful for presenting server identity, capabilities, and supported versions in a single request instead of probing with separate `tools/list`, `prompts/list`, and `resources/list` requests.

server/discover supports caching

The `server/discover` operation supports caching, as described in the caching utility spec; its result may include `ttlMs` (milliseconds, e.g. 3600000) and `cacheScope` (e.g. "public").

MCP-Protocol-Version header required on every POST

Every POST request to the MCP endpoint MUST include an MCP-Protocol-Version header, for example 'MCP-Protocol-Version: 2026-07-28'. The header value MUST match the io.modelcontextprotocol/protocolVersion field carried in the request body's _meta; if they do not match, the server MUST reject the request with 400 Bad Request and a HeaderMismatch JSON-RPC error (code -32020).

UnsupportedProtocolVersionError returned with 400 Bad Request

If the server does not implement the requested protocol version (unknown to the server, or a known version it chose not to support), it MUST respond with HTTP 400 Bad Request and an UnsupportedProtocolVersionError listing its supported versions in a 'supported' field.

Missing MCP-Protocol-Version header handling

A server that supports clients implementing protocol versions earlier than 2025-06-18 (which did not define the MCP-Protocol-Version header) MAY treat a request that omits the header as protocol version 2025-03-26. A server that does not support such clients MUST reject a request without the header per Server Validation (400 Bad Request with -32020 HeaderMismatch).

Detecting modern vs legacy servers on 400 Bad Request

A client supporting both modern (per-request-metadata) MCP versions and a legacy initialize-handshake version MAY detect the server era by attempting a modern request first. On 400 Bad Request the client SHOULD inspect the response body before falling back, because modern servers also use 400 for UnsupportedProtocolVersionError, MissingRequiredClientCapabilityError, and header-validation failures. If the body contains a recognized modern JSON-RPC error, the server is modern — retry using the advertised 'supported' versions or correct the request. If the body is empty or not a recognized modern JSON-RPC error, fall back to initialize and continue with the legacy version.

Per-request _meta replaces initialize handshake (RequestMetaObject)

In MCP 2026-07-28, every request's `params._meta` is a `RequestMetaObject` containing: `progressToken?: ProgressToken`, `"io.modelcontextprotocol/protocolVersion": string` (required), `"io.modelcontextprotocol/clientInfo"?: Implementation`, `"io.modelcontextprotocol/clientCapabilities": ClientCapabilities` (required), and the deprecated `"io.modelcontextprotocol/logLevel"?: LoggingLevel`, plus arbitrary additional string keys. `RequestParams` declares `_meta: RequestMetaObject` as required.

protocolVersion in _meta MUST match MCP-Protocol-Version header

The `_meta` key `io.modelcontextprotocol/protocolVersion` states the MCP Protocol Version being used for the request and is required. For the HTTP transport this value MUST match the `MCP-Protocol-Version` header; otherwise the server MUST return `400 Bad Request`. If the server does not support the requested version, it MUST return an `UnsupportedProtocolVersionError`.

clientInfo is advisory and MUST NOT drive behaviour

`io.modelcontextprotocol/clientInfo` identifies the client software; clients SHOULD include it on every request unless configured not to. The `Implementation` schema requires `name` and `version`; other fields are optional. The value is self-reported and unverified: servers SHOULD NOT use it to change behaviour and SHOULD NOT rely on it for security decisions.

UNSUPPORTED_PROTOCOL_VERSION = -32022 shape and HTTP 400 MUST

The MCP-specific error code UNSUPPORTED_PROTOCOL_VERSION is -32022, returned when the request's protocol version is unknown to the server or unsupported (e.g. a known experimental or draft version the server chose not to implement). Its error object is `Error & { code: -32022; data: { supported: string[]; requested: string } }` within a JSONRPCErrorResponse. For HTTP, the response status code MUST be 400 Bad Request.

Example -32022 unsupported protocol version response

Example UnsupportedProtocolVersionError: {"jsonrpc": "2.0", "id": 1, "error": {"code": -32022, "message": "Unsupported protocol version", "data": {"supported": ["2026-07-28", "2025-11-25"], "requested": "1900-01-01"}}}. This shows protocol versions are date strings such as 2026-07-28 and 2025-11-25.

Request _meta carries protocolVersion, clientInfo, clientCapabilities

In the 2026-07-28 schema, request params `_meta` (RequestMetaObject) carries the well-known keys "io.modelcontextprotocol/protocolVersion" (e.g. "2026-07-28"), "io.modelcontextprotocol/clientInfo" ({name, version}), and "io.modelcontextprotocol/clientCapabilities" (an object, may be empty {}).

Example: prompts/get request with _meta handshake fields

Example prompts/get request: {"jsonrpc": "2.0", "id": "get-prompt-example", "method": "prompts/get", "params": {"_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientInfo": {"name": "ExampleClient", "version": "1.0.0"}, "io.modelcontextprotocol/clientCapabilities": {}}, "name": "code_review", "arguments": {"code": "def hello():\n print('world')"}}}. Client requests carry protocolVersion, clientInfo and clientCapabilities inside params._meta.

server/discover request shape and MUST-implement rule

DiscoverRequest is { jsonrpc: "2.0"; id: RequestId; method: "server/discover"; params: RequestParams } and asks the server to advertise its supported protocol versions, capabilities, and other metadata. Servers MUST implement server/discover. Clients MAY call it but are not required to, because version negotiation can also happen inline via per-request _meta.

server/discover request example with _meta version negotiation keys

Example server/discover request: {"jsonrpc": "2.0", "id": "discover-1", "method": "server/discover", "params": {"_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientInfo": {"name": "ExampleClient", "version": "1.0.0"}, "io.modelcontextprotocol/clientCapabilities": {}}}}.

DiscoverResultResponse shape and example result fields

DiscoverResultResponse is { jsonrpc: "2.0"; id: RequestId; result: DiscoverResult }. An example result is {"resultType": "complete", "supportedVersions": ["2026-07-28"], "capabilities": {"tools": {}, "resources": {}}, "_meta": {"io.modelcontextprotocol/serverInfo": {"name": "ExampleServer", "version": "1.0.0"}}, "ttlMs": 3600000, "cacheScope": "public"}.

DiscoverResult shape for server/discover

DiscoverResult (the result of a `server/discover` request) has: optional `_meta` (ResultMetaObject), required `resultType: string`, required `supportedVersions: string[]`, required `capabilities: ServerCapabilities`, optional `instructions?: string`, required `ttlMs: number`, required `cacheScope: "public" | "private"`, plus an index signature `[key: string]: unknown`.

server/discover result example JSON

Example DiscoverResult: {"resultType": "complete", "supportedVersions": ["2026-07-28"], "capabilities": {"tools": {}, "resources": {}}, "_meta": {"io.modelcontextprotocol/serverInfo": {"name": "ExampleServer", "version": "1.0.0"}}, "instructions": "This server provides weather and resource utilities. Prefer `get_weather` for forecast lookups.", "ttlMs": 3600000, "cacheScope": "public"}. Server info is carried in `_meta` under the key `io.modelcontextprotocol/serverInfo`.

supportedVersions in DiscoverResult drives version negotiation

DiscoverResult.supportedVersions is an array of MCP protocol version strings the server supports. The client should choose a version from this list for use in subsequent requests.

CacheableResult ttlMs semantics

`ttlMs` is a hint from the server for how long (in milliseconds) the client MAY cache the response before re-fetching, analogous to HTTP Cache-Control max-age. If 0, the response SHOULD be considered immediately stale and the client MAY re-fetch every time the result is needed. If positive, the client SHOULD consider the result fresh for that many milliseconds after receiving the response.

DiscoverResult.instructions purpose

DiscoverResult.instructions is optional natural-language guidance describing the server and its features. Clients can use it to improve an LLM's understanding of available tools (e.g., including it in a system prompt). It should focus on information that helps the model use the server effectively and should not duplicate information already in tool descriptions.

Implementation interface (name, version, title, icons, description, websiteUrl)

The Implementation interface describes an MCP implementation: `icons?: Icon[]`, `name: string` (required, programmatic/logical identifier, used as display name fallback), `title?: string` (human-readable display name), `version: string` (required), `description?: string`, and `websiteUrl?: string`. If `title` is not provided, `name` should be used for display, except for Tool where `annotations.title` takes precedence over `name`.

Request _meta carries protocolVersion, clientInfo, clientCapabilities

In protocol version 2026-07-28, per-request `_meta` (RequestMetaObject) carries handshake data under prefixed keys: `io.modelcontextprotocol/protocolVersion` (e.g., "2026-07-28"), `io.modelcontextprotocol/clientInfo` (an object with name and version), and `io.modelcontextprotocol/clientCapabilities` (a ClientCapabilities object).

Protocol version string 2026-07-28 in request _meta

Requests carry the negotiated protocol version in params._meta under the key "io.modelcontextprotocol/protocolVersion"; the version identifier for this specification revision is "2026-07-28". Client identity and capabilities also travel per-request as "io.modelcontextprotocol/clientInfo" and "io.modelcontextprotocol/clientCapabilities".

Give your agent this brain