Skip to content
Conduit

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

willkhinz/mcpscancommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

Before you start

  • Node.js 20 or newer
~/Library/Application Support/Claude/claude_desktop_config.json
{
  "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, 2026

mcpscan

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:

  1. 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.
  2. 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 popular postmark-mcp package 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.
  3. 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

ClientLocationNotes
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.tomlTOML 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)

RuleSeverityCatches
known-malicious-packagecriticalPackages on the bundled community blocklist (ships in-package; no network calls)
dangerous-commandcriticalcurl … | sh, sudo, destructive patterns
hardcoded-secretcriticalOpenAI/GitHub/AWS/Slack/Google token shapes inside config files
inline-shell-scripthighsh -c '…' blobs nobody can review in git
shell-chaininghigh||, &&, backticks, command substitution
insecure-transporthighPlain-HTTP MCP endpoints
sensitive-env-inlinehighAWS secret keys etc. embedded directly in config
unpinned-packagemediumnpx -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 cost probes 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

↑↓ navigate openesc close