Read the version, not the date
MCP revisions are named by date, which reads like a release announcement. It is not: a revision is an identifier that clients negotiate, and a client may sit several behind indefinitely. Your server's job is to state which revision it implements and to keep working for clients that ask for an older one.
The layers, ordered by how much a revision hurts
| Layer | Exposure to a revision |
|---|---|
| Your business logic | None, if it never imports protocol types |
| Tool names and schemas | Barely — this is the stable part |
| Result envelopes | Some — the shape around your payload does move |
| Session and transport | Most — this is where revisions actually land |
| Authorisation | Occasionally, and always toward stricter |
The design consequence is blunt: put a boundary between the protocol layer and everything else. Here that boundary is that the MCP adapter is a thin wrapper over the same functions the REST routes call, so a transport change touches one file.
Statelessness is the direction of travel
Every revision so far has pushed toward servers that can answer a request without remembering the last one. That is not a style preference — it is what makes a server deployable behind a load balancer or on serverless infrastructure. Keep per-session state in memory and each revision feels like a rewrite; keep none and most are a version bump.
What breaks, in practice
- Session handling — how a session is established, carried and resumed.
- Header expectations — which headers a client must send and a server must echo.
- Result envelopes — extra optional fields around your content, which is why you should never build them by hand in twelve places.
- Authorisation strictness — requirements about token audience and resource indicators have only ever tightened.
What does not break
Tool names, descriptions, and input schemas. Across every revision to date, the thing users
actually depend on — "the model can call publish_html with content and get a URL" — has
kept working. That stability is why the ecosystem grew.
Extensions, and knowing when to skip one
Newer capabilities arrive as extensions rather than core changes: rendered surfaces, long-running tasks, richer round-trips. That is deliberate, and it is permission to ignore the ones your product does not need. A publishing server needs tools and authorisation. It does not need a task queue, so it does not implement one.
Asking the user, and asking the model
Two capabilities worth understanding even if you skip them: elicitation lets a server pause and ask the human for a value, sampling lets a server ask the client's model to reason on its behalf. Both invert the usual direction of control — see the post on both.
Authorisation keeps converging on OAuth
The trajectory is unambiguous: hosted servers are expected to behave like ordinary OAuth 2.1 resource servers, with discovery documents, dynamic registration, PKCE and audience-bound tokens. Building that early is the cheapest bet in this space, because none of it has been walked back.
Deprecation is a policy, not an event
Revisions mark things deprecated well before removing them, so the correct response to a deprecation notice is to schedule work rather than do it. The failure mode to avoid is chasing release candidates into production: a candidate is an invitation to test, and your users' clients have not moved yet.
A checklist for surviving the next one
- Declare the revision you implement, and keep accepting the previous one.
- Keep protocol types out of your business logic entirely.
- Construct result envelopes in exactly one place.
- Hold no per-session state you cannot rebuild from the request.
- Have a test that calls
tools/listand asserts the count and the names. That one catches most accidental breakage.
What this deployment does
One adapter file; twelve tools that are thin wrappers over the same functions the REST
endpoints use; no in-memory session state; OAuth 2.1 with PKCE and working revocation; and a gate
that asserts tools/list returns exactly twelve named tools. When a revision lands,
the work is in the adapter, and the gate says whether it worked.
Should I implement the newest revision immediately?
Implement it, ship it behind negotiation, and keep serving the previous one. Clients move on their own schedule and you do not control it.
How do I know which revision a client wants?
It tells you during initialisation. Servers that ignore that and assume the newest are the ones that break for half their users.
Is stdio going away?
No. It remains the right transport for local tools. The revisions have been about making hosted servers work well, which is a different problem.
Where do I read the actual changes?
The specification itself, at modelcontextprotocol.io. A blog post is the wrong place to learn a version number.