SkillTotal
← Back to home

We scanned every MCP server in the official registry

Four in five expose tools to an agent. Two in three can reach the network. Nearly a third can execute shell commands. Almost none of that is a vulnerability — and that is exactly why it is worth measuring.

To check one server rather than the population, scan it. For how the analysis works, see the docs.

Deterministic static scan of every distinct component in the public MCP registry — 17,535 of them — engine v0.49.0, ruleset 59, scanned 2026-09-19 against the registry as of 2026-08-16. The registry lists a server per published version, so its 73,460 entries collapse to 17,535 distinct components; counting the raw list would count one package many times.

What these components can do

Every figure is a capability: something the shipped code is able to do. A capability is not a vulnerability — a server that runs shell commands may exist precisely to run them. What it shows is the reach an agent inherits when it hands work to a component.

Exposes MCP tools
88.2%
Can reach the network
64.8%
Can execute shell commands
21.1%
Reads the filesystem
25.0%
Writes the filesystem
20.9%
Runs code at install time
7.4%
Delegated (OAuth/OIDC) authentication
5.8%
Evaluates code dynamically
3.1%
Scoped, short-lived identity
0.5%

OWASP Agentic Skills Top 10

Every rule with an honest static fit carries its OWASP class, so the same scan says which classes this population exhibits. A class counts components, not verdicts: the rules under Malicious Skills include exfiltration paths and evasion idioms a legitimate tool can carry, and no component here carries a malicious indicator. Classes with no evidence are left out rather than shown as zero.

ClassComponentsShare
AST03 Over-Privileged Skills1,90512.4%
AST02 Supply Chain Compromise1,2167.9%
AST01 Malicious Skills730.5%
AST05 Unsafe Deserialization530.3%

Which rules fired

38 rules matched something in this population; the 15 most frequent are below, and every rule is counted in the raw JSON. A rule firing describes what the code does, not what it intends — most of the traffic here is capability rules, which add nothing to the risk score. That is why the risk table below is so much flatter than the capability table above.

RuleComponentsShare
ST-MCP-DETECTED13,52488.2%
ST-NET-NODE7,41748.3%
ST-NET-PY2,78218.1%
ST-FS-PY-READ2,34315.3%
ST-SHELL-NODE2,12113.8%
ST-FS-PY-WRITE1,96412.8%
ST-FS-NODE-READ1,54710.1%
ST-EXPOSE-BIND1,3638.9%
ST-FS-NODE-WRITE1,3128.6%
ST-MCP-DANGEROUS-TOOL1,2988.5%
ST-SHELL-PY1,1497.5%
ST-AUTH-DELEGATED8955.8%
ST-INSTALL-NPM-PREPARE7494.9%
ST-MCP-SERVER-EXEC6954.5%
ST-INSTALL-NPM3752.4%

Risk levels

A capability contributes zero to the risk score; only risky constructs and malicious indicators do. A secret the component ships is reported separately as an exposure and does not raise the level either. The distribution is therefore far flatter than the table above — and that gap is the finding.

LOW
15,22599.3%
MEDIUM
900.6%
HIGH
220.1%
CRITICAL
4<0.1%

0 components (0.0%) carry at least one malicious indicator: a match against a rule for a known attack shape, not a verdict on the rest (see below).

Coverage

15,341 of 17,535 components were scanned (87.5%). Nothing was dropped silently — each exclusion is counted under its reason.

Not scanned becauseComponentsShare
repository or package no longer reachable1,6379.3%
slower than the time bound3021.7%
larger than the size bound1881.1%
other650.4%
access denied20.0%

The registry itself

  • 73,460 entries resolve to 17,535 distinct components.
  • 9.3% of the population points at a repository or package that is gone or private.
  • 7,312 components are hosted on GitHub across 4,325 owners — yet a single owner accounts for 18% of them, and the ten largest for 29.1%.

What this report does not claim

No count of leaked credentials. The engine does detect embedded secrets, but a sample of those hits in this population was dominated by values published on purpose — analytics project keys vendors document as safe to expose, on-chain addresses, public vendor constants. A raw count would measure shape rather than exposure, and presenting it as a number of leaks would be a false statement about named projects. A figure will appear when it can carry a precision estimate from a labelled sample.

No claim that any component is safe. A malicious indicator is a match against a published rule for a known attack shape: decode-and-execute, hidden Unicode, instructions planted for the agent, auto-run hooks, credentials sent out. A count of zero means no component matched one, not that none is harmful: code fetched at run time is out of a static scan's sight, and so is an attack no rule describes yet.

No component is named. These are population statistics.

Method and data

  • Deterministic regex + AST analysis. The component is never executed and no LLM is involved, so the same population through the same engine reproduces the same numbers.
  • Scanned components by ruleset: 11,774 with ruleset 56, 9 with ruleset 57, 30 with ruleset 58, 3,528 with ruleset 59. The later ruleset re-scanned only the components whose result its changes could affect, plus those that exceeded a bound on the first pass.
  • Two disclosed bounds: 50 MB per fetch and 60s of wall clock per component.
  • Shares are rounded to one decimal place so that each table sums exactly to its total (largest-remainder method); a share can therefore sit up to 0.1 point from its unrounded value. The counts beside them are exact.
  • Full report · Raw JSON · The harness that produced it