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 collapses the previous two-endpoint design (a long-lived SSE channel plus a separate POST endpoint) into a single HTTP endpoint that the client POSTs to and that the server may upgrade to a stream when it needs to push messages. 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.
Track the session with Mcp-Session-Id
On initialize, the server may assign a session by setting the Mcp-Session-Id response header. The client must echo that header on every subsequent request. The server uses it to key per-session state: rate-limit counters, scoped credentials, and audit logs. See mcp-security for per-session isolation rules.
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
Mcp-Session-Id: 1a2b3c4d
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }When a session ends, the client sends an HTTP DELETE to the endpoint with the session header. A server that no longer recognizes a session ID returns 404, and the client starts a fresh initialize.
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 re-send initialize on a new session.
Migrate off the deprecated HTTP+SSE transport
The HTTP+SSE transport (spec revision 2024-11-05) is deprecated. 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.