# Model Context Protocol transports compared

Canonical: https://warmtransfer.net/knowledge/mcp-transport-differences

Last verified: 2026-09-30

MCP revision 2026-07-28 specifies two standard transport bindings, stdio and Streamable HTTP, while also permitting custom transports[^49]. Protocol semantics remain identical across every transport, with bindings defining message framing, delivery, request metadata handling, and termination signalling[^31].

## Protocol rules across transports

Regardless of the selected transport binding, MCP JSON-RPC messages MUST be UTF-8 encoded[^50]. A transport binding MUST deliver client-sent requests and notifications to the server, and server-sent responses and notifications to the client[^30]. No other message direction exists in MCP revision 2026-07-28, meaning servers do not initiate JSON-RPC requests and clients do not send JSON-RPC responses[^30].

All protocol metadata travels in the message body under `_meta` `io.modelcontextprotocol/*` fields[^1]. A binding MAY additionally mirror selected body fields into envelope metadata, but the body remains the source of truth[^1]. Custom transports MUST preserve the JSON-RPC message format, message patterns, and per-request metadata model[^4]. When a custom transport runs over a reliable bidirectional byte stream, such as Unix domain sockets or TCP, it SHOULD reuse stdio framing[^4].

MCP revision 2026-07-28 removed protocol-level sessions and the `Mcp-Session-Id` header from Streamable HTTP, and removed the `initialize` and `notifications/initialized` handshake so that every request carries its protocol version and client capabilities in `_meta`[^32].

## Standard transport mechanisms

| Capability or behavior | stdio | Streamable HTTP |
| --- | --- | --- |
| Execution context | Subprocess launched by client[^35] | Remote single HTTP POST endpoint[^21] |
| Framing format | Newline-delimited JSON-RPC without embedded newlines[^35] | HTTP POST request bodies with JSON or SSE responses[^20] |
| Stream structure | Single shared stdout channel without per-request streams[^43] | Per-request POST response or SSE stream[^20] |
| Metadata transport | Inline body metadata without header layer[^36] | Body metadata mirrored in HTTP headers[^1][^26] |
| Cancellation mechanism | `notifications/cancelled` referencing request ID[^34] | Closing the request SSE response stream[^9] |

### The stdio transport

In the stdio transport, the client launches the MCP server as a subprocess, delivering messages newline-delimited on stdin and stdout without embedded newlines[^35]. Stream purity is enforced: the server MUST NOT write anything to 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[^45]. The server MAY write UTF-8 strings to stderr for any logging purpose; clients MAY capture, forward, or ignore that output and SHOULD NOT assume stderr output indicates an error[^44].

Because all server messages share a single stdout channel without per-request streams, the server MUST NOT write JSON-RPC requests to stdout, and the client MUST NOT write JSON-RPC responses to stdin[^43][^37]. Server-to-client interactions are carried in `InputRequiredResult` replies[^37]. All request metadata is carried inline in the JSON-RPC message body, leaving stdio with no header layer[^36]. Clients using transports such as stdio MAY ignore `x-mcp-header` tool annotations entirely[^57].

To cancel an in-flight request on stdio, the client MUST send a `notifications/cancelled` notification referencing the request ID[^34]. Shutdown SHOULD be initiated by the client closing the server's stdin, waiting for the process to exit, and forcibly terminating it if it does not exit within a reasonable time[^42]. Servers SHOULD exit promptly when stdin is closed or reads return end-of-file[^42]. If the server exits unexpectedly, the client SHOULD restart it; in-flight requests are lost and can be retried against the new process[^38].

### The Streamable HTTP transport

Under Streamable HTTP in MCP revision 2026-07-28, the server MUST provide a single MCP endpoint path supporting POST, and every client JSON-RPC message MUST be a new HTTP POST to that endpoint[^21]. On each POST, the client MUST include an `Accept` header listing both `application/json` and `text/event-stream`[^8]. When the POST body is a JSON-RPC request, the server MUST return either `Content-Type: application/json` with a single JSON object or `Content-Type: text/event-stream` with an SSE stream, and clients MUST support both forms[^20]. When the POST body is an accepted JSON-RPC notification, the server MUST return HTTP 202 Accepted with no body[^18].

The server MUST NOT send independent JSON-RPC requests on an SSE response stream[^17]. Notifications on that stream MUST relate to the originating client request, and the final JSON-RPC response SHOULD terminate the stream[^17]. Closing an SSE response stream MUST be treated by the server as cancellation of that request, with no `notifications/cancelled` message required or expected[^9]. Streamable HTTP does not support SSE stream resumability or message redelivery; broken response streams lose in-flight requests, requiring clients to re-issue them with new request IDs[^16].

Servers SHOULD include an `X-Accel-Buffering: no` response header when initiating an SSE stream, and are encouraged non-normatively to emit periodic SSE comment lines as keep-alives on long-lived streams[^25].

### HTTP headers and validation

Every POST to the MCP endpoint MUST include an `MCP-Protocol-Version` header matching the `io.modelcontextprotocol/protocolVersion` field in the body's `_meta`[^27]. Additional headers are required based on the request type:[^26]

- The `Mcp-Method` header (mirroring `method`) is required on all requests[^26].
- The `Mcp-Name` header (mirroring `params.name` or `params.uri`) is required on `tools/call`, `resources/read`, and `prompts/get` requests[^26].
- Clients using Streamable HTTP MUST support `x-mcp-header` tool annotations, mirroring designated tool parameter values into `Mcp-Param-{name}` headers and excluding from `tools/list` results any tool whose annotation violates constraints[^57].

If mirrored headers are missing, malformed, or do not match the body, a server processing the body MUST reject the request with HTTP 400 Bad Request and JSON-RPC error code -32020 (`HeaderMismatch`)[^27][^10]. If the server does not implement the requested RPC method, it MUST return HTTP 404 Not Found with JSON-RPC error code -32601[^14]. If it does not implement the requested protocol version, it MUST return HTTP 400 Bad Request with an `UnsupportedProtocolVersionError` listing its supported versions[^14].

For security, Streamable HTTP servers MUST validate the `Origin` header on all incoming connections and respond with HTTP 403 Forbidden when it is present and invalid[^19]. Servers running locally SHOULD bind only to localhost (`127.0.0.1`), and SHOULD implement authentication for all connections[^13].

## Subscriptions and event delivery

MCP revision 2026-07-28 replaced the Streamable HTTP GET endpoint and legacy subscription methods with `subscriptions/listen`, establishing a single long-lived POST response stream for server-to-client change notifications[^7]. On Streamable HTTP, long-lived change notifications flow across the SSE response stream of this `subscriptions/listen` POST, whereas request-scoped notifications such as `notifications/progress` and `notifications/message` flow on the specific request's SSE stream[^12].

On stdio, active `subscriptions/listen` notifications share the common stdout channel, requiring clients to correlate them using the `io.modelcontextprotocol/subscriptionId` field in `_meta`[^46]. Across both transports, the server MUST send `notifications/subscriptions/acknowledged` before any other notification on a subscription[^33]. On stdio, this ordering is enforced per subscription ID, allowing messages from other subscriptions to interleave before the acknowledgment[^33].

A client cancels a `subscriptions/listen` subscription by closing the SSE stream on Streamable HTTP, or by sending a `notifications/cancelled` notification referencing the listen request ID on stdio[^29]. If an stdio connection terminates and re-establishes, the client MUST re-send `subscriptions/listen` because the server holds no subscription state across reconnections[^39].

## Backward compatibility and version evolution

Protocol revisions 2024-11-05 through 2025-11-25 specified that clients SHOULD support stdio whenever possible[^41]. Across revisions, remote HTTP transport behavior evolved through several iterations:[^22][^51][^52][^54]

- **Revision 2024-11-05**: Required two endpoints (SSE and HTTP POST) via the HTTP with SSE transport, sending an `endpoint` SSE event directing future POSTs[^22]. This transport was deprecated in revision 2025-03-26 under feature lifecycle policy SEP-2596, designating Streamable HTTP as its replacement with an earliest removal date 3 months after SEP-2596 reaches Final[^23].
- **Revision 2025-03-26**: Permitted Streamable HTTP POST bodies to batch arrays of requests, notifications, or responses[^51].
- **Revision 2025-06-18 and 2025-11-25**: Required POST bodies to be single JSON-RPC messages, eliminating array batching[^52]. Revision 2025-11-25 required MCP endpoints to support both GET and POST, permitted standalone GET SSE streams, allowed server session IDs via `MCP-Session-Id`, maintained resumability via `Last-Event-ID`, and treated disconnects as non-cancelling[^54][^53][^55].

A Streamable HTTP server supporting only revision 2026-07-28 SHOULD return 405 Method Not Allowed to GET or DELETE, SHOULD ignore `Mcp-Session-Id` without minting or echoing IDs, and SHOULD ignore `Last-Event-ID`[^11]. Because `MCP-Protocol-Version` was not defined prior to revision 2025-06-18, a modern server MAY treat an omitted header as protocol version 2025-03-26, or MUST reject it if earlier clients are unsupported[^56].

To maintain compatibility with legacy servers:
- On stdio, a dual-era client SHOULD probe with `server/discover` before sending other requests[^3]. Receiving a `DiscoverResult` or recognized modern error indicates a modern server, while any other error or timeout triggers fallback to `initialize` (which MUST NOT be keyed to a single error code)[^3].
- On Streamable HTTP, a dual-era client MAY attempt a modern request first; upon receiving a 400 Bad Request with an empty body or an unrecognized JSON-RPC error, it SHOULD fall back to `initialize`[^2].
- To support older HTTP+SSE servers, a client receiving a 400, 404, or 405 response lacking a modern JSON-RPC error issues a GET to obtain the legacy `endpoint` SSE event[^24].

Clients SHOULD cache era determinations for the lifetime of the process on stdio or origin on HTTP, and MAY persist them across restarts of identical configurations[^6]. In contrast, a legacy client connecting to a modern-only server always fails without fall-forward capability: stdio modern servers reject `initialize` with an implementation-defined error, and modern HTTP servers reject requests lacking required headers with 400 Bad Request[^28].

## See also

- [The MCP subscriptions listen stream and notification delivery](https://warmtransfer.net/knowledge/mcp-subscriptions-listen)
- [Webex published MCP servers for external AI clients](https://warmtransfer.net/knowledge/webex-mcp-servers)

## Applicability

Applies to: Model Context Protocol project MCP specification. Deployments: custom-transport, local-subprocess, and remote-http. Sources checked 2026-09-30. The specific protocols and rules documented here apply to MCP revisions 2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25, and 2026-07-28[^50][^35][^44][^8][^19][^13][^54][^53][^55][^51][^52][^22][^41]. Deployment models explicitly defined include local subprocesses, remote HTTP endpoints, and custom transport implementations[^49][^4][^35][^21].

## What remains uncertain

Header requirements for notification POSTs on Streamable HTTP are not defined by MCP revision 2026-07-28[^15].

The following items are not covered by the sources below:
- Which transport and MCP revision each Webex MCP server actually implements is not covered by the sources below.
- Authorization requirements by transport, including OAuth on Streamable HTTP versus credentials from environment on stdio, are not covered by the sources below.
- Official SDK support status for the 2026-07-28 stateless transports and dual-era fallback is not covered by the sources below.
- The server-initiated subscription teardown signal, including whether a successful listen response or notifications/cancelled is used, is not covered by the sources below.
- Whether SEP-2596 has reached Final and the resulting earliest removal date of HTTP+SSE is not covered by the sources below.
- Gateway and load balancer behaviour with Mcp-Method routing headers and long-lived SSE idle timeouts is not covered by the sources below.
- Custom transports in the field such as WebSocket or Unix socket bindings are not covered by the sources below.

## Sources

[^1]: In MCP revision 2026-07-28 all protocol metadata travels in the message body under _meta io.modelcontextprotocol/* fields; a binding MAY additionally mirror selected body fields into envelope metadata, but the body remains the source of truth. Source: [Overview (Transports) - MCP specification revision 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports), section Request Metadata. Checked 2026-09-30.
[^2]: On Streamable HTTP, a client that supports both modern and legacy MCP versions MAY detect the server's era by attempting a modern request first; on 400 Bad Request it SHOULD inspect the response body and fall back to initialize only if the body is empty or is not a recognized modern JSON-RPC error. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Backward Compatibility, introductory paragraph and bullets. Checked 2026-09-30.
[^3]: On stdio, a client that supports both modern (2026-07-28 and later) and legacy initialize-based MCP versions SHOULD probe with server/discover before any other request; a DiscoverResult or a recognized modern JSON-RPC error means the server is modern, while any other error or no response within a reasonable timeout means legacy and the client falls back to initialize, and the fallback MUST NOT be keyed to one specific error code. Source: [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio.md), section Backward Compatibility. Checked 2026-09-30.
[^4]: In MCP revision 2026-07-28 custom transports MUST preserve the JSON-RPC message format, the message patterns and the per-request metadata model, and custom transports that run over a reliable bidirectional byte stream such as Unix domain sockets or TCP SHOULD reuse the stdio framing. Source: [Overview (Transports) - MCP specification revision 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports), section Custom Transports, second and third paragraphs. Checked 2026-09-30.
[^5]: A Streamable HTTP client written for MCP revisions 2025-03-26 through 2025-11-25 that drops and later resumes a response stream would, against a 2026-07-28-only server, have its in-flight request cancelled rather than preserved, because the newer revision treats stream closure as cancellation and ignores Last-Event-ID (inferred). Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Cancellation; section Backward Compatibility, subsection Earlier Streamable HTTP Revisions. Checked 2026-09-30.
[^6]: In MCP revision 2026-07-28, clients SHOULD cache the modern-or-legacy era determination for the lifetime of the server process on stdio or of the origin on HTTP, and MAY persist it across restarts of the same server configuration, re-probing if the cached assumption later fails. Source: [Model Context Protocol specification 2026-07-28, Versioning and Compatibility](https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning), section Backward Compatibility with Initialization-Based Versions, paragraph beginning The era determination. Checked 2026-09-30.
[^7]: MCP revision 2026-07-28 replaced the Streamable HTTP GET endpoint and the resources/subscribe and resources/unsubscribe methods with subscriptions/listen, a single long-lived POST-response stream for opted-in server-to-client change notifications. Source: [Model Context Protocol specification 2026-07-28, Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog), section Major changes, item 4. Checked 2026-09-30.
[^8]: In Streamable HTTP the client MUST include an Accept header listing both application/json and text/event-stream on each POST. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Sending Messages, numbered item 2. Checked 2026-09-30.
[^9]: In Streamable HTTP under MCP revision 2026-07-28, the server MUST treat the closing of a request's SSE response stream as cancellation of that request; no notifications/cancelled message is required or expected. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Cancellation. Checked 2026-09-30.
[^10]: In Streamable HTTP under MCP revision 2026-07-28, a server that processes the request body MUST reject a request whose mirrored header values are missing, malformed or do not match the body, returning HTTP 400 Bad Request with JSON-RPC error code -32020 (HeaderMismatch). Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Request Metadata, subsection Server Validation. Checked 2026-09-30.
[^11]: A Streamable HTTP server that supports only MCP revision 2026-07-28 SHOULD respond to an HTTP GET or DELETE on the MCP endpoint with 405 Method Not Allowed, SHOULD ignore an Mcp-Session-Id header without minting or echoing session IDs, and SHOULD ignore a Last-Event-ID header. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Backward Compatibility, subsection Earlier Streamable HTTP Revisions. Checked 2026-09-30.
[^12]: In Streamable HTTP under MCP revision 2026-07-28, long-lived change notifications are delivered on the SSE response stream of a subscriptions/listen POST, while request-scoped notifications such as notifications/progress and notifications/message flow only on the response stream of the request they relate to. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Receiving Messages, paragraph beginning Long-lived notification streams. Checked 2026-09-30.
[^13]: In Streamable HTTP under MCP revision 2026-07-28, servers running locally SHOULD bind only to localhost (127.0.0.1) rather than all interfaces, and servers SHOULD implement proper authentication for all connections. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Security & Endpoint, items 2 and 3. Checked 2026-09-30.
[^14]: In Streamable HTTP under MCP revision 2026-07-28, a server that does not implement the requested RPC method MUST respond with 404 Not Found and a JSON-RPC error with code -32601, and a server that does not implement the requested protocol version MUST respond with 400 Bad Request and an UnsupportedProtocolVersionError listing its supported versions. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Request Metadata, subsection Protocol Version Header, fourth and fifth paragraphs. Checked 2026-09-30.
[^15]: MCP revision 2026-07-28 defines no client-to-server notifications over Streamable HTTP: the only client-sent core notification, notifications/cancelled, is used only on stdio, and header requirements for notification POSTs are not defined by the revision. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Sending Messages, Note box after the numbered list. Checked 2026-09-30.
[^16]: MCP revision 2026-07-28 removed SSE stream resumability and message redelivery (the Last-Event-ID header and SSE event IDs) from Streamable HTTP; a broken response stream loses the in-flight request and clients MUST re-issue it as a new request with a new request ID. Source: [Model Context Protocol specification 2026-07-28, Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog), section Major changes, item 9. Checked 2026-09-30.
[^17]: In Streamable HTTP under MCP revision 2026-07-28 the server MUST NOT send independent JSON-RPC requests on an SSE response stream; notifications on that stream MUST relate to the originating client request, and the final JSON-RPC response SHOULD terminate the stream. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Receiving Messages, bullet list. Checked 2026-09-30.
[^18]: In Streamable HTTP under MCP revision 2026-07-28, when the POST body is a JSON-RPC notification that the server accepts, the server MUST return HTTP 202 Accepted with no body. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Sending Messages, numbered item 5. Checked 2026-09-30.
[^19]: In Streamable HTTP under MCP revision 2026-07-28, servers MUST validate the Origin header on all incoming connections and MUST respond with HTTP 403 Forbidden when an Origin header is present and invalid. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Security & Endpoint, item 1. Checked 2026-09-30.
[^20]: In Streamable HTTP under MCP revision 2026-07-28, when the POST body is a JSON-RPC request the server MUST return either Content-Type application/json with a single JSON object or Content-Type text/event-stream with an SSE response stream, and the client MUST support both. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Sending Messages, numbered item 6. Checked 2026-09-30.
[^21]: In Streamable HTTP under MCP revision 2026-07-28 the server MUST provide a single MCP endpoint path that supports POST, and every JSON-RPC message sent by the client MUST be a new HTTP POST to that endpoint. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), introduction, final paragraph; section Sending Messages, first paragraph. Checked 2026-09-30.
[^22]: In the HTTP with SSE transport of MCP revision 2024-11-05, the server MUST provide two endpoints (an SSE endpoint and a regular HTTP POST endpoint) and, when a client connects, MUST send an endpoint event containing the URI the client is to use for all subsequent POSTed messages. Source: [Transports - MCP specification revision 2024-11-05](https://modelcontextprotocol.io/specification/2024-11-05/basic/transports), section HTTP with SSE, paragraphs following the Security Warning. Checked 2026-09-30.
[^23]: 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), with Streamable HTTP as the migration path and an earliest removal printed as three months after SEP-2596 reaches Final. Source: [Model Context Protocol specification 2026-07-28, Deprecated Features](https://modelcontextprotocol.io/specification/2026-07-28/deprecated), section Deprecated, table row HTTP+SSE transport. Checked 2026-09-30.
[^24]: Under MCP revision 2026-07-28, a client that wants to support older HTTP+SSE servers POSTs a request to the server URL and, if it fails with 400, 404 or 405 and the response body is not a recognized modern JSON-RPC error, issues a GET expecting an SSE stream whose first event is an endpoint event, after which it uses the old transport. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Backward Compatibility, subsection HTTP+SSE Transport (2024-11-05), Clients list. Checked 2026-09-30.
[^25]: In Streamable HTTP under MCP revision 2026-07-28, servers SHOULD include the X-Accel-Buffering: no response header when initiating an SSE stream, and are encouraged (non-normatively) to emit periodic SSE comment lines as keep-alives on long-lived streams such as the subscriptions/listen response. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Receiving Messages, paragraph on X-Accel-Buffering and the following Note box. Checked 2026-09-30.
[^26]: In Streamable HTTP under MCP revision 2026-07-28, the Mcp-Method header (mirroring method) is required on all requests and the Mcp-Name header (mirroring params.name or params.uri) is required on tools/call, resources/read and prompts/get requests. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Request Metadata, subsection Standard Request Headers, table. Checked 2026-09-30.
[^27]: In Streamable HTTP under MCP revision 2026-07-28, every POST to the MCP endpoint MUST include an MCP-Protocol-Version header whose value MUST match the io.modelcontextprotocol/protocolVersion field in the request body's _meta; on mismatch the server MUST reject with 400 Bad Request and a HeaderMismatch JSON-RPC error. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Request Metadata, subsection Protocol Version Header, first three paragraphs. Checked 2026-09-30.
[^28]: Per the MCP 2026-07-28 compatibility matrix, a legacy client against a modern-only server fails: on stdio the server rejects initialize with an implementation-defined JSON-RPC error, and on HTTP the request lacks the required headers and is rejected with 400 Bad Request; legacy clients have no fall-forward mechanism. Source: [Model Context Protocol specification 2026-07-28, Versioning and Compatibility](https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning), subsection Compatibility Matrix, row Legacy client / Modern server. Checked 2026-09-30.
[^29]: In MCP revision 2026-07-28 a client cancels a subscriptions/listen subscription by closing the SSE stream on Streamable HTTP, or by sending notifications/cancelled referencing the subscriptions/listen request ID on stdio. Source: [Model Context Protocol specification 2026-07-28, Subscriptions](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions), section Cancellation, first bullet. Checked 2026-09-30.
[^30]: In MCP revision 2026-07-28 a transport binding MUST deliver client-sent requests and notifications to the server and server-sent responses and notifications to the client; no other message direction exists, so servers do not initiate JSON-RPC requests and clients do not send JSON-RPC responses. Source: [Overview (Transports) - MCP specification revision 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports), section Messages, second paragraph. Checked 2026-09-30.
[^31]: In MCP revision 2026-07-28 protocol semantics are identical on every transport; a transport is a binding that defines only message framing and delivery, how request metadata is carried, and how cancellation and termination are signalled. Source: [Overview (Transports) - MCP specification revision 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports), Overview, second paragraph. Checked 2026-09-30.
[^32]: MCP revision 2026-07-28 removed protocol-level sessions and the Mcp-Session-Id header from the Streamable HTTP transport, and removed the initialize / notifications/initialized handshake so that every request carries its protocol version and client capabilities in _meta. Source: [Model Context Protocol specification 2026-07-28, Key Changes](https://modelcontextprotocol.io/specification/2026-07-28/changelog), section Major changes, items 1 and 2. Checked 2026-09-30.
[^33]: In MCP revision 2026-07-28 the server MUST send notifications/subscriptions/acknowledged before any other notification on a subscription; on stdio this ordering is defined per subscription ID rather than per channel, so messages belonging to other subscriptions MAY be interleaved before it. Source: [Model Context Protocol specification 2026-07-28, Subscriptions](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions), section Acknowledgment, first paragraph. Checked 2026-09-30.
[^34]: On stdio in MCP revision 2026-07-28 the client MUST cancel an in-flight request by sending a notifications/cancelled notification that references the request ID, because there is no per-request stream to close. Source: [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio.md), section Cancellation. Checked 2026-09-30.
[^35]: In the stdio transport the client launches the MCP server as a subprocess, and messages are newline-delimited on stdin and stdout and MUST NOT contain embedded newlines. Source: [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio.md), stdio page, opening paragraph and bullet list. Checked 2026-09-30.
[^36]: On stdio in MCP revision 2026-07-28 all request metadata is carried inline in the JSON-RPC message body; there is no header layer. Source: [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio.md), section Request Metadata. Checked 2026-09-30.
[^37]: On stdio in MCP revision 2026-07-28 the server MUST NOT write JSON-RPC requests to stdout and the client MUST NOT write JSON-RPC responses to stdin; server-to-client interactions are carried in InputRequiredResult replies. Source: [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio.md), sections Sending Messages and Receiving Messages (final paragraph). Checked 2026-09-30.
[^38]: On stdio in MCP revision 2026-07-28, if the server process exits unexpectedly the client SHOULD restart it; in-flight requests are lost and can be retried against the fresh process. Source: [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio.md), section Unexpected Termination. Checked 2026-09-30.
[^39]: On stdio in MCP revision 2026-07-28, if the connection is terminated and then re-established the client MUST re-send subscriptions/listen to re-establish its subscriptions, because the server holds no subscription state across reconnections. Source: [Model Context Protocol specification 2026-07-28, Subscriptions](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions), section Cancellation, subsection Graceful Closure, paragraph beginning On stdio. Checked 2026-09-30.
[^40]: MCP revision 2026-07-28 appears to no longer recommend that clients support stdio whenever possible: the sentence is absent from the 2026-07-28 transports overview and stdio pages as retrieved (inferred). Source: [Overview (Transports) - MCP specification revision 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports), Overview, introductory paragraphs (absence of the sentence). Checked 2026-09-30.
[^41]: MCP revisions 2024-11-05, 2025-03-26, 2025-06-18 and 2025-11-25 each state that clients SHOULD support stdio whenever possible. Source: [Transports - MCP specification revision 2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports), Transports page, introduction, sentence after the numbered list. Checked 2026-09-30.
[^42]: On stdio in MCP revision 2026-07-28 the client SHOULD initiate shutdown by closing the server's input stream, waiting for the server to exit, and forcibly terminating the process if it does not exit within a reasonable time; servers SHOULD exit promptly when stdin is closed or reads return end-of-file. Source: [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio.md), section Shutdown. Checked 2026-09-30.
[^43]: On stdio in MCP revision 2026-07-28 all server messages share the single stdout channel; there are no per-request streams. Source: [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio.md), section Receiving Messages, first paragraph. Checked 2026-09-30.
[^44]: On stdio the server MAY write UTF-8 strings to stderr for any logging purpose, and the client MAY capture, forward or ignore that output and SHOULD NOT assume stderr output indicates an error condition. Source: [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio.md), stdio page, opening bullet list, stderr bullets. Checked 2026-09-30.
[^45]: On stdio the server MUST NOT write anything to 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. Source: [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio.md), stdio page, opening bullet list, last two bullets. Checked 2026-09-30.
[^46]: On stdio in MCP revision 2026-07-28 clients MUST correlate notifications delivered for an active subscriptions/listen request using the io.modelcontextprotocol/subscriptionId field in _meta. Source: [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio.md), section Receiving Messages, numbered item 3. Checked 2026-09-30.
[^47]: The MCP 2026-07-28 Cancellation page says a server MUST send notifications/cancelled referencing a subscriptions/listen request ID when it tears down that subscription stream, and MUST NOT send notifications/cancelled for any other purpose (disputed). Source: [Cancellation - MCP specification revision 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/cancellation), introduction, second paragraph; section Behavior Requirements item 2. Checked 2026-09-30.
[^48]: The MCP 2026-07-28 Subscriptions page says that a server ending a subscription on its own initiative SHOULD send a successful subscriptions/listen response (resultType complete) before closing the stream, and describes no server-sent notifications/cancelled (disputed). Source: [Model Context Protocol specification 2026-07-28, Subscriptions](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions), section Cancellation, second bullet, and subsection Graceful Closure. Checked 2026-09-30.
[^49]: MCP revision 2026-07-28 specifies two standard transport bindings, stdio and Streamable HTTP, and also permits custom transports. Source: [Overview (Transports) - MCP specification revision 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports), Overview, introductory paragraphs (numbered list of binding pages). Checked 2026-09-30.
[^50]: MCP JSON-RPC messages MUST be UTF-8 encoded regardless of transport. Source: [Overview (Transports) - MCP specification revision 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports), section Messages, first paragraph. Checked 2026-09-30.
[^51]: In MCP revision 2025-03-26, the body of a Streamable HTTP POST could be a single JSON-RPC request, notification or response, or an array batching one or more requests and/or notifications, or an array batching one or more responses. Source: [Transports - MCP specification revision 2025-03-26](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports), section Streamable HTTP, subsection Sending Messages to the Server, item 3. Checked 2026-09-30.
[^52]: In MCP revision 2025-06-18, the body of a Streamable HTTP POST MUST be a single JSON-RPC request, notification or response; the batching alternatives printed in revision 2025-03-26 are absent. Source: [Transports - MCP specification revision 2025-06-18](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports), section Streamable HTTP, subsection Sending Messages to the Server, item 3. Checked 2026-09-30.
[^53]: In MCP revision 2025-11-25, a Streamable HTTP disconnection SHOULD NOT be interpreted as the client cancelling its request, and to cancel the client SHOULD explicitly send an MCP CancelledNotification. Source: [Transports - MCP specification revision 2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports), section Streamable HTTP, subsection Sending Messages to the Server, item 6, Disconnection bullets. Checked 2026-09-30.
[^54]: In MCP revision 2025-11-25, the Streamable HTTP MCP endpoint MUST support both POST and GET, the client MAY open a standalone SSE stream with HTTP GET, and the server MAY assign a session ID in an MCP-Session-Id header on the response containing the InitializeResult, which the client MUST then include on all subsequent HTTP requests. Source: [Transports - MCP specification revision 2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports), section Streamable HTTP, introduction; subsections Listening for Messages from the Server and Session Management. Checked 2026-09-30.
[^55]: In MCP revision 2025-11-25, a Streamable HTTP client wishing to resume after a disconnection SHOULD issue an HTTP GET to the MCP endpoint with a Last-Event-ID header, and the server MAY replay messages that would have been sent after that event ID on the disconnected stream. Source: [Transports - MCP specification revision 2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports), section Streamable HTTP, subsection Resumability and Redelivery, item 2. Checked 2026-09-30.
[^56]: The MCP-Protocol-Version HTTP header was not defined by protocol versions earlier than 2025-06-18; under revision 2026-07-28 a server that supports such clients MAY treat a request omitting the header as protocol version 2025-03-26, and a server that does not support them MUST reject the request. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Request Metadata, subsection Protocol Version Header, final paragraph. Checked 2026-09-30.
[^57]: In MCP revision 2026-07-28, clients using Streamable HTTP MUST support x-mcp-header annotations, mirroring designated tool parameter values into Mcp-Param-{name} headers and excluding from tools/list results any tool whose annotation violates the constraints, whereas clients using other transports such as stdio MAY ignore x-mcp-header annotations entirely. Source: [Model Context Protocol specification 2026-07-28, Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http), section Request Metadata, subsection Custom Headers from Tool Parameters, and Schema Extension final paragraph. Checked 2026-09-30.
