Skip to main content
Glama
README.md
# MCP Doctor

**Diagnose, optimize, and manage MCP servers across coding agents.**

[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![npm version](https://img.shields.io/npm/v/@frankxai/mcp-doctor.svg)](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.