API vs MCP: After the Stateless Spec, the Difference Is Who Reads the Docs
Every few weeks someone asks whether MCP replaces REST. It does not. The question is still worth answering carefully, because the line between the two moved in July, and most of the explanations written before then are now describing a protocol that no longer exists.
An HTTP API is a contract between two pieces of software written by people who read documentation. A developer opens the reference, learns that POST /v1/invoices wants a customer ID and an array of line items, writes the call, and ships it. The knowledge lived in a human head at build time and then got frozen into source code. When the endpoint changes, something breaks in production and a person goes and fixes it.
MCP moves the reading step to runtime and hands it to a different reader. An MCP server publishes a list of tools, each with a name, a description in plain English, and a JSON schema for its inputs. A model asks the server what it can do, gets back a machine-readable answer, and picks a call based on what the user actually asked for. Nobody typed POST /v1/invoices into a file anywhere. The model saw create_invoice on a list and chose it.
That is the whole distinction. Everything else follows from it.
The Interface Is Written for a Different Audience
Once you accept that the caller is a model rather than a programmer, a lot of ordinary API design advice inverts.
Endpoint count, for one. A mature REST API might have forty endpoints, and that is fine, because a developer greps the docs once and forgets the rest. A good MCP server usually has fewer than a dozen tools. Every tool you expose sits in the model’s context on every turn, competing for attention with the user’s actual request. Twelve well-named tools beat forty precise ones, because the failure mode is no longer a 400 response; it is the model choosing the wrong thing confidently.
Descriptions become load-bearing code. In an API, the docstring is a courtesy. In MCP it is the routing logic. If two tools have descriptions that sound alike, the model will mix them up, and no amount of schema validation saves you. I have watched a server work perfectly in tests and fall apart in real use because search_orders and list_orders were never distinguished in prose.
Errors change job too. A 422 with a machine-readable body is good API design and bad MCP design. The model reads your error message and tries again, so “customer_id must be a UUID, you sent an email address; look it up with find_customer first” is worth more than any status code. You are writing for something that will act on the sentence.
What the July Spec Actually Removed
The 2026-07-28 revision is the largest structural change the protocol has had, and it went in one direction: making MCP servers boring to operate.
The initialize handshake is gone. The session header is gone, and with it the idea of a protocol-level session at all. Every request now carries its own protocol version, client identity, and capabilities inside its metadata, so any request can hit any server instance without warm-up. Alongside that came cacheable list results, header-based routing, and a real extensions framework with two official extensions shipping: MCP Apps, which lets a server hand back an interactive HTML interface rendered in a sandboxed frame, and Tasks, for work that outlives a single call.
The practical consequence is the one the maintainers stated themselves: a remote MCP server is now no different from any other HTTP workload. Your existing load balancer works. Autoscaling works. CDN caching in front of tool listings works. The operational argument against MCP, that it needed special stateful infrastructure nobody wanted to run, mostly evaporated in a single release.
So if the operational difference has collapsed, and MCP rides on the same HTTP that your API does, what is left to choose between?
Choose by Caller, Not by Technology
The useful question is who or what is on the other end.
If the caller is software written by a person who can read your docs, you want an API. Deterministic, versioned, granular, with the full surface exposed. Nothing about agents changes this. The billing integration your partner’s engineering team spent three weeks on should not go through a model.
If the caller is an agent working from a user’s stated intent, you want an MCP server, and it should sit on top of the API rather than replace it. The MCP layer is a translation shim: it collapses several endpoints into one intent-shaped tool, fills in the arguments a human would have known to supply, and returns text the model can reason over rather than a raw payload. Most teams that do this well end up with a thin server, a few hundred lines, wrapping an API that already existed.
Security is where the two genuinely diverge, and it deserves more attention than it gets. With an API you authorize a client you can identify, and that client behaves the same way every time. With MCP the caller is a model that may have just read a support ticket containing instructions written by someone hostile. Authorization gets you part of the way, and the spec has been hardening steadily: issuer validation, issuer-bound client credentials, Client ID Metadata Documents as the preferred registration path. But none of that addresses an agent that was talked into calling a tool it was legitimately allowed to call. Think about what a compromised turn can reach, and scope tools accordingly. Read-heavy servers are much safer than write-heavy ones, and it is worth being honest about which one you are building.
What Is Still Unsettled
Discovery is thin. Registries exist, and they are early. Versioning tool descriptions is an unsolved problem, because the description is behavior, so changing a sentence is a breaking change with no version number attached to it. Tool sprawl inside big organizations is arriving faster than anyone has governance for; several teams shipping servers into the same host means a model staring at ninety tools, which is the forty-endpoint problem again with worse ergonomics.
None of that argues against building one. It argues for keeping it small, and for remembering what it sits on.
The API is still underneath. It always was.