From Server-Sent Events to Streamable HTTP: How MCP Fixed Its Deployment Problem
Source: hackernews
The original MCP spec, released in November 2024, arrived with a straightforward premise: give language models a standard way to connect to external tools, data sources, and services. The protocol built on JSON-RPC 2.0, defined three primitive types (Tools, Resources, and Prompts), and provided two transport options: stdio for local processes and HTTP+SSE for remote servers. Sixteen months later, the question being raised is whether the MCP which exists today is meaningfully the same protocol as the one that launched, and the answer turns on a specific design decision about HTTP transport.
Why HTTP+SSE Was Always Going to Struggle
The stdio transport held up well. You spawn a child process, communicate over stdin and stdout, and exchange JSON-RPC messages. Straightforward, reliable, and requiring no infrastructure management. If you are building local tooling or a coding assistant that manages its own server processes, stdio in early 2026 looks nearly identical to stdio in late 2024.
The HTTP+SSE transport is where the original spec ran into the gap between design and deployment. Server-Sent Events requires a persistent HTTP connection. The client connects to a /sse endpoint and keeps that connection open while the server pushes events. For browser push notifications or real-time dashboards, SSE is a reasonable choice. For a bidirectional RPC protocol deployed to modern infrastructure, it creates immediate problems.
Load balancers terminate idle connections after 30 to 120 seconds. Serverless platforms like Lambda, Cloud Run, and Vercel Functions assume each invocation is stateless and short-lived; persistent connections are not supported. Reverse proxies buffer streaming responses or strip chunked transfer encoding headers. HTTP/2 multiplexing changes the semantics of persistent connections in ways that interact poorly with SSE’s assumptions. None of these are exotic edge cases. They describe the majority of production HTTP infrastructure that MCP servers were expected to run on.
The original transport also required two distinct endpoints and a multi-step handshake: establish a GET connection to /sse, receive a session endpoint URL via an endpoint event, then POST to that session-specific URL for all subsequent messages. Two connection types, stateful session tracking on the server, and a persistent background connection that most hosting platforms actively work against.
What Streamable HTTP Actually Changed
The March 2025 spec revision replaced HTTP+SSE with what the spec calls Streamable HTTP. The conceptual shift is worth stating directly: instead of a persistent SSE connection as the transport layer, you have a standard HTTP endpoint that can optionally stream its response.
A client sends a POST request to a single endpoint with the JSON-RPC message as the body. The server responds with either a standard JSON body for simple interactions, or an SSE stream for long-running operations where incremental results matter. An optional GET endpoint lets the server initiate its own event stream, but that is genuinely optional for many use cases.
The initialization exchange looks like standard HTTP:
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": { "tools": {} },
"clientInfo": { "name": "my-client", "version": "1.0.0" }
}
}
The server can respond with a plain JSON body. Subsequent tool calls follow the same pattern; streaming is opt-in at the response level, not a requirement at the connection level. This maps cleanly to how load balancers, serverless runtimes, and reverse proxies handle ordinary HTTP traffic.
The spec also added support for resumable streams via the Last-Event-ID header, which matters for long-running tool operations where a network interruption would otherwise require restarting the operation from scratch.
The Security Problem the Transport Redesign Left Alone
Moving to Streamable HTTP addressed deployment complexity. The security model remained largely untouched, and it was the more pressing concern throughout MCP’s first year.
The original spec had no mandatory authentication mechanism. Servers were expected to implement their own auth, which in practice meant a significant portion of tutorial implementations ran unauthenticated, and the ecosystem grew with inconsistent security practices across published servers.
Tool injection is the attack pattern most specific to MCP. If a model is connected to an MCP server and that server returns malicious tool descriptions or crafted tool outputs, the model may execute unintended operations as if they were legitimate requests. The threat is more serious than ordinary prompt injection because the attack arrives through a privileged channel: the model has been specifically configured to trust tool responses from that server. Security researchers documented scenarios where a compromised MCP server could instruct the model to exfiltrate data through other connected tools, or invoke tools with attacker-controlled parameters. The confused deputy problem, which has recurred in ambient authority systems for decades, surfaced in MCP almost immediately after launch.
OAuth 2.0 support was added to the spec as a recommended authentication mechanism. Uptake across third-party servers has been uneven. A protocol specification can require auth; it cannot force every developer publishing an MCP server to implement it correctly.
What the Ecosystem Built, and Where It Cut Corners
By early 2026, the MCP server registry has grown to thousands of integrations. This reflects genuine adoption and also a quality distribution problem that no spec revision addresses.
Many servers are thin wrappers around REST APIs that offer no meaningful benefit over direct API calls. The three-primitive model was designed with specific semantics: Resources are things the model reads with no external side effects; Tools are actions with real-world consequences that may require explicit user permission; Prompts are reusable templates with defined parameters. A large portion of implementations collapse everything into Tools and ignore Resources entirely.
This matters for access control. A client that wants to distinguish between the model reading data and the model initiating an action needs the Resource and Tool distinction to be used correctly. When a server exposes file reads, database queries, and write operations all as Tools, the permission model a client might want to enforce becomes harder to reason about. The difference between resources/read and tools/call in the protocol is meaningful; collapsing them is a design choice that compounds the security problems the spec already has.
The official Python and TypeScript SDKs have been updated for the current spec. Testing and debugging tooling has improved substantially since the original release. The gap between what the spec intends and what a large portion of published servers implement has not closed as quickly.
Whether This Is Still the Same Protocol
The Streamable HTTP transport is not backward-compatible with the original SSE transport. A server built against the 2024 spec does not work with a client implementing the 2025 revision without code changes. That makes the version boundary real, not just nominal.
The stdio transport has not changed significantly. Local MCP integrations built in 2024 largely continue to work. The breaking changes are concentrated in the remote server scenario, which is where deployment complexity, security concerns, and ecosystem quality issues were all most acute. The version break is smaller than it appears for local tooling and larger than it appears for anyone running a hosted MCP server.
Whether this constitutes a new protocol or a revised one is partly semantic. The JSON-RPC message format is unchanged. The three primitives are unchanged. The overall architectural model, where a host application brokers communication between a language model and one or more servers that expose capabilities, is unchanged. What changed is the HTTP transport layer that most production deployments actually rely on. That is significant enough to cause real ecosystem disruption, and it is also the kind of revision that happens when a protocol designed on paper meets real infrastructure. Staying with SSE would have meant a protocol that worked in local development and failed in production.
The question worth sitting with is not whether the transport change was necessary, but why the original spec shipped with an HTTP transport that conflicted so directly with standard hosting environments. The answer is probably that MCP launched fast, the stdio transport covered the most immediate local use cases, and the HTTP transport was a known compromise accepted in the interest of getting something shipped. That is not unusual for protocols trying to establish adoption before the deployment story is fully worked out. The spec is in better shape now; the ecosystem has roughly two years of server implementations to migrate or deprecate.