{"slug": "mcp-schema-drift-isn-t-a-rate-it-s-a-small-set-of-servers-that-never-stop-moving", "title": "MCP schema drift isn't a rate, it's a small set of servers that never stop moving", "summary": "A developer's census of 474 MCP servers across three snapshots over 72 hours found that only 5.1% changed their tool contract, far below the linear projection of 8.8%, revealing that schema drift is concentrated in a small set of actively-developed servers while most are frozen. The analysis also showed that only 18% of tools declare an outputSchema, meaning the majority have no declared contract to break, and the developer plans to refine the monitoring approach based on community feedback.", "body_md": "Two days ago I measured that [4.4% of MCP servers changed their tool contract in 36 hours](https://dev.to/theopslog/44-of-mcp-servers-changed-their-tool-contract-in-36-hours-i3m), and refused to annualise it on the grounds that changes probably cluster.\n\nI now have a third snapshot, and the caution was warranted more strongly than I expected.\n\nSame 474 servers, three snapshots: baseline, +36h, +72h.\n\n| changed since baseline | |\n|---|---|\n| +36 hours | 21 (4.4%) |\n| +72 hours | 24 (5.1%) |\n\nTwenty-one servers moved in the first 36 hours. In the next 36 hours, **three more did.** A constant independent rate would have predicted 42 by day three. The real number was 24 — **57% of the linear projection**, and the gap widens the further you extrapolate.\n\nTwo other things fell out of the comparison:\n\nThis is not \"MCP servers change at ~3% a day.\" It is:\n\n**A small set of actively-developed servers that change constantly, and a large majority that are effectively frozen.**\n\nThe first snapshot caught almost the entire volatile subset in one pass. Everything after that is scraping a much thinner seam — a few genuinely new movers, plus repeat churn from the same handful.\n\nIf you annualised my original number you'd conclude that most of the registry rewrites itself within a month. That's wrong, and it's wrong in the direction that makes you build the wrong thing: continuous revalidation of everything, when what you actually need is to identify the ~5% that moves and watch *those*.\n\nI hashed `inputSchema`\n\n. On the last post [anp2network](https://dev.to/theopslog) pointed out that `tools/list`\n\nalso carries `outputSchema`\n\nwhen a server declares structured output, and that it binds any caller parsing results just as hard.\n\nThat's correct and I was blind to it. So I measured the declared surface:\n\n| surface | coverage |\n|---|---|\ntools with `outputSchema`\n|\n1,553 / 8,629 (18.0%) |\ntools with `annotations`\n|\n6,251 / 8,629 (72.4%) |\nservers declaring any `outputSchema`\n|\n155 / 476 (32.6%) |\n\nOnly 18% of tools declare an output contract at all. Which cuts both ways: output drift is a real hazard for the 18%, and for the other 82% there is simply **no declared contract to break** — you are parsing whatever comes back and hoping.\n\nI'd argue the 82% is the bigger problem, and it doesn't show up in any drift measurement because there's nothing to diff.\n\n[zira125](https://dev.to/theopslog) suggested hashing `inputSchema`\n\n, `outputSchema`\n\n, `description`\n\nand `annotations`\n\nseparately and *classifying* changes rather than treating every hash mismatch as equally bad — additive optional fields warn, required-field additions and enum narrowing fail. That's obviously right, and v2 of my census now captures all four separately.\n\n[komo](https://dev.to/theopslog) framed the deployment shape: snapshot contracts as build artifacts and fail fast when the hash moves. And [Mads Hansen](https://dev.to/theopslog) pointed out something I'd waved through — **\"tool added\" is not automatically safe**, because a new overlapping tool changes selection and can silently redirect calls that used to go somewhere else, even though every old invocation still validates.\n\nBetween them that's a better spec than I had when I started. The useful version is not a monitor that re-checks everything on a timer. It's:\n\n474 servers comparable across all three snapshots, drawn as a seeded random sample (`random.seed(20260730)`\n\n) from the 5,346 registry endpoints that complete an anonymous handshake, so every re-run hits identical servers. `initialize`\n\n→ `notifications/initialized`\n\n→ `tools/list`\n\n, handling SSE frames and threading `Mcp-Session-Id`\n\n. SHA-256 per surface, sorted keys.\n\nThree snapshots is enough to see that a straight line is the wrong model. It is not enough to say what the right one is. I'll keep taking them.", "url": "https://wpnews.pro/news/mcp-schema-drift-isn-t-a-rate-it-s-a-small-set-of-servers-that-never-stop-moving", "canonical_source": "https://dev.to/theopslog/mcp-schema-drift-isnt-a-rate-its-a-small-set-of-servers-that-never-stop-moving-243c", "published_at": "2026-08-02 19:30:51+00:00", "updated_at": "2026-08-02 20:17:44.866017+00:00", "lang": "en", "topics": ["developer-tools", "ai-infrastructure"], "entities": ["MCP", "anp2network", "zira125", "komo", "Mads Hansen"], "alternates": {"html": "https://wpnews.pro/news/mcp-schema-drift-isn-t-a-rate-it-s-a-small-set-of-servers-that-never-stop-moving", "markdown": "https://wpnews.pro/news/mcp-schema-drift-isn-t-a-rate-it-s-a-small-set-of-servers-that-never-stop-moving.md", "text": "https://wpnews.pro/news/mcp-schema-drift-isn-t-a-rate-it-s-a-small-set-of-servers-that-never-stop-moving.txt", "jsonld": "https://wpnews.pro/news/mcp-schema-drift-isn-t-a-rate-it-s-a-small-set-of-servers-that-never-stop-moving.jsonld"}}