From Theory Delta | Methodology | Published 2026-02-24
MCP Streamable HTTP (spec 2025-03-26, replacing deprecated SSE) supports two modes: stateless for serverless deployment (Lambda, Workers) and stateful for full-featured servers. The spec implies this is a deployment choice with a clear tradeoff.
The tradeoff is not a dial -- it is a hard binary with three production failure modes that are not obvious from the spec:
Failure 1: Sampling silently hangs in stateless mode. FastMCP with stateless_http=True permanently hangs (no error, no timeout) when the server attempts sampling. Maintainers closed the original report (FastMCP #678) as "expected behavior." Bidirectional communication is architecturally impossible when each request creates and destroys a fresh server instance. FastMCP #1156 later added explicit detection and error messages, but the default experience before that was an infinite hang with no diagnostic output.
Failure 2: Load balancers strip Mcp-Session-Id. Nginx, ALB, and most proxies require explicit configuration to route on this header. MCP clients use fetch() and do not forward cookies, making cookie-based sticky sessions non-functional. Without header-based routing, stateful requests from the same client hit different backend instances and silently lose session context. (python-sdk #880 -- labeled P1, documents the horizontal scaling gap)
Failure 3: CORS silences the session ID. The MCP Inspector itself had this bug through v0.18.0 -- it stored the session ID but did not attach it to follow-up requests, producing false-negative debugging results. Developers debugging stateful servers with the Inspector see the server appear broken when the failure is in the debugging tool. (Inspector #905)
Additionally: DNS rebinding protection is off by default in both SDKs. Any MCP server running on localhost is vulnerable to malicious webpages without explicit origin validation.
Mcp-Session-Id.enableDnsRebindingProtection: true (TypeScript SDK) or TransportSecuritySettings (Python SDK). Bind to 127.0.0.1, not 0.0.0.0. Validate Origin and Host headers.| Tool | Version | Result |
|---|---|---|
| MCP TypeScript SDK | v1.x / v2 pre-release | DNS rebinding off by default (CVE-2025-66414) |
| MCP Python SDK | v1.x | Session persistence in-memory only (#880) |
| FastMCP | latest (Feb 2026) | Sampling hangs indefinitely in stateless mode (#678) |
| Google ADK | latest (Feb 2026) | Streamable HTTP transport reviewed |
| Cloudflare Workers (Hono) | latest (Feb 2026) | Stateless deployment path validated |
| AWS Lambda | latest (Feb 2026) | Stateless deployment path reviewed |
| MCP Inspector | through v0.18.0 | Session ID not attached to follow-up requests (#905) |
Confidence: empirical -- tested across 7 environments. Failure modes independently confirmed by GitHub issues and CVEs linked above.
Unlinked claim: The June 2026 spec redesign timeline is sourced from maintainer comments across multiple SDK issues, not a single canonical URL. If you have a direct link to the post-mortem or redesign announcement, contribute it.
Open questions: Has anyone implemented external session persistence (Redis/DynamoDB) for the MCP Python SDK? Does the proposed June 2026 spec redesign eliminate the stateless/stateful binary? Are there MCP clients that correctly handle Mcp-Session-Id through standard proxies without custom configuration?
Seen different? Contribute your evidence -- theory delta is what makes this knowledge base work.