15,465 MCP Servers, Zero Governance: The Gap in the Agent Supply Chain
💡 Tool Tip:API Key Rotator、API Tester、API Doc Generator
On September 24, 2026, OX Security published research analyzing 15,465 published MCP servers across three public registries, narrowing the dataset to 5,095 unique hostnames for infrastructure analysis. Four findings are worth keeping. First, 15.6 percent of the hostnames, 796 of 5,095, resolve outside the United States, including 19 in China and 18 in Russia. Second, about 0.45 percent route through home networks and consumer tunneling services. Third, 2.3 percent no longer resolve, and six of those domains were unregistered and available for USD 4 to 12 a year, letting anyone impersonate the former server. Fourth, in a test against Claude Code with Haiku 3.5, a single always-allow approval was reused to read a sensitive file including .env with no second prompt. Here are the four findings and how to harden your MCP footprint.
1. The Dataset: 15,465 Servers, 5,095 Hostnames
Start with the method, because the trustworthiness of the conclusions depends on the sample. OX Security Research pulled 15,465 published MCP servers from three public registries, namely mcp-official-registry, cline-marketplace and github-mcp-registry, then narrowed the dataset to 5,095 unique hostnames for infrastructure analysis. The deduplication step matters: the same endpoint can appear in several registries, and without deduplication you mistake noise for scale. The study's conclusion is that MCP is, in many cases, shadow AI infrastructure, because it lets AI agents, developer workstations and automated pipelines connect to third-party servers on demand, routing around the governance enterprises spent a decade building around the cloud. Code sample 1 expresses that inventory logic in the fewest lines.
# Finding 1: the dataset. MCP servers are published across multiple public
# registries. Deduplicate before you reason about infrastructure, because the
# same endpoint can appear in several places.
REGISTRIES = ["mcp-official-registry", "cline-marketplace", "github-mcp-registry"]
def build_inventory(registries):
servers = [s for r in registries for s in fetch(r)]
hostnames = {host(s.url) for s in servers if s.url}
return {
"servers": len(servers), # 15,465 published servers
"unique_hostnames": len(hostnames), # 5,095 unique hostnames
"by_registry": {r: len(fetch(r)) for r in registries},
}15.6% of hostnames resolve outside the US
2. Finding One: Infrastructure Without Borders
The first finding goes straight at data residency. Of the hostnames analyzed, 15.6 percent, 796 of 5,095, resolve outside the United States, including 19 in China and 18 in Russia. The crux is the protocol itself: MCP has no protocol-level concept of geographic region. An enterprise can enforce strict residency controls on its own cloud workloads while its AI agents connect freely to servers sitting outside those same controls. This is not a misconfiguration in one place but a structural mismatch in the governance boundary: you wrote the residency rule on the cloud you control, but the agent's connection path never passes through those rules. Code sample 2 shows how to quantify the exposure by resolving each hostname and classifying its location.
# Finding 2: infrastructure without borders. MCP has no protocol-level
# concept of geographic region, so an enterprise can enforce strict residency
# on its own workloads while its agents connect freely to servers outside
# those controls. Resolve every hostname and classify its location.
def residency(hostnames):
out = {"outside_us": 0, "in_china": 0, "in_russia": 0, "unresolved": 0}
for h in hostnames:
ip = dns_resolve(h)
if ip is None:
out["unresolved"] += 1 # 2.3% no longer resolve
continue
country = geoip_country(ip) # e.g. "CN", "RU", "US"
if country != "US":
out["outside_us"] += 1 # 796 of 5,095 = 15.6%
if country == "CN":
out["in_china"] += 1 # 19
if country == "RU":
out["in_russia"] += 1 # 18
return out3. Findings Two and Three: Consumer Infrastructure and Abandoned Domains
The second finding is production traffic running on consumer infrastructure. The research identified MCP servers proxied through home networks and consumer tunneling services, about 0.45 percent of the dataset. That means production AI workflows can depend on infrastructure with no uptime guarantee, no enterprise access controls and no real auditability, because it was never built to be enterprise infrastructure in the first place. The third finding is abandoned domains as live risk. 2.3 percent of the hostnames analyzed no longer resolve; six of those domains, likely still referenced in someone's config or pipeline, were unregistered and available for about USD 4 to 12 a year. Anyone can buy one and start impersonating the server it used to point to, while clients that still trust the endpoint connect as usual. Code sample 3 writes that detection: treat resolution failure as an incident, not a warning.
# Finding 3: abandoned domains, live risk. When a domain lapses, anyone can
# register it and impersonate the server it used to point to -- while stale
# configs and pipelines still trust and call that endpoint. Treat resolution
# failure as an incident, not a warning.
def domain_risk(hostnames, price_range=(4, 12)):
risks = []
for h in hostnames:
if dns_resolve(h) is None:
registrable = registrable_domain(h)
if not is_registered(registrable):
risks.append({
"host": h,
"domain": registrable,
"available_for": f"${price_range[0]}-${price_range[1]}/yr",
"impact": "anyone can impersonate the former server",
})
return risks # 6 such domains in the studyOne always-allow bought access to .env
4. Finding Four: Trust That Outlives the Decision That Granted It
The fourth finding is the closest to daily life. OX tested a trust-based prompt injection against Claude Code paired with Haiku 3.5. A malicious MCP server first asked for access to a harmless file, and the user approved it with an always-allow permission. The server then requested a sensitive file, .env among them, and got it with no further prompt required. The same attack failed against Opus 4.6 and 4.7. The vendor's response, in short as OX reports it, was that once always-allow is granted, that is the documented behaviour, and that model-level detection of malicious content is a best-effort heuristic, not a security boundary. The lesson is plain: any persistent approval is a standing pass you must scope and expire. Code sample 4 makes per-call approval the default.
# Finding 4: trust that outlives the decision that granted it. A malicious
# MCP server asked for a harmless file, the user chose always-allow, and the
# server then read a sensitive file (.env among them) with no second prompt.
# Any persistent approval is a standing grant you must scope and expire.
def approve(request, scope="session"):
if scope == "always":
return {"decision": "always-allow",
"warning": "this grant can be reused for ANY later request "
"the server makes, not just the one you saw"}
return {"decision": "allow-once",
"expires": "end-of-call",
"re_prompt": "every future request"}
# Least privilege for MCP means per-call approval for anything touching
# secrets, credentials, or data outside the task's declared scope.5. Why It Matters
Put the four findings together and the shape becomes clear. This is not a vulnerability in a particular server; it is a mismatch between a governance model and the speed of adoption. Was a decade and many billions of dollars of data residency work a genuine, non-negotiable floor, or merely compliance theater that enterprises are prepared to abandon the moment AI offers enough convenience? OX does not claim to hold the answer, but it does offer one judgement: adoption and security are not the same axis, and a secure ecosystem does not grow automatically out of adoption. It happens because someone, somewhere, decided to care. For engineering teams, that means onboarding an MCP server deserves the same inventory, classification and periodic review as any other production dependency, rather than being a line of config in a developer's environment. Code sample 5 gives a hardening checklist and a CI gate function.
# The practical fix set. Adoption and security are different axes, so make
# the secure path the default path in your agent config and CI.
HARDENING = [
"inventory every MCP server in dev configs and production agents",
"record owner, hostname and the data each server can reach",
"remove stale endpoints and unpinned, unused servers",
"ban blanket always-allow for secrets, credentials and company data",
"recheck domain ownership, egress rules, credentials and logs",
]
def gate(server) -> list:
fails = []
if not server.pinned_version: fails.append("unpinned server version")
if server.resolves_outside_allowlist(): fails.append("egress outside allowlist")
if not server.has_owner: fails.append("no named owner")
return failsInventory first, then remove stale endpoints
6. Hardening Your MCP Footprint
Finally, the practice. First, inventory: register every MCP server across developer configs and production agents, recording its hostname, owner and the data it can reach, as code samples 1 and 5 do. Second, clean up: remove stale endpoints and unpinned, unused servers so they are not left hanging for later. Third, ban blanket always-allow for secrets, credentials and company data, moving to per-call approval with expiring grants, as code sample 4 does. Fourth, recheck: domain ownership, egress rules, credentials and logs, especially for tools that can reach company data. Fifth, treat resolution failures as incidents rather than noise, as code sample 3 does. Put these steps into your default config and CI, and the convenience of MCP connections will not come at the cost of your governance boundary.
📌 Frequently Asked Questions
What data did the research analyze?
OX Security analyzed 15,465 published MCP servers across three public registries (mcp-official-registry, cline-marketplace and github-mcp-registry), then narrowed the dataset to 5,095 unique hostnames for infrastructure analysis.
What does 'infrastructure without borders' mean?
15.6 percent of the hostnames, 796 of 5,095, resolve outside the United States, including 19 in China and 18 in Russia. MCP has no protocol-level concept of geographic region, so an enterprise can enforce strict residency on its own cloud workloads while its agents connect freely to servers outside those controls.
What is the abandoned-domain risk?
2.3 percent of hostnames no longer resolve, and six of those domains were unregistered and available for about USD 4 to 12 a year, while likely still referenced in someone's config or pipeline. Anyone who buys one can impersonate the server it used to point to, and clients or workflows that still trust the endpoint will connect as usual.
What is 'trust that outlives the decision'?
OX tested a trust-based prompt injection against Claude Code paired with Haiku 3.5. A malicious MCP server first asked for a harmless file and the user approved it with an always-allow permission; the server then requested a sensitive file, .env among them, and got it with no further prompt. The same attack failed against Opus 4.6 and 4.7.
How did the vendor respond?
As OX describes it, Anthropic's response was, in short, that once always-allow is granted, that is the documented behaviour, and that model-level detection of malicious content is a best-effort heuristic rather than a security boundary.