# I scanned 10 MCP servers – here's what agents can't know before connecting

> Source: <https://github.com/davidnichols-ops/trustcard>
> Published: 2026-07-15 00:45:49+00:00

The "npm audit" for MCP servers. A trust card for every Model Context Protocol server — before you connect.

Every day, agents connect to MCP servers they've never met. They don't know whether the server installs, whether it speaks the current protocol, whether its tool schemas are valid, whether it exposes destructive tools, or whether it leaks secrets — **until something breaks or something leaks.**

`mcp-trustcard`

gives every MCP server a **public trust card** in one command:

```
npx mcp-trustcard @modelcontextprotocol/server-github
MCP Trustcard: github-mcp-server  @modelcontextprotocol/server-github
────────────────────────────────────────────────────────────────────────
Installability             PASS  @modelcontextprotocol/server-github@2025.4.8
Protocol handshake         PASS  github-mcp-server 0.6.2 · 717ms
Tool schema validity       PASS  26 tools, all schemas valid
Destructive capabilities   PASS  no destructive verbs; 11 write/exec tool(s)
Authentication             PASS  no auth required to list tools
Secret exposure            UNKNOWN  no secrets seen in this run (single probe)
Protocol version           WARN  negotiated 2024-11-05 (latest is 2025-06-18)
Latency & failure rate     PASS  1ms avg, 0% failure
────────────────────────────────────────────────────────────────────────
Score                      86/100
```

The MCP registry is growing fast. Security and quality verification are not. Recent research has found widespread exploitable weaknesses across MCP servers — tool poisoning, prompt injection via tool descriptions, shadowing, and secret leakage. Clients currently connect blind.

This project is a **public ranking surface**. If maintainers argue with a score, that's traction. If they ask how to improve, that's a product. If teams want private scanning, that's a company.

| Check | Pts | What it probes |
|---|---|---|
| Installability | 15 | Does the package resolve and install from npm? |
| Protocol handshake | 25 | Does it respond to `initialize` over stdio JSON-RPC? |
| Tool schema validity | 15 | Are `tools/list` schemas well-formed JSON Schema? |
| Destructive capabilities | 10 | Does it expose delete/drop/kill/overwrite tools? |
| Authentication | 10 | Is auth required, absent, or unknown? |
| Secret exposure | 10 | Do tool descriptions or errors leak secret-shaped strings? |
| Protocol version | 10 | Does it negotiate the latest protocol version? |
| Latency & failure rate | 5 | Handshake latency + 3-ping failure rate |

Each check returns `PASS`

/ `WARN`

/ `FAIL`

/ `UNKNOWN`

and a partial-credit score. The total is the headline number.

Scanned 2026-07-14. Servers are probed as a **naive client** — `npx -y <pkg>`

with no extra args or env. This is exactly what an agent does on first contact. Servers that require configuration fail the handshake, which is the point: **clients can't discover that requirement before connecting.**

| # | Server | Score | Handshake | Tools | Proto | Destructive | Notes |
|---|---|---|---|---|---|---|---|
| 1 | `@playwright/mcp` |
87/100 |
PASS · 838ms | 24 | 2025-06-18 | WARN | 6/24 destructive (browser actions) |
| 2 | `chrome-devtools-mcp` |
87/100 |
PASS · 1021ms | 29 | 2025-06-18 | WARN | 5/29 destructive |
| 3 | `@modelcontextprotocol/server-filesystem` |
87/100 |
PASS · 768ms | 14 | 2025-06-18 | WARN | 3/14 destructive (write/delete) |
| 4 | `@modelcontextprotocol/server-github` |
86/100 |
PASS · 717ms | 26 | 2024-11-05 | PASS | Lags latest protocol version |
| 5 | `@modelcontextprotocol/server-memory` |
85/100 |
PASS · 789ms | 9 | 2025-06-18 | WARN | 3/9 destructive (delete_*) |
| 6 | `@upstash/context7-mcp` |
85/100 |
PASS · 997ms | 2 | 2025-06-18 | WARN | Heuristic flagged descriptions |
| 7 | `@eslint/mcp` |
85/100 |
PASS · 915ms | 1 | 2025-06-18 | WARN | 1 tool (lint-files) |
| 8 | `@modelcontextprotocol/server-brave-search` |
33/100 |
FAIL | 0 | — | UNKNOWN | Needs `BRAVE_API_KEY` env — undocumented to client |
| 9 | `@modelcontextprotocol/server-puppeteer` |
28/100 |
FAIL | 0 | — | UNKNOWN | Handshake timeout (needs config/launch args) |
| 10 | `@storybook/mcp` |
28/100 |
FAIL | 0 | — | UNKNOWN | Handshake timeout (needs project context) |

**4 of 10 recognizable MCP servers cannot complete a protocol handshake when invoked the way an agent invokes them.** There is no machine-readable way for a client to learn *why* before connecting. That gap is the wedge.

```
npm install -g mcp-trustcard
# or just:
npx mcp-trustcard <server-spec>
# single server, text report
npx mcp-trustcard @modelcontextprotocol/server-github

# single server, JSON
npx mcp-trustcard --json @modelcontextprotocol/server-memory

# batch scan (JSON array of specs)
mcp-trustcard --batch servers/official.json --json-out results.json
```

Exit code is non-zero when the score is below 50, so it drops straight into CI.

```
- uses: davidnichols-ops/trustcard@v0.1
  with:
    server: @modelcontextprotocol/server-github
    min-score: "50"
    json-out: reports/github.json
```

The action fails the job when the score drops below `min-score`

. See `.github/workflows/healthcheck.yml`

for a full matrix that scans all 10 servers on every push and on a daily cron for drift detection.

`npm view <spec>`

— resolve the package (installability).- Spawn
`npx -y <spec>`

as a child process with stdio JSON-RPC. - Send
`initialize`

with the latest protocol version, measure latency. - Send
`notifications/initialized`

, then`tools/list`

. - Validate each tool's
`inputSchema`

as JSON Schema. - Scan tool names + descriptions for destructive verbs and secret-shaped strings.
- Probe 3 quick
`tools/list`

pings for failure rate. - Score and print the trust card.

No dependencies. Pure Node stdlib. The whole probe runs in seconds.

**Single probe.** Secret exposure is`UNKNOWN`

unless a secret surfaces in one run. A real audit needs fuzzing and traffic replay.**Naive invocation.** Servers that need args/env fail the handshake. That's a feature, not a bug — it surfaces the discovery gap — but maintainers can fairly argue their server works fine*with*documented config. Good. Let's have that conversation in the scorecard metadata.**Heuristic destructive detection.** Flagging is keyword-based and will have false positives (e.g. a description that mentions "delete" in passing). v2 will use call-site analysis.**No auth flow testing.** We detect that auth*seems*required; we don't exercise OAuth.**stdio only.** HTTP/SSE transports are next.

This repo ships with a proposal for a standard ** mcp.health** metadata field that servers can publish so clients can render a trust card

*before*connecting. See

[. The tracker issue is filed against the spec registry.](/davidnichols-ops/trustcard/blob/master/PROPOSAL.md)

`PROPOSAL.md`

Scores are disputable — that's the point. To get your server scanned or to contest a score:

- Open an issue with the server spec.
- Optionally include a
`mcp.health`

snippet (see`PROPOSAL.md`

) so we can verify declared vs. observed behavior.

If you want to add a check, the scorecard is in `lib/checks.js`

and is deliberately small.

MIT
