← Guides

Guide

Streamable HTTP vs SSE: MCP Transports Explained

August 18, 2026 · 7 min read

If you run a remote MCP server in 2026, you're dealing with two HTTP transports: the original HTTP+SSE pair from the first public spec, and Streamable HTTP, which replaced it. Plenty of servers still speak only the old one, plenty of clients still fall back to it, and the differences are exactly the kind of thing that breaks quietly during a migration. Here's how the two actually work on the wire and what to do about it.

A short history

The 2024-11-05 revision of MCP defined two transports: stdio for local servers, and HTTP+SSE for remote ones. The 2025-03-26 revision replaced HTTP+SSE with Streamable HTTP, and later revisions (2025-06-18 onward) refined it — most notably requiring the MCP-Protocol-Version header on subsequent requests. HTTP+SSE has been deprecated for years now, but "deprecated" and "gone" are different things: a long tail of tutorials, templates, and deployed servers keeps it alive.

How HTTP+SSE works

The old transport splits the conversation across two endpoints:

  • The client opens a long-lived GET to an SSE endpoint (conventionally /sse).
  • The server's first SSE message is an endpoint event containing a URL, usually with a session token baked in.
  • The client POSTs every JSON-RPC message to that URL, and every response comes back over the SSE stream — the POSTs themselves just return 202.

The design works, but the always-open GET is the weakness: it ties a session to one connection on one server instance, which fights load balancers, serverless platforms that bill by connection time, and proxies that kill idle streams. Losing the stream loses the session.

How Streamable HTTP works

Streamable HTTP collapses everything onto a single endpoint (conventionally /mcp):

  • The client POSTs each JSON-RPC message to the endpoint with Accept: application/json, text/event-stream.
  • The server chooses per request: answer with a plain application/json body, or open an SSE stream for that request — useful for streaming progress before the final result.
  • Sessions are explicit and header-based: the server may return Mcp-Session-Id on initialize, and the client echoes it on every later request.
  • An optional standing GET lets servers push unsolicited messages; servers that don't need it simply return 405.
  • SSE messages can carry event IDs, and a client can resume a broken stream with Last-Event-ID — reconnection is part of the design rather than a session-ending event.

The practical consequence: a Streamable HTTP server can be completely stateless per request, which is why it deploys cleanly to serverless platforms and behind ordinary load balancers.

What clients expect in 2026

Streamable HTTP is the default everywhere that matters — the official SDKs, Claude, and the major MCP client implementations all speak it first. Well-behaved clients still implement a fallback dance for legacy servers: try a POST to the given URL, and if it fails in a way that suggests an old server, attempt a GET expecting an SSE endpoint event. But you cannot rely on every client doing this, and the fallback adds a failed round trip to every connection. A new server has no reason to expose only SSE; an old one serving real traffic should migrate.

Migration notes

  • Add, don't replace. Serve Streamable HTTP on /mcp while keeping the legacy /sse endpoint alive until traffic on it dies. Both can share the underlying server logic; only the transport layer differs.
  • Make sessions real. If you issue Mcp-Session-Id, store sessions somewhere all instances can reach, and return 404 for unknown sessions so clients know to re-initialize — see the session failure modes.
  • Fix your proxy config. SSE responses on the new endpoint still need buffering disabled and generous read timeouts, same as the old one.
  • Honor the version header. Accept MCP-Protocol-Version on requests and validate it against what you negotiated — silently ignoring it hides client bugs; rejecting it without supporting the negotiation flow breaks valid clients.
  • Watch both endpoints during the transition. A migration is precisely when handshake regressions appear, and they'll appear on whichever endpoint you're not manually testing. Scheduled checks against both — the approach in our monitoring guide — cover the gap.

If you're unsure what your server actually speaks today, a single POST tells you: a Streamable HTTP server answers initialize directly; a legacy server typically returns 404 or 405 on the POST and only makes sense once you GET its SSE endpoint. The curl walkthrough shows the exact requests.