Where State Coherence Lives When MCP Is Stateless
The gap, named by omission
Anthropic’s “Building agents that reach production systems with MCP” (2026-04-22) does a very careful job of mapping out the production-MCP surface: remote servers, intent-based tool grouping, code-orchestration sandboxes, Tool Search, Programmatic Tool Calling, MCP Apps, Elicitation, Vaults and CIMD auth, Skills and Plugins. It says absolutely nothing about state anywhere in the document: no mention of idempotency, freshness, stale reads, consistency, multi-agent coordination or tool-call caching.
That isn’t an omission the protocol will just quietly fill in. The 2026-07-28 spec removes protocol-level sessions by design. Mcp-Session-Id is gone, and tasks/list is gone with it. The tasks SEP explains why in four words, “tasks/list scoping cannot be defined,” and the reason given is that a task could have been bound to a session, SEP-2567 removed sessions, and there is no other natural scope a server could define on its own. The roadmap the maintainers published on 2026-08-22 lists five priority areas for the year ahead. The only one that comes close to state is ETag-style versioning of tool results under caching, which is a read-side concern. None of them mention concurrency, conflict resolution or shared mutable state. Take those together and the direction is very clear: MCP is being made deliberately stateless, and state coordination is being pushed out of the protocol rather than deferred within it.
Which brings us to the next question for anyone running multiple agents against shared state: if the protocol itself doesn’t provide coherence, where does it reside?
The shape that fits a stateless protocol
If it’s a stateless protocol, then a wire-protocol extension to add state is the wrong thing to do. That goes against the very direction the spec has just taken. Coherence belongs at the layer above the protocol, in the application or orchestration layer the agents are already running in.
The spec itself makes the point. Its own suggestion for a server that needs state across calls is, verbatim, that “servers that need cross-call state use explicit, server-minted handles passed as ordinary tool arguments.” State carried in the application layer above the protocol is precisely where this argument puts coherence.
The failure modes worth closing are the familiar distributed-systems ones, with agents as the writers:
- Stale read. Agent B acts on an artifact that agent A has already superseded.
- Lost update. Two agents read-modify-write the same artifact, and one of the writes is lost.
- Single-writer violation. Multiple writers to an artifact that should have had exactly one.
- Zombie write. A writer whose grant was taken back while it was stalled comes back and writes, or fires an effect, on authority it no longer has.
The mechanism is perfectly straightforward once you’ve named it: track a read version per shared artifact, issue single-writer grants, and reject a write whose read version is stale, surfacing a typed conflict rather than letting the lost update go in. It’s keyed on the artifact (the read and write set) rather than the task or the tool call. It makes no contact with the wire protocol at all.
What the handle pattern looks like when it ships
The shipped shape is a fairly standard stdio MCP server, stale-write-guard-fs, with ten tools. Six of them carry the coherence check and are listed below, and four, added in v0.15.0, hand a path to another session. State resides in the server’s coordinator. The protocol carries nothing but plain tool arguments, which is the handle pattern the specification prescribes, applied to coherence.
| Tool | What the agent passes | What comes back, or what is refused |
|---|---|---|
swg_read |
path |
content, plus two handles: version and owner_generation |
swg_write |
path, content |
denied stale_view if the file moved since the read, by a peer commit or an out-of-band edit |
swg_write_cas |
path, expected_version, new_content |
a typed version_mismatch with current_version if a peer committed first, never an auto-merge |
swg_gate |
path, expected_version, expected_generation |
proceed, or a deny if the file moved or the grant it was read under was reclaimed |
swg_reacquire |
path |
the current bytes to write from after a deny |
swg_status |
nothing | coordinator on, off, or unknown, and per-path enforcement |
Two handles rather than one, and the second is the one a version can’t replace. The crash-recovery sweep can reclaim a stalled agent’s grant without the file’s bytes moving, so a version check alone would just let the zombie through. swg_gate takes both comparands immediately before any irreversible action (a webhook, a deploy, an opened PR) and holds if either of them has moved. That’s the distinction a fence makes that a lock doesn’t, and it’s been on the MCP surface since v0.14.0 rather than only in the Python API.
The four tools added in v0.15.0, swg_transfer, swg_accept, swg_decline and swg_withdraw, hand a path’s grant to a named successor session, and the giver is then refused its next write of that path while the handoff is live. Same pattern. The handoff record is state the server holds, and the successor’s identity is simply passed as an ordinary argument.
Put the handles next to the two records every agent system keeps. The version and the generation are the ledger the infrastructure can verify. “Task complete” is the one the model narrates. A stateless protocol is perfectly capable of carrying both equally well. Only one of them can be verified.
How this composes with what is already shipping
There is real prior art for MCP-first coordination, and it’s important to be precise about what each piece does. Guild keys its atomic claims on task rows. swoofer/mcp-coordinator uses announce-before-write intentions over MQTT plus a tamper-evident audit chain. Both are real solutions to real coordination problems. As far as our checks on 2026-05-28 and 2026-05-29 go, neither tracked artifact read versions or detected stale reads. They are keyed on tasks and intentions rather than on the set of artifact reads and writes. That’s two products on two dates, not a survey.
So this isn’t a competing coordinator. It’s the coherence layer that sits underneath whatever task coordinator or framework you’re already running. Different keying, composes cleanly.
Scope, stated plainly
Everything above is single-host. It covers writers going through one coordinator on one machine, and the guarantees apply to those writers. A writer on a different host is never coordinated. An edit that comes in via a synced or network mount is a foreign edit: the content-hash check catches it at the next tool call on that file, and the server never sees or blocks it as it happens. Cross-host coherence is a much harder problem, it hasn’t shipped, and this doesn’t solve it in any way.
The server is cooperative. It guards agents that route file access through the tools. The full taxonomy of how a write disappears covers which failures are the runtime’s responsibility to prevent and which remain the application’s.
One open question I haven’t closed
If the dominant MCP surface becomes code-execution sandboxes (a named surface in the production guidance) rather than raw tool calls, coherence may need to move to state across sandbox executions and the typed SDKs they invoke. That’s a different shape from the artifact coherence we have at the tool boundary. I don’t think that’s settled, and I’d much rather say so than pretend it is.
Why it matters
The protocol team made a very clean decision and stated it publicly. Any request can go to any instance, there’s no stickiness and no shared session store, and anyone who wants state across calls creates a handle and threads it through. That’s a good decision for the protocol, and it leaves the concurrent-state half of the problem to whoever is building on top of it.
One very concrete next step. Take one MCP server your agents write through and ask what it returns from a read that a subsequent write has to present back. If the answer is nothing, two agents reading the same file have no way of knowing that one of them is late, and the first lost update is purely a matter of scheduling.
The server, its ten tools, and offline reproductions of each failure above are at github.com/Cohexa-ai/agent-coherence.
Frequently asked
Does MCP handle two agents writing the same file?
No. The 2026-07-28 spec removes protocol-level sessions by design, and the 2026-08-22 roadmap contains no work on concurrency, conflict resolution or shared mutable state. Coordination for shared writes has to be in the layer above the protocol.
Why not extend the MCP wire protocol to carry state?
That's exactly the opposite of what the spec has just said. The spec's own recommendation for a server that needs state across calls is to create an explicit handle from a tool and have the client pass it back as a normal argument. That puts the state in the application layer rather than on the wire.
Does this work across machines?
No. It only covers writers that are routed through one coordinator on a single host. A writer on another host is never coordinated at all, and an edit that comes in via a synced or network mount is only picked up at the next tool call as a foreign edit, never fenced as it happens.