Live migration & conformance analyzer for MCP servers targeting the 2026-07-28 stateless spec. Probes stdio/HTTP servers read-only and reports findings as JSONL/Markdown.
mcp-migrate
Live conformance analyzer and safe patcher for the MCP 2026-07-28 spec. Probes a running MCP server — over stdio or Streamable HTTP — and reports what needs to change, with severity, remediation, and machine-readable JSONL output.
Pre-release —
0.xTargeting the MCP2026-07-28release candidate (locked 2026-05-21, final expected 2026-07-28). The CLI interface and JSONL schema may change before v1.
Contents
Install
go install github.com/P4ST4S/mcp-migrate/cmd/mcp-migrate@latest
Or build from source:
git clone https://github.com/P4ST4S/mcp-migrate
cd mcp-migrate
go build -o ./bin/mcp-migrate ./cmd/mcp-migrate
Docker:
docker run --rm ghcr.io/p4st4s/mcp-migrate analyze --transport http --url http://host.docker.internal:3000/mcp
Requires Go 1.21+.
Quick start
Analyze a Streamable HTTP server:
mcp-migrate analyze --transport http --url http://localhost:3000/mcp
Analyze a stdio server:
mcp-migrate analyze --transport stdio --server-command "node ./server.js"
Filter to breaking findings:
mcp-migrate analyze --transport http --url http://localhost:3000/mcp \
| jq -r 'select(.severity == "breaking") | [.rule, .enforcement, .message] | @tsv'
Render a Markdown report:
mcp-migrate analyze --transport http --url http://localhost:3000/mcp \
--format markdown > report.md
Preview source-code patches without writing:
mcp-migrate patch --path ./src --allow-pending
Apply patches:
mcp-migrate patch --path ./src --allow-pending --write
Commands
analyze
| Flag | Default | Description |
|---|---|---|
| --transport | http | http or stdio |
| --url | — | Streamable HTTP endpoint (HTTP only) |
| --server-command | — | Server command to spawn (stdio only) |
| --format | jsonl | jsonl or markdown |
| --spec-target | 2026-07-28 | Target spec version |
| --allow-resource-read | off | Include resources/read probes |
| --allow-mutating-probes | off | Allow probes that may modify state |
patch
Rewrites –32002 (legacy resource-not-found error code) to –32602 in Go, JS/TS, and Python source files. Only replaces occurrences where the surrounding code confirms a resource-not-found context.
| Flag | Default | Description |
|---|---|---|
| --path | — | File or directory to scan (required) |
| --write | off | Write changes to disk (default: dry-run) |
| --allow-pending | off | Required: the underlying SEP-2164 is still Draft |
Without --allow-pending, patch refuses with an explanation. This is intentional: patching based on a non-final spec carries the risk of a second migration.
Safety
analyze is read-only by default. Default probes: server/discover, tools/list, resources/list, prompts/list. resources/read requires --allow-resource-read. tools/call is never sent.
Hidden-state detection repeats the same read-only list probes and compares canonicalized results. Drift caused by explicit handle fields (stateHandle, etc.) is normalized and ignored.
patch is dry-run by default. Writes nothing without --write. Substitutions are context-confirmed: –32002 is replaced only when a resource-not-found signal (resources/read, resource not found, ResourceNotFound) appears within ±2 lines of the occurrence in non-comment code. Distant mentions in comments do not qualify. Patches are idempotent.
Secret redaction. JSONL and Markdown output never contains tokens, auth headers, environment variables, stderr, response bodies, raw headers, cookies, URL userinfo, or sensitive query parameters.
Output format
JSONL: one finding per line, each an independent JSON object.
{
"schema": "mcp-migrate/finding/v1",
"rule": "server-discover-required",
"sep": { "id": "SEP-2575", "status": "Accepted", "verification": "unverified" },
"severity": "breaking",
"enforcement": "report-only",
"spec_target": "2026-07-28",
"source": { "mode": "live", "ref": "http://localhost:3000/mcp" },
"message": "Server does not expose the stateless server/discover RPC.",
"remediation": "Implement server/discover with supported versions, server capabilities, and server identity.",
"autofix": false,
"status": "confirmed"
}
Empty output is valid and means no findings were produced.
enforcement is "enforced" when the underlying SEP is Final and verified, and the detection method is direct observation. It is "report-only" when the SEP is not yet Final, the detection relies on differential inference (e.g. list drift), or the rule is pending final-spec reconciliation.
Full schema: docs/REPORT_SCHEMA.md.
Example reports from test fixtures:
| Profile | JSONL | Markdown | |---|---|---| | HTTP — compliant | http-compliant.jsonl | http-compliant.md | | HTTP — legacy | http-legacy.jsonl | http-legacy.md | | HTTP — mixed | http-mixed.jsonl | http-mixed.md | | HTTP — stateful lists | http-stateful-lists.jsonl | http-stateful-lists.md | | stdio — compliant | stdio-compliant.jsonl | stdio-compliant.md | | stdio — legacy | stdio-legacy.jsonl | stdio-legacy.md | | stdio — stateful lists | stdio-stateful-lists.jsonl | stdio-stateful-lists.md |
Severity model
| Severity | Meaning |
|---|---|
| breaking | Incompatible with a strict 2026-07-28 peer. Does not mean the server breaks on July 28. |
| deprecated | Still functional, but in the Deprecated lifecycle state. Earliest removal: 12 months after deprecation. |
| warning | Operational risk or non-conformance that may affect portability, scaling, or future migration. |
| info | Modernization or interoperability suggestion. |
Development
go test ./...
go build ./...
Tests use httptest.Server fixtures for HTTP and Go helper processes for stdio. No external dependencies — the module is dependency-free.
To regenerate the testdata/examples/ JSONL and Markdown files after a rule change:
UPDATE_EXAMPLES=1 go test ./internal/analyze/live
Contributing
See CONTRIBUTING.md for contribution guidelines, ground rules for new rules, patch requirements, and the evidence-strength model.
Internal documentation:
docs/SPEC_RULES.md— rule definitions, SEP references, severity rationaledocs/REPORT_SCHEMA.md— JSONL schema referencedocs/PLAN.md— implementation plan and phase status
License
Apache-2.0. See LICENSE.