The Stateful Trap That Hobbled MCP
MCP's initial protocol imposed a significant architectural constraint: inherent statefulness. Previously, a client initiated interaction with an initialize request to an MCP endpoint. The server would then mint and return a unique session ID, a token critical for all subsequent client-server communication. every follow-up request had to carry this identifier.
This design created a fundamental flaw for scalable deployments. The mandatory session ID pinned the client to the specific server instance that initially processed the initialize call. This broke standard load balancing paradigms. If a load balancer, say a round-robin router, directed a subsequent request to a different instance, that server would lack any record of the session. The result was a debilitating 400 "session not found" error, halting client operations. Similarly, if an instance crashed, all its active session states were instantly lost, causing immediate client request failures.
Developers were forced into complex, inefficient workarounds to mitigate these issues. Common solutions included implementing sticky sessions, which ensured a client consistently hit the same server instance. Another approach involved deploying shared state stores, such as a Redis instance, to centralize and synchronize session data across all servers. Both methods introduced unnecessary operational overhead, increased network latency, and significantly raised infrastructure costs. These were protocol-induced burdens, not choices.
Stateless by Default: A Protocol Reborn
MCP's new specification, '2026-07-28', introduces a radical shift. Two key proposals, SEP-2575 and SEP-2567, redefine the protocol's core. SEP-2575 eliminates the initialize and initialized handshake, while SEP-2567 removes the MCP-Session-Id header and its associated protocol-level session.
These changes transform a multi-step tool call into a single, self-contained HTTP request. Previously, context was fragmented; now, all necessary information rides in a meta field within the JSON body. This design makes every request independent, mirroring stateless HTTP principles.
Alignment with standard HTTP infrastructure is complete. New headers, MCP-Method and MCP-Name, now carry critical routing information. This allows network components like gateways, firewalls, and rate limiters to make decisions without parsing the JSON payload. Such efficiency is crucial for performance, especially on Cloudflare.
The protocol no longer requires Durable Objects to speak MCP, simplifying deployment. Services can scale down to zero when idle, significantly reducing operational costs and expanding deployment options. This shift eliminates the pain points of sticky sessions or shared Redis instances, making MCP truly stateless by default.
Smarter Infrastructure and Application State
Statelessness unlocks massive deployment advantages. Serverless platforms like Cloudflare Workers and Google Cloud Run now scale to zero when idle, drastically cutting operational costs. Servers no longer maintain persistent connections, eliminating the need for always-on instances to hold session state. This fundamentally changes infrastructure provisioning.
Protocol no longer burdens state management. Instead, state becomes an application-level concern. Tools can mint explicit handles, say a basket_id or browser_id. The model then passes this identifier back as an ordinary argument on later tool calls. This hands developers greater flexibility, allowing them to manage state precisely as needed, rather than conforming to protocol-enforced patterns.
MCP adopts HTTP-inspired caching for enhanced client-side efficiency. New time to live and cache scope hints inform clients about the freshness of tool, prompt, and resource lists. This allows clients to cache responses confidently, avoiding persistent connections for updates. For further reading on robust stateless API design, explore Statelessness in API Design: Understanding & Examples - Unkey. These hints ensure clients know precisely how long data remains valid across users.
Enjoying this? Get one like it in your inbox each morning.
one email a day · unsubscribe in two clicks · no third-party tracking
New Patterns for Complex Interactions
Complex interactions now follow a clear, client-driven pattern. Previously, the server pushed unsolicited follow-up questions, a security footgun. The new specification prevents this. For multi-turn interactions, the server returns an input_required result.
This result includes a serialized request_state payload, encapsulating all context for the pending action. A client receives input_required, prompts the user (say, "Are you sure?"), then re-initiates the original request. The client attaches the user's response and echoes the request_state. This ensures the client always drives the interaction. Any server instance can pick up the resumed request, reinforcing statelessness.
Long-running operations leverage the now-official 'tasks' extension. This feature graduated from experimental status. For a task like processing a refund, the server immediately acknowledges the request. It returns a response indicating the job is running, preventing connection blocking.
Clients then track progress asynchronously. They can poll using tasks/get or subscribe via subscriptions/listen. This allows retrieval of the final result once the long-running task completes. This design eliminates the need for persistent connections during lengthy computations, improving protocol efficiency and resilience.
Frequently Asked Questions
What was the main problem with the old stateful MCP?
The old protocol required session IDs that pinned clients to specific server instances. This made load balancing difficult, required complex workarounds like sticky sessions or Redis, and made the system fragile, as a server restart could lose session state.
How does the new stateless MCP solve these problems?
It removes session handshakes and IDs entirely (spec 2026-07-28). Every request is self-contained, allowing for standard round-robin load balancing, improved resilience, and the ability for servers to scale down to zero, reducing costs.
How is state managed in the new MCP if the protocol is stateless?
State is now managed at the application level, not the protocol level. Developers can have a tool create an explicit handle (e.g., 'browser_id') that the model passes back in subsequent calls, a flexible pattern common in standard HTTP APIs.
What happens to long-running tool calls without a persistent connection?
The new spec graduates the 'tasks' extension to an official feature. For a long-running job, the server can immediately return a task ID, and the client can then poll or subscribe to that task to get progress updates and the final result asynchronously.

