MCPResilience

MCPResilience

Enables MCP clients to seamlessly operate across legacy and modern protocol versions, auto-detecting the client's era on the first request and supporting the experimental Tasks extension with full compatibility.

Category
Visit Server

README

🛡️ MCPResilience

A Resilient, Spec-Compliant MCP Server Built on the Official SDK v2

Speak MCP however your client speaks it. MCPResilience auto-detects legacy and modern protocol eras on the very first request — and survives the difference.

MCP Spec SDK Language License


🔌 Client Modes

MCPResilience auto-detects which protocol era a connecting client speaks — no configuration needed:

  1. ⚡ Modern Stateless Clients — clients whose first request carries the _meta envelope (io.modelcontextprotocol/protocolVersion + clientInfo) skip the handshake entirely. tools/call can be their very first message.
  2. 🤝 Legacy Handshake Clients — clients without that envelope are routed through the traditional initialize flow, with -32600 Invalid request parameters enforced on anything sent before initialize completes.

See Protocol Support for the full breakdown of both eras.


🧠 What This Is

MCPResilience exists because swapping a hand-rolled MCP server for the official SDK isn't a drop-in change — the wire format shifts in ways that break naive migrations. This project tackles that in two stages:

  1. SDK Migration — replace a hand-rolled MCP server core with the official MCP SDK v2, targeting the 2026-07-28 spec, to gain a stateless core and type-safe Pydantic serialization.
  2. Compatibility Hardening — make sure the migration doesn't silently drop support for clients still using the legacy handshake, lose data to upstream schema gaps, or break the experimental Tasks extension mid-flight.

Both stages are documented honestly below, including the one upstream SDK bug that surfaced along the way.


📊 Key Results

All Phase 5 compatibility tests and Phase 6 benchmarks pass, end-to-end, on the official MCP SDK v2 — with full support for both protocol eras and the experimental Tasks extension, plus one upstream SDK bug identified and patched (see Known SDK Quirk).

Tasks extension: what changed under the SDK migration

Aspect Legacy behavior SDK v2 behavior
Declaring task support Boolean longRunning: true flag execution object, e.g. execution: {"taskSupport": "required"}
Task handle location Top-level taskHandle in result Moved to metadata envelope: result._meta.taskHandle
Terminal success state "succeeded" "completed"
Task content delivery Returned via tasks/get polling Delivered only via the tools/call response stream — tasks/get returns status metadata only (statusMessage, createdAt, etc.)
Re-cancelling a finished task {cancelled: true} or -32602 error Idempotent — returns CancelTaskResult with status: "cancelled"

🏗️ How It Works

Incoming connection
        │
        ▼
  First request received
        │
        ▼
  Does it carry the _meta envelope?
  (protocolVersion + clientInfo)
        │
   ┌────┴────┐
  Yes         No
   │           │
   ▼           ▼
Modern Era   Legacy Era
(stateless)  (handshake required)
   │           │
   ▼           ▼
tools/call   initialize → any request
runs          (initialize enforced,
immediately    notifications/initialized
               not blocked)
   │           │
   └─────┬─────┘
         ▼
  Era locked for the
  life of the connection

📡 Protocol Support

Stateless Era (2026-07-28)

Under the modern spec, the traditional initialize → notifications/initialized handshake is obsolete. The server runs a serve_dual_era_loop:

  • If the first request includes the _meta envelope with io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientInfo, the server locks into the modern stateless era.
  • Clients can send tools/call as their very first request — no initialize call needed.

Legacy Era

If the first request lacks the modern _meta envelope, the server locks into the legacy era:

  • Any request sent before initialize (e.g. tools/call) is rejected with -32600 Invalid request parameters.
  • Once initialize has been answered, the server does not wait for notifications/initialized before processing further requests.

Version Mismatch Handling

Modern requests specifying an unsupported protocol version in the _meta envelope are rejected cleanly with -32022 Unsupported protocol version — the connection itself is preserved rather than dropped.


🧩 Tasks Extension Deep Dive

The experimental Tasks extension underwent the most wire-format churn of anything in the migration (see the comparison table in Key Results). Two behaviors are worth calling out specifically:

  • tasks/get is metadata-only now. Task content is delivered exclusively through the tools/call response stream; polling tasks/get will only ever return status fields like statusMessage and createdAt — never the payload itself.
  • Cancellation is idempotent by design. Re-cancelling a task that's already completed or cancelled returns a successful CancelTaskResult rather than an error, unlike the legacy server's -32602 on repeat cancellation.

Known SDK Quirk

SDK Issue #2156 — execution field stripped from tools/list. The current Pydantic schema for v2026_07_28.Tool doesn't define the experimental execution field, so serialize_server_result silently strips it from tools/list responses.

Workaround: a targeted monkeypatch on mcp_types.methods.serialize_server_result intercepts the validated output and restores the execution dictionary from the original handler data. This is a stopgap — remove it once the upstream schema ships the field natively.


🔧 Technical Notes (the parts that weren't trivial)

  1. Era detection happens exactly once, on the first request. There's no mid-connection upgrade path — a client that opens without the _meta envelope stays in the legacy era for the life of that connection, even if it starts sending modern-shaped requests later.
  2. The task handle didn't just move, its contract changed. Relocating taskHandle from the top-level result to result._meta also freed up the top-level result object to be reserved purely for immediate content output and the isError flag — a cleaner separation than the legacy shape allowed.
  3. The monkeypatch is scoped narrowly on purpose. It only intercepts serialize_server_result to restore one missing field, rather than forking or wrapping the SDK's schema wholesale — keeping the patch easy to delete the moment upstream ships a fix.

🛠️ Tech Stack

  • Protocol: JSON-RPC 2.0 over the Model Context Protocol, spec 2026-07-28
  • SDK: Official MCP SDK v2 — Pydantic-based schema validation & serialization
  • Server core: Python, stateless-first request handling (serve_dual_era_loop)
  • Testing: Phase 5 compatibility suite + Phase 6 benchmark run

🚀 Getting Started

git clone https://github.com/HoorShumail/MCPResilience.git
cd MCPResilience
pip install -r requirements.txt

Adjust the commands above to match your actual package layout and entry point.

Run the compatibility suite and benchmarks with:

pytest

⚠️ Honest Limitations

  • The Tasks extension is still experimental upstream. It isn't finalized in the core MCP spec, so its wire format could shift again in a future SDK release — this server tracks the SDK's current experimental implementation, not a stable target.
  • The execution-field fix is a monkeypatch, not a permanent solution. It patches serialize_server_result at runtime rather than fixing the underlying schema — it needs to be removed once SDK Issue #2156 ships an upstream fix.
  • Era detection is first-request-only. A client locked into the legacy era at connection start has no path to "upgrade" to the stateless era mid-connection, even if its later requests look modern.

🙏 Acknowledgments

  • Official MCP SDK v2 — Model Context Protocol maintainers
  • Model Context Protocol specification (2026-07-28)

🧑‍💻 Author

Hoor Shumail AI | Machine Learning | Agentic AI | Multi-Agent Systems | Career Intelligence

📜 License

This project is developed for educational, research, and portfolio purposes.

It builds upon the official Model Context Protocol SDK — refer to that SDK's own license and the Model Context Protocol specification for terms governing those components.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured