An open, reproducible security scorecard for the most-installed Model Context Protocol servers, graded A–F by Sentinel's engine at a pinned commit. Every finding links to a line of code, the rules are public, and each grade ships an embeddable badge you can re-run and verify yourself.
stripe/agent-toolkit:[](https://sentinel-engine-ggaj.onrender.com/registry/stripe__agent-toolkit.html)The most-installed MCP servers are genuinely well-built — 26 of the 28 graded here earn an A, and an honest scorecard reports what it measures. The grades are earned, not given: below, a real SSRF finding the engine produced in one of them, alongside a disclosed CVE from exactly the class these rules exist to catch.
The convert_to_markdown(uri) tool passes a user-controlled URI straight to a local fetch with no allowlist. MCP-SSRF-USER-CONTROLLED-URL High (CWE-918) → caps the grade at B.
OS command injection (CWE-78): a crafted authorization_endpoint URL reaches a system shell — a disclosed example of the class MCP-SHELL-EXEC-SURFACE targets (CWE-78).
Source: NVD CVE-2025-6514. A client, not a server in this list — cited as class evidence.
28 servers graded at a pinned commit, 24 findings cited to a line of code. Ranked by composite score. Click any row for the full report and its embeddable badge.
| # | Server | Install proxy / wk | Listed | Grade |
|---|---|---|---|---|
| 1 | GLips/Figma-Context-MCP | 75,862 | mcp.so · pulsemcp | A100 |
| 2 | apify/actors-mcp-server | 14,964 | mcp.so · pulsemcp | A100 |
| 3 | cloudflare/mcp-server-cloudflare | 1,808 | mcp.so · pulsemcp | A100 |
| 4 | e2b-dev/mcp-server | 4,079 | mcp.so · pulsemcp | A100 |
| 5 | grafana/mcp-grafana | 3,220 | mcp.so · pulsemcp | A100 |
| 6 | mendableai/firecrawl-mcp-server | 93,369 | mcp.so · pulsemcp | A100 |
| 7 | modelcontextprotocol/servers-archived | 2,007 | official-servers-repo | A100 |
| 8 | ppl-ai/modelcontextprotocol | 1,408 | mcp.so · pulsemcp | A100 |
| 9 | pydantic/pydantic-ai | 18,280 | mcp.so | A100 |
| 10 | qdrant/mcp-server-qdrant | 669,382 | mcp.so · pulsemcp | A100 |
| 11 | stripe/agent-toolkit | 25,231 | mcp.so · pulsemcp | A100 |
| 12 | supabase-community/supabase-mcp | 64,916 | mcp.so · pulsemcp | A100 |
| 13 | tavily-ai/tavily-mcp | 28,489 | mcp.so · pulsemcp | A100 |
| 14 | Flux159/mcp-server-kubernetes | 10,069 | mcp.so · pulsemcp | A99 |
| 15 | mongodb-js/mongodb-mcp-server | 63,752 | mcp.so · pulsemcp | A99 |
| 16 | redis/mcp-redis | 2,696 | mcp.so · pulsemcp | A99 |
| 17 | 21st-dev/magic-mcp | 13,350 | mcp.so · pulsemcp | A98 |
| 18 | block/goose | 50,846 | mcp.so | A98 |
| 19 | browserbase/mcp-server-browserbase | 1,754 | mcp.so · pulsemcp | A98 |
| 20 | exa-labs/exa-mcp-server | 18,395 | mcp.so · pulsemcp | A98 |
| 21 | getsentry/sentry-mcp | 85,444 | mcp.so · pulsemcp | A98 |
| 22 | modelcontextprotocol/servers | 63,459 | official-servers-repo · mcp.so | A98 |
| 23 | upstash/context7 | 523,993 | mcp.so · pulsemcp | A98 |
| 24 | sooperset/mcp-atlassian | 234,582 | mcp.so · pulsemcp | A96 |
| 25 | github/github-mcp-server | 31,296 | mcp.so · pulsemcp | A95 |
| 26 | chroma-core/chroma-mcp | 39,707 | mcp.so · pulsemcp | A94 |
| 27 | microsoft/markitdown | 32,981 | mcp.so · pypi | B94 · capped |
| 28 | awslabs/mcp | 1,661 | mcp.so · pulsemcp | B84 · capped |
We never publish a grade we can't back. These 7 servers are withheld with a specific reason — a language or packaging our analysis does not yet cover, or a high-privilege local agent still in grading calibration. Naming the gap is the point.
| Server | Install proxy / wk | Status | Why withheld |
|---|---|---|---|
| executeautomation/mcp-playwright | 17,255 | coverage pending | high-privilege local agent (drives a local browser to arbitrary URLs / runs page JS) - grading calibration in progress |
| googleapis/genai-toolbox | 15,907 | coverage pending | tools are defined in user-supplied YAML config, not in source |
| makenotion/notion-mcp-server | 125,682 | coverage pending | tools are generated at runtime from an OpenAPI spec, not defined in source |
| microsoft/mcp | 3,429 | coverage pending | no analyzable MCP tool source at the pinned commit (docs/CLI repo, no source in a supported language) |
| microsoft/playwright-mcp | 5,999,263 | coverage pending | tool implementation ships in the playwright-core dependency (repo index.js is a shim) - not present at the pinned commit |
| oraios/serena | 26,227 | coverage pending | high-privilege local coding agent (shell + filesystem tools) - grading calibration in progress |
| wonderwhy-er/DesktopCommanderMCP | 43,397 | coverage pending | high-privilege local agent (terminal command execution) - grading calibration in progress |
The scanner is open source and fully deterministic: the same repo at the same commit produces the same grade, byte for byte. Prerequisites are the Rust toolchain and Git — the scan runs on your machine, and your code never leaves it.
Swap in any owner/name and the pinned commit from its score page (or results/scores.json) to reproduce that grade instead.
Stars don't predict security — but they do help people find the scorecard. If this was useful, star anwen-labs/sentinel-mcp.
Every score is open and reproducible: the rules are public, each scan pins a commit, and every finding carries a file:line evidence pointer. Re-run it, get the same grade.
Repo code at a pinned commit: tool-description injection, secret handling & exfiltration, egress/SSRF, permission scope vs. declared purpose, supply-chain provenance.
No analyzable tool source at the pin → the grade is withheld, never guessed. Nine servers sit in that honest bucket today.
Unauthenticated exposure is a live-deployment property. We score code, not running endpoints.
A finding requires a real tool-input path to a sink; a shell or fetch tool is weighed against its declared purpose — the top documented false-positive cause.
The registry is free research. Point the open scanner at your repo, or request a scan and we'll add it — same engine, same evidence-backed grade, your code never leaves your machine.
pack-mcp-core@0.1.0.