How often do MCP servers break their callers? We diffed 13,629 of them
Two months of snapshots from every remote MCP server in the directory, classified as breaking, compatible, or cosmetic. 18% shipped a breaking change, most of them by removing a property.
An MCP server is an API whose contract is whatever tools/list says right now. There is no version you pin, no changelog you subscribe to, and no deprecation window. The client asks, the server answers, and if the answer changed since yesterday, nobody tells you.
So we counted. This directory probes every remote MCP server it knows about every six hours and keeps a snapshot whenever the answer changes. Between August 20 and October 26, 2026, that came to 60,980 snapshots from 13,629 servers. We ran every consecutive pair through the same classifier the directory uses, which sorts each change into breaking, compatible, or cosmetic.
The short version
- 18% of servers shipped at least one breaking change, 2,515 of 13,629, in the time we watched them: 14 days on average.
- Half of all servers changed their contract at all (7,209). Of those, more than one in three broke something.
- 1 in 10 changes was breaking. A third were cosmetic, a third compatible, and a fifth moved nothing but the version string.
- The most common break is a removed property, ahead of new length limits and new required arguments.
- 52% of changes rewrote a tool's description or annotations, the text a model reads to decide when and how to call it.
What changed, change by change
45,430 consecutive snapshot pairs differed in their tools or prompts. Each one gets the severity of the worst thing in it:
| Severity | Changes | Share |
|---|---|---|
| Cosmetic: descriptions, titles, annotations | 15,472 | 34% |
| Compatible: new tools, new optional arguments | 14,881 | 33% |
| Version or protocol string only | 9,184 | 20% |
| Breaking: existing callers can fail | 4,791 | 10.5% |
| Excluded (see method) | 1,102 | 2.4% |
Breaking is the smallest bucket, and that is the problem with it. A tenth of changes is rare enough that nobody checks every deploy, and common enough that across a few dozen servers an agent depends on, one of them is always moving.
What a break looks like
In order of how often we saw them:
- A property removed. An argument the server used to accept, or a field it used to return, is gone. On the way in, a caller still sending it is now sending something outside the contract. On the way out, a caller reading it gets nothing.
- A new
maxLength,maximum,minimum, orpattern. The argument still exists, but values that worked yesterday are rejected today. - A new required argument. Every existing call omits it.
additionalProperties: falseadded. Extra fields that were silently ignored now fail validation.- A tool removed outright. 29% of breaking changes removed at least one tool or prompt.
An illustrative example, combining two of the most common breaks:
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" },
- "limit": { "type": "integer" }
+ "limit": { "type": "integer", "maximum": 50 },
+ "workspace_id": { "type": "string" }
},
- "required": ["query"]
+ "required": ["query", "workspace_id"]
}Two breaks in one deploy. Every call without workspace_id fails, and every call with limit: 100 does too. An agent that worked on Monday gets validation errors on Tuesday, and the server's version string may not have moved.
Most servers break rarely, a few break constantly
Of the 2,515 servers with a breaking change, 61% had exactly one. 27 had ten or more. The distribution matters for what you do about it: you cannot avoid servers that change, because half of them do, but the ones that break repeatedly are a small, identifiable group.
The changes that are not breaking, and still matter
Half of all changes rewrote the description or annotations on at least one tool. That classifies as cosmetic, correctly: no caller's code stops working because a description got longer.
But for an agent, the description is the instructions. It decides when the tool gets called and what gets passed to it, and annotations like readOnlyHint and destructiveHint are what a client uses to decide whether to ask before running it. A server that flips destructiveHint from true to false has changed nothing a type checker would notice, and possibly what your agent does without asking. Two snapshots cannot tell you whether an edit like that was innocent, only that it happened. That is worth knowing on its own.
Method
- Source. Every server in the directory with
source = probesnapshots, 2026-08-20 to 2026-10-26. Servers came from manual submissions and public registry crawls, so the set includes test and hobby servers next to production ones. Each server was observed for 14 days on average, so these are rates over a short window, not over a year. - Contract = tools + prompts. Resource lists are left out. Many servers list files or records there, which come and go with the data, not with a deploy.
- Classification is
schemadiff, the open-source engine behind this directory. It treats input and output schemas in opposite directions: a narrower input breaks callers, a narrower output does not. - Excluded: 728 changes whose only breaking part was an
anyOf,oneOf, or$refthe classifier does not analyse and flags for review by hand, and 387 changes reverted in the very next snapshot, which are more likely a flapping deploy than a decision. 13 changes fell in both groups, so 1,102 in total. - Counted per consecutive pair. A server probed into a new state counts once, however long it stays there.
What to do about it
If an agent you run depends on remote MCP servers, three things help, in order of effort:
- Read the change before your agent does. Every server in the directory has a history page, and the change feed lists what moved across all of them, classified by the same engine. Reading a diff explains each verdict.
- Get told when one of yours breaks. Watch emails you when a server you depend on ships a breaking change, naming the tools that broke and linking to the classified history.
- Check your own server before you ship. If you run an MCP server, the CLI diffs your current contract against the last one in CI and fails the build on a breaking change you did not mean to make. The CI guide has the setup.