Everything so far has been taught from five projects โ what was built, what broke, and what the person building it concluded. That is the useful half.
This page is the other half: what the specification itself requires, in its own words, and an honest accounting of where these five projects meet it, beat it, or miss it.
The specification uses RFC 2119 keywords: MUST is a requirement, SHOULD is a strong recommendation with a defensible exception, MAY is optional.
The three principles
The spec opens with three, before any protocol detail:
User consent and control
Users must explicitly consent to and understand all data access and operations. Users must retain control over what data is shared and what actions are taken.
This is project #3's entire subject โ and note that "understand" is doing as much work as "consent". An approval card that says "approve
empty_jar {id:38}?" with no context technically obtains consent and fails this principle, which is exactly why project #4 carriesoriginup the tree.Data privacy
Hosts must obtain explicit user consent before exposing user data to servers. Hosts must not transmit resource data elsewhere without user consent.
The direction here is easy to miss. It is not only about what servers send you โ it is about what your host sends them.
Tool safety
Tools represent arbitrary code execution and must be treated with appropriate caution. In particular, descriptions of tool behavior such as annotations should be considered untrusted, unless obtained from a trusted server.
There it is, in the specification, in the same words project #3 arrived at independently.
The line that validates project #3
Said twice, and the second time as a MUST:
For trust & safety and security, clients MUST consider tool annotations to be untrusted unless they come from trusted servers.
Project #3's thesis โ a hint from the other
side of a network boundary is not a permission model โ was reached by
reasoning about destructiveHint from first principles, and it turns out to be
the specification's own position.
That is a useful thing to know for two reasons. It means the argument was right. And it means the flag exists anyway, so plenty of implementations are reading it, because a field in a schema is an invitation.
Where the five projects stand
| Requirement | Status | Where |
|---|---|---|
| Annotations untrusted โ MUST | โ
Exceeds. The host never reads destructiveHint, not even as a tiebreaker. | The gate |
| Human in the loop able to deny โ SHOULD | โ Met, and it survives delegation. | Five agents, one human |
| Show tool inputs to the user before calling โ SHOULD | โ The approval card shows exact arguments. โ ๏ธ But only for gated calls โ default-allow means ungated calls run unseen. | The gate |
requestState integrity-protected โ MUST | โ ๏ธ Partially. HMAC-signed and verified. But the spec also asks for replay protection โ see below. | Data does not stay yours |
Validate Origin, prevent DNS rebinding โ MUST | โ Not implemented. These are hosted on Vercel rather than localhost, which sidesteps the specific attack, but the requirement is unconditional. | Transports |
| Rate limit tool invocations โ MUST | โ Not implemented at the server. The host caps itself with five seatbelts, which is a different thing. | Seatbelts |
| Log tool usage for audit โ SHOULD | โ Exceeds. Every loop event is a row, replayable. | Replay |
| Deterministic tool ordering โ SHOULD | โ Met, and it is why prompt caching works. | |
| Disambiguate tools from multiple servers โ SHOULD | โ
server__tool, split on the first separator. | One shelf, many servers |
| Tool execution errors returned to the model โ SHOULD | โ Refusals are sentences the model can act on. | What a tool sends back |
The requestState requirements, in full
Project #5's page gets the headline right โ sign it, verify it, reject what fails. The specification asks for more than that, and the extra parts are worth having.
If
requestStateinfluences authorization, resource access, or business logic, servers MUST protect its integrity (e.g. HMAC or AEAD) and MUST reject state that fails verification.
Then, for replay:
| Include inside the protected payload | Rejects |
|---|---|
| the authenticated principal | state minted for one user, presented by another |
| a short expiry (TTL) | state captured today, replayed next month |
| an identifier for the originating request โ the method name and a digest of its salient parameters | state from a cheap call, presented on an expensive one |
That third row is the clever one. Without it, an attacker takes the
requestState from a call they were allowed to make and attaches it to a
different call, inheriting whatever the server decided the first time.
Things in the spec this course does not cover
Named so you know they exist and that their absence here is a choice.
| Feature | What it is |
|---|---|
| Pagination | tools/list supports a cursor. Matters when a server has hundreds of tools. |
| Caching | tools/list results carry ttlMs and cacheScope. |
| Subscriptions | subscriptions/listen opens the long-lived stream that carries notifications/tools/list_changed and friends. |
| Progress & cancellation | Progress notifications on a request's own SSE stream; closing the stream is the cancellation. |
x-mcp-header | Mirror a tool parameter into an Mcp-Param-* HTTP header so proxies can route on it without parsing the body. |
| Extensions | Opt-in, negotiated: Tasks (long-running work with durable handles), Skills over MCP, MCP Apps (interactive UI inline in a conversation). |
The honest summary
The specification and these five projects agree on almost everything that matters, and the two places they disagree are places the projects are behind it, not ahead.
What the projects add is not new rules. It is the cost of the rules: that a default-deny gate produces click-fatigue in ninety seconds, that a refusal worded badly makes a model retry until it has burned ten iterations, that a counter re-scopes itself the moment you split a request in two.
The specification tells you what to build. Forty things breaking tells you what it feels like to build it.
Sources: MCP specification, revision 2026-07-28 ยท Tools ยท Multi round-trip requests ยท Streamable HTTP ยท Roots (deprecated)