MP-201c · Module 1
Streamable HTTP
4 min read
Streamable HTTP is MCP's remote transport protocol, designed for servers that live on the network rather than on the local machine. The pattern is straightforward: the client sends JSON-RPC requests as HTTP POST bodies to a single endpoint, and the server responds either with a direct JSON response or upgrades the connection to a Server-Sent Events (SSE) stream for long-running operations. This dual-mode response is what makes it "streamable" — short requests get immediate answers, long requests get progressive updates.
Session management in Streamable HTTP uses a server-issued session token returned in the Mcp-Session-Id response header. The client must include this token in all subsequent requests. This is how the server correlates requests from the same logical session — tool state, conversation context, and capability negotiations are all scoped to the session ID. If the client omits the session ID, the server may reject the request or start a new session, losing accumulated state.
The GET endpoint serves a different purpose: it opens a long-lived SSE stream for server-initiated messages. This is how MCP servers push notifications, progress updates, and resource-change events to the client without the client polling. The client maintains one persistent GET connection for receiving pushes and sends individual POST requests for each RPC call. Reconnection on the GET stream should be automatic — the EventSource API handles this natively in browsers, but custom clients need explicit retry logic with the Last-Event-ID header.
Do This
- Use direct JSON responses for fast operations (< 1 second)
- Upgrade to SSE streams only for long-running tools that benefit from progress updates
- Include Mcp-Session-Id in every request when using stateful servers
- Implement automatic reconnection with Last-Event-ID on the GET SSE stream
Avoid This
- Stream every response regardless of duration — the overhead is not worth it for fast calls
- Ignore the session token and hope the server figures it out
- Use WebSockets instead of SSE — MCP specifies SSE for a reason (simpler, HTTP-native, proxy-friendly)
- Forget to handle the case where a session token expires mid-conversation