{"_id":"@a5omic/mcp-compat","name":"@a5omic/mcp-compat","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@a5omic/mcp-compat","version":"0.1.0","description":"Dual-era compatibility primitives and diagnostics for legacy and stateless MCP.","keywords":["mcp","model-context-protocol","compatibility","migration","protocol","json-rpc","ai","typescript"],"type":"module","license":"MIT","author":{"name":"Atomics Hub"},"repository":{"type":"git","url":"git+https://github.com/Atomics-hub/mcp-compat.git"},"bugs":{"url":"https://github.com/Atomics-hub/mcp-compat/issues"},"homepage":"https://github.com/Atomics-hub/mcp-compat#readme","engines":{"node":">=18"},"packageManager":"npm@11.6.0","publishConfig":{"access":"public","provenance":true},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"bin":{"mcp-compat":"dist/cli.js"},"scripts":{"build":"tsup","typecheck":"tsc --noEmit","test":"vitest run","test:coverage":"vitest run --coverage","test:package":"node scripts/verify-package.mjs","lint":"eslint .","lint:package":"node scripts/lint-package.mjs","format:check":"prettier --check .","pack:check":"npm pack --dry-run --cache .npm-cache","release:check":"node scripts/check-release.mjs","verify":"npm run format:check && npm run lint && npm run typecheck && npm run test:coverage && npm run build && npm run lint:package && npm run test:package && npm run pack:check","prepublishOnly":"npm run verify"},"overrides":{"esbuild":"^0.28.1"},"devDependencies":{"@arethetypeswrong/cli":"^0.18.5","@eslint/js":"^10.0.1","@types/node":"^26.2.0","@vitest/coverage-v8":"^4.1.11","eslint":"^10.9.0","fast-check":"^4.3.0","prettier":"^3.6.2","publint":"^0.3.24","tsup":"^8.5.0","typescript":"^5.9.2","typescript-eslint":"^8.67.0","vitest":"^4.1.11"},"_id":"@a5omic/mcp-compat@0.1.0","gitHead":"4aa123be599ca7e01755ee1fafdd46267ccb23c9","_nodeVersion":"24.8.0","_npmVersion":"11.6.0","dist":{"integrity":"sha512-i3nGyzkYHTQNPz1DZtfuBUbOeqFQ79n8hBXSBSG3n5/AyfpWH5nNMCAbJNjooSw+l64hyuvNwavEccLGFN5QAA==","shasum":"44e67ea80e94b35d4776cae862a1dab9215f4c67","tarball":"https://registry.npmjs.org/@a5omic/mcp-compat/-/mcp-compat-0.1.0.tgz","fileCount":12,"unpackedSize":325034,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHKlozMPHw0OhN29Gc8/RfL8SIJrqPXRmypvP/StsggsAiA3tDA6eZoPluEOHMLTgcOB50XSHyt3XSDJfejEpFMvpQ=="}]},"_npmUser":{"name":"a5omic","email":"therekishianime@gmail.com"},"directories":{},"maintainers":[{"name":"a5omic","email":"therekishianime@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-compat_0.1.0_1787611846571_0.5332831103561311"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-24T22:50:46.410Z","0.1.0":"2026-08-24T22:50:46.714Z","modified":"2026-08-24T22:50:46.912Z"},"maintainers":[{"name":"a5omic","email":"therekishianime@gmail.com"}],"description":"Dual-era compatibility primitives and diagnostics for legacy and stateless MCP.","homepage":"https://github.com/Atomics-hub/mcp-compat#readme","keywords":["mcp","model-context-protocol","compatibility","migration","protocol","json-rpc","ai","typescript"],"repository":{"type":"git","url":"git+https://github.com/Atomics-hub/mcp-compat.git"},"author":{"name":"Atomics Hub"},"bugs":{"url":"https://github.com/Atomics-hub/mcp-compat/issues"},"license":"MIT","readme":"# mcp-compat\n\n[![npm version](https://img.shields.io/npm/v/%40a5omic%2Fmcp-compat)](https://www.npmjs.com/package/@a5omic/mcp-compat)\n[![CI](https://github.com/Atomics-hub/mcp-compat/actions/workflows/ci.yml/badge.svg)](https://github.com/Atomics-hub/mcp-compat/actions/workflows/ci.yml)\n[![license](https://img.shields.io/npm/l/%40a5omic%2Fmcp-compat)](LICENSE)\n\nDual-era compatibility primitives and diagnostics for the Model Context Protocol.\n\n`mcp-compat` helps libraries, gateways, clients, and servers handle the boundary between handshake-era MCP (`2025-11-25` and earlier) and stateless MCP (`2026-07-28`). The core has **zero runtime dependencies** and does not import either generation of the official SDK.\n\n```bash\nnpm install @a5omic/mcp-compat\n```\n\n```ts\nimport {\n  detectMcpEra,\n  negotiateProtocolVersion,\n  withModernMeta,\n} from \"@a5omic/mcp-compat\";\n\nconst request = withModernMeta({\n  jsonrpc: \"2.0\",\n  id: 1,\n  method: \"tools/list\",\n});\n\ndetectMcpEra(request).era; // \"modern\"\nnegotiateProtocolVersion([\"2026-07-28\", \"2025-11-25\"]); // \"2026-07-28\"\n```\n\nIt also ships a safe, CI-friendly CLI:\n\n```bash\nnpx @a5omic/mcp-compat probe https://example.com/mcp\nnpx @a5omic/mcp-compat audit transcript.json --strict\n```\n\n## Why this exists\n\nMCP now has two lifecycle eras with materially different wire behavior.\n\n| Concern                   | Legacy through `2025-11-25` | Modern `2026-07-28`         |\n| ------------------------- | --------------------------- | --------------------------- |\n| Opening                   | `initialize` handshake      | No required handshake       |\n| Version                   | Negotiated once             | Declared on every request   |\n| Identity and capabilities | Connection-scoped           | Per-request `_meta`         |\n| Discovery                 | Initialize result           | `server/discover`           |\n| Sessions                  | `Mcp-Session-Id`            | Removed                     |\n| HTTP routing              | Body inspection             | `Mcp-Method` and `Mcp-Name` |\n| Change stream             | Session GET / subscriptions | `subscriptions/listen`      |\n\nA dual-era implementation can serve both. A modern-only side and a legacy-only side cannot communicate directly. Some features cannot be translated without application knowledge, so this package reports those boundaries instead of silently changing semantics.\n\nProtocol references:\n\n- [MCP `2026-07-28` announcement](https://blog.modelcontextprotocol.io/posts/2026-07-28/)\n- [MCP specification](https://modelcontextprotocol.io/specification/2026-07-28)\n- [Official TypeScript SDK migration documentation](https://ts.sdk.modelcontextprotocol.io/v2/)\n\n## Core API\n\n### Detect a protocol era\n\n```ts\nimport { detectMcpEra } from \"@a5omic/mcp-compat\";\n\nconst detection = detectMcpEra(message, {\n  \"MCP-Protocol-Version\": \"2026-07-28\",\n  \"MCP-Method\": \"tools/call\",\n  \"MCP-Name\": \"search\",\n});\n\n// {\n//   era: \"modern\",\n//   confidence: \"high\",\n//   protocolVersion: \"2026-07-28\",\n//   signals: [...],\n//   issues: []\n// }\n```\n\nConflicting signals return `era: \"unknown\"` with explicit issues. Unknown future version strings are not guessed from date ordering: MCP protocol revisions are an enumerated set.\n\n### Add modern per-request metadata\n\n```ts\nimport { withModernMeta } from \"@a5omic/mcp-compat\";\n\nconst modern = withModernMeta(\n  {\n    jsonrpc: \"2.0\",\n    id: \"call-1\",\n    method: \"tools/call\",\n    params: {\n      name: \"search\",\n      arguments: { query: \"otters\" },\n      _meta: { \"vendor.example/traceId\": \"trace-1\" },\n    },\n  },\n  {\n    clientInfo: { name: \"my-client\", version: \"2.0.0\" },\n    clientCapabilities: {},\n  },\n);\n```\n\nExisting vendor metadata is preserved. The input object is never mutated.\n\n### Mirror modern HTTP routing headers\n\n```ts\nimport { normalizeMcpHeaders } from \"@a5omic/mcp-compat\";\n\nnormalizeMcpHeaders(modern);\n// {\n//   \"Content-Type\": \"application/json\",\n//   \"Accept\": \"application/json, text/event-stream\",\n//   \"MCP-Protocol-Version\": \"2026-07-28\",\n//   \"MCP-Method\": \"tools/call\",\n//   \"MCP-Name\": \"search\"\n// }\n```\n\nPrincipal-name routing is supported for tool calls, prompts, resource reads, and task operations.\nValues that are not safe plain-ASCII header values are encoded using MCP's Base64 sentinel format and decoded before comparison.\n\n### Negotiate supported revisions\n\n```ts\nimport { negotiateProtocolVersion } from \"@a5omic/mcp-compat\";\n\nnegotiateProtocolVersion([\"2025-11-25\", \"2026-07-28\"]);\n// \"2026-07-28\"\n\nnegotiateProtocolVersion([\"2023-01-01\"]);\n// null\n```\n\nThe local list determines preference order. No lexical date comparison is used.\n\n### Build a conforming unsupported-version error\n\n```ts\nimport { createUnsupportedProtocolError } from \"@a5omic/mcp-compat\";\n\ncreateUnsupportedProtocolError(7, \"2028-01-01\");\n// JSON-RPC error -32022 with requested and supported revisions\n```\n\n### Classify endpoint compatibility\n\n```ts\nimport { classifyCompatibility } from \"@a5omic/mcp-compat\";\n\nclassifyCompatibility(\"legacy\", \"modern\").status; // \"incompatible\"\nclassifyCompatibility(\"modern\", \"dual\").status; // \"compatible\"\nclassifyCompatibility(\"legacy\", \"legacy\").status; // \"compatible\"\n```\n\n## Audit messages and transcripts\n\n```ts\nimport { auditMcpMessage, auditMcpTranscript } from \"@a5omic/mcp-compat\";\n\nconst report = auditMcpMessage(message, headers);\nconst transcript = auditMcpTranscript([\n  { message: firstRequest, headers: firstHeaders },\n  { message: firstResponse, headers: responseHeaders },\n]);\n```\n\nFindings have stable codes, severities, messages, and JSON paths. Current checks include:\n\n- JSON-RPC 2.0 structure;\n- conflicting versions and protocol-era signals;\n- body/header method, subject, and version mismatches;\n- required modern protocol version and capabilities, plus recommended client identity;\n- forbidden modern `Mcp-Session-Id` usage;\n- removed lifecycle and session methods;\n- missing modern `resultType`;\n- malformed legacy initialization;\n- missing routing headers for tools, prompts, resources, and tasks.\n\n## Probe live endpoints\n\n```ts\nimport { probeMcpEndpoint } from \"@a5omic/mcp-compat\";\n\nconst report = await probeMcpEndpoint(\"https://example.com/mcp\", {\n  timeoutMs: 5_000,\n  maxResponseBytes: 1_048_576,\n});\n\nreport.support; // \"dual\" | \"modern\" | \"legacy\" | \"unknown\"\n```\n\nThe probe performs only two protocol lifecycle operations:\n\n1. modern `server/discover`;\n2. legacy `initialize`.\n\nIt never lists or invokes tools, reads resources, retrieves prompts, or supplies credentials. When initialize returns a session ID, cleanup sends a best-effort `DELETE`.\n\nRedirects are rejected, response bodies are bounded, timeouts are enforced, embedded URL credentials are forbidden, and caller cancellation is supported.\n\n> [!WARNING]\n> A server-side product must not expose arbitrary probe URLs to untrusted users without outbound network policy. Any URL-fetching feature can otherwise become an SSRF primitive. Restrict schemes, hosts, ports, DNS resolution, and private network access at the deployment boundary.\n\n## CLI\n\n### Detect\n\n```bash\nmcp-compat detect request.json\nmcp-compat detect request.json --headers headers.json --json\ncat request.json | mcp-compat detect -\n```\n\nExit code is `0` for a recognized era, `1` for unknown, and `2` for invalid input or usage.\n\n### Audit\n\n```bash\nmcp-compat audit request.json --headers headers.json\nmcp-compat audit transcript.json --strict --json\n```\n\nA transcript can be an array of raw messages or entries shaped as `{ \"message\": ..., \"headers\": ... }`.\n\nAudit exits `1` when errors exist. `--strict` also makes warnings fail. This makes it suitable as a CI gate.\n\n### Probe\n\n```bash\nmcp-compat probe https://example.com/mcp\nmcp-compat probe https://example.com/mcp --timeout 10000 --json\n```\n\nProbe exits `0` for dual-era support, `1` for a known single era, and `2` when support cannot be established.\n\n### Input guards\n\n```bash\nmcp-compat audit large.json --max-bytes 1048576\nmcp-compat probe https://example.com/mcp --max-response-bytes 1048576\n```\n\nFiles are size-checked before parsing. Standard input is counted incrementally.\n\n## What this package does not do\n\n`mcp-compat` does not claim that every feature can be translated between eras.\n\n- It does not invent semantics for legacy sampling, roots, elicitation, or logging.\n- It does not proxy arbitrary tool calls.\n- It does not hide capability mismatches.\n- It does not treat an unknown future revision as compatible.\n- It does not replace the official SDK or conformance suite.\n\nUse it as a small compatibility layer, router primitive, diagnostic engine, migration gate, or input to a purpose-built gateway.\n\n## Runtime and package support\n\n- Node.js 18 or newer\n- ESM and CommonJS\n- Built-in TypeScript declarations\n- Zero runtime dependencies\n- Fetch-compatible runtimes for live probing\n\n## Security\n\nSee [SECURITY.md](SECURITY.md). Please report vulnerabilities privately rather than opening a public issue.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md). Protocol rules require an authoritative specification or official SDK reference plus positive and negative tests.\n\n## License\n\nMIT © Atomics Hub\n\n`mcp-compat` is an independent project and is not affiliated with or endorsed by the Model Context Protocol maintainers.\n","readmeFilename":"README.md","_rev":"1-67f2ee090e17922331b4168bbccee8a9"}