DEV Community

md sultan mahamud
md sultan mahamud

Posted on

The MCP registry checks a package at publish. Here's what drifts after that.

When you install an MCP server from the official registry, you get exactly the package version the entry lists. The registry checks that version when the entry is published: it fetches it from npm or PyPI and confirms the package names the server.

I read the registry's source to see what happens after that. The package check runs again only when the publisher edits the entry. Nothing re-checks entries on a schedule. Repository links are checked against a URL pattern and never fetched.

That's a reasonable design for a young registry, and it isn't anyone's mistake. But it means entries can drift. So I checked the whole registry against npm, PyPI and GitHub and counted what no longer matches.

What I counted

Registry snapshot 2026-10-04: 38,977 servers (the latest version of each name). Lookups ran on 2026-10-06.

What Count Out of Share
Repository link returns 404 (missing or private) 4,298 28,743 entries with a GitHub link 15.0%
Listed version is withdrawn upstream (npm deprecated / PyPI yanked) 663 14,431 npm/PyPI entries 4.6%
Linked repository is archived 309 24,256 reachable repos 1.3%
Listed package or version can't be installed at all 157 14,431 npm/PyPI entries 1.1%
Active, but no package, no remote and no website 216 38,977 0.6%

Together, at least 5,192 of 38,977 entries (13.3%), more than 1 in 8, had at least one of these.

A few notes on reading this:

  • The 157 are the clearest case of drift. All of them were published after the registry's version check existed. If validation was on (it is by default), each one passed an exact-version check and the package or version disappeared later.
  • Withdrawn doesn't mean malicious. I classified the publishers' own deprecation messages. Most are renames, moved distributions and discontinued packages. A few say the backing service shut down, and 12 publishers cite a security issue. A registry-driven install still gets the withdrawn version, with no warning.
  • A 404 can be a renamed or private repo. I don't tell those apart.

The fix is now being tracked

I opened a feature request on the registry, modelcontextprotocol/registry#1715. It asks to re-run the existing checks on a schedule and record the result (for example lastVerifiedAt plus a status) instead of deleting anything.

On 2026-10-23, a member of the MCP organization consolidated the older re-validation request (#93) and five endpoint-health reports into that issue, so periodic re-validation now has one implementation tracker. The direction in the thread: dated results, explicit "auth-required / transient / unknown" states, and no removal on a single failed check.

That last point matters. A missing repo or a yanked version is a fact a client should see. It shouldn't silently turn into a takedown.

What this doesn't say

  • Nothing here says whether any server is safe or unsafe. I didn't run or call any server's tools. Everything comes from the registry and public package records.
  • The numbers are a dated snapshot. The registry has grown since then, and I haven't recounted these figures.

If you publish an MCP server

Five minutes of housekeeping:

  1. Open your registry entry's repository.url. Does it still load?
  2. Is the version you list still published, and not deprecated or yanked?
  3. If you renamed or moved the package, publish an update that points to the new one.

Full tables, with each figure's source and date: https://protocolprobe.com/mcp/reports/registry-vs-reality
Dataset (CC BY 4.0, citable): https://doi.org/10.5281/zenodo.23386799

Disclosure: I built ProtocolProbe, a free directory that reads the registry's public data. Corrections welcome: hello@protocolprobe.com.

Top comments (3)

Collapse
 
skillselion profile image
Skillselion •

On that 404 line: GitHub keeps a redirect when a repository is renamed or transferred, so the old URL of a renamed repo usually answers with a 301 to the new location, and the REST API does the same for /repos/{owner}/{repo}. The redirect only breaks if someone later creates a new repository under the old name. So a renamed repo is probably not in the 4,298 at all: most HTTP clients follow the 301 silently, which puts renames in your reachable count. Record the 301 instead and they become a separate group.

That also gives #1715 a cheap extra state: "moved", with the new URL attached. A client can update its link from that state.

One trap we hit keeping a skills catalog in sync with GitHub (we run Skillselion): unauthenticated API calls run out at 60 an hour and come back 403 or 429, while a private repo comes back 404. If the script logs any non-200 as missing, a rate-limited run looks like mass deletion.

Collapse
 
autenai profile image
Auten •

From the publisher side (Auten team here, we have one small entry, ai.auten/mcp): the drift you describe is easy to cause without noticing. Our server.json version only moves when we republish it, so every npm bump is a separate manual step, and the registry entry was the first thing to lag: it sat a version behind npm until we noticed.

One downstream question: GitHub's MCP registry (api.mcp.github.com, which feeds the VS Code gallery) shows the same version as our official entry. Did you check whether withdrawn or uninstallable versions stay listed there too? If curated mirrors just copy the entry, a dated lastVerifiedAt from #1715 would be the only signal that ever reaches those clients.

Collapse
 
deanlee profile image
Dean Lee •

Point-in-time verification treats package validity as a permanent state rather than a decaying signal. Once an entry passes the initial registration gate, the registry essentially issues an unhedged put option on the publisher's future maintenance. Upstream yanked packages and 404 repos are just the visible default rate on that promise.

The distinction between recording a dated verification state and executing silent takedowns is the right architectural choice. For automated agent runtimes, a binary registry that drops failing entries causes cascading execution failures where an agent cannot even diagnose why a tool disappeared. Surfacing the verification timestamp lets the runtime price the availability risk itself before binding the execution context.