MCP Doctor
by FrankX-AI
README.md
# MCP Doctor
**Diagnose, optimize, and manage MCP servers across coding agents.**
[](LICENSE)
[](https://www.npmjs.com/package/@frankxai/mcp-doctor)
---
## Quick Start
```bash
npx @frankxai/mcp-doctor audit
```
One command scans your Claude Code configuration, checks every MCP server across all scopes, and gives you a health report with fix commands.
## Usage
### For Humans (CLI)
```bash
# Full health check — spawns each server, verifies MCP handshake
npx @frankxai/mcp-doctor audit
# Quick mode — config-only validation (instant, no spawning)
npx @frankxai/mcp-doctor audit --quick
# Filter to a specific project
npx @frankxai/mcp-doctor audit --project my-project
# Browse curated MCP preset packs
npx @frankxai/mcp-doctor recommend
npx @frankxai/mcp-doctor recommend ai-architect
```
### For CI (check any server you build)
`check` spawns a stdio MCP server, lists its tools and lints them. It needs no config file, so it works in CI on a server you are building.
```bash
npx @frankxai/mcp-doctor check -- node dist/server.js
# PASS my-server@1.2.0 — 12 tool(s)
npx @frankxai/mcp-doctor check --json -- node dist/server.js # JSON report, exit 1 on any issue
```
| Rule | Fails when |
|---|---|
| `connect` | The server does not start or answer `initialize` + `tools/list` within 15 s (its stderr is included) |
| `name` | A tool name is not `^[a-z][a-z0-9_]{0,63}$` |
| `duplicate` | Two tools share a name |
| `description` | A description is missing or under 20 characters |
| `schema` | `inputSchema.type` is not `"object"` |
On Windows, spawn `node <script>` directly rather than `npx <pkg>`, because `npx` resolves to `npx.cmd`.
### Score a server against best practice
`check` asks "does it work?". `score` asks "will an agent pick and use it well?". It grades the tool surface on seven criteria drawn from the MCP spec, Anthropic's [Writing effective tools for agents](https://www.anthropic.com/engineering/writing-tools-for-agents), and leading public servers. Each criterion is worth 2 points: all tools pass, half pass, or fewer.
```bash
npx @frankxai/mcp-doctor score -- node dist/server.js
npx @frankxai/mcp-doctor score --json --min 80 -- node dist/server.js # CI gate: exit 1 below 80%
npx @frankxai/mcp-doctor score --prefix sis -- node dist/server.js # brand prefix differs from server name
```
| Criterion | Full marks when |
|---|---|
| Annotations | every tool sets `readOnlyHint` and `openWorldHint`; writers also set `destructiveHint` and `idempotentHint` |
| Titles | every tool has a human `title` |
| Service prefix | names start with the service (`mcp-doctor` → `mcp_doctor_…`, or `--prefix`) |
| Descriptions | 80+ characters: when to use it, what it returns, what it costs |
| Bounded inputs | every property is described and bounded (`maxLength`, `enum`, `maximum`, `maxItems`, anchored bounded `pattern`); no-input tools set `additionalProperties: false` |
| Output schema | `outputSchema` declared, so results can carry `structuredContent` |
| Paging | list and search tools take a limit with a maximum, or a cursor |
A server with no tools scores 0. Error quality, response size, auth and evals can't be seen from `tools/list`, so they are printed as a manual checklist. For reference, `@modelcontextprotocol/server-filesystem` scores 57%, and `mcp-doctor serve` scores 100%.
### As an MCP Server (Universal Agent Access)
mcp-doctor runs as an MCP server so an agent can diagnose its own MCP setup.
```bash
# Install globally (recommended — avoids cold-start timeouts)
npm install -g @frankxai/mcp-doctor
# Add to Claude Code
claude mcp add mcp-doctor -- mcp-doctor serve
# Or with explicit path (if 'mcp-doctor' isn't in PATH)
claude mcp add mcp-doctor -- $(which mcp-doctor) serve
```
For Cursor, Cline, Windsurf — add to their respective config file:
```json
{
"mcpServers": {
"mcp-doctor": {
"command": "mcp-doctor",
"args": ["serve"]
}
}
}
```
For VS Code (`.vscode/mcp.json`):
```json
{
"servers": {
"mcp-doctor": {
"type": "stdio",
"command": "mcp-doctor",
"args": ["serve"]
}
}
}
```
Exposes 4 read-only tools with typed, structured output: `mcp_doctor_audit`, `mcp_doctor_agents`, `mcp_doctor_misplaced_configs`, `mcp_doctor_preset_packs`. It scores 100% on its own `mcp-doctor score` bar.
### For Claude Code (SessionStart Hook)
Auto-check MCP health on every new session:
```json
// .claude/settings.json → hooks.SessionStart
{
"type": "command",
"command": "bash .claude/hooks/mcp-doctor-check.sh",
"timeout": 8
}
```
Or use the programmatic API:
```typescript
import { scanAllServers, findDuplicates, findMisplacedConfigs, checkAllServers, analyzeTiers, redactSecrets } from "@frankxai/mcp-doctor";
const servers = scanAllServers();
const health = await checkAllServers(servers, { quick: true });
const tiers = analyzeTiers(servers, health);
```
### Multi-Agent Support
Detects and reads MCP configs from major coding agents:
```bash
npx @frankxai/mcp-doctor agents
```
| Agent | Config Location | Key | Supported |
|-------|----------------|-----|-----------|
| Claude Code | `~/.claude.json` | `mcpServers` | Yes |
| Cursor | `~/.cursor/mcp.json` | `mcpServers` | Yes |
| Cline | `globalStorage/.../cline_mcp_settings.json` | `mcpServers` | Yes |
| Windsurf | `~/.codeium/windsurf/mcp_config.json` | `mcpServers` | Yes |
| VS Code | `~/.config/Code/User/mcp.json` | `servers` | Yes |
Config differences are normalized automatically (VS Code's `servers` key, Windsurf's `serverUrl` field, etc.).
## What It Does
### Misplaced Config Detection
Claude Code ignores `mcpServers` in `settings.json` files; they belong in `~/.claude.json`. MCP Doctor detects misplaced configs:
```
⚠ MISPLACED MCP CONFIGS (CRITICAL)
──────────────────────────────────────────────────
Claude Code IGNORES mcpServers in settings.json files!
MCP servers must be in ~/.claude.json (use: claude mcp add)
✗ /home/user/.claude/settings.json
These servers are configured but NEVER loaded:
- my-server
- other-server
How to fix:
1. Remove mcpServers from settings.json
2. Re-add each server with: claude mcp add <name> -e KEY=val -- <command>
3. Verify with: /mcp in Claude Code
```
### Health Audit
Scans `~/.claude.json` across all project scopes and checks:
- Server connectivity (spawns each stdio server and verifies MCP initialize + ping handshake)
- Missing or placeholder environment variables (`YOUR_API_KEY_HERE`)
- Duplicate registrations across scopes (user, project-local, .mcp.json)
- Command resolution and startup failures during full probes
```
HEALTH REPORT
──────────────────────────────────────────────────
✓ playwright [user]
✓ memory [project-local]
✓ nanobanana [project-local]
⚠ grok [project-local] XAI_API_KEY not configured
⚠ replicate [project-local] REPLICATE_API_TOKEN not configured
✗ my-server [project-local] Exited before handshake
4 healthy 1 broken 2 missing config 0 skipped
```
### Duplicate Detection
Finds servers registered multiple times across different scopes:
```
DUPLICATES FOUND
──────────────────────────────────────────────────
⚠ nanobanana registered 4x:
→ project-local (my-project)
→ project-local (other-project)
→ project-local (System32)
→ project-local (system32)
Tip: Duplicates waste startup time. Keep one per scope.
```
### Tier Recommendations
Categorizes servers into **always-on**, **on-demand**, or **remove**:
```
TIER RECOMMENDATIONS
──────────────────────────────────────────────────
Always-On (load every session)
● playwright — Core utility — useful in nearly every session
● memory — Core utility — useful in nearly every session
On-Demand (add when needed)
◐ nanobanana — Useful but not every session
◐ sequential-thinking — Useful but not every session
◐ lyric-genius — Workflow-specific — add only for relevant sessions
Remove (broken or misconfigured)
✗ grok — Missing environment variable: XAI_API_KEY not configured
```
### Fix Commands
Generates copy-paste-ready commands to clean up your setup:
```
SUGGESTED FIX COMMANDS
──────────────────────────────────────────────────
# Remove broken/misconfigured servers:
claude mcp remove grok
claude mcp remove replicate
# On-demand commands (save for when needed):
claude mcp add nanobanana -e GEMINI_API_KEY=AIza... -- uvx nanobanana-mcp-server@latest
claude mcp add sequential-thinking -- npx -y @modelcontextprotocol/server-sequential-thinking
```
### Health Score
Seven successful protocol probes out of eight attempted probes score 88/100. Quick mode and setups without runtime probes are unverified:
```
SCORE
──────────────────────────────────────────────────
MCP Health Score: 88/100
8 total servers | 7 healthy | 0 duplicates | 1 should remove
```
## Preset Packs
Pre-configured MCP stacks for common workflows. Each pack specifies which servers to run always-on vs. on-demand.
| Pack | Description | Always-On | On-Demand |
|------|-------------|-----------|-----------|
| `web-developer` | Next.js, Vercel, testing | 2 | 1 |
| `content-creator` | Blogging, images, email | 2 | 1 |
| `data-engineer` | Databases, APIs, pipelines | 2 | 1 |
| `music-producer` | AI music, lyrics, audio | 1 | 2 |
| `ai-architect` | Agents, multi-model systems | 3 | 1 |
| `agent-os` | Hermes, OpenClaw, DeepAgents, Claude Code, Codex, GitHub, Vercel, browser automation, memory | 4 | 3 |
| `devops` | CI/CD, infrastructure, containers | 2 | 1 |
| `mobile-dev` | React Native, Flutter, native | 1 | 2 |
| `researcher` | Academic, technical writing | 2 | 1 |
| `security` | Auditing, pen testing, compliance | 2 | 1 |
| `minimal` | Just the essentials | 1 | 0 |
## Security
MCP Doctor reads `~/.claude.json` which contains API keys and tokens. Here is how they are protected:
- **Secret redaction**: Output passes through `redactSecrets()` and `redactArgSecrets()` — known env values, command-line arguments, and API key regex patterns are replaced with `[REDACTED:KEY_NAME]`
- **Safe env inheritance**: Spawned processes only receive safe system vars (`PATH`, `HOME`, etc.) + the server's own declared env — `NODE_OPTIONS` and `NODE_PATH` are not inherited
- **Execution boundary**: Remote servers are skipped. Commands started by full audits can use their own network access.
See [SECURITY.md](SECURITY.md) for vulnerability reporting.
## How It Works
MCP Doctor reads your Claude Code configuration from `~/.claude.json`, which stores MCP server definitions across multiple scopes:
1. **User scope** — Global servers available in all projects
2. **Project-local scope** — Servers specific to a project directory
3. **.mcp.json** — Project-level config files checked into repos
For each server found, it:
- Validates the configuration structure
- (Full mode) Resolves commands through the SDK transport and reports startup failures
- Detects placeholder environment variables
- Scans `settings.json` files for misplaced MCP configs
- (Full mode) Spawns the process and performs an MCP `initialize` + `ping` handshake
- Cross-references against a database of known MCP servers for tier recommendations
## MCP Scope Explained
The scope hierarchy in Claude Code:
```
~/.claude.json
├── mcpServers: {} ← User scope (all projects)
└── projects:
├── /path/to/project-a:
│ └── mcpServers: {} ← Project-local scope
└── /path/to/project-b:
└── mcpServers: {} ← Project-local scope
/path/to/project/.mcp.json ← Shared project scope (committed to git)
```
## Contributing
Contributions welcome.
```bash
git clone https://github.com/frankxai/mcp-doctor
cd mcp-doctor
pnpm install
pnpm run build
node dist/cli.js audit --quick
```
## License
MIT
## Protocol health and configuration checks
The audit --quick command validates configuration and starts no server processes.
A valid configuration is unchecked, and its runtime score is unverified. Missing
commands and placeholder environment values remain visible configuration findings.
Remote servers are also untested by this audit.
Full stdio audits use the installed official MCP SDK to initialize and perform a
ping. Only a successful protocol exchange is healthy; a process staying alive or
exiting cleanly is insufficient. Resources-only servers do not need to implement
tools/list. The reported score is the percentage of attempted stdio probes that
succeeded. Duplicates, configuration defects and removal advice are reported
separately, and no attempted probes means no numeric score.
Initialization and RPCs share one probe deadline. Shutdown uses the SDK's owned
child handle and termination escalation, followed by an exit check, with a separate
bounded cleanup allowance. Failed cleanup cannot produce a healthy result.
Parent NODE_OPTIONS, NODE_PATH and credentials are not inherited by default;
explicit server environment values remain caller-controlled. SDK output buffering
is limited to 1 MiB. Diagnostics retain at most 2 KiB of redacted complete stderr
lines; oversized lines are omitted.
Full audit runs third-party commands from the selected configuration. Use it when
you intend to execute those commands. Suggested CLI commands redact known
credentials, so supply credential placeholders privately before using them.
The protocol lifecycle follows the installed SDK's compatibility support. These
checks do not certify every transport or modern stateless MCP revision. CI verifies
the declared minimum Node version and Node 24 on Windows and Linux, including the
audit API, CLI and MCP tools from an actual installed tarball.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues