DEV Community

curatedmcp
curatedmcp

Posted on

I scanned my laptop for shadow MCP servers

I run a curated MCP catalog, and the most common thing I hear from security
folks is: "we have no idea what MCP servers our engineers have installed."

MCP configs are scattered across every AI client — ~/.claude.json,
.mcp.json, ~/.cursor/mcp.json, Windsurf's mcp_config.json, VS Code's
mcp.json, Gemini's settings.json. Each server in those files is software
that can read files, hold API tokens in plaintext, and reach the network.
Server-side AI gateways never see any of it, because it runs on laptops.

So: a single command that finds all of them and flags the risky ones.

npx -y @curatedmcp/auditor

It scans the known config locations for Claude Code, Claude Desktop,
Cursor, Windsurf, Copilot/VS Code, and Gemini CLI; checks each server
against a risk-classified catalog; and flags credential-in-env,
filesystem/keychain access, network egress, and "shadow" servers that
appear in no catalog at all. Exits non-zero on high-risk findings, so you
can run it in CI or a pre-commit hook.

Privacy: the scan runs entirely locally and prints to your terminal.
There's an optional shareable web report (it asks first, or --share),
which uploads server names + risk flags only — never commands, args, env
values, or paths. The server-side schema rejects payloads that carry
them. --offline skips all network calls including the catalog fetch.

MIT licensed, ~600 lines of TypeScript, no dependencies beyond chalk:
https://github.com/oneprofile-dev/mcp-auditor

Would love feedback on:

  • Config locations I'm missing (JetBrains? Zed? Cline?)
  • Whether the risk heuristics are too noisy or too quiet
  • What an org-wide version of this should report

Sam
curatedmcp.com/scan

Top comments (1)

Collapse
 
hiper2d profile image
Aliaksei Zelianouski

Calling them shadow is generous. People installed these on purpose and then never thought again about the random npx server sitting on their AWS creds in plaintext env with full filesystem read. The CI exit-code is the useful part - nobody runs a scanner by hand twice.