mcp server
mcpscan
Zero-dependency CLI: inventory MCP server configs across every AI client, detect drift, flag supply-chain risk, and measure context-token cost per server
Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- Node.js 20 or newer
{
"mcpServers": {
"willkhinz-mcpscan": {
"command": "npx",
"args": [
"-y",
"mcpscan"
]
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 23, 2026mcpscan
Zero-dependency CLI that inventories your MCP server configs across every AI client, detects cross-client drift, flags supply-chain risk, and measures the context-token cost of each server.
npx mcpscan
No API keys. No accounts. No network calls required to scan — everything runs locally.
Why this exists
Model Context Protocol (MCP) adoption exploded, and with it a quiet operational mess:
- Configs are duplicated per client. Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, Gemini CLI, Codex CLI, and opencode each keep their own MCP config in a different file at a different path. Add or fix a server in one client and the others silently diverge.
- MCP configs execute code on your machine. Every
"command": "npx -y <package>"entry downloads and runs whatever the registry serves at startup. In September 2025 the popularpostmark-mcppackage was found backdoored, BCC-ing every sent email — including password resets and API keys — to an attacker address. Users had pasted that config from the internet, exactly as designed. - Every enabled server taxes every message. MCP clients inject all connected servers' tool schemas into the model context. Nobody tells you what that costs until you're wondering why your agent feels slow and expensive. On this machine, mcpscan found one forgotten server eating ~1.3k tokens (~80% of total MCP overhead) per message.
Existing tools cover parts of this — mcp-doctor (JSON syntax + health checks), agentseal (heavyweight security suite), pipelock / gateways (proxying). None of them give you a lightweight, offline inventory + drift + cost + risk view in a single command. That's mcpscan.
What it does
mcpscan inventory + drift + risk findings for all discovered clients
mcpscan cost live-probe each server (stdio handshake / HTTP initialize),
count tools, estimate tokens added to context per message
mcpscan export machine-readable output (--json | --md) for CI and docs
Discovery matrix
| Client | Location | Notes |
|---|---|---|
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json (+ Win/Linux variants) | |
| Claude Code | ~/.claude.json, project .mcp.json | |
| Cursor | ~/.cursor/mcp.json, project .cursor/mcp.json | |
| VS Code | .../Code/User/mcp.json, project .vscode/mcp.json | |
| Windsurf | ~/.codeium/windsurf/mcp_config.json | |
| Gemini CLI | ~/.gemini/settings.json | |
| Codex CLI | ~/.codex/config.toml | TOML parsed by bundled mini-parser |
| opencode | ~/.config/opencode/opencode.json (+ alt paths) | supports array-command form |
Parsers tolerate JSONC (comments, trailing commas) the way real-world configs actually look.
Risk rules (all static, all local)
| Rule | Severity | Catches |
|---|---|---|
known-malicious-package | critical | Packages on the bundled community blocklist (ships in-package; no network calls) |
dangerous-command | critical | curl … | sh, sudo, destructive patterns |
hardcoded-secret | critical | OpenAI/GitHub/AWS/Slack/Google token shapes inside config files |
inline-shell-script | high | sh -c '…' blobs nobody can review in git |
shell-chaining | high | ||, &&, backticks, command substitution |
insecure-transport | high | Plain-HTTP MCP endpoints |
sensitive-env-inline | high | AWS secret keys etc. embedded directly in config |
unpinned-package | medium | npx -y some-package without an exact version — silent supply-chain swaps |
Drift detection
Any server name present in 2+ clients is compared across transport, command+args, URL, and env-var keys (values are never printed). Divergence is reported per client so you can see exactly which copy is stale.
Token cost estimation
For stdio servers mcpscan performs a real MCP handshake (initialize → tools/list) over newline-delimited JSON-RPC, sums the serialized tool schemas, and estimates tokens at ~3.6 chars/token (JSON-dense text). For HTTP/SSE servers it sends a best-effort initialize. Estimates are clearly labeled as estimates — but relative sizes between servers are what matter, and those hold up.
Install
npm install -g mcpscan # or just: npx mcpscan
Node.js >= 20. Runtime dependencies: zero.
Usage
mcpscan # full local audit
mcpscan --project . # also scan this repo's project-level configs
mcpscan --strict # non-zero exit on medium findings too (CI mode)
mcpscan export --json > mcp-inventory.json
mcpscan cost --timeout 10000 # live probe; prints per-server token share
Exit codes: 0 clean/warnings · 1 critical/high found (or medium+ with --strict) · 2 usage error. This makes mcpscan droppable straight into CI:
# .github/workflows/mcp-audit.yml
- run: npx mcpscan --project . --strict
Example session (real output, macOS)
$ mcpscan
mcpscan v0.1.0
Config files discovered
✓ Claude Desktop ~/Library/Application Support/Claude/...
✓ Claude Code ~/.claude.json
✓ opencode ~/.config/opencode/opencode.json
Servers: 3 entries
• higgsfield [http] → https://mcp.higgsfield.ai/mcp
• shared-memory [stdio] → npx -y mcp-shared-memory
• ox-alpha [stdio] → node ~/.claude-openrouter-proxy/mcp-server.js
Risk findings
MEDIUM "mcp-shared-memory" runs unpinned via npx
→ Pin an exact version ... or vendor the package locally.
$ mcpscan cost
shared-memory 14 ~ 1.3k 79%
ox-alpha 2 ~ 332 21%
higgsfield unreachable — HTTP 401
total ≈ 1.6k tokens of tool schema carried in context per message
Privacy & safety
- Scanning is 100% offline. The only outbound requests ever made are the explicit
costprobes against your own configured servers, which your client already talks to. - Env var values are never printed anywhere — only key names and set/unset status.
- The malicious-package blocklist ships inside the package; no telemetry, no phone-home.
Limitations
- Token figures are estimates calibrated for English/JSON text, not exact tokenizer counts.
- Codex TOML support covers common
[mcp_servers.*]layouts, not the full TOML spec. - HTTP probing speaks JSON-RPC-over-HTTP; streamable-SSE-only endpoints may report "reachable" without tool counts.
Development
git clone https://github.com/willkhinz/mcpscan && cd mcpscan
npm install && npm test && npm run build
PRs welcome — especially new discovery paths and blocklist entries (with public disclosure links).
License
MIT © Will Hinz