← Все статьи

Руководство по миграции на stateless-протокол MCP: что меняет релиз-кандидат 2026-07-28 для каждого AI-шлюза

Спецификация MCP 2026-07-28 удаляет session ID и initialize-рукопожатие. Пошаговое руководство по миграции: сравнение кода до и после, настройка балансировщика нагрузки, обновление SDK, паттерн явных хендлов и путь отката.

· TheRouter

Руководство по миграции на stateless-протокол MCP: что меняет релиз-кандидат 2026-07-28

Спецификация MCP 2026-07-28 удаляет session ID и initialize-рукопожатие. Если вы управляете MCP-сервером, прокси или шлюзом — каждый запрос теперь самодостаточен и может быть обработан любым экземпляром сервера. Это руководство проведёт вас через миграцию шаг за шагом: сравнение кода до/после, изменения инфраструктуры, обновление SDK и путь отката — чтобы вы были готовы к финальной дате спецификации 28 июля.

Мы написали это руководство, потому что stateless-изменение MCP напрямую влияет на маршрутизацию AI-трафика через шлюзы. TheRouter маршрутизирует OpenAI-совместимые запросы через настроенных провайдеров, и когда операторы шлюзов меняют обработку MCP-трафика, политики routing и fallback должны следовать за ними. Источник: MCP 2026-07-28 Release Candidate, получено 2026-07-20.

Что изменилось: до и после

Ключевое изменение в MCP 2026-07-28 — удаление двух функций протокола, которые требовали stateful-развёртывания:

  1. Рукопожатие initialize/initialized (удалено SEP-2575). Версия протокола, информация о клиенте и capabilities теперь передаются в _meta каждого запроса. Новый метод server/discover заменяет обмен capabilities.
  2. Header Mcp-Session-Id и протокольные сессии (удалены SEP-2567). Больше нет session pinning, нет необходимости в shared session store.

До (2025-11-25): Клиент обязан сначала отправить initialize-запрос, получить session ID и включать Mcp-Session-Id header в каждый последующий вызов:

// Шаг 1: Initialize-рукопожатие
POST /mcp
{"jsonrpc":"2.0","id":1,"method":"initialize",
 "params":{"protocolVersion":"2025-11-25","capabilities":{},
 "clientInfo":{"name":"my-app","version":"1.0"}}}

// Сервер возвращает Mcp-Session-Id: 1868a90c-3a3f-4f5b

// Шаг 2: Каждый последующий вызов несёт session header
POST /mcp
Mcp-Session-Id: 1868a90c-3a3f-4f5b
{"jsonrpc":"2.0","id":2,"method":"tools/call",
 "params":{"name":"search","arguments":{"q":"otters"}}}

После (2026-07-28): Один самодостаточный запрос, который может обработать любой экземпляр:

POST /mcp
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search
Content-Type: application/json

{"jsonrpc":"2.0","id":1,"method":"tools/call",
 "params":{"name":"search","arguments":{"q":"otters"},
 "_meta":{"io.modelcontextprotocol/clientInfo":{"name":"my-app","version":"1.0"}}}}

Нет рукопожатия, нет session ID, ничто не привязывает к конкретному экземпляру. Источник: MCP 2026-07-28 Release Candidate, получено 2026-07-20.

Чек-лист миграции: инфраструктура

  1. Меняйте три значения, а не три SDK. Замените api_key, base_url и model в существующем клиенте OpenAI. Код запроса и ответа оставьте неизменным.
  2. Сопоставьте model ID явно. ID модели у целевого провайдера почти никогда не совпадает с OpenAI ID. Держите словарь { openai_id: target_id } вне бизнес-логики.
  3. Проверьте формат streaming. SSE-чанки должны соответствовать контракту OpenAI: data: {...} + data: [DONE]. Прогоните один streaming вызов до продакшена.
  4. Проверьте rate-limit заголовки. Некоторые провайдеры не возвращают x-ratelimit-*. Добавьте обёртку с безопасным дефолтом.
  5. Оставьте путь отката. Раскатайте замену под feature flag, гоняйте оба endpoint в shadow-режиме 24 часа, затем переключайтесь.

Шаг 1: Отключите sticky sessions и session affinity

Если ваш балансировщик нагрузки (NGINX, HAProxy, AWS ALB, Azure App Service ARR) использует sticky routing на основе Mcp-Session-Id или cookie affinity для MCP-эндпоинтов — отключите это. Протокол теперь stateless, любой экземпляр сервера может обработать любой запрос.

NGINX до:

upstream mcp_backend {
    ip_hash;  # или sticky cookie
    server mcp1:8080;
    server mcp2:8080;
}

NGINX после:

upstream mcp_backend {
    # Round-robin, sticky sessions не нужны
    server mcp1:8080;
    server mcp2:8080;
}

Azure App Service: Установите clientAffinityEnabled: false в ARM-шаблоне или конфигурации App Service. Источник: Microsoft Tech Community — MCP Stateless on App Service, получено 2026-07-20.

Шаг 2: Настройте routing по Mcp-Method headers

Streamable HTTP transport теперь требует header Mcp-Method для каждого запроса и Mcp-Name для вызовов инструментов, чтения ресурсов и запроса prompts (SEP-2243). Это позволяет вашему шлюзу маршрутизировать, ограничивать частоту запросов или логировать MCP-трафик без разбора JSON-RPC body.

Пример NGINX — routing по Mcp-Method:

location /mcp {
    # Отдельные лимиты для tools/call и tools/list
    if ($http_mcp_method = "tools/call") {
        set $rate_zone tool_calls;
    }
    if ($http_mcp_method = "tools/list") {
        set $rate_zone tool_lists;
    }
    proxy_pass http://mcp_backend;
}

Серверы отклоняют запросы, в которых headers и body не совпадают. Убедитесь, что ваш reverse proxy сохраняет headers Mcp-Method и Mcp-Name при проксировании.

Шаг 3: Выведите из эксплуатации shared session store

Если вы использовали Redis, Memcached или базу данных для разделения маппингов Mcp-Session-Id → состояние между экземплярами MCP-серверов — эта инфраструктура больше не нужна для состояния протокола. Вы можете вывести её из эксплуатации или перепрофилировать для состояния приложения (см. паттерн явных хендлов ниже). Источник: 4sysops — MCP 2026-07-28 Overview, получено 2026-07-20.

Шаг 4: Включите кеширование ответов

Результаты списков и чтения ресурсов теперь содержат поля ttlMs и cacheScope (SEP-2549), по аналогии с HTTP Cache-Control. Ваш шлюз может кешировать ответы tools/list на время, указанное в ttlMs, а cacheScope сообщает, можно ли разделять ответ между пользователями ("global") или только для одного пользователя.

Это устраняет необходимость держать SSE-поток открытым только для отслеживания изменений списка инструментов.

Чек-лист миграции: SDK и серверный код

Шаг 5: Обновите MCP SDK

Beta-версии всех четырёх SDK Tier 1 доступны сейчас. Источник: Beta SDKs for the 2026-07-28 MCP Spec Release Candidate, получено 2026-07-20.

SDKBeta-версияКоманда установки
Pythonv2.0.0b1uv add "mcp[cli]==2.0.0b1" или pip install "mcp[cli]==2.0.0b1"
TypeScriptv2 betanpm install @modelcontextprotocol/server@beta
Gov1.7.0-pre.1Pre-release тег на существующем модуле
C#2.0.0-preview.1Установите preview-пакет ModelContextProtocol

Важно для авторов библиотек: Если вы публикуете библиотеку, зависящую от Python-пакета mcp, добавьте верхнюю границу сейчас (например, mcp>=1.27,<2), чтобы релиз v2 не застал ваших пользователей врасплох.

Шаг 6: Удалите код initialize-рукопожатия

Если ваш сервер реализует собственный обработчик initialize — его можно удалить. В новой модели:

  • Информация о клиенте приходит из _meta.io.modelcontextprotocol/clientInfo в каждом запросе
  • Версия протокола приходит из HTTP-header MCP-Protocol-Version
  • Capabilities сервера предоставляются через новый метод server/discover вместо ответа на initialize

Python v1 (до):

@app.handle("initialize")
async def handle_initialize(params):
    return {"protocolVersion": "2025-11-25",
            "capabilities": {"tools": {}},
            "serverInfo": {"name": "my-server", "version": "1.0"}}

Python v2 (после):

from mcp.server import MCPServer

mcp = MCPServer("my-server")

@mcp.tool()
def search(q: str) -> str:
    """Поиск."""
    return f"Results for {q}"
# server/discover обрабатывается SDK автоматически

Шаг 7: Используйте паттерн явных хендлов для stateful-инструментов

Удаление протокольной сессии не означает, что ваше приложение не может хранить состояние. Если инструментам нужно сохранять состояние между вызовами — создайте явный хендл и пусть модель передаёт его как аргумент:

@mcp.tool()
def create_session(config: dict) -> dict:
    """Создать рабочую сессию и вернуть хендл."""
    session_id = store.create(config)  # сохранить в Redis/БД
    return {"session_id": session_id}

@mcp.tool()
def continue_work(session_id: str, action: str) -> dict:
    """Продолжить работу в существующей сессии."""
    state = store.get(session_id)  # получить из shared store
    result = process(state, action)
    store.update(session_id, state)
    return result

Этот паттерн мощнее скрытого session state: модель видит хендл, может комбинировать его между инструментами, рассуждать о нём и передавать между шагами. Источник: MCP 2026-07-28 Release Candidate — Stateless Protocol, Stateful Applications, получено 2026-07-20.

Шаг 8: Обновите обработку кодов ошибок

Код ошибки для отсутствующего ресурса меняется с кастомного MCP -32002 на стандартный JSON-RPC -32602 (Invalid Params) согласно SEP-2164. Обновите весь клиентский код, который проверяет литеральное значение -32002.

- if error.code == -32002:
-     handle_resource_not_found()
+ if error.code == -32602:
+     handle_resource_not_found()

Шаг 9: Обработайте устаревшие функции

В этом релизе три функции помечены как deprecated (SEP-2577):

ФункцияЗаменаСрочность
RootsПараметры инструментов, URI ресурсов или конфигурация сервераНизкая — работает 12+ месяцев
SamplingПрямая интеграция с API LLM-провайдеровНизкая — работает 12+ месяцев
Loggingstderr для stdio transport; OpenTelemetry для структурированной observabilityНизкая — работает 12+ месяцев

Это аннотационные deprecation. Методы, типы и capability flags продолжают работать в этом релизе и во всех версиях спецификации, опубликованных в течение года. Но планируйте миграцию уже сейчас.

Запросы от сервера к клиенту: Multi Round-Trip Requests (MRTR)

Если ваш сервер отправляет запросы клиенту во время вызова инструмента (например, диалоги подтверждения через elicitation), механизм изменился. Вместо удержания SSE-потока сервер теперь возвращает InputRequiredResult:

{
  "resultType": "inputRequired",
  "inputRequests": {
    "confirm": {
      "type": "elicitation",
      "message": "Удалить 3 файла?",
      "schema": {"type": "boolean"}
    }
  },
  "requestState": "eyJzdGVwIjox..."
}

Клиент собирает ответы и повторно отправляет исходный вызов с inputResponses и переданным requestState. Любой экземпляр сервера может обработать повторный запрос, потому что всё необходимое содержится в payload. Источник: MCP 2026-07-28 Release Candidate — Multi Round-Trip Requests, получено 2026-07-20.

Путь отката

28 июля ничего не сломается принудительно. Новые SDK поддерживают обратную совместимость:

  • Новые клиенты и старые серверы: Клиенты с протоколом 2026-07-28 автоматически возвращаются к initialize-рукопожатию при подключении к серверам версии 2025-11-25 и старше.
  • Новые серверы и старые клиенты: Python v2 серверы отвечают как на устаревшее initialize-рукопожатие, так и на server/discover, поэтому существующие клиенты продолжают подключаться.
  • Смешанное развёртывание: Во время перехода можно одновременно запускать экземпляры серверов 2025-11-25 и 2026-07-28. Старые экземпляры сохраняют session affinity, новые — stateless.

Если миграция столкнётся с проблемами — откатите SDK на v1 и снова включите sticky sessions. Старый протокол продолжает работать.

Изменение стоимости

Stateless-протокол снижает инфраструктурные затраты тремя способами:

  1. Нет shared session store. Больше не нужен Redis или Memcached для хранения состояния протокольных сессий между экземплярами.
  2. Проще балансировка нагрузки. Round-robin вместо sticky sessions — не нужны балансировщики с поддержкой affinity или сложные health checks.
  3. Кеширование ответов. ttlMs и cacheScope в результатах списков позволяют шлюзам кешировать ответы tools/list, сокращая избыточные вызовы.

Компромисс: если ваши инструменты имеют сложные stateful-workflow, теперь вы управляете состоянием явно (Redis, БД и т.д.) вместо того, чтобы полагаться на протокол. Но это состояние всегда лучше было выносить наружу — протокольная сессия была удобством, а не решением.

Интеграция с TheRouter

TheRouter маршрутизирует OpenAI-совместимые запросы через настроенных провайдеров и поддерживает routing и fallback провайдеров/моделей, когда продуктовые пути поддерживают это. Stateless-изменение MCP влияет на то, как операторы шлюзов проксируют MCP-трафик наряду со стандартными вызовами LLM API:

  • Routing на основе headers. Headers Mcp-Method и Mcp-Name позволяют маршрутизировать MCP и LLM API трафик через один шлюз с разными правилами rate limiting и routing.
  • Единый fallback. Если MCP-сервер недоступен — применяются те же паттерны fallback routing, что и для LLM API провайдеров. См. наше руководство по LLM API Fallback Routing.
  • Согласованная миграция. Если вы мигрируете с OpenAI на TheRouter — stateless-изменение MCP упрощает шлюзовый слой. См. наше руководство по миграции с OpenAI на TheRouter.

Таймлайн и следующие шаги

ДатаСобытие
21 мая 2026Release candidate заморожен
Сейчас (июль 2026)Beta-версии SDK доступны для всех четырёх Tier 1 SDK
28 июля 2026Публикация финальной спецификации
~Январь 2027Устаревшие функции (Roots, Sampling, Logging) — самое раннее возможное удаление

Пункты действий:

  1. Протестируйте beta SDK на ваших рабочих нагрузках сейчас.
  2. Проведите аудит конфигурации балансировщика нагрузки и шлюза на предмет session affinity.
  3. Проверьте весь код, зависящий от Mcp-Session-Id, initialize или кода ошибки -32002.
  4. Спланируйте миграцию stateful-инструментов на паттерн явных хендлов.
  5. Обновите мониторинг для отслеживания нового header Mcp-Method в целях observability.

Источники

Помощь и контакты