Skip to main content
Glama

🛡️ 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.


Related MCP server: mcp-uni

🧠 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 initializenotifications/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.

F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    A dual-protocol MCP server that supports both modern Streamable HTTP and legacy HTTP+SSE protocols, providing backward compatibility for clients while offering advanced features like session resumability.
  • A
    license
    Not graded
    quality
    C
    maintenance
    A universal MCP server that acts as a unified gateway for dynamically connecting and managing multiple MCP servers via a single HTTP endpoint.
    10
    6
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server that enables agents to dynamically switch between multiple AI models (OpenAI, Anthropic, Google, etc.) with unified protocol-driven configuration and capability discovery.
    Apache 2.0

View all related MCP servers

Related MCP Connectors

  • Manage feature requests, votes, roadmaps, and changelogs from any MCP client.

  • Official MCP server for Qase — manage test cases, runs, suites, defects via AI tools.

  • Official remote MCP server for Archivist AI TTRPG campaign memory: characters, sessions, and more.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/HoorShumail/MCPResilience'

If you have feedback or need assistance with the MCP directory API, please join our Discord server