DEV Community

weiseer
weiseer

Posted on • Originally published at github.com

I scanned 200 popular MCP server packages. Here is what I found.

The MCP ecosystem has been growing fast, but the supply-chain hygiene has not kept up. MCPwn (CVE-2026-33032, CVSS 9.8) exposed 2,600+ instances. The Shai-Hulud npm worm stole MCP auth tokens from 172 packages. MCPSafe found high-severity bugs in official MCPs from Atlassian, GitHub, Cloudflare, and Microsoft. Perplexity open-sourced Bumblebee in May 2026 specifically because no good scanner existed.

So I built one. Today I'm shipping @weiseer/mcp-doctor — an open-source install-time trust gate for MCP server packages — together with the validation dataset that surfaced its first real finding.

TL;DR

npx @weiseer/mcp-doctor @some/mcp-server
Enter fullscreen mode Exit fullscreen mode

Returns PASS / WARN / BLOCK with cited evidence per signal. The full scoring rubric is open-source so you can argue with the methodology rather than trust a black-box. Free public scan endpoint at https://api.weiseer.com/scan, 60 requests/min/IP, no auth.

Live dataset of 200 popular MCP-related packages at https://api.weiseer.com/dataset/scan_200.json. Leaderboard view at https://api.weiseer.com/leaderboard.

What the 200-package scan found

Verdict Count
PASS 138 (69%)
WARN 58 (29%)
BLOCK 3 (1.5%)
ERROR 1 (npm 404)

1 package had a hardcoded LLM API key

The scanner's D3_hardcoded_credentials_in_source signal fires on common provider key patterns (sk-ant-*, sk-*, AKIA*, ghp_*, npm_*, AIza*) in published source. It is a hard-block: −50 points, no questions.

One of the 200 packages tripped it with a real-looking sk-ant-... Anthropic key embedded in its bundled JavaScript source. The maintainer was emailed within the hour using their npm publisher contact. They have 7 days to rotate the key, deprecate the bad version, and republish reading from process.env. After that window closes (2026-06-06), I'll reference the pattern anonymously — but I'll keep the specific package name private indefinitely if they ask.

This is the Shai-Hulud-class risk in concrete form: a single embedded key, in a single npm package, that any tool scanning the agent's dependency tree could exfiltrate.

Six "official" MCP servers are silently abandoned

This one surprised me:

Package Days since last release Repository URL
@modelcontextprotocol/create-server 550 none
@modelcontextprotocol/server-postgres 541 none
@modelcontextprotocol/server-gdrive 501 none
@modelcontextprotocol/server-github 416 none
@modelcontextprotocol/server-slack 399 none
@modelcontextprotocol/server-puppeteer 382 none

These are still cited in nearly every MCP tutorial. None have a repository field in package.json, so source-to-binary verification is impossible. If you depend on any of them in production, mirror the source today.

@google/generative-ai is also installed broadly via npm but Google has archived its GitHub repo in favor of @google/genai.

2 typosquats of official servers

Self-explanatory — both blocked with −40 HARD C4_name_typosquats_official. Short-name comparison catches packages within edit-distance 1 of well-known official names.

The rubric is open-source by design

I am not a security vendor and these scores are not a black box. Every signal in rubric.yaml has:

  • An ID (e.g. D3_hardcoded_credentials_in_source)
  • A deduction value (how much it costs you)
  • A rationale (why we think it matters)

If you think A1_unpinned_deps is too aggressive, open a PR. If you think B2_single_maintainer unfairly punishes new packages, open a PR. The whole point of an open rubric is that ecosystem trust is a public good, not vendor secret sauce.

I ran the scanner on my own 9 packages first (@weiseer/*) and published the results in the same leaderboard. They all PASS at 100/100 — but two signals (B2_single_maintainer, B3_repo_under_60d_old) are explicitly suppressed via the self_disclosure flag because they're trivially expected on packages published the same day. I'd rather show the suppression than score myself perfect with a rigged rubric.

How to use it

Single package:

npx @weiseer/mcp-doctor @some/package
Enter fullscreen mode Exit fullscreen mode

Audit your existing MCP config:

npx @weiseer/mcp-doctor --config ~/Library/Application\ Support/Claude/claude_desktop_config.json
Enter fullscreen mode Exit fullscreen mode

CI gate to block bad MCPs in PRs:

- uses: weiseer/mcp-doctor-action@v1
  with:
    config-path: '.mcp/claude_desktop_config.json'
    policy: 'block-only'  # or strict, or report
Enter fullscreen mode Exit fullscreen mode

README trust badge:

![MCP Trust](https://api.weiseer.com/badge?pkg=YOUR_PACKAGE)
Enter fullscreen mode Exit fullscreen mode

Pricing

Tier Price Get
Free $0 Single scan + Trust Badge + leaderboard, 60 req/min/IP
Pro $19/mo Repo monitoring, drift alerts, badge history
Team $49/mo 5 repos, Slack/Webhook alerts, custom policy YAML
Enterprise $299/mo Unlimited repos, audit log export, SLA

What is broken / what I want feedback on

  • A1_unpinned_deps calibration — npm convention is ^ ranges. v0.2 raised the threshold to >5 deps AND >70% caret, but I might still be over-firing.
  • B3_repo_under_60d_old — suppressed for self_disclosure packages but maybe should be more nuanced (new fork vs new project).
  • Typosquat detection — currently short-name edit-distance ≤1. Might miss creative variants.
  • MCP-specific signals (D series) — capability-declaration mismatches are very domain-specific and the rule layer feels thin.

If you spot a false positive when you run it on your packages, please open an issue with the package name + which signal you think is misfiring. The faster the rubric matures, the more useful this is for everyone.

Links

Apache-2.0.

Top comments (0)