Skip to main content
Glama

🛡️ MCPResilience

Устойчивый, соответствующий спецификации MCP-сервер на официальном SDK v2

Говорите на MCP так, как говорит ваш клиент. MCPResilience автоматически определяет эпохи протокола — легаси и современную — уже по первому запросу и переживает разницу.

MCP Spec SDK Language License


🔌 Режимы клиентов

MCPResilience автоматически определяет, какую эпоху протокола использует подключающийся клиент — настройка не требуется:

  1. ⚡ Современные клиенты без состояния — клиенты, чей первый запрос несёт конверт _meta (io.modelcontextprotocol/protocolVersion + clientInfo), полностью пропускают рукопожатие. tools/call может быть их самым первым сообщением.

  2. 🤝 Клиенты с легаси-рукопожатием — клиенты без такого конверта направляются через традиционный поток initialize, с принудительным -32600 Invalid request parameters для всего, что отправлено до завершения initialize.

Полную разбивку обеих эпох см. в разделе Поддержка протокола.


Related MCP server: mcp-uni

🧠 Что это такое

MCPResilience существует потому, что замена самописного MCP-сервера на официальный SDK — не замена «на лету»: формат провода меняется так, что ломает наивные миграции. Этот проект решает задачу в два этапа:

  1. Миграция на SDK — замена самописного ядра MCP-сервера на официальный MCP SDK v2, нацеленный на спецификацию 2026-07-28, чтобы получить ядро без состояния и типобезопасную сериализацию Pydantic.

  2. Упрочнение совместимости — гарантия, что миграция не приведёт к молчаливой потере поддержки клиентов, всё ещё использующих легаси-рукопожатие, не потеряет данные из-за пробелов в вышестоящей схеме и не сломает экспериментальное расширение Tasks на полпути.

Оба этапа честно задокументированы ниже, включая один баг вышестоящего SDK, всплывший по ходу дела.


📊 Ключевые результаты

Все тесты совместимости фазы 5 и бенчмарки фазы 6 проходят — от начала до конца, на официальном MCP SDK v2 — с полной поддержкой обеих эпох протокола и экспериментального расширения Tasks, плюс один обнаруженный и пропатченный баг вышестоящего SDK (см. Известная особенность SDK).

Расширение Tasks: что изменилось при миграции на SDK

Аспект

Поведение легаси

Поведение SDK v2

Объявление поддержки задач

Булев флаг longRunning: true

Объект execution, например execution: {"taskSupport": "required"}

Расположение дескриптора задачи

Верхнеуровневый taskHandle в result

Перемещено в конверт метаданных: result._meta.taskHandle

Конечное состояние успеха

"succeeded"

"completed"

Доставка содержимого задачи

Через опрос tasks/get

Только через поток ответа tools/call — tasks/get возвращает только метаданные статуса (statusMessage, createdAt и т.д.)

Повторная отмена завершённой задачи

{cancelled: true} или ошибка -32602

Идемпотентно — возвращает CancelTaskResult со статусом "cancelled"


🏗️ Как это работает

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

📡 Поддержка протокола

Эпоха без состояния (2026-07-28)

Согласно современной спецификации, традиционное рукопожатие initialize → notifications/initialized устарело. Сервер запускает serve_dual_era_loop:

  • Если первый запрос включает конверт _meta с io.modelcontextprotocol/protocolVersion и io.modelcontextprotocol/clientInfo, сервер фиксируется в современной эпохе без состояния.

  • Клиенты могут отправлять tools/call самым первым запросом — вызов initialize не требуется.

Эпоха легаси

Если первый запрос не содержит современного конверта _meta, сервер фиксируется в эпохе легаси:

  • Любой запрос, отправленный до initialize (например, tools/call), отклоняется с -32600 Invalid request parameters.

  • После ответа на initialize сервер не ждёт notifications/initialized перед обработкой дальнейших запросов.

Обработка несоответствия версий

Современные запросы, указывающие неподдерживаемую версию протокола в конверте _meta, аккуратно отклоняются с -32022 Unsupported protocol version — само соединение сохраняется, а не разрывается.


🧩 Глубокое погружение в расширение Tasks

Экспериментальное расширение Tasks претерпело наибольшие изменения формата провода из всего, что было в миграции (см. сравнительную таблицу в Ключевых результатах). Стоит особо выделить два поведения:

  • tasks/get теперь только метаданные. Содержимое задач доставляется исключительно через поток ответа tools/call; опрос tasks/get будет возвращать только поля статуса, такие как statusMessage и createdAt, — но никогда сам полезный груз.

  • Отмена идемпотентна по замыслу. Повторная отмена задачи, которая уже completed или cancelled, возвращает успешный CancelTaskResult, а не ошибку, в отличие от легаси-сервера с -32602 при повторной отмене.

Известная особенность SDK

Проблема SDK #2156 — поле execution удаляется из tools/list. Текущая схема Pydantic для v2026_07_28.Tool не определяет экспериментальное поле execution, поэтому serialize_server_result молча удаляет его из ответов tools/list.

Обходной путь: точечный monkeypatch на mcp_types.methods.serialize_server_result перехватывает проверенный вывод и восстанавливает словарь execution из исходных данных обработчика. Это временное решение — удалите его, как только вышестоящая схема нативно включит это поле.


🔧 Технические заметки (то, что было нетривиальным)

  1. Определение эпохи происходит ровно один раз, по первому запросу. Пути обновления на середине соединения нет — клиент, открывший соединение без конверта _meta, остаётся в эпохе легаси на всё время этого соединения, даже если позже начнёт отправлять запросы современного вида.

  2. Дескриптор задачи не просто переехал — изменился его контракт. Перенос taskHandle из верхнеуровневого result в result._meta также освободил верхнеуровневый объект result для того, чтобы он был зарезервирован исключительно под немедленный вывод содержимого и флаг isError — более чистое разделение, чем допускала форма легаси.

  3. Monkeypatch намеренно узко ограничен. Он перехватывает только serialize_server_result, чтобы восстановить одно недостающее поле, а не форкает и не оборачивает схему SDK целиком — это упрощает удаление патча, как только вышестоящий SDK выпустит исправление.


🛠️ Технологический стек

  • Протокол: JSON-RPC 2.0 поверх Model Context Protocol, спецификация 2026-07-28

  • SDK: Официальный MCP SDK v2 — проверка схемы и сериализация на основе Pydantic

  • Ядро сервера: Python, обработка запросов без состояния (serve_dual_era_loop)

  • Тестирование: набор совместимости фазы 5 + прогон бенчмарков фазы 6


🚀 Начало работы

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

Подгоните команды выше под фактическую структуру вашего пакета и точку входа.

Запустите набор совместимости и бенчмарки с помощью:

pytest

⚠️ Честные ограничения

  • Расширение Tasks всё ещё экспериментально в вышестоящем проекте. Оно не финализировано в основной спецификации MCP, поэтому его формат провода может снова измениться в будущих версиях SDK — этот сервер отслеживает текущую экспериментальную реализацию SDK, а не стабильную цель.

  • Исправление поля execution — это monkeypatch, а не постоянное решение. Он патчит serialize_server_result во время выполнения, а не исправляет базовую схему — его нужно удалить, как только проблема SDK #2156 получит вышестоящее исправление.

  • Определение эпохи — только по первому запросу. Клиент, зафиксированный в эпохе легаси при старте соединения, не имеет пути «обновления» до эпохи без состояния на середине соединения, даже если его последующие запросы выглядят современно.


🙏 Благодарности

  • Официальный MCP SDK v2 — сопровождающие Model Context Protocol

  • Спецификация Model Context Protocol (2026-07-28)

🧑💻 Автор

Hoor Shumail AI | Машинное обучение | Агентный ИИ | Мультиагентные системы | Карьерный интеллект

📜 Лицензия

Этот проект разработан в образовательных, исследовательских и портфолио-целях.

Он построен на основе официального Model Context Protocol SDK — для условий, регулирующих эти компоненты, обратитесь к собственной лицензии этого SDK и спецификации Model Context Protocol.

Related MCP Connectors

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.
    4 npm
    6
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables multiple MCP clients to securely access various third-party MCP backends through a single HTTP gateway, with modern MCP handshake compatibility and session lifecycle management.
    39 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP clients to connect over HTTP/SSE, call simple echo, arithmetic, uppercasing, and time tools, and run asynchronous tasks with approval elicitations via the Tasks extension.
    8 npm
    MIT