What I got wrong and how
The first pull stopped at page 25. The response came back with no metadata.nextCursor field, and I read that as exhaustion: no cursor left, so no more servers. An absent cursor is not proof the list ended. It can mean a transient response, a proxy dropping the field, or a pull that simply stopped retrying at the wrong moment. I did not check for any of those. I saw an empty field and called the audit done.
The registry also sorts results alphabetically by server name. Page 25 at 100 records per page covers roughly the first 2,500 names, and names near the front of the alphabet lean heavily on ai.* reverse-domain prefixes, the namespace hosted AI startups tend to register under. The sample that produced 759 was not a random slice of the registry. It was the first slice, skewed toward exactly the kind of hosted, no-repository server the original piece went on to flag. The 83% hosted figure and the 56% hosted-no-repo figure were both measuring a biased subset and reporting it as the whole population.
The fix was mechanical: page until the cursor is actually empty, and prove it by tracking every cursor value seen and refusing to count a repeat as new progress. 879 pages, 87,819 version records. Deduplicated by server name, keeping the latest version, that is 26,300 unique servers. A duplicate-(name,version) check across the full pull returned zero, so no page was re-fetched and double-counted. A cursor cycle guard, which flags a cursor value coming back a second time, never fired.
curl -s "https://registry.modelcontextprotocol.io/v0/servers?cursor=$CURSOR&limit=100" # looped on metadata.nextCursor, recording every cursor value returned # exhaustion = nextCursor comes back empty AND no cursor value repeats across the run # 879 pages, 87,819 version records, deduped by name: 26,300 unique servers
Exhaustion means two conditions held at once: the cursor came back empty, and no cursor value repeated anywhere in the pull. Checking only the first one is what produced 759.
The numbers
| Metric | Count | Note |
|---|---|---|
| Unique servers | 26,300 | 87,819 version records before dedupe; 25,997 active, 303 deprecated |
| Expose a hosted remote | 14,638 (56%) | 14,058 streamable-http, 1,067 SSE endpoints |
| Ship an installable package | 12,576 (48%) | 8,271 npm, 3,517 PyPI, 964 MCPB, 849 OCI, 105 NuGet, 35 Cargo |
| Both remote and package | 1,316 | Run it yourself or use theirs |
| Neither | 402 | No hosted endpoint, no installable package |
| No public repository | 6,136 (23%) | Nothing to read before you trust it |
| Hosted remote, no repository | 5,564 of 14,638 (38%) | The number that matters |
Point-in-time snapshot, 2026-09-01. Compare that to Glama, which indexes roughly 37,800 servers: the official registry is about 70% the size of the largest community index. The framing I used two weeks ago, that the official registry is nearly empty next to the community directories, is simply false.
What survived the correction and what didn’t
Some of the original findings held up at the corrected scale. Some did not. The full before and after, no cherry-picking:
- Hosted share: 83% then, 56% now. Still a majority, a smaller one.
- Hosted with no repository: 56% of hosted servers then, 38% of hosted servers now.
- Installable packages: 21% then, 48% now, nearly half the registry.
- Plaintext http endpoints: zero then, zero now. 15,125 of 15,125 declared endpoints are https.
- Version pinning: held at roughly 90% of package versions exact-pinned.
- Deprecated SSE transport: 20 servers then, 1,042 servers now.
- Credential hygiene: did not hold. Covered below in its own section.
The 38%
5,564 hosted servers, 38% of the 14,638 that expose a remote endpoint, list no public repository. You point an agent holding your credentials at their endpoint, and there is nothing to read first.
This is not a vulnerability, and not an accusation against any specific operator. It is an accountability gap, and it sits under a bit over a third of the hosted ecosystem, smaller than the more-than-half the biased sample suggested, still large enough to matter for anyone wiring a remote MCP server into a workflow that touches customer data.
Who publishes them
A reader on r/mcp asked who actually owns the no-repo servers: a handful of platforms, or thousands of individual publishers. The exhaustive pull answers it. 6,136 servers have no public repository, spread across 4,268 distinct publisher IDs.
96% of those publishers, 4,084 of them, have exactly one no-repo server registered. 73% of all no-repo servers come from a publisher whose only entry is that one server. This is a long tail of individual developers and small teams, most of whom published once and moved on, not a small set of platforms hiding a large share of the total.
96 publishers have three or more no-repo servers, and together they account for 1,304 servers, about a fifth of the no-repo total. The two largest by volume are io.github.Evozim with 374 servers and io.github.Wxt-ai with 122. Both read as bulk-generated or templated listings rather than a normal publishing pattern. ai.smithery shows up too, at 38, but Smithery is a hosting platform: it lists servers it hosts on behalf of other people, a different accountability model than an individual publishing their own code without a repo link.
A required repository field on submission fixes this going forward. It does not fix the 6,136 servers already in the registry. Nothing does, short of contacting thousands of individual publishers one at a time.
The 9%
The one genuinely new negative finding is in the environment variable data. 7,123 environment variables across all package manifests have names that look like credentials, patterns like API_KEY or _TOKEN. 6,455 of those are flagged isSecret in the manifest. 668 are not, about 9% of the credential-shaped total.
That flag exists so a client can decide whether to mask a value in logs, terminal output, or a settings screen. A client that honors isSecret and trusts the manifest to set it correctly will treat those 668 variables as plain text. The original piece checked a 172-version sample and found the flag applied every time. At full scale it is not universal, it just looked that way in the slice that got checked first.
What to actually do about it
None of this needs a consultant to check. Point the free scanner at your own configs and read the output:
npx mcp-scan@latest
No install, no account, no telemetry. It reads the AI tool configs already on your machine and tells you what your agents can reach. If you are wiring a remote MCP server into something that touches customer data, the three questions worth answering before launch are: can I read this server’s source, what does my token let it do if it is hostile, and would I notice.
If you would rather have a person answer those against your real setup and hand back something you can forward to a customer or an auditor, that is what the MCP Risk Review is. Fixed price, 48 hours, one report.
Method and reproducibility
Data for this correction was pulled 2026-09-01 from registry.modelcontextprotocol.io/v0/servers, paged via metadata.nextCursor to exhaustion: 879 pages, 87,819 version records, cursor confirmed empty with no cursor value repeating across the run. Deduplicated by server name keeping the latest version, giving 26,300 unique servers, 25,997 active and 303 deprecated. A duplicate-(name,version) check across the full pull returned zero. Every figure above is a count over published manifest fields only. No server was contacted, probed, or scanned. Anyone can reproduce it with the curl command near the top of this piece.
Fair disclosure on the 38%: ThynkQ runs a read-only MCP server of its own, publishing services and pricing. It answers the same three questions I just asked of everyone else, which is the only reason I think they are fair to ask.