{"id":"8329f63b-611b-4860-9662-a8b75a7b85dc","slug":"prognosticate-x-mcp-compat","kind":"mcp","name":"mcp-compat","summary":"Zero-dependency Model Context Protocol (MCP) compatibility bridge and prompt cache normalizer","owner":"Prognosticate-X","repoUrl":"https://github.com/Prognosticate-X/mcp-compat","license":"MIT","licenseTier":"permissive","trust":"community","stars":0,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-10-02T02:39:04.000Z","addedAt":"2026-10-21T22:02:20.866Z","logoUrl":"https://avatars.githubusercontent.com/u/48873992?u=29f5927088af40fbd30471ed372d36907d8927d4&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["memory-knowledge","developer-tools","utilities"],"tags":["ai-agents","claude-code","json-rpc","llm","prompt-caching"],"runtime":"node","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-26T11:58:15.346Z","sample":false,"url":"https://conduits.dev/tools/prognosticate-x-mcp-compat","language":"JavaScript","transports":["stdio"],"install":{"npm":"@prognosticate-x/mcp-compat"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# mcp-compat\n\n[![CI](https://github.com/Prognosticate-X/mcp-compat/actions/workflows/ci.yml/badge.svg)](https://github.com/Prognosticate-X/mcp-compat/actions/workflows/ci.yml)\n[![GitHub release](https://img.shields.io/github/v/release/Prognosticate-X/mcp-compat?color=blue)](https://github.com/Prognosticate-X/mcp-compat/releases/latest)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![npm version](https://img.shields.io/npm/v/@prognosticate-x/mcp-compat.svg)](https://www.npmjs.com/package/@prognosticate-x/mcp-compat)\n[![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18.0.0-brightgreen)](https://nodejs.org)\n[![Zero Dependencies](https://img.shields.io/badge/dependencies-0-success)](package.json)\n\n> **Zero-dependency Model Context Protocol (MCP) compatibility bridge and prompt cache normalizer.**  \n> Fixes silent tool dropping in Claude Code ([#88128](https://github.com/anthropics/claude-code/issues/88128)) and boosts prompt cache hit rates from 0% to 100% ([#23571](https://github.com/anomalyco/opencode/issues/23571)).\n\n[English (US)](README.md) | [中文文档 (Chinese)](docs/README_zh.md) | [Upstream Advisory](docs/UPSTREAM_ADVISORY.md)\n\n---\n\n## The Problem\n\n### 1. Silent Tool Drops in Claude Code ([#88128](https://github.com/anthropics/claude-code/issues/88128))\nIn **Claude Code** (v2.1.235+), the client-side Zod validator mistakenly enforces `ttlMs` and `cacheScope` as **required** fields for `tools/list`, `resources/list`, and `prompts/list` under protocol revision `2026-07-28`.\n- Conformant MCP servers (e.g., Rust `rmcp` 3.1.2, Python `FastMCP`) omit these optional fields according to the official specification.\n- Claude Code rejects the response, retries 4 times with exponential backoff, and then **permanently drops all tools from the server for the session**. No diagnostic error is shown to the user or model.\n\n### 2. Prompt Cache Invalidation Snowball ([#23571](https://github.com/anomalyco/opencode/issues/23571))\nModern LLM providers (Anthropic, OpenAI, DeepSeek) offer Prompt Caching, cutting input token costs by up to 90%.\n- Unstable key ordering in tool definitions and input schemas between server restarts invalidates the prompt cache on every reconnection.\n- As a result, users and organizations pay full price on every session restart.\n\n---\n\n## The Solution\n\n`mcp-compat` acts as a transparent, drop-in stdio shim between your MCP client and server:\n\n```\n┌─────────────────────────────────────────────────────────┐\n│     Client (Claude Code / OpenCode / Agent Framework)   │\n└───────────────────────────┬─────────────────────────────┘\n                            │ stdio (JSON-RPC 2.0)\n                            ▼\n┌─────────────────────────────────────────────────────────┐\n│                       mcp-compat                        │\n│  ─────────────────────────────────────────────────────  │\n│  1. Injects safe default cache hints (ttlMs: 0, etc.)   │\n│  2. Deeply sorts tool schemas & keys deterministically  │\n│  3. Translates dual-era error codes (2025 <-> 2026)     │\n│  4. Bounds request tracking (TTL eviction & max cap)    │\n└───────────────────────────┬─────────────────────────────┘\n                            │ stdio (JSON-RPC 2.0)\n                            ▼\n┌─────────────────────────────────────────────────────────┐\n│            Upstream Server (Rust / Python / Go)         │\n└─────────────────────────────────────────────────────────┘\n```\n\n1. **Cache Hint Backfill**: Injects `ttlMs: 0` and `cacheScope: \"private\"` into discovery responses, satisfying overly-strict client validators without altering server semantics.\n2. **Deterministic Schema Canonicalization**: Applies recursive alphabetical key sorting (`deepSortKeys`) to all tool definitions and `inputSchema` properties, guaranteeing byte-level serialization stability.\n3. **Dual-Era Error Translation**: Normalizes legacy error codes (`-32002` ResourceNotFound) to standardized 2026 equivalents (`-32602` INVALID_PARAMS).\n\n---\n\n## Upstream Community Status\n\n| Upstream Project | Tracking Item | Status | Contribution |\n|---|---|:---:|---|\n| **Anthropic Claude Code** | [#88128](https://github.com/anthropics/claude-code/issues/88128) | Active | [Comment #5944611446](https://github.com/anthropics/claude-code/issues/88128#issuecomment-5944611446) (Root cause + Workaround) |\n| **Microsoft Agent Framework** | [#8245](https://github.com/microsoft/agent-framework/issues/8245) | In Review | [PR #8960](https://github.com/microsoft/agent-framework/pull/8960) (Deterministic Schema Sorting) |\n\nSee [docs/UPSTREAM_ADVISORY.md](docs/UPSTREAM_ADVISORY.md) for full technical details.\n\n---\n\n## Quick Start\n\n### Option A: Install Globally (Recommended for shortest command)\n```bash\n# Install once globally:\nnpm install -g @prognosticate-x/mcp-compat\n\n# Run directly anywhere with short command (no prefix needed):\nmcp-compat -- uvx fastmcp run server.py\nmcp-compat -- ./target/release/my-mcp-server\n```\n\n### Option B: Run On-The-Fly via `npx` (Zero installation)\n```bash\n# Run via npm package:\nnpx -y @prognosticate-x/mcp-compat -- uvx fastmcp run server.py\n\n# Or run directly from GitHub (always latest):\nnpx -y github:Prognosticate-X/mcp-compat -- uvx fastmcp run server.py\n```\n\n### Configuration Examples\n\n#### Claude Code (`~/.claude.json` or project `.claude.json`)\n```json\n{\n  \"mcpServers\": {\n    \"my-server\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@prognosticate-x/mcp-compat\", \"--\", \"uvx\", \"fastmcp\", \"run\", \"server.py\"]\n    }\n  }\n}\n```\n\n#### Claude Desktop (`claude_desktop_config.json`)\n```json\n{\n  \"mcpServers\": {\n    \"database\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\",\n        \"mcp-compat\",\n        \"--ttl\",\n        \"600000\",\n        \"--\",\n        \"/path/to/my-rust-server\"\n      ]\n    }\n  }\n}\n```\n\n---\n\n## CLI Options\n\n```\nmcp-compat [options] -- <server-command> [args...]\n\nOptions:\n  --ttl <ms>             Default TTL in ms if omitted by server (default: 0)\n  --scope <public|priv>  Default cacheScope if omitted ('private' | 'public', default: 'private')\n  --no-sort              Disable deterministic tool & schema ordering\n  --verbose              Log debug & negotiation information to stderr\n  --stats                Print session telemetry summary on process exit\n  --help                 Show this help message\n```\n\n---\n\n## Benchmark Results\n\nRun the prompt cache stability benchmark:\n```bash\nnpm run bench\n```\n\n```\n========================================================================\n  MCP Prompt Cache Stability & Token Invalidation Benchmark\n========================================================================\n\nSimulating 5 server restarts with dynamic tool registration...\n\n--- [1] Raw Non-Deterministic Output (Typical Unordered Server) ---\n  Session 1: SHA-256 = 9e6e11ec4333d842...\n  Session 2: SHA-256 = 574492347932ca6e...\n  Session 3: SHA-256 = 1262ca4d272aedd7...\n  => Prompt Cache Hit Rate: 0.0% (Total Cache Invalidation ❌)\n\n--- [2] Normalized Output (via mcp-compat) ---\n  Session 1: SHA-256 = 8541d45dc2166852...\n  Session 2: SHA-256 = 8541d45dc2166852...\n  Session 3: SHA-256 = 8541d45dc2166852...\n  => Prompt Cache Hit Rate: 100.0% (Perfect Cache Preservation ✅)\n```\n\n---\n\n## Programmatic API\n\nYou can also embed `mcp-compat` directly into your Node.js application:\n\n```javascript\nimport { McpBridgeEngine, deepSortKeys } from 'mcp-compat';\n\nconst engine = new McpBridgeEngine({\n  defaultTtlMs: 60000,\n  defaultCacheScope: 'private',\n  deterministicOrder: true\n});\n\n// Pass inbound and outbound frames\nconst outboundToServer = engine.processClientMessage(clientJsonRpc);\nconst inboundToClient = engine.processServerMessage(serverJsonRpc);\n\n// Inspect session telemetry\nconsole.log(engine.getDiagnostics());\n```\n\n---\n\n## Security & Reliability\n\n- **Zero Third-Party Dependencies**: Pure Node.js standard library (Node 18+). Zero supply-chain attack surface.\n- **Memory Leak Protection**: Pending request tracking includes a 60-second TTL eviction timer and a 10,000-entry hard cap.\n- **Recursion Depth Bounded**: `deepSortKeys` enforces a `MAX_SORT_DEPTH = 50` limit to prevent stack overflow from deeply nested payloads.\n- **Zero Semantic Mutation**: Requests such as `tools/call` pass through unmodified.\n\n---\n\n## Testing\n\nThe project includes unit tests, bug reproduction simulations, and real-process IPC integration tests:\n\n```bash\nnpm test\n```\n\n```\n✔ Claude Code #88128 Bug Reproduction Suite (3 tests)\n✔ MCP Normalizer & Compatibility Layer Suite (8 tests)\n✔ End-to-End Real Process IPC Test Suite (4 tests)\n  18 passed, 0 failed\n```\n\n---\n\n## License\n\n[MIT](LICENSE) © 2026 Prognosticate X\n"}