mcp-medic 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -14
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +23 -2
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
# mcp-medic
|
|
2
2
|
|
|
3
|
+
[](https://github.com/shivam039/mcp-doctor/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/mcp-medic)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
|
|
3
7
|
Diagnose broken MCP (Model Context Protocol) server configs before they break your agent silently.
|
|
4
8
|
|
|
5
|
-
`mcp-medic` validates MCP server configurations, executes full protocol initialization handshakes across stdio/SSE/HTTP transports, checks all exposed tool JSON schemas against standard specifications, and simulates sample calls — providing actionable suggestions
|
|
9
|
+
`mcp-medic` validates MCP server configurations, executes full protocol initialization handshakes across stdio/SSE/HTTP transports, checks all exposed tool JSON schemas against standard specifications, and simulates sample calls — providing actionable suggestions and CI-ready exit codes.
|
|
10
|
+
|
|
11
|
+
## Why this exists
|
|
12
|
+
|
|
13
|
+
A broken MCP server config usually doesn't fail loudly — it fails as your agent silently missing a tool, retrying a handshake forever, or getting a malformed schema it can't reason about. Those bugs are miserable to track down after the fact. `mcp-medic` catches them at the config level, before an agent ever touches the server: it actually connects (real `initialize` handshake, real `tools/list`), so "the config parses" and "the server actually works" are checked together, in CI, with a real exit code.
|
|
14
|
+
|
|
15
|
+
## ⚠️ How this works — please read before pointing it at a config
|
|
16
|
+
|
|
17
|
+
`mcp-medic` validates a config by **actually connecting to the servers in it**:
|
|
18
|
+
- `stdio` transport → it **spawns the configured `command`** as a real child process on your machine.
|
|
19
|
+
- `sse`/`http` transport → it **makes real network requests** to the configured `url`, including any `headers` you've set (e.g. auth tokens).
|
|
20
|
+
|
|
21
|
+
This is the whole point (a real handshake, not a schema guess) — but it means you should only run it against configs you trust, the same way you'd only `npm install` a `package.json` you trust. See [SECURITY.md](./SECURITY.md) for the full threat model.
|
|
6
22
|
|
|
7
23
|
---
|
|
8
24
|
|
|
@@ -11,17 +27,17 @@ Diagnose broken MCP (Model Context Protocol) server configs before they break yo
|
|
|
11
27
|
- 🔍 **Auto-Discovery**: Run `mcp-medic check` with no arguments to auto-discover Claude Desktop, `.mcp.json`, and VS Code/Cursor MCP configuration paths across macOS, Windows, and Linux.
|
|
12
28
|
- 💡 **Auto-Fix Suggestions**: Diagnose issues with clear, actionable fix suggestions using `--show-fixes`.
|
|
13
29
|
- 🌐 **Registry Validation**: Validate published registry entries directly using `mcp-medic check --registry <server-id>`.
|
|
14
|
-
-
|
|
15
|
-
-
|
|
30
|
+
- 🧪 **Fleet Validation** (experimental): Scan and validate monorepos or multi-team configurations with `mcp-medic check-all "<glob>"`.
|
|
31
|
+
- 🧪 **Drift Detection** (experimental): Catch environment divergence between staging and production configs with `mcp-medic diff <configA> <configB>`.
|
|
16
32
|
- 📜 **Policy-as-Code**: Enforce organizational constraints (e.g., banned transports, domain allowlists, minimum description lengths) via `.mcp-medic-policy.json` / `--policy`.
|
|
17
33
|
- 📸 **Snapshot Baseline Mode**: Filter out legacy diagnostics with `--snapshot <baseline.json>` to gate only on newly introduced regressions.
|
|
18
34
|
- 📊 **CI Reporting**: Export standard JUnit XML (`--export-junit <file.xml>`) and JSON (`--export-json <file.json>`) for seamless CI dashboard visualization.
|
|
19
35
|
- 👀 **Watch Mode**: Re-run validation on save using `mcp-medic watch <path>`.
|
|
20
36
|
- ⚡ **Transport Hardening**: Full handshake validation across stdio, HTTP (with OAuth token refresh), and SSE (with automatic retry resilience).
|
|
21
|
-
-
|
|
37
|
+
- 🧪 **VS Code Extension** (experimental, not yet on the Marketplace): in-editor squiggles and hover tooltips — runnable from source today, see [vscode-extension/](./vscode-extension/).
|
|
22
38
|
- 🚦 **CI Usability & Exit Codes**: Strict exit code taxonomy (`0` clean, `1` diagnostic failures, `2` usage/syntax errors) and `--fail-on <error|warning>`.
|
|
23
39
|
- 🤖 **GitHub Action**: Drop-in CI integration via `shivam039/mcp-doctor@main` (or `mcp-medic-action`).
|
|
24
|
-
- 🧩 **Community Checks
|
|
40
|
+
- 🧩 **Community Checks** (framework ready, no packages published yet): a conformance test helper (`runCheckConformanceSuite`) so anyone can build and publish their own `mcp-medic-check-*` plugin.
|
|
25
41
|
|
|
26
42
|
---
|
|
27
43
|
|
|
@@ -65,6 +81,7 @@ npx mcp-medic watch path/to/config.json
|
|
|
65
81
|
| `diff <configA> <configB>` | Detect drift between two configuration files |
|
|
66
82
|
| `check --registry <id>` | Validate a published registry server directly |
|
|
67
83
|
| `watch <path>` | Watch configuration file and re-run checks on file save |
|
|
84
|
+
| `fix <path>` | Interactively apply mechanical suggested fixes (see [Auto-Fix](#auto-fix-mcp-medic-fix) below) |
|
|
68
85
|
| `--config <path>` | Explicit configuration path |
|
|
69
86
|
| `--policy <path>` | Apply organizational policy rules (`.mcp-medic-policy.json`) |
|
|
70
87
|
| `--snapshot <path>` | Compare against baseline snapshot, reporting regressions only |
|
|
@@ -76,6 +93,8 @@ npx mcp-medic watch path/to/config.json
|
|
|
76
93
|
| `--verbose`, `-v` | Output raw JSON-RPC traffic and debug messages |
|
|
77
94
|
| `--json` | Output full diagnostic report in JSON |
|
|
78
95
|
| `--timeout <ms>` | Per-server handshake timeout in milliseconds (default: `5000`) |
|
|
96
|
+
| `--help`, `-h` | Show usage help |
|
|
97
|
+
| `--version`, `-V` | Print the installed version |
|
|
79
98
|
|
|
80
99
|
### Exit Codes
|
|
81
100
|
|
|
@@ -85,6 +104,26 @@ npx mcp-medic watch path/to/config.json
|
|
|
85
104
|
|
|
86
105
|
---
|
|
87
106
|
|
|
107
|
+
## Auto-Fix (`mcp-medic fix`)
|
|
108
|
+
|
|
109
|
+
For the small subset of diagnostics that carry a mechanical fix (today: upgrading a `security.untrusted-remote` server's `http://` URL to `https://`), `mcp-medic fix` will show you a diff and ask for confirmation before touching your config file:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
mcp-medic fix path/to/config.json
|
|
113
|
+
|
|
114
|
+
# Preview every available fix without prompting or writing anything
|
|
115
|
+
mcp-medic fix path/to/config.json --dry-run
|
|
116
|
+
|
|
117
|
+
# Only offer fixes from one specific check
|
|
118
|
+
mcp-medic fix path/to/config.json --check security.untrusted-remote
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- Fixes are **never bulk-applied** — each one is shown as a diff and requires an explicit `y`/`N`.
|
|
122
|
+
- A `.bak` copy of the original file is written before any change, unconditionally.
|
|
123
|
+
- Most diagnostics (schema issues, the two other security checks) don't have a mechanical fix — `fix` reports "No auto-fixable diagnostics found" for those rather than guessing.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
88
127
|
## Policy-as-Code (`.mcp-medic-policy.json`)
|
|
89
128
|
|
|
90
129
|
Define organization-wide policies that compose with built-in checks:
|
|
@@ -99,11 +138,9 @@ Define organization-wide policies that compose with built-in checks:
|
|
|
99
138
|
|
|
100
139
|
---
|
|
101
140
|
|
|
102
|
-
## VS Code Extension
|
|
141
|
+
## VS Code Extension (experimental)
|
|
103
142
|
|
|
104
|
-
The `mcp
|
|
105
|
-
- Inline squiggles on `.mcp.json`, `mcp.json`, and `claude_desktop_config.json` files as you edit.
|
|
106
|
-
- Hover tooltips showing the full diagnostic explanation and actionable suggested fix.
|
|
143
|
+
**Not published on the VS Code Marketplace yet.** The diagnostics logic (inline squiggles + hover tooltips on `.mcp.json`, `mcp.json`, and `claude_desktop_config.json` files) is real and working, but it's currently only runnable from source as an Extension Development Host, or packaged locally as a `.vsix`. See [vscode-extension/README.md](./vscode-extension/README.md) for setup — it takes about five minutes.
|
|
107
144
|
|
|
108
145
|
---
|
|
109
146
|
|
|
@@ -138,20 +175,42 @@ jobs:
|
|
|
138
175
|
| `schema.type-mismatch` | `mcp-medic` | **Official** | Flags invalid JSON schema types and enum mismatches |
|
|
139
176
|
| `schema.missing-description` | `mcp-medic` | **Official** | Flags tools and properties missing documentation |
|
|
140
177
|
| `schema.sample-call-simulation` | `mcp-medic` | **Official** | Simulates and validates synthetic call payloads |
|
|
178
|
+
| `security.untrusted-remote` | `mcp-medic` | **Official** (heuristic) | Flags non-HTTPS or raw-IP SSE/HTTP server URLs |
|
|
179
|
+
| `security.overbroad-permissions` | `mcp-medic` | **Official** (heuristic) | Flags tools with unscoped shell/filesystem/network parameters |
|
|
180
|
+
| `security.prompt-injection-risk` | `mcp-medic` | **Official** (heuristic) | Flags instruction-like language in tool descriptions aimed at the model |
|
|
141
181
|
| `policy.*` | `mcp-medic` | **Official** | Evaluates policy-as-code rules (transports, domains, length) |
|
|
142
|
-
| `community.strict-typing` | `mcp-medic-check-strict-typing` | *
|
|
143
|
-
| `community.no-empty-enums` | `mcp-medic-check-no-empty-enums` | *
|
|
182
|
+
| `community.strict-typing` | `mcp-medic-check-strict-typing` | *Planned / example* | Would enforce strict property type annotations |
|
|
183
|
+
| `community.no-empty-enums` | `mcp-medic-check-no-empty-enums` | *Planned / example* | Would ensure non-empty enum option lists |
|
|
184
|
+
|
|
185
|
+
The two `community.*` rows above are examples of what a check plugin could look like — **those packages aren't published yet**. `runCheckConformanceSuite()` (used by the official checks' own tests) is the tool for validating a plugin conforms to the `Check` interface; see [Authoring Custom Checks](./docs/AUTHORING_CHECKS.md) if you want to build and publish one.
|
|
186
|
+
|
|
187
|
+
The `security.*` checks are heuristic — they pattern-match on what a server *declares* (URLs, tool descriptions, schemas), not what it actually does at runtime. Every diagnostic they produce says so explicitly; they're a signal to investigate, not proof of a problem.
|
|
144
188
|
|
|
145
|
-
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Known Limitations
|
|
192
|
+
|
|
193
|
+
- **Handshake timeout defaults to 5000ms** per server (`--timeout <ms>` to change it). A slow-starting stdio server or a server behind a slow network path can fail with `status: 'timeout'` even though it would eventually respond.
|
|
194
|
+
- **`schema.sample-call-simulation`** builds synthetic payloads from a tool's declared JSON Schema and checks the schema is internally consistent (e.g. catches an empty `enum`, or conflicting `minimum`/`maximum`) — it does **not** actually invoke the tool, and it does not validate business logic, side effects, or whether the tool's real output matches its declared schema.
|
|
195
|
+
- **`security.*` checks are heuristic pattern-matching**, not a security audit — see the note above. They can both miss real issues and flag benign configs (e.g. a legitimate local dev server on plain `http://`).
|
|
196
|
+
- **Fleet commands (`check-all`, `diff`) are newer and less battle-tested** than `check`/`watch` — the core check pipeline they're built on is the same, but edge cases in glob matching or drift diffing are more likely.
|
|
197
|
+
- **The VS Code extension and community check packages are not shipped/published** — see the sections above.
|
|
198
|
+
- **First run via `npx`** pays a one-time cost to resolve and download the package; once installed (or on a warm npx cache), `--help`/`--version` return in well under 100ms.
|
|
146
199
|
|
|
147
200
|
---
|
|
148
201
|
|
|
202
|
+
## Contributing & Support
|
|
203
|
+
|
|
204
|
+
- 🐛 [Report a bug](https://github.com/shivam039/mcp-doctor/issues/new?template=bug_report.md) / 💡 [Request a feature](https://github.com/shivam039/mcp-doctor/issues/new?template=feature_request.md)
|
|
205
|
+
- 📋 See [CONTRIBUTING.md](./CONTRIBUTING.md) before opening a PR
|
|
206
|
+
- 📝 [CHANGELOG](./CHANGELOG.md)
|
|
207
|
+
|
|
149
208
|
## Governance, Stability & Security
|
|
150
209
|
|
|
151
210
|
- 🏛️ [Governance & Project Sustainability](./GOVERNANCE.md)
|
|
152
|
-
- 📜 [
|
|
211
|
+
- 📜 [Stability & Deprecation Policy](./docs/STABILITY_POLICY.md) — v1.0's initial stable surface
|
|
153
212
|
- 🔒 [Security Policy & Threat Model](./SECURITY.md)
|
|
154
|
-
- 💡 [RFC Process](./docs/RFC_PROCESS.md)
|
|
213
|
+
- 💡 [RFC Process](./docs/RFC_PROCESS.md) (for changes to the frozen 1.0 surface)
|
|
155
214
|
|
|
156
215
|
---
|
|
157
216
|
|
|
@@ -164,6 +223,8 @@ npm run typecheck
|
|
|
164
223
|
npm run test
|
|
165
224
|
```
|
|
166
225
|
|
|
226
|
+
The VS Code extension (`vscode-extension/`) is a separate, independently-installed package — see [vscode-extension/README.md](./vscode-extension/README.md).
|
|
227
|
+
|
|
167
228
|
## License
|
|
168
229
|
|
|
169
230
|
MIT
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
export interface ParsedArgs {
|
|
3
|
-
command: 'check' | 'watch' | 'check-all' | 'diff' | 'fix' | 'help';
|
|
3
|
+
command: 'check' | 'watch' | 'check-all' | 'diff' | 'fix' | 'help' | 'version';
|
|
4
4
|
configPath?: string;
|
|
5
5
|
configPathB?: string;
|
|
6
6
|
globPattern?: string;
|
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
3
3
|
import * as readline from 'node:readline/promises';
|
|
4
4
|
import { resolve } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
5
6
|
import { runChecks, registerConnectImpl } from './orchestrator.js';
|
|
6
7
|
import { formatReportHuman, formatReportJSON } from './report.js';
|
|
7
8
|
import { loadConfig } from './config-loader.js';
|
|
@@ -40,6 +41,9 @@ export function parseArgs(argv) {
|
|
|
40
41
|
else if (arg === '--help' || arg === '-h') {
|
|
41
42
|
args.command = 'help';
|
|
42
43
|
}
|
|
44
|
+
else if (arg === '--version' || arg === '-V') {
|
|
45
|
+
args.command = 'version';
|
|
46
|
+
}
|
|
43
47
|
else if (arg === '--fail-on') {
|
|
44
48
|
const val = argv[++i];
|
|
45
49
|
if (val !== 'error' && val !== 'warning') {
|
|
@@ -95,7 +99,7 @@ export function parseArgs(argv) {
|
|
|
95
99
|
positional.push(arg);
|
|
96
100
|
}
|
|
97
101
|
}
|
|
98
|
-
if (args.command !== 'help') {
|
|
102
|
+
if (args.command !== 'help' && args.command !== 'version') {
|
|
99
103
|
const first = positional[0];
|
|
100
104
|
if (first === 'check' || first === 'watch' || first === 'check-all' || first === 'diff' || first === 'fix') {
|
|
101
105
|
args.command = first;
|
|
@@ -147,6 +151,17 @@ async function loadProtocol() {
|
|
|
147
151
|
registerConnectImpl(mod.connect);
|
|
148
152
|
}
|
|
149
153
|
}
|
|
154
|
+
/** Reads the installed package's version from package.json, one directory up from dist/cli.js. */
|
|
155
|
+
function getPackageVersion() {
|
|
156
|
+
try {
|
|
157
|
+
const pkgPath = fileURLToPath(new URL('../package.json', import.meta.url));
|
|
158
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
159
|
+
return pkg.version ?? 'unknown';
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return 'unknown';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
150
165
|
function printHelp() {
|
|
151
166
|
const helpText = `
|
|
152
167
|
${pc.bold('mcp-medic')} — Diagnose broken MCP server configs before they break your agent.
|
|
@@ -173,6 +188,7 @@ OPTIONS
|
|
|
173
188
|
--json Output report in JSON format
|
|
174
189
|
--timeout <ms> Per-server handshake timeout in milliseconds (default: 5000)
|
|
175
190
|
--help, -h Show help
|
|
191
|
+
--version, -V Print the installed mcp-medic version
|
|
176
192
|
|
|
177
193
|
FIX OPTIONS (mcp-medic fix)
|
|
178
194
|
--check <id> Only offer fixes from this check id (e.g. security.untrusted-remote)
|
|
@@ -422,6 +438,10 @@ export async function main(argv = process.argv.slice(2), deps = {}) {
|
|
|
422
438
|
printHelp();
|
|
423
439
|
return 0;
|
|
424
440
|
}
|
|
441
|
+
if (args.command === 'version') {
|
|
442
|
+
console.log(getPackageVersion());
|
|
443
|
+
return 0;
|
|
444
|
+
}
|
|
425
445
|
if (args.command === 'fix' && args.registryServer) {
|
|
426
446
|
console.error(pc.red('mcp-doctor fix does not support --registry — there is no local file to write the fix to.'));
|
|
427
447
|
return 2;
|
|
@@ -532,7 +552,8 @@ export async function main(argv = process.argv.slice(2), deps = {}) {
|
|
|
532
552
|
if (!targetPath) {
|
|
533
553
|
const discovered = discoverConfigFiles();
|
|
534
554
|
if (discovered.length === 0) {
|
|
535
|
-
console.error(pc.
|
|
555
|
+
console.error(pc.yellow('No MCP configuration files discovered (checked Claude Desktop, .mcp.json, and VS Code/Cursor locations). ' +
|
|
556
|
+
'Specify a file path (mcp-medic check <path>) or create a .mcp.json in your project.'));
|
|
536
557
|
return 2;
|
|
537
558
|
}
|
|
538
559
|
if (discovered.length === 1) {
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-medic",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Diagnose broken MCP (Model Context Protocol) server configs before they break your agent silently.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=18"
|
|
10
|
+
},
|
|
8
11
|
"bin": {
|
|
9
12
|
"mcp-medic": "dist/cli.js",
|
|
10
13
|
"mcpmedic": "dist/cli.js",
|
|
@@ -35,7 +38,10 @@
|
|
|
35
38
|
"json-schema",
|
|
36
39
|
"linter",
|
|
37
40
|
"llm",
|
|
38
|
-
"agents"
|
|
41
|
+
"agents",
|
|
42
|
+
"security",
|
|
43
|
+
"validator",
|
|
44
|
+
"ci"
|
|
39
45
|
],
|
|
40
46
|
"author": "Shivam Dixit",
|
|
41
47
|
"license": "MIT",
|