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

transport rules

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

Connections are not sessions or conversations

An open connection, such as a STDIO process, is not a conversation or session: clients may interleave unrelated requests on the same transport, and a server must not treat connection or process identity as a proxy for conversation or session continuity. Long-lived requests such as `subscriptions/listen` remain request/response, where the response is an open stream of notifications, and their state is scoped to the request itself rather than the underlying connection.

Cancellation over Streamable HTTP: closing the SSE stream

On the Streamable HTTP transport, closing the SSE response stream is the cancellation signal. The server MUST treat a client disconnect as cancellation of that request. No `notifications/cancelled` message is required or expected on Streamable HTTP.

Cancellation over stdio requires notifications/cancelled

On the stdio transport there is no per-request stream to close, so the client MUST send a `notifications/cancelled` notification referencing the request ID to cancel a request.

Three core message patterns: request/response, multi round-trip, subscribe/notify

The MCP 2026-07-28 core protocol defines three message patterns composed from JSON-RPC requests, responses, and notifications: (1) Request and Response, (2) Multi Round-Trip Requests, and (3) Subscribe and Notify. Every transport carries all of these patterns; transports differ only in how messages are framed and delivered. A protocol revision that adds a pattern defines it on the patterns overview page, and transports carry new patterns without changes.

MCP 2026-07-28 transports: two standard bindings (stdio, Streamable HTTP)

The MCP specification revision 2026-07-28 defines two standard transport bindings: (1) stdio — newline-delimited messages over the standard streams of a client-launched subprocess; (2) Streamable HTTP — each message is an HTTP POST to a single MCP endpoint, with replies arriving either as a JSON object or as a request-scoped SSE stream. Clients and servers MAY also implement custom transports.

Bindings MAY mirror body metadata into envelope metadata; body is source of truth

A transport binding MAY additionally mirror selected body fields into envelope metadata. The Streamable HTTP transport mirrors the per-request metadata into HTTP headers so intermediaries can route and inspect requests without parsing the body. The body remains the source of truth, and bindings that mirror metadata must define how mismatches are rejected.

Custom transports MUST preserve JSON-RPC format, message patterns, and per-request metadata

Implementers who support custom transports MUST preserve the JSON-RPC message format, the MCP message patterns, and the per-request metadata model. Custom transports SHOULD document their connection establishment, message framing, and cancellation patterns to aid interoperability.

Custom byte-stream transports SHOULD reuse stdio framing

Custom transports that run over a reliable bidirectional byte stream (for example Unix domain sockets or TCP) SHOULD reuse the stdio framing rather than defining a new one. The stdio binding is just newline-delimited JSON-RPC over a byte stream; only its process-lifecycle rules are specific to standard streams.

Protocol semantics are identical on every transport

MCP protocol semantics are identical on every transport. A transport is a binding: it defines how messages are framed and delivered, how request metadata is carried, and how cancellation and termination are signaled. It does not define what the messages mean; the message patterns are part of the core protocol and are the same on every binding.

stdio transport framing: newline-delimited JSON-RPC

In the MCP stdio transport the client launches the server as a subprocess. The server reads JSON-RPC messages from stdin and writes JSON-RPC messages to stdout. Each message is a single JSON-RPC request, notification, or response. Messages are delimited by newlines and MUST NOT contain embedded newlines.

stdio stderr rules (MAY log, SHOULD NOT treat as errors)

On the stdio transport the server MAY write UTF-8 strings to stderr for any logging purposes including informational, debug, and error messages. The client MAY capture, forward, or ignore the server's stderr output and SHOULD NOT assume stderr output indicates error conditions.

stdout/stdin purity MUST NOT rules

The server MUST NOT write anything to its stdout that is not a valid MCP message, and the client MUST NOT write anything to the server's stdin that is not a valid MCP message.

Custom stream transports reuse stdio framing

The stdio wire format (one newline-delimited JSON-RPC message per line over a reliable bidirectional byte stream) works unchanged over Unix domain sockets, TCP, or similar channels. Custom transports built on such streams SHOULD reuse this framing and the stdio message rules; only subprocess-specific aspects (launch, stderr, shutdown by closing the stream, process restart) need channel-specific equivalents.

stdio: client MUST NOT send JSON-RPC responses

On stdio the client sends JSON-RPC requests and notifications to the server's stdin, one message per line, and MUST NOT write JSON-RPC responses.

Three kinds of server messages on stdio stdout

Over stdio all server messages share the single stdout channel with no per-request streams. The server writes three kinds of messages: (1) responses to client requests correlated by JSON-RPC id, (2) notifications relating to an in-flight request such as notifications/progress and notifications/message, and (3) notifications delivered for an active subscriptions/listen request.

Era determination SHOULD be cached per server

The modern/legacy era determination is a property of the server, not of an individual request. Clients SHOULD cache the result for the lifetime of the server process (stdio) or origin (HTTP), and MAY persist it across restarts of the same server configuration, re-probing if the cached assumption later fails.

Detecting whether a server is modern or legacy

A client interoperating with both eras detects the server's era per transport: on stdio, probe with `server/discover` and fall back on any error that is not a recognized modern error; on Streamable HTTP, attempt a modern request and inspect the body of a `400 Bad Request` before falling back. A recognized modern JSON-RPC error (such as UnsupportedProtocolVersionError) identifies a modern server, so the client retries with a supported version instead of falling back; anything else identifies a legacy server.

Dual-era server selects behaviour from how the client opens

A dual-era server selects its behavior from the client's opening request: a request carrying modern per-request `_meta` is served statelessly according to the 2026-07-28 revision, while an `initialize` request selects legacy semantics scoped to the stdio process or the HTTP session as specified by the negotiated legacy protocol version. A dual-era server MAY serve both eras concurrently on the same endpoint or process.

2026-07-28 removes protocol sessions and Mcp-Session-Id

In MCP revision 2026-07-28, protocol-level sessions and the `Mcp-Session-Id` header were removed from the Streamable HTTP transport (SEP-2567). List endpoints (`tools/list`, `resources/list`, `prompts/list`) no longer vary per-connection. Servers needing cross-call state must use explicit, server-minted handles passed as ordinary tool arguments.

SSE resumability and Last-Event-ID removed; MUST re-issue with new request ID

Revision 2026-07-28 removes SSE stream resumability and message redelivery (the `Last-Event-ID` header and SSE event IDs) from the Streamable HTTP transport. A broken response stream loses the in-flight request, and clients MUST re-issue it as a new request with a new request ID.

Mcp-Method and Mcp-Name headers required on Streamable HTTP POST

Streamable HTTP POST requests must carry the standard MCP request headers `Mcp-Method` and `Mcp-Name`. Support was also added for custom headers derived from tool parameters via `x-mcp-header` (SEP-2243).

HTTP+SSE transport deprecated since 2025-03-26

The HTTP+SSE transport (defined in specification revision 2024-11-05) was deprecated in revision 2025-03-26 and reclassified as Deprecated under SEP-2596. Migration path: use the Streamable HTTP transport. Earliest removal: three months after SEP-2596 reaches Final.

x-mcp-header extension maps tool parameters to HTTP headers

The `x-mcp-header` extension property is placed directly inside the JSON Schema of a tool input property; its value gives the name portion of the resulting `Mcp-Param-{name}` HTTP header on Streamable HTTP requests. Example: a `region` property with "x-mcp-header": "Region" called with "region": "us-west1" makes the client add the header `Mcp-Param-Region: us-west1`. This lets load balancers, proxies and WAFs route without parsing the body.

stdio backward-compatibility probe uses server/discover first

On stdio there is no per-request HTTP status code to drive fallback, so a client that supports both modern servers (per-request `_meta`) and legacy servers (the `initialize` handshake) **SHOULD** send `server/discover` first, then apply the stdio backward-compatibility fallback rules.

Streamable HTTP: single MCP endpoint accepting POST only

In the 2026-07-28 Streamable HTTP transport, the server MUST provide a single HTTP endpoint path (the 'MCP endpoint', e.g. https://example.com/mcp) that supports POST. Every JSON-RPC request or notification is sent as its own HTTP POST. The server answers each request with either a single JSON object or an SSE stream scoped to that request. The GET stream endpoint and protocol-level sessions were removed in revision 2026-07-28.

Origin header validation and DNS rebinding (MUST)

Streamable HTTP servers MUST validate the Origin header on all incoming connections to prevent DNS rebinding attacks. If the Origin header is present and invalid, servers MUST respond with HTTP 403 Forbidden; the body MAY be a JSON-RPC error response with no id. Servers SHOULD bind only to localhost (127.0.0.1) rather than 0.0.0.0 when running locally, and SHOULD implement proper authentication for all connections.

Client POST requirements: Accept header and body content

Client rules for Streamable HTTP: (1) the client MUST use HTTP POST to send JSON-RPC messages; (2) the client MUST include an Accept header listing both application/json and text/event-stream; (3) the client MUST include the request metadata headers on each POST; (4) the POST body MUST be a single JSON-RPC request or notification and the client MUST NOT send JSON-RPC responses.

202 Accepted for accepted notifications

If the POST body is a JSON-RPC notification and the server accepts it, the server MUST return HTTP status 202 Accepted with no body. If it cannot accept it, the server MUST return an HTTP error status (e.g. 400 Bad Request) whose body MAY be a JSON-RPC error response with no id.

Response content types: application/json or text/event-stream

If the POST body is a JSON-RPC request, the server MUST return either Content-Type: application/json (a single JSON object) or Content-Type: text/event-stream (an SSE response stream). The client MUST support both content types.

Rules for SSE response streams (notifications before final response)

On an SSE response stream the server MAY send JSON-RPC notifications such as notifications/progress or notifications/message before the final response, and these notifications MUST relate to the originating client request. The server MUST NOT send independent JSON-RPC requests on this stream. The final JSON-RPC response SHOULD terminate the stream.

X-Accel-Buffering: no on SSE responses

When initiating an SSE stream, servers SHOULD include the header 'X-Accel-Buffering: no' in the HTTP response so reverse proxies such as nginx disable response buffering and deliver SSE events immediately.

Last-Event-ID resumability not supported

Resumable SSE streams via the Last-Event-ID header are not supported in the 2026-07-28 Streamable HTTP transport. A server implementing only this revision SHOULD ignore a Last-Event-ID header.

Standard request headers Mcp-Method and Mcp-Name

Two standard mirrored headers are REQUIRED for compliance: 'Mcp-Method' mirrors the JSON-RPC 'method' field and is required for all requests; 'Mcp-Name' mirrors params.name or params.uri and is required for tools/call, resources/read, and prompts/get requests. If the Mcp-Name source value cannot be safely represented as plain ASCII, clients MUST encode it using the Base64 sentinel format.

Header value encoding: type conversion and Base64 sentinel

Clients MUST encode parameter values before putting them in HTTP headers. Type conversion: string used as-is; integer converted to decimal string (e.g. 42, -7); boolean converted to lowercase "true"/"false". When a value cannot be safely represented as plain ASCII (non-ASCII characters, control characters, or leading/trailing whitespace), clients MUST Base64-encode the UTF-8 representation in the format 'Mcp-Param-{Name}: =?base64?{Base64EncodedValue}?='. The same rule applies to Mcp-Name. The prefix '=?base64?' and suffix '?=' are case-sensitive and MUST appear exactly in lowercase. Clients MUST also Base64-encode any plain-ASCII value that itself matches the sentinel pattern.

Base64 header encoding examples

Encoding examples: "us-west1" is plain ASCII so it is sent as 'Mcp-Param-Region: us-west1'; "Hello, 世界" contains non-ASCII so it becomes 'Mcp-Param-Greeting: =?base64?SGVsbG8sIOS4lueVjA==?='; " padded " has leading/trailing spaces so it becomes 'Mcp-Param-Text: =?base64?IHBhZGRlZCA=?='; "line1\nline2" contains a newline so it becomes 'Mcp-Param-Text: =?base64?bGluZTEKbGluZTI=?='; the literal "=?base64?literal?=" matches the sentinel pattern so it becomes 'Mcp-Param-Val: =?base64?PT9iYXNlNjQ/bGl0ZXJhbD89?='.

Server validation of mirrored headers against body

Servers that process the request body MUST reject requests where header values do not match the corresponding body values, preventing vulnerabilities when components rely on different sources of truth (e.g. a load balancer routing on the header while the server executes on the body). Validation failure conditions include: a required standard header (MCP-Protocol-Version, Mcp-Method, Mcp-Name) is missing; a header value does not match the body value (servers MUST Base64-decode Mcp-Name and Mcp-Param-{Name} sentinel values before comparing); or a header value contains invalid characters. When validating integer parameters, servers SHOULD compare numerically rather than as strings (42.0 equals 42).

Custom header matrix: when to include, omit, and reject

Behaviour matrix for Mcp-Param headers: when a parameter value is provided, the client MUST include the header and the server MUST validate that it matches the body; when the parameter value is null, the client MUST omit the header and the server MUST NOT expect it; when the parameter is not in arguments, the client MUST omit the header and the server MUST NOT expect it; when the client omits the header but the value is in the body, the client is non-conforming and the server MUST reject the request.

Intermediary handling of Mcp-Param headers

Intermediate servers that do not recognize an Mcp-Param-{Name} header MUST forward it and otherwise ignore it, per the HTTP Semantics RFC (RFC 9110). Servers MUST reject requests with a recognized Mcp-Param-{Name} header containing invalid characters. Intermediaries MUST return an appropriate HTTP error status (e.g. 400 Bad Request) for validation failures but are not required to return a JSON-RPC error response. Intermediaries enforcing policy on mirrored headers SHOULD verify the MCP-Protocol-Version header indicates a version requiring header–body validation, and SHOULD reject the request if the version is older or the header absent.

Header name case-insensitivity, value case-sensitivity

HTTP header names (field names per RFC 9110) are case-insensitive, and clients and servers MUST use case-insensitive comparisons for header names. Header values, such as method names, are case-sensitive.

Removed mechanisms from 2025-03-26..2025-11-25 Streamable HTTP

Protocol versions 2025-03-26 through 2025-11-25 used Streamable HTTP differently: servers could assign a session via the Mcp-Session-Id header (terminated with HTTP DELETE), clients could open a standalone SSE stream with HTTP GET for server-initiated messages, servers could send JSON-RPC requests on SSE streams, and streams were resumable via Last-Event-ID. None of these are part of the 2026-07-28 revision.

Handling legacy traffic: 405 for GET/DELETE, ignore session headers

A server supporting only the 2026-07-28 revision that receives legacy traffic SHOULD respond as follows: HTTP GET or DELETE to the MCP endpoint gets 405 Method Not Allowed; an Mcp-Session-Id header on a request is ignored and the server does not mint or echo session IDs; a Last-Event-ID header is ignored because streams are not resumable.

HTTP+SSE (2024-11-05) transport deprecated

The HTTP+SSE transport from protocol version 2024-11-05 has been deprecated since protocol version 2025-03-26 and is classified as Deprecated under the feature lifecycle policy (SEP-2596). New implementations SHOULD NOT adopt it; existing implementations SHOULD migrate to Streamable HTTP. It is eligible for removal in a future revision.

Client fallback procedure to legacy HTTP+SSE transport

Clients wanting to support old HTTP+SSE servers should: accept a server URL from the user; attempt to POST a request with the Accept header listing application/json and text/event-stream. If it succeeds, assume the new Streamable HTTP transport. If it fails with HTTP 400 Bad Request, 404 Not Found, or 405 Method Not Allowed AND the body is not a recognized modern JSON-RPC error, issue a GET to the URL expecting an SSE stream whose first event is an 'endpoint' event; when that event arrives, assume the old HTTP+SSE transport and use it for all subsequent communication. Servers supporting old clients should keep hosting both the old SSE and POST endpoints alongside the new MCP endpoint.

Give your agent this brain