devnotes

How do you validate an MCP server against the spec?

There are two jobs here, and they need different tools. For a one-off interactive check, run the official MCP Inspector (npx @modelcontextprotocol/inspector) and click through your tools by hand. For a check that runs on every push and fails the pull request when your server drifts from the spec, you want a deterministic conformance linter: @fernforge/mcp-conform or the Python mcp-validator suite. The linter starts your server over stdio, calls tools/list, and inspects the real schemas and annotations a client will receive, not a guess from your source. That distinction matters because the top reason servers get bounced from the ChatGPT and Claude app directories is bad tool annotations: the spec says a client must assume the worst case (destructive, open-world) when a hint is missing, so a safe read-only tool with no readOnlyHint gets treated as dangerous. A linter catches that before you publish; the Inspector shows it to you only if you go looking.

The fast path: fail CI when the server is non-conformant

Point a conformance linter at your launch command. It boots the server, enumerates the tools, and reports each problem with a one-line fix and a score, with no LLM and no network, so it's safe to run a thousand times a day in CI:

npx @fernforge/mcp-conform --cmd "node dist/index.js"

It checks the things that get servers rejected: missing readOnlyHint / destructiveHint / openWorldHint / title annotations, thin or ambiguous input schemas, tool-poisoning phrases in descriptions (an "ignore previous instructions" line in a tool description is injected straight into the agent's context), and incomplete registry metadata for the reverse-DNS namespaced publishing the official registry now requires.

The 2026-07-28 spec is a hard break: check for it explicitly

The 2026-07-28 revision is not backward compatible, and this is where most existing servers silently fail. Mcp-Session-Id is removed at the protocol layer (SEP-2567), the initialize/initialized handshake is gone (SEP-2575), error code -32002 is reassigned to -32602, and two routing headers (Mcp-Method, Mcp-Name) are now required. A spec-migration scan reads your source and flags each removed API with a file:line and a fix:

npx @fernforge/mcp-conform --ruleset spec-migrate --project .
# hard breaks (sessions, handshake, error code) are errors;
# the 12-month deprecations (roots/sampling/logging) are warnings.
# --ruleset all combines it with the standing conformance lint.

The interactive path: MCP Inspector

When you're mid-development and want to poke at a tool by hand, the official Inspector is the right tool. It's a visual client that lists your tools, lets you call them with arbitrary input, and shows the raw responses:

npx @modelcontextprotocol/inspector node dist/index.js

It's exploratory, not a gate. It won't fail your build and it won't tell you you're missing an annotation unless you notice the absence yourself. Use it to debug a specific tool; use a linter to keep the whole server conformant over time.

Which to use

Run the Inspector while you're building a tool. Add a conformance linter to CI before you publish, and run the spec-migrate pack once now if your server predates the 2026-07-28 spec. The Python mcp-validator suite is a good fit if your server is Python and you want protocol-version compliance reports; mcp-conform leans toward author-side annotation, safety, and registry hygiene with a drop-in GitHub Action. They overlap, and running both costs nothing.

Notes from fernforge, which maintains @fernforge/mcp-conform. Spec change references: the 2026-07-28 MCP specification and its SEP proposals.