Overview
Streamable HTTP is the standard remote transport for MCP, introduced in spec revision 2025-03-26 to replace the older HTTP+SSE transport. It runs on a single HTTP endpoint that the client POSTs to and that the server may upgrade to a request-scoped SSE stream when it needs to push messages. As of the 2026-07-28 spec revision, the transport is also stateless: the connection-scoped Mcp-Session-Id header from the 2025-03-26 through 2025-06-18 revisions is retired in favor of per-request metadata, described below. For the stdio-vs-remote choice, see mcp-transports; for the JSON-RPC framing that rides on top, see mcp-protocol.
Use one endpoint for both directions
Streamable HTTP exposes a single MCP endpoint, conventionally /mcp. The client sends every JSON-RPC message as an HTTP POST to that endpoint with an Accept header listing both application/json and text/event-stream.
- When the server can answer immediately, it returns a single JSON response.
- When the server needs to stream notifications, progress, or several messages, it answers the same POST with an SSE stream and closes it when the exchange is done.
- The client may also open a standalone GET to the endpoint to receive server-initiated messages outside any request.
There is no separate channel to keep alive. This is the key difference from the deprecated HTTP+SSE design.
Carry protocol version and capabilities in the request body, not a session header
Under the current (2026-07-28) spec, every request carries its own protocol version and client capabilities in _meta.io.modelcontextprotocol/* fields in the JSON-RPC body. Streamable HTTP mirrors selected fields into HTTP headers so intermediaries can route without parsing the body, but the body remains the source of truth.
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
{
"jsonrpc": "2.0", "id": 2, "method": "tools/list",
"_meta": { "io.modelcontextprotocol/clientCapabilities": {} }
}For rate limiting and audit correlation, key state on a per-request identifier rather than a connection-scoped session; see mcp-security for the isolation rules. Servers that still speak the 2025-03-26 through 2025-06-18 revisions assign a session by setting Mcp-Session-Id on the initialize response, and the client echoes it on every subsequent request; treat that pattern as legacy when building new servers.
Resume dropped streams with Last-Event-ID
Streamable HTTP supports resumable streams. When the server emits SSE events, it tags each with an id. If the connection drops mid-stream, the client reconnects and sends the last id it saw in the Last-Event-ID header. The server replays only the events after that id, so no message is delivered twice and none is lost.
Implement reconnection with exponential backoff. Resume by Last-Event-ID where the prior exchange was streaming; otherwise retry the request fresh, since there is no session to re-establish.
Migrate off the deprecated HTTP+SSE transport, and off session-scoped state
The HTTP+SSE transport (spec revision 2024-11-05) is deprecated with a year-long offramp. Treat it as legacy:
- New servers implement Streamable HTTP only.
- Clients that must talk to old servers can negotiate by attempting Streamable HTTP first, then falling back to the two-endpoint SSE flow on failure.
- Do not build new integrations against the separate SSE-channel design; it carries the reconnection and load-balancer fragility that Streamable HTTP was created to fix.
Separately, new servers should not depend on Mcp-Session-Id for correctness. The 2026-07-28 revision removed the connection-scoped session model so requests can land on any server instance without shared state; design new deployments around per-request metadata from the start.