mcp-doctor — a static-analysis linter for MCP server quality (feedback welcome) #3322
Replies: 4 comments 4 replies
|
I found a mixed-coverage edge case in Minimal pair, in separate # before/server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("synthetic")
@mcp.tool()
def lookup(key: str) -> str:
"""Look up a synthetic value.
Args:
key: Key to look up.
"""
return key# after/server.py
from mcp.types import Tool
lookup_tool = Tool(
name="lookup",
description="Look up a synthetic value.",
inputSchema={
"type": "object",
"properties": {"key": {"type": "string", "description": "Key to look up."}},
"required": ["key"],
},
)python -m mcp_doctor.cli before --json > baseline.json
python -m mcp_doctor.cli after --json --diff-against baseline.json --fail-on-breaking-changeThe actual analyzer → JSON snapshot → CLI path produces I saw the documented raw-schema → raw-schema limitation; this is the cross-style case where unknown coverage is interpreted as known absence. A separate “parameter schema inspected” flag, with parameter-level comparison only when both snapshots have coverage, would avoid conflating those states. Legacy snapshots missing these fields need the same consideration. Scope: reproduced on Python 3.12.3 against the pinned analyzer and CLI, using synthetic sources. No MCP SDK/server was run, so this is not a runtime wire-schema equivalence test. Disclosure: I co-founded Mnemoverse. Codex performed the source analysis, synthetic reproduction, and wrote this comment on my behalf. |
|
Hi Edward, thanks for the minimal repro — that made this trivial to confirm and fix. You found the real root cause: Fixed at the source rather than adding a "schema inspected" flag: the analyzer now statically resolves Kept it honest about the remaining edge: if any property name in the schema isn't a string literal (a dynamic key, or an unresolved Shipped in v0.9.3: vishalhabib99/mcp-doctor@45a52c5, with your repro as a permanent regression test. Attributed to you in the README's changelog and the known-limitations section. |
|
Nice tool — the diff-against fix above is a good example of exactly the kind of thing static checks should be catching. One check worth adding on the annotation side (separate from the parameter-coverage checks discussed above): the spec's own doc comment on A lint rule flagging |
|
Thanks both — two real fixes shipped from this thread, both released. @edwardizgorodin — your @christian-bru — good catch on the spec's own Both scoped to the Python/FastMCP decorator style for now, same as the existing annotation checks — happy to extend to the raw |
Uh oh!
There was an error while loading. Please reload this page.
I've been building mcp-doctor, a small static-analysis CLI that audits MCP server implementations for the things that actually break an agent calling them: missing tool descriptions, undocumented parameters, no error handling, no README coverage. Point it at a repo, get a score and a concrete list of what to fix.
It's new (MIT, Python, not on PyPI yet — install from the repo) so I've been dogfooding it against real servers rather than just the examples I wrote it against. That surfaced two real precision bugs in the tool itself (test fixtures getting flagged as production issues), both fixed. It also surfaced a genuine, actionable finding on a real server — filed as homeassistant-ai/ha-mcp#2324 — which felt like a good sign the checks are catching real things, not just noise.
Currently Python-only (FastMCP
@mcp.tool()decorator style and the low-level SDKTool(...)constructor style). TypeScript/JS support is the obvious next gap given how much of the ecosystem is there.If anyone's willing to run it against their own server and tell me what it gets wrong, that'd be genuinely useful — happy to fix false positives fast.
All reactions