candourlabs
← All articles

MCP Is Exploding and Nobody Built the Tooling — So I Built a Config Scanner

MCP is exploding and nobody built the tooling — so I built a config scanner


The premise

The Model Context Protocol has gone from a niche Anthropic announcement to 97 million monthly SDK downloads, 10,000+ public servers, and 41% of enterprises running it in some production stage — in under two years. YC lists "Software for Agents" as a top request for startups. The protocol got donated to the Linux Foundation.

And yet the tooling layer around it barely exists. I keep seeing the same thing in every Claude Code thread: someone copies an .mcp.json from a README, commits it, and the server just... doesn't load. Or worse — a shared config with a hardcoded API key gets pushed to GitHub.

I decided to build the boring tool nobody had: a config scanner that reads your MCP config and tells you what will break, what's insecure, and what's deprecated — before it costs you a debugging session.

Why configs fail

MCP config is a deceptively simple shape — a mcpServers object mapping a name to a server definition — but the rules around it are strict and undocumented in one place:

The catch is that a config that looks identical to a healthy one can still be a landmine. That's exactly the boring, low-latency, "I'm confused" problem worth a tool.

The tool

mcp-companion scans a project's MCP configs across clients — .mcp.json, mcp.json, .cursor/mcp.json (Cursor), .vscode/mcp.json (VS Code), mcp_config.json (Windsurf, including its serverUrl + ${env:VAR} syntax), and Zed's context_servers — validates every server entry, and reports by severity:

Zero dependencies, CI-friendly exit codes (0 clean, 1 issues, 2 error), and a one-line --summary for GitHub Actions. All online checks are opt-in — the default run is fast, deterministic, and offline. npx mcp-companion and you get a report in seconds.

The two bugs that dogfooding caught

Same discipline that caught depclear's builtin-module false positive paid off again.

Bug #1: a crash on the most common input. My package-name extractor — which collects the npm packages a stdio server pulls via npx (the seam for a future stale-server check) — crashed with Cannot read properties of undefined on simple, unscoped packages like pkg. The regex had a single optional capture group: for scoped packages it captured, for plain ones it didn't, and I read the group unconditionally. The test suite caught it the second I ran it against a real-world-shaped config — not a crafted happy path. Fix was two characters of logic (m[1] || m[0] → then realising m[0] is the full package token).

Bug #2: the first "secret detector" was both leaky and noisy. My first pass treated any key matching KEY|TOKEN|SECRET as a hardcoded credential — so healthy configs using ${GITHUB_PAT} were flagged. That's the false-positive class that gets tools uninstalled. Fix: only flag values that look like live secrets (sk-, ghp_, AIza, a raw JWT prefix, Bearer ...) and aren't ${VAR} references. A legit env-var reference is never a secret.

Why this matters

There's a pattern to the devtools that win: they appear after a capability explodes, in the layer nobody bothered with. depcheck dominated unused-dependency scanning for a decade because it was boring and correct. MCP has the same shape right now — huge adoption, obvious confusion, and no standard tooling.

The free CLI is the distribution engine. The registry staleness check and org policy the obvious paid layer later, the same way hosted dashboards follow open-source CLIs.

The takeaway for the "make money with AI" crowd: don't build the model wrapper. Build the tool that checks the work of the thousand new unvetted scripts people are copy-pasting into their repos. That's where the durable value — and the honest demand — is.


Built with AI-assisted development, honestly disclosed. Source and roadmap: github.com/candourthetruthsayer/mcp-companion — live on npm as mcp-companion.