--- published: true layout: post title: MCP Wrote Itself the Deprecation Policy It Has Not Written for You image: https://kinlane-images.s3.amazonaws.com/apievangelist/api-evangelist-images/mcp-wrote-itself-the-deprecation-policy.png date: 2026-08-16 author: Kin Lane tags: - MCP - Versioning - Breaking Changes - Deprecation - Agents - API Governance --- Nathan Booker asked me a good question on LinkedIn a couple of weeks back, and it has been sitting in my notebook since. He wondered whether changes to MCP APIs are really breaking changes at all — that when your API is agent-facing you can evolve much more quickly, because there is reasoning on the other end that can deal with the change, the way a person deals with a redesigned interface. Traditional breaking change classification, he suggested, may no longer apply. It is the kind of question I like, because the lazy answer is available in both directions and neither one is right. So I went and counted. The first thing to say is that MCP takes change more seriously than the conversation gives it credit for. The Model Context Protocol has a feature lifecycle and deprecation policy, adopted through its proposal process, and it is genuinely good. Features move through Active, Deprecated, and Removed. There is a minimum twelve-month window between deprecation and the earliest possible removal. The deprecation proposal has to document a migration path, or explicitly state that none is needed, and a named replacement has to already exist before the deprecation lands. There is one canonical page listing everything on its way out and by when. The client libraries are required to mark deprecated surface using the language's own mechanism, and should emit a runtime warning when you touch it, and a library that keeps failing to do that can be relegated. That is the deprecation practice I have been asking API providers for since 2015. The working group wrote it for itself and shipped it. Now go one layer down. When you publish a server to the MCP registry you must give it a version string, it has to be unique for that publication, and it is immutable once published. Semantic versioning is recommended. Version ranges are prohibited. All real, all enforced — and all of it about *identity*. It exists so a registry can tell you which publication is which and which one is newest. There is a deprecation status in the registry metadata, which is more than I expected to find, and you can leave a free-text note with it. What there is nowhere to put is a date by which the thing stops working, a structured pointer to what replaced it, or anything scoped smaller than the whole server. You can deprecate a listing. You cannot deprecate a tool. Go one more layer down, to the tool surface itself — which tools exist, what they are called, what their descriptions say — and there is nothing. No policy, no field, no convention. Which is unfortunate, because that is the layer an agent actually binds to. A model does not consume your server version. It reads a list of tools with names and descriptions and decides what to call on the strength of that text. So I counted, to find out whether that gap shows up in behavior. I walked the entire public MCP registry: 66,954 publication records across 20,359 distinct servers. **96.9% of the version strings parse as valid semantic versions.** That is near-total compliance with a recommendation that carries no enforcement at all. Whatever else is happening here, this is not a population that ignores versioning guidance. But 59.5% of registered servers published exactly once and never again. Only about one and a half percent ever use the deprecation status that exists. And across 369 first-party MCP server repositories, exactly one mentions a sunset in its README. People are doing what they were told. **The gap is in what they were told.** The discipline in this ecosystem degrades in exact proportion to how close you get to the thing the consumer depends on, and that is a very different finding from anybody being careless. Here is the part the old taxonomy has no name for. A tool description is not documentation. It is input. When you write the description for an MCP tool you are writing part of the prompt that decides whether a model calls it and how. Rewrite that sentence and you have changed the behavior of every agent bound to it — and the change produces no schema diff, trips no semantic version rule, fails no lint, and sails through every breaking-change gate anyone has built, because those instruments watch structure and the change was in prose. Of the 61,097 MCP tools I have catalogued, 58,937 carry a prose description. The ungoverned surface is not an edge case. It is nearly the whole thing. [minherz wrote this up from production experience](https://leoy.blog/posts/versioning-strategy-for-mcp-tools/) better than I can, and his line is the one to keep: that is a breaking change regardless of whether the JSON schema is backward compatible. Which brings me back to Nathan, and to an answer I did not expect to be so lopsided. He is right that the inherited classification does not fit. He is right that an agent will shrug off a field renamed from `qty` to `quantity` in a way that would break every hand-written client ever shipped. But the tolerance runs one direction only. Agents are more forgiving of *syntactic* change and considerably less forgiving of semantic and economic change than the people they replaced, because a human who hits a 402 or a revoked scope or a surprise rate limit files a ticket, and an agent retries, degrades, or quietly stops producing an outcome somebody is depending on. The changes I have been calling the real breaking changes for years — the price, the limit, the terms, the scope you can no longer get — get worse under agents, not better, because the party who would have noticed is not a party anymore. And the strongest argument against evolving faster on the theory that the agents will cope is that MCP itself did not make that argument. At the one layer it actually governs, it chose twelve months, a mandatory migration path, and a runtime warning in your IDE. Nobody in that room said the models would figure it out. The other thing worth watching is where the market has put its fix. Cloudflare shipped a feature letting portal administrators rename and redescribe tools on servers they do not own, and the reason they gave is that you have no control over how the server author named the tools or wrote the descriptions, and unclear names make it harder for agents. Read that twice. Nobody builds an override layer for metadata that does not matter, so it is independent proof that the prose is load-bearing. But notice which side of the table the fix is on. **The thing shipping in production is the consumer overriding what the producer wrote, not the producer telling the consumer anything.** That is consumer-side governance showing up on its own because the producer side does not exist, and it is exactly what always happens when producers do not give consumers what they need — everyone builds it themselves, one at a time, and the ecosystem ends up with thousands of private forks of your metadata and no shared truth about what your tools do. I have [written up the full guidance](https://guidance.apievangelist.com/store/agent-surface-change/), but the short version for anyone running an MCP server today: treat the description as part of the contract and give a description change the notice you would give a schema change. Version the tool surface instead of inheriting a number from your REST API, because your descriptions can be rewritten without your API moving at all — the common advice to align those two versions makes the most agent-relevant change class invisible by construction. Removing a tool is the most severe thing you can do. Say what is going away and say when, somewhere a machine can read it. Test behaviorally, because a schema diff provably cannot see this. And carry your pricing and rate limits into the same discipline as your schemas. None of that needs a new specification to start, and some of it will eventually want one. The registry already crossed from identity into lifecycle the day it added a deprecation status. Giving that status a sunset date, a structured successor, and tool-level granularity is an incremental proposal into a working group that has already proven it will adopt a serious deprecation policy when somebody writes one. That is the difference between saying a thing is broken and doing the work. This is not broken. It is unfinished at exactly one layer, and it happens to be the layer everything else now runs on.