How it works
Stateless transport pushes the amount of state a server instance holds toward zero. Each request carries everything the instance needs to serve it — caller identity, a reference to any conversation or context, and the parameters of the call. No instance pins a session in memory, so the next request from the same client can land on a different instance and still succeed.
The control loop looks like this:
- A client sends an ordinary HTTP request. Under MCP's streamable HTTP transport it may open a stream and receive incremental events, then the connection closes.
- The server authenticates and authorizes the request on its own, without assuming prior in-memory context.
- Any durable state — conversation history, tool results, checkpoints — lives in an external store the request points at, not in the process.
- A load balancer routes freely; there is no sticky session and no server affinity.
The result is that server instances become interchangeable. You can add, drain, restart, or kill an instance mid-flight and the next request is unaffected. State still exists — it just does not live in the transport or the process serving it. That separation is the whole point.
Why it matters in an agent harness
Agent traffic is bursty and long-lived in a way that punishes sticky sessions. A single run fans out into many tool calls, subagents, and retries; if each depended on a pinned server, one restart would strand an entire trajectory. Stateless transport removes that coupling and buys you several harness properties directly.
- Failure containment: an instance crash or deploy takes out at most the in-flight request, not the run. The client retries and lands elsewhere.
- Horizontal scale: you scale on ordinary HTTP metrics. No session table to shard, no affinity to preserve.
- Reversibility and restarts: because durable state lives outside the process, you can roll a server back or forward without losing agent context. Recovery becomes a data problem, not a transport problem.
- Observability: requests are self-describing, so a trace is legible without reconstructing hidden server memory.
The tradeoff is honest: you push complexity into the state store and into every request, which now must carry or reference its context. That makes idempotency and durable execution non-optional — a retried request must not double-execute a side effect. Stateless transport is what makes those guarantees possible, not a substitute for them.
Stateless transport vs stateful sessions
| Stateless transport | Stateful session transport | |
|---|---|---|
| Where state lives | External store, per request | In the server process |
| Routing | Any instance | Sticky / pinned instance |
| Restart impact | One in-flight request | Every session on that instance |
| Scaling | Ordinary HTTP | Session-table sharding |
| Cost | Heavier requests, external store | Cheaper hop, fragile failover |
The distinction changes a design decision: choose stateful sessions only when a high-frequency, low-latency exchange genuinely cannot tolerate re-sending context, and you accept fragile failover. For most agent harnesses the reverse is true — trajectories are long, restarts are frequent, and legibility matters more than shaving a hop.
The Rifty take
We treat statelessness as a control property, not a scaling trick. A harness you can restart at any moment without losing an agent's place is a harness you actually control; one that pins runs to a living process is a harness holding you hostage to uptime. We accept heavier, self-describing requests and an explicit external store as the price of instances we can kill without ceremony.
Implementation checks
- Verify no server instance holds conversation or tool state in process memory — kill a random instance mid-run and confirm the run continues.
- Make every state-changing request idempotent so retries and re-routes cannot double-apply a side effect.
- Keep durable context in an external store the request references, and version it so rollbacks stay coherent.
- Confirm authorization is re-evaluated per request, not cached from a prior session.
- Load-test with sticky routing disabled; affinity that "works" quietly masks hidden state.
- Trace one full request end to end and check it is legible without server-side memory.
Frequently asked questions
Is stateless transport the same as MCP's streamable HTTP?
Streamable HTTP is one implementation of stateless transport, not a synonym. MCP's streamable HTTP lets a client send an ordinary HTTP request and receive streamed events without a pinned session, so any server instance can serve it. Stateless transport is the broader property that transport realizes.
Does stateless mean the agent has no memory?
No. Stateless refers to the server process, not the system. Conversation history, tool results, and checkpoints still exist — they live in an external store each request references. The transport carries no hidden memory, which is exactly what lets any instance serve any request.
Why does stateless transport require idempotency?
Because requests can be retried and re-routed to different instances, a state-changing call may arrive more than once. Without idempotency, a retry double-executes the side effect. Stateless transport makes retries safe and routine, so idempotency stops being optional and becomes a hard requirement for every mutating operation.
When would I still choose a stateful session?
Choose sticky sessions only when a high-frequency, low-latency exchange truly cannot afford to re-send or reference context per request, and you accept that a restart drops every session on that instance. For most agent harnesses — long trajectories, frequent deploys — that tradeoff runs the wrong way.
How does stateless transport help failure containment?
An instance crash or deploy takes out at most the in-flight request, never the whole run. The client retries and lands on another interchangeable instance. Because durable state lives outside the process, recovery becomes a data-store concern rather than a transport one, keeping blast radius to a single request.