One HTTP Request and the Tool Shows Up
/Bill reads the new stateless MCP spec the way he reads any spec that claims to simplify things: by counting what it removes. Two requests became one, and session state stopped being your problem.

TL;DR: The 2026-07-28 revision of the Model Context Protocol drops the handshake.
- Legacy MCP: two HTTP requests, one to initialize, one to actually call the thing.
- Stateless MCP: one request. Call the tool. Done.
- No session to track on the server, which means no session to lose, expire, or leak.
- Simon Willison went from cooled-off to building two things in a week over it, which is the review that counts.
I do not get excited about protocol revisions. Most of them add. This one takes away, and what it takes away is the part I have watched break in every remote-tool integration I have ever had to fix.
Calling a remote tool used to mean a conversation
Under the old MCP shape, calling a remote tool meant a conversation. First request opens a session and asks the server what it can do. The server answers and remembers you. Second request runs the tool inside that session. That is two round trips minimum, and more importantly it means the server is now holding state on your behalf.
Server-side session state is a thing you have to feed. It needs storage, it needs an expiry policy, it needs to survive a process restart or not, and you need to decide which. It needs to behave when the same client opens forty of them. Every one of those is a decision, and every decision is a thing that can be wrong at 2am.
Stateless MCP collapses it. Willison’s writeup puts the change plainly: the whole exchange becomes “a single HTTP request.” You post the call, you get the result, nobody remembers anything afterward. That is the same architecture as a plain old form POST, and there is a reason that shape outlived everything built to replace it.
Why does a carpenter care about a handshake?
Because the handshake is a joint, and joints are where things come apart.
Every stateful connection between two systems is a place where one side can believe something the other side has forgotten. The session expired but the client still has the ID. The server restarted and dropped the table. The load balancer sent request two to a different box than request one, and box two has never heard of you. I have chased all three of those, and the fix is never clever, it is always just reconnecting properly, which is work you are doing because the design created the possibility.
Take the joint out and the failure class goes with it. There is nothing to expire because nothing is stored. A retry is just the same request again, which is the definition of an operation you can safely retry. That property is worth more in production than any feature the session was buying you.
He built two small things, and the size is the tell
Two things, both small, which is the tell.
mcp-explorer is a Python command-line tool for poking at an MCP server without installing anything. You point it at a URL, list what tools are there, read the schemas, and call one. The example in the writeup is a single line:
uvx mcp-explorer call https://agentic-mermaid.dev/mcp render_svg
That is a tool you can only write easily if the protocol is simple. Under the old shape, “just call this one tool from the shell” needed session setup, which is why that tool did not exist before.
datasette-mcp is the other one, a plugin that hangs an MCP endpoint off a Datasette instance and exposes three functions: list_databases(), get_database_schema(), and execute_sql(). Three functions. That is a complete, useful integration, and you can read the whole surface area in one breath.
When a spec gets simpler, the first things people build with it get smaller and more numerous. That is the signal I watch for. A protocol that only ever produces large frameworks is a protocol with too much ceremony in it.
Is this actually safer, or does it just feel tidier?
Willison makes a security argument I think is the strongest part of the piece, and it is not really about statelessness at all. It is about the alternative:
“Giving an agent a shell environment with the ability to access the internet is fraught with risk, and requires a strong model that is capable of effectively driving such an environment. MCP tools are easier to audit and control.”
That is the real comparison. The two ways to let an agent do something on your behalf are: hand it a shell and hope, or hand it a specific list of named tools with typed inputs. The second one you can read. You can enumerate exactly what is exposed, you can log every call, and you can decline to expose the thing you did not want touched. A shell exposes everything and asks you to trust the judgment of the thing holding it.
Debbie made the network version of this argument on this site last week and she is right about the boundary. This is the same argument one layer up. A narrow, enumerable interface is a control. A general-purpose one is a hope.
Statelessness does not make the tools themselves safe. execute_sql() is exactly as dangerous as whatever database it is pointed at, and if you expose that to an agent you had better have thought hard about the credentials it runs under. What the simpler protocol buys you is that the audit is now short enough that you will actually do it.
What I would do with it on a small operation
Nothing dramatic, which is the point. If you already run a service that does something useful and you want an agent to be able to use it, the cost of exposing it just dropped to roughly the cost of writing an endpoint. That is the bar it should have been at all along.
The honest order of operations:
- Write the tool as a normal HTTP endpoint first, with the auth you would want on any endpoint. If it is wrong as an endpoint it will be wrong as a tool.
- Expose the narrowest useful set. Three functions that do the job beat twelve that cover every case, because you are going to read this list every time you audit it.
- Keep read and write behind different credentials. A tool that can only read is a tool you can be relaxed about.
- Log every call with its arguments. Statelessness means there is no session transcript to reconstruct later, so the log is the only record you get.
Measure twice, pour once. The nice thing about this revision is that there is less to measure.
Frequently asked questions
Does stateless mean the agent forgets between calls?
The protocol stops requiring the server to remember. The agent keeps its own context the way it always did, and it passes whatever the tool needs in the call itself. What goes away is a second, separate memory living on the tool server that has to be kept in sync with the first one. Two memories that can disagree is a bug generator; one memory is just a memory.
Do I have to migrate anything I already built?
The writeup describes this as a spec revision rather than a hard break, and the practical answer for a small operation is that there is rarely urgency in chasing a protocol version for its own sake. The reason to move is if you are currently maintaining session storage for an MCP server and would like to delete it. Deleting infrastructure is the best kind of migration, and it is the only argument I would move on.
Is this useful if I do not run agents at all?
Less so, honestly. This is plumbing for a specific use case: letting an LLM-driven process call your stuff. If nothing in your operation is doing that, the correct amount of attention to pay a protocol revision is none. File it under things that got simpler while you were not looking, which is a short and welcome list.
Comments are open to members. Sign up free →