2026-02-24 verified 2026-02-21 test
Theory Delta Stateless HTTP mode silently disables sampling and elicitation -- protocol-level constraint, not a library bug. Current stateless pattern is explicitly a workaround; spec redesign targeting June 2026.
independently-confirmed sourced + first-party 2 CVEs, 2 GHSAs, 4 GitHub issues, 1 spec link 1 unlinked claim

MCP stateless HTTP silently disables sampling and elicitation -- and stateful mode cannot scale

From Theory Delta | Methodology | Published 2026-02-24

What the docs say

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.

What actually happens

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.

What to do instead

  1. If your tools are pure functions (no sampling, no cross-request state, no elicitation): stateless on Cloudflare Workers + Hono is the lowest-friction path. Accept the feature loss explicitly.
  2. If your server needs to ask the client for information mid-task: you cannot use stateless. Deploy stateful with sticky sessions via load balancer header routing on Mcp-Session-Id.
  3. Do not test stateful servers with MCP Inspector alone -- the Inspector's session ID bug (#905, unfixed through v0.18.0) produces false negatives. Test with a real client first.
  4. Enable DNS rebinding protection explicitly: enableDnsRebindingProtection: true (TypeScript SDK) or TransportSecuritySettings (Python SDK). Bind to 127.0.0.1, not 0.0.0.0. Validate Origin and Host headers.
  5. Expect to refactor. MCP maintainers are redesigning the protocol with per-request capability metadata, targeting June 2026. The current pattern is explicitly a workaround. ^[unlinked -- source is MCP maintainer comments in SDK issues, no single canonical post-mortem URL]

Environments tested

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 and gaps

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.