MCP Deep Dive Part 3 — From SSE to Streamable HTTP
Why Regular HTTP Doesn't Work
Regular HTTP has a structure where the client makes a request, the server responds, and the connection closes. This simple structure creates two problems for MCP.
First, you can't see intermediate progress. Bulk searching issues in Jira or calling external APIs multiple times can take several seconds. With regular HTTP, the client just has to wait until the result comes out. There's no way for the server to say "50% done" in the middle of processing.
Second, connection re-establishment costs are high. MCP's agentic loop involves repeated tool_calls. With regular HTTP, you'd have to repeat TCP connection establishment → TLS handshake → HTTP header exchange every time.
The Emergence of SSE (Server-Sent Events)
The initial version of MCP (2024-11-05) solved this problem with SSE.
SSE starts a response with Content-Type: text/event-stream and then, without closing the connection, the server pushes data whenever it wants.
data: {"type":"progress","value":30}\n\n
data: {"type":"progress","value":70}\n\n
data: {"type":"result","issues":[...]}\n\nUnlike WebSocket, SSE operates over regular HTTP, so it passes through existing infrastructure like firewalls, nginx proxies, and AWS ALB without any special configuration. This is why SSE was advantageous for early MCP adoption.
SSE's Structure: Two Endpoints
However, SSE is a unidirectional stream from server→client. Client→server messages had to be sent via separate HTTP POST. As a result, the old MCP SSE approach required managing two endpoints.
sequenceDiagram
participant C as Client
participant S as MCP Server
C->>S: GET /sse (establish connection)
S-->>C: SSE stream open
C->>S: POST /message (tool_call)
S-->>C: SSE event (progress 30%)
S-->>C: SSE event (progress 70%)
S-->>C: SSE event (result)This structure had three problems:
- Managing 2 endpoints —
/sseand/messagemust be maintained separately - Response loss on connection failure — If the SSE connection drops, in-progress work results are lost
- Forced state maintenance — Server must maintain long-lived connections per client, making scale-out difficult
SSE With the SSE approach, the server must maintain each client's connection in memory. When hundreds of clients connect simultaneously, server resource burden increases linearly, and if you put multiple servers behind a load balancer, Sticky Session configuration becomes necessary.
Streamable HTTP — MCP's Current Standard
In the March 26, 2025 MCP spec update (version 2025-03-26), SSE was deprecated and Streamable HTTP became the official standard.
Core Change: Single Endpoint
Streamable HTTP handles both POST and GET with a single /mcp endpoint. And the server dynamically decides the response method.
Client → POST /mcp (tool_call)
Server response option A → 200 OK + JSON body (simple result)
Server response option B → 200 OK + text/event-stream (upgrade to SSE when streaming needed)sequenceDiagram
participant C as Client
participant S as MCP Server
C->>S: POST /mcp (initialize)
S-->>C: 200 OK + Mcp-Session-Id: abc123
C->>S: POST /mcp (tool_call, Session-Id: abc123)
S-->>C: SSE stream (upgrade if needed)
S-->>C: data: progress 30%
S-->>C: data: progress 70%
S-->>C: data: resultSSE didn Streamable HTTP didn't abandon SSE. It removed the "forced requirement to always keep an SSE connection open". Responses that need streaming still push data in SSE format. The decision just moved to the server's hands.
SSE vs Streamable HTTP Comparison
| Item | HTTP+SSE (old) | Streamable HTTP (new) |
|---|---|---|
| Endpoints | 2 endpoints: /sse + /message | Single /mcp endpoint |
| Connection method | Always persistent connection | Stream upgrade only when needed |
| Server architecture | Forced stateful | Supports stateless |
| Connection drop recovery | Response loss | Resumable with Mcp-Session-Id |
| Serverless deployment | Not possible | Possible (Lambda, etc.) |
| Infrastructure compatibility | Standard HTTP | Standard HTTP (same) |
Mcp-Session-Id — The Key to Session Resumption
The newly introduced Mcp-Session-Id header in Streamable HTTP enables connection resumption.
The server includes a session ID in the initialization response. The client then attaches this ID as a header in all subsequent requests.
POST /mcp HTTP/1.1
Content-Type: application/json
Mcp-Session-Id: abc123-xyz789
{"jsonrpc":"2.0","id":5,"method":"jira_search","params":{...}}Even if Wi-Fi drops and reconnects, if you reconnect with the same session ID, the server can pick up the previous context and continue processing. Even if you put your laptop in sleep mode and wake it up, agentic work continues without interruption.
Why Not WebSocket
The reason for not using WebSocket, which supports bidirectional real-time communication, is also clear.
MCP's communication pattern is sufficiently served by HTTP POST for client→server and optional SSE stream for server→client. True bidirectionality isn't needed.
And WebSocket requires an Upgrade header, which often requires special configuration in corporate firewalls or proxies. You also can't attach an Authorization header in browsers. Streamable HTTP is standard HTTP POST/GET, so existing infrastructure (WAF, ALB, nginx) works as-is.
Practical Implications
From the perspective of operating an MCP Server in a container environment like ECS, the transition to Streamable HTTP brings two practical changes.
Scale-out becomes easier. The SSE approach required Sticky Session configuration. Requests from a specific client had to always go to the same server instance. With Streamable HTTP + stateless server architecture, the load balancer can send requests to any instance, and state can be restored with the session ID.
More resilient to connection instability. Even if the network drops during a long-running agentic task, the session can be resumed. Client restarts or network hiccups don't result in work failure.
Summary
MCP's transport layer evolved in the order: regular HTTP → HTTP+SSE → Streamable HTTP.
- Regular HTTP only allows unidirectional request-response, no real-time streaming
- HTTP+SSE solved streaming but forced two endpoints and stateful servers
- Streamable HTTP overcomes all these limitations with single endpoint + optional SSE + session resumption
Over these three parts of the series, we've examined MCP's concepts, JSON-RPC 2.0, and transport layer. Understanding how these three layers mesh together makes it clear where to look when designing or troubleshooting an MCP Server.
MCP Official Spec — Transports — Official specification documentation for the Streamable HTTP transport layer