Аннотация

28 июля 2026 года Model Context Protocol получил ревизию 2026-07-28 — крупнейшее изменение спецификации с момента запуска. Протокол перестал быть stateful: исчезли обмен initialize/initialized и заголовок Mcp-Session-Id, а server-to-client запросы (elicitation, sampling, roots) переехали в схему Multi Round-Trip Requests12. Для того, кто держит MCP-сервер сам, это меняет не набор инструментов, а операционную модель: вместо sticky sessions, общего хранилища сессий и разбора JSON-тела на шлюзе остаётся обычная HTTP-нагрузка, которую можно поставить за round-robin балансировщик23.

Разбор собран по первичным документам: тексту спецификации и её changelog, SEP-предложениям, документации SDK и release notes, — плюс независимые разборы от вендоров шлюзов, платформы, security-компании и практический гайд по миграции. Данные на 2026-10-19. Независимых замеров latency и throughput до и после миграции в открытом доступе нет, поэтому все числа ниже взяты из спецификации и документации, а не из бенчмарков.

Введение

Актуальность. MCP перестал быть протоколом для локального stdio-процесса: по данным авторов спецификации, суммарные загрузки Tier 1 SDK приближаются к половине миллиарда в месяц, а TypeScript- и Python-SDK перешли порог в миллиард скачиваний1. На такой нагрузке транспортная модель начинает значить больше, чем удобство API.

Спецификация делит протокол на базовый уровень, версионирование, паттерны сообщений, авторизацию, серверные и клиентские возможности и утилиты, причём базовый протокол, версионирование и паттерны обязаны поддерживать все реализации4. Ревизия меняет именно этот слой, а не набор функций.

Цель — разобрать механику ревизии 2026-07-28 и ответить на практический вопрос: что конкретно нужно поменять в self-hosted MCP-сервере и в инфраструктуре перед ним, а что можно не трогать. Границы: расширения MCP Apps и Skills over MCP упоминаются только как контекст, производительность не измеряется, а сравнение с альтернативными протоколами (A2A, AT Protocol) выходит за рамки текста.

Как сессия мешала масштабированию

В ревизии 2025-11-25 вызов инструмента по Streamable HTTP начинался с handshake: клиент отправлял initialize, сервер заводил сессию и возвращал Mcp-Session-Id, который все последующие запросы обязаны были повторять2. Формально это выглядело как мелочь, но именно идентификатор привязывал клиента к тому инстансу, который сессию создал25.

Авторы предложения SEP-1442 «Make MCP Stateless (by default)» описали последствия прямым текстом: «A simple stateless load balancer (e.g. L4/L7 round-robin) cannot be used, as it would route a client’s requests to different backend servers, none of which would have the correct session state»3. Дальше по цепочке идут три издержки, знакомые любому, кто выводил stateful-сервис в прод: sticky sessions на балансировщике, общий store сессий с сетевой задержкой на каждый запрос и потеря всей сессии при рестарте одного инстанса35.

Impediment to Scalability: The most critical issue is the difficulty of load balancing stateful MCP.3

Показательна и форма: SEP-1442 подписан пятью авторами — Jonathan Hefner, Mark Roth, Shaun Smith, Harvey Tuch и Kurtis Van Gent3. Это не жалоба одного пользователя, а согласованная позиция, и касается она транспортной модели, а не удобства API.

Stateless-ядро: что убрали и что поставили на место

Ревизия удаляет initialize/initialized (SEP-2575) и заголовок Mcp-Session-Id вместе с самим понятием протокольной сессии (SEP-2567)62. Взамен каждый запрос обязан быть самоописывающим: в _meta должны присутствовать io.modelcontextprotocol/protocolVersion и io.modelcontextprotocol/clientCapabilities, а клиент «SHOULD» присылать io.modelcontextprotocol/clientInfo7. Запрос без обязательных полей считается некорректным: сервер обязан ответить JSON-RPC ошибкой -32602 и HTTP 400 Bad Request7.

Спецификация формулирует принцип жёстко: сервер не должен выводить контекст из предыдущих запросов на том же соединении, а состояние, живущее дольше одного запроса, обязано передаваться явным идентификатором7.

Servers MUST NOT rely on prior requests over the same connection to establish context (e.g., capabilities, protocol version, client identity). Every request supplies this metadata in its _meta field.7

Вместо handshake появился RPC server/discover, который серверы обязаны реализовать: он возвращает supportedVersions, capabilities, serverInfo и опциональные instructions8. Вызывать его клиенту не обязательно — можно сразу отправить любой запрос и обработать ошибку версии, — но он удобен в двух случаях: показать пользователю возможности сервера одним запросом и детектировать эру сервера на stdio, где нет HTTP-статусов для fallback89.

Согласование версии стало пошаговым, а не сессионным: если сервер не поддерживает запрошенную версию, он возвращает UnsupportedProtocolVersionError (-32022) со списком поддерживаемых, а клиент выбирает общую версию и повторяет запрос9. Матрица совместимости в спецификации перечисляет шесть комбинаций «modern/legacy/dual-era» клиента и сервера; ключевой практический вывод — legacy-клиент против modern-сервера не работает и не имеет механизма «fall-forward», поэтому modern-серверу рекомендуется перечислять поддерживаемые версии в тексте ошибки на initialize9.

Для оператора это означает ровно то, ради чего всё затевалось: рестарт инстанса больше не убивает диалог, а запросы можно раскладывать round-robin без общего хранилища210. Важная оговорка: stateless только протокол, а не приложение. Авторы спецификации предлагают явные handle’ы — инструмент возвращает basket_id, модель передаёт его аргументом в следующий вызов, — и считают такой вариант не компромиссом, а улучшением: «The model can compose handles across tools, reason about them, and hand them off between steps»2.

MRTR: server-to-client запросы без открытого потока

До ревизии сервер, которому нужно было спросить пользователя о подтверждении, отправлял elicitation/create, sampling/createMessage или roots/list по удерживаемому SSE-потоку111. В stateless-мире удерживать поток негде, поэтому введён паттерн Multi Round-Trip Requests (SEP-2322): сервер отвечает результатом с resultType: "input_required", внутри которого лежат inputRequests (карта запросов с серверными ключами) и опциональный requestState, а клиент повторяет исходный вызов, добавляя inputResponses и тот же requestState11.

Правила узкие и их стоит знать наизусть. Отправлять InputRequiredResult разрешено только на prompts/get, resources/read и tools/call; на любые другие запросы — запрещено11. В ответе обязан быть хотя бы один из inputRequests или requestState, а запросы внутри inputRequests не должны требовать возможностей, которые клиент не объявил11. Если серверу нужна возможность, отсутствующая в clientCapabilities, он возвращает MissingRequiredClientCapabilityError (-32021) с перечнем недостающего и HTTP 4007.

Самое интересное — requestState. Это непрозрачная строка, которую клиент возвращает как есть, и спецификация прямо предупреждает, что сервер обязан считать её подконтрольной атакующему: при влиянии на авторизацию или доступ к ресурсам её целостность нужно защищать (HMAC или AEAD) и отклонять при провале проверки11. Рекомендуемый набор полей внутри — аутентифицированный principal, короткий TTL и идентификатор исходного запроса с дайджестом параметров; при этом отдельно оговорено, что эти меры не дают гарантии однократности, и сервер, которому нужно «ровно один раз», должен обеспечивать это сам11.

Побочный, но полезный эффект — SEP-2260: server-to-client запросы теперь разрешены только пока сервер обрабатывает активный клиентский запрос2. Пользователя больше не могут спросить «из ниоткуда», и каждая elicitation трассируется к действию, которое он или его агент инициировали2.

Цена схемы — дополнительные round-trip’ы. Каждый вопрос пользователю — это новый HTTP-запрос с полным _meta, а не сообщение в уже открытом канале. Для интерактивных подтверждений это нормально, для сценариев с десятком уточнений — заметно; и именно поэтому результаты, полученные повторным запросом с inputResponses или requestState, запрещено кэшировать12.

Транспорт: три заголовка и их цена

Streamable HTTP в этой ревизии требует MCP-Protocol-Version на каждом POST, причём значение обязано совпадать с io.modelcontextprotocol/protocolVersion в теле: расхождение — 400 и ошибка HeaderMismatch (-32020)13. Дополнительно обязательны Mcp-Method (все запросы) и Mcp-Name (tools/call, resources/read, prompts/get)1314.

Смысл прост: промежуточный слой — балансировщик, rate limiter, WAF — может принимать решения по заголовкам, не разбирая JSON-RPC тело115. Tigera перечисляет, что это открывает: per-tool rate limiting для дорогих инструментов, маршрутизация resources/read на read-оптимизированные реплики, дешёвые ранние отказы и видимость операций MCP в существующих access-логах15.

Второй, куда менее очевидный механизм — x-mcp-header. Сервер может пометить примитивный параметр инструмента этим свойством в inputSchema, и конформный клиент обязан продублировать значение аргумента в заголовок Mcp-Param-{Name}13. Ограничения прописаны детально: только string, integer или boolean (тип number запрещён), целые в безопасном диапазоне JavaScript, параметр должен быть статически достижим только по цепочке properties, имя — валидный HTTP-токен, переводы строк запрещены, не-ASCII кодируется base6413. Клиент, встретивший нарушение, обязан исключить инструмент из результата tools/list13; Python SDK 2.3.0 сделал следующий шаг и падает при регистрации такого инструмента с InvalidSignature, называя инструмент и причину16.

Практический пример конфигурации шлюза, который маршрутизирует по операции, а не по телу (домены обезличены):

location /mcp {
    # маршрутизация по заголовку операции, без разбора JSON-RPC тела
    set $mcp_pool tools_backend;
    if ($http_mcp_method = "resources/read") { set $mcp_pool read_backend; }

    proxy_buffering off;         # иначе SSE-события залипают в буфере nginx
    proxy_read_timeout 3600s;    # для долгих subscriptions/listen
    proxy_pass http://$mcp_pool;
}

Оговорка, которую легко пропустить: отключить буферизацию должен сам сервер, отдавая в SSE-ответе заголовок X-Accel-Buffering: no; без этого nginx накапливает события и ломает их доставку13.

Почему «любой балансировщик» — не вся правда

Заголовки действительно дают дешёвую маршрутизацию, но из этого не следует, что политику безопасности можно строить только на них. Кристиан Поста из agentgateway приводит конкретный сценарий: шлюз разрешает агенту единственный «безопасный» инструмент echo по allowlist заголовков, а тот же сервер экспонирует printEnv. Запрос с Mcp-Name: echo и телом tools/call для printEnv пройдёт header-only прокси и выполнится на бэкенде17.

The proxy sees Mcp-Name: echo, decides “echo is safe,” and forwards. The header said echo. The body ran printEnv and dumped its environment variables, secrets and all.17

Спецификация этот класс атак закрывает: сервер, обрабатывающий тело, обязан сверить заголовки с телом и вернуть HeaderMismatch14. Но полагаться на то, что «сервер за моей спиной проверит инвариант, на котором построено моё решение», — ровно та ошибка, из которой рождаются CVE17. Tigera формулирует компромисс аккуратно: заголовок — это заявление, которое сервер в итоге проверит, а тело остаётся истиной; быстрый отказ по заголовку безопасен, а разрешение чувствительной операции требует разбора тела15.

Второе ограничение header-only подхода — каталог инструментов. tools/list — это тело ответа, и прокси, не читающий тело, не может отфильтровать недоступные инструменты: пользователь с правами на 2 инструмента из 100 увидит все 100, а модель будет раз за разом вызывать запрещённые17. Отсюда практическое правило: заголовки — для маршрутизации, метрик и ранних отказов; авторизация по инструменту — на уровне, который видит аргументы и identity.

Кэширование каталога и стабильность префикса промпта

Результаты server/discover, tools/list, prompts/list, resources/list, resources/templates/list и resources/read обязаны нести ttlMs и cacheScope (SEP-2549)121. ttlMs — подсказка свежести в миллисекундах, по семантике близкая к Cache-Control: max-age; 0 означает «сразу устарело», отсутствие поля клиент трактует как 0, отрицательное значение игнорируется12. cacheScope принимает public или private: первое разрешает кэшировать любому посреднику, второе — только в пределах контекста авторизации, и общий кэш между разными токенами запрещён12.

Ключ кэша — метод плюс влияющие на результат параметры (например, uri для resources/read или cursor для страницы списка); ответы на повтор запроса с inputResponses/requestState кэшировать нельзя12. Уведомления и TTL дополняют друг друга: listChanged работает как немедленная инвалидация, TTL — как способ не дёргать сервер между изменениями12.

Для self-hosted сервера тут два практических следствия. Первое — экономия: каталог инструментов меняется редко, а агент запрашивает его постоянно, и без кэша каждый цикл платит лишний round-trip и лишние токены15. Второе — риск: описание инструмента и его JSON Schema напрямую влияют на то, какой инструмент выберет модель, поэтому «отравленная» запись живёт ровно ttlMs и делится ровно настолько, насколько разрешает cacheScope18. Этот риск обычно недооценивают: сервер, ставящий ttlMs: 3600000 и cacheScope: public на персонализированный список, сам создаёт инцидент.

Отдельно спецификация просит детерминированный порядок инструментов в tools/list — это стабилизирует префикс промпта и повышает попадания в upstream prompt cache612.

Подписки, ретраи и отсутствие resumability

Долгоживущие уведомления переехали в subscriptions/listen: клиент открывает один запрос с фильтром (toolsListChanged, promptsListChanged, resourcesListChanged, resourceSubscriptions), сервер первым сообщением присылает notifications/subscriptions/acknowledged с фактически принятым набором, а все последующие уведомления несут io.modelcontextprotocol/subscriptionId, равный JSON-RPC id этого запроса19. Это заменяет и HTTP GET-эндпоинт, и resources/subscribe, и roots/list_changed619.

Цена — потеря возобновляемости. Last-Event-ID и SSE event id удалены: оборванный поток теряет запрос, и клиент обязан переотправить его как новый, с новым id613. В core-протоколе нет ключа идемпотентности, поэтому вопрос «задублирует ли ретрай платёж, деплой или удаление» целиком зависит от того, написан ли инструмент так, чтобы это заметить18. Для self-hosted это прямое требование к дизайну инструментов: идемпотентность через клиентский ключ в аргументах, а не надежда на транспорт.

Мелочи, которые ломают продакшн чаще, чем кажется: серверу рекомендуется периодически отправлять SSE-комментарий (:) как keep-alive на тихих подписках, а при реконнекте на stdio клиент обязан заново отправить subscriptions/listen, потому что состояние подписок между переподключениями не сохраняется19.

Tasks: длинные операции как расширение

Экспериментальные задачи вынесены из ядра в официальное расширение io.modelcontextprotocol/tasks (SEP-2663): блокирующий tasks/result заменён на polling через tasks/get, добавлен tasks/update для ввода от клиента, tasks/list удалён, а сервер может вернуть задачу без отдельного opt-in на каждый запрос620.

Механика: сервер возвращает CreateTaskResult с resultType: "task", taskId, начальным статусом, TTL и рекомендованным интервалом опроса; задача создаётся durably до отправки ответа; клиент опрашивает tasks/get, а в состоянии input_required получает inputRequests и отвечает через tasks/update; статусы — working, input_required, completed, failed, cancelled20. Мотивация в документации сформулирована без маркетинга: удерживать соединение до конца операции мешают таймауты посредников, а task id переживает рестарт клиента20.

Для оператора это означает, что «долгая работа» больше не требует ни открытого потока, ни отдельного хранилища сессий — но требует настоящего хранилища задач с TTL и идемпотентным созданием.

Авторизация: iss, CIMD и привязка к issuer

Авторизация в MCP по-прежнему опциональна и строится на OAuth 2.1; сервер обязан реализовать Protected Resource Metadata (RFC 9728), а клиент — использовать её для поиска authorization server21. Ревизия добавила три вещи, важные именно для самостоятельного хостинга.

Первое — обязательная проверка iss по RFC 9207: authorization server должен возвращать параметр iss, а клиент обязан сверить его с запомненным issuer до обмена кода121. Это закрывает класс mix-up атак, описанный в RFC 9207: без iss клиент, работающий с несколькими authorization server’ами, не может понять, кто именно выпустил ответ22.

The iss parameter serves as an effective countermeasure to “mix-up attacks”.22

Второе — смена модели регистрации клиентов: Dynamic Client Registration формально депрецирован, вместо него предлагаются Client ID Metadata Documents (CIMD)2324. DCR продолжает работать для обратной совместимости, но помечен как подлежащий удалению в будущей ревизии1. Практический побочный эффект, знакомый всем, кто писал CLI-клиент: при DCR нужно указывать application_type, иначе authorization server отклоняет localhost-redirect’ы для desktop и CLI приложений (SEP-837)124.

Третье — привязка учётных данных к issuer: клиент обязан хранить их с ключом по идентификатору authorization server, не переиспользовать с другим и регистрироваться заново при смене сервера (SEP-2352)16.

Отдельный класс риска, который ревизия не отменяет, описан в Security Best Practices: MCP proxy server со статическим client ID, динамической регистрацией клиентов и consent-cookie на стороне стороннего authorization server открывает classic confused deputy — код выдаётся без повторного согласия пользователя25. Stateless-топология такие прокси не запрещает, а иногда и поощряет.

Для self-hosted сборки это обычно означает: свой authorization server должен отдавать iss, а клиентская часть — уметь CIMD или хотя бы не ломаться на отсутствии DCR. Практический минимум для своей сборки: убедиться, что authorization server возвращает iss в authorization response, и что клиент сверяет его с записанным issuer; для самописных серверов это требует явной доработки.

Миграция: dual-era, SDK и операционный чек-лист

Спецификация допускает dual-era сервер: запрос с modern _meta обслуживается stateless, а initialize переключает на legacy-семантику, и оба режима могут работать на одном эндпоинте9. Это единственный способ не сломать старых клиентов, потому что legacy-клиент не умеет откатываться вперёд и увидит только ошибку9.

В SDK картина разная. TypeScript SDK v2 разложен на отдельные пакеты @modelcontextprotocol/client и @modelcontextprotocol/server; для переименований есть codemod npx @modelcontextprotocol/codemod@latest v1-to-v2 ., но adoption самой ревизии 2026-07-28 автоматизировать нельзя — документация прямо называет его архитектурным изменением (createMcpHandler, multi-round-trip, versionNegotiation)26. Cloudflare в Agents SDK v0.20.0 перевёл серверы на фабрику, создающую изолированный экземпляр на запрос, объявил McpAgent deprecated и feature-frozen и добавил isLegacyRequest() для постепенного перевода трафика27.

Python SDK 2.3.0 показывает, как выглядит зрелость на практике: невалидный x-mcp-header теперь падает при регистрации инструмента, клиент после HeaderMismatch (-32020) перезапрашивает tools/list и повторяет вызов один раз, появился лимит max_sse_event_size (по умолчанию 1 MiB на событие), а MCPServer(subscriptions=False) отключает subscriptions/listen и честно объявляет listChanged и subscribe выключенными16.

Операционный чек-лист, который следует из перечисленного:

  • Инстансы без памяти. Любой узел обслуживает любой запрос; in-process кэши и счётчики не должны быть привязаны к соединению7.
  • Состояние — в БД по handle. basket_id/job_id в аргументах инструмента, TTL и владелец в хранилище, а не в памяти процесса2.
  • Идемпотентность инструментов. Ключ идемпотентности в аргументах обязателен для платящих и разрушающих операций: транспорт ретраит без гарантий18.
  • Валидация на двух уровнях. Шлюз разбирает тело для чувствительных операций, сервер проверяет HeaderMismatch; метрика по -32020 — индикатор атак или багов клиента1417.
  • Кэш по правилам. ttlMs и cacheScope выставляются осознанно, персонализированные списки — только private12.
  • Наблюдаемость. traceparent/tracestate/baggage в _meta стандартизованы, так что трейс проходит от хоста через шлюз в сервер62.

Депрекации: что реально даёт двенадцать месяцев

Политика жизненного цикла (SEP-2596) впервые зафиксирована формально: депрецированная функция остаётся в спецификации, новые реализации не должны её внедрять, а самая ранняя точка удаления — первая ревизия, выпущенная не раньше чем через двенадцать месяцев231. В реестре сейчас шесть позиций: Roots, Sampling и Logging (миграция — параметры инструментов и OpenTelemetry вместо logging), DCR (миграция — CIMD), includeContext в sampling и транспорт HTTP+SSE (миграция — Streamable HTTP)23.

Здесь и возникает главное расхождение в трактовках. Блог и часть гайдов читают это как «у вас есть год на всё»15, а security-разбор Equixly — иначе: «The initialize handshake and Mcp-Session-Id are gone, not deprecated. Older clients keep working only if you run the old path alongside the new one»18. Обе формулировки верны, но говорят о разном: двенадцатимесячное окно относится к фичам в состоянии Deprecated, а handshake и сессия — не депрецированы, а удалены как breaking change, и совместимость обеспечивается исключительно dual-era реализацией923. Для планирования это принципиально: год есть у Roots/Sampling/Logging, а на stateless-путь нужно переходить сейчас, если вы хотите обслуживать клиентов 2026-07-28.

Дискуссионные вопросы и противоречия

Stateless ≠ проще. Официальная позиция: сессии убраны, и это снимает sticky routing и общий store12. Критическая: состояние не исчезло, оно переехало в приложение и в базу, а handle теперь проходит через контекст модели и через всё, что может на этот контекст влиять18. Примирение простое: протокол перестал быть местом хранения состояния, но не отменил необходимость его хранить; выигрыш — в операционной простоте, а не в отсутствии состояния.

«Любой L7-балансировщик». Solo.io и документация подчёркивают горизонтальное масштабирование и round-robin102; agentgateway возражает, что header-only прокси делает атаку вида «заголовок echo, тело printEnv» тривиальной, а фильтрацию tools/list — невозможной17. Обе позиции совместимы: маршрутизация по заголовкам — да, авторизация по заголовкам — нет. Tigera добавляет третий нюанс: заголовки дают дешёвые ранние отказы, но разрешение чувствительной операции всё равно требует тела15.

Безопасность и statelessness. В релизных материалах авторизация описана как «hardened»1, а Equixly фиксирует, что statelessness «does not make your deployment more secure»: найденные в популярных MCP-серверах уязвимости — обычные command injection и path traversal, а не дефекты протокола18. Меняются места, где принимается решение (шлюз, заголовки, requestState), а не качество кода за интерфейсом.

Порядок и кэш. Детерминированный порядок tools/list подаётся как улучшение prompt-кэша6, но кэшируемые описания инструментов — одновременно канал влияния на выбор инструмента моделью18. Один и тот же ttlMs может экономить запросы и продлевать жизнь отравленной записи; спецификация даёт механизм, но не даёт политики.

Недостаточность данных

Публичных измерений latency и throughput «до/после» для реального сервера найти не удалось; все заявления о выигрыше остаются аргументами об архитектуре, а не измерениями. Нет открытых данных о доле серверов, уже обслуживающих 2026-07-28, — есть только косвенные признаки (релизы SDK, changelog платформ)2627. Не опубликовано ни одного разбора инцидента, связанного с HeaderMismatch, отравлением кэша каталога или злоупотреблением requestState: класс атак описан, эксплуатация — нет. Независимого аудита реализации x-mcp-header в SDK на момент написания тоже нет, поэтому утверждение «валидация работает» опирается на код и release notes, а не на тесты третьей стороны1316.

Заключение

Ревизия 2026-07-28 — это перевод MCP из «протокола с сессией» в «протокол с самодостаточным запросом». Механика складывается из четырёх частей: per-request _meta и server/discover вместо handshake, MRTR вместо server-to-client запросов по открытому потоку, три обязательных заголовка и кэшируемые списки, плюс отдельная линия ужесточения OAuth (iss, CIMD, привязка к issuer)2111321.

Практический вывод для self-hosted сервера: миграция окупается не «модностью», а снятием целого класса эксплуатационных проблем — sticky sessions, общего store сессий, потери диалога при рестарте. Но она требует дисциплины в трёх местах, где раньше всё делал протокол: явные handle’ы вместо скрытого состояния, идемпотентность инструментов вместо надежды на транспорт и осознанные ttlMs/cacheScope вместо «закэшируем на час»21812.

Дальше стоит смотреть на три вещи: как быстро Tasks-расширение станет стандартом для CI- и batch-сценариев20, появится ли в core ключ идемпотентности, и как будут сосуществовать header-based маршрутизация и body-aware авторизация в реальных шлюзах1715. До появления независимых замеров любые утверждения о выигрыше в latency стоит считать гипотезой.

Quality Metrics

MetricValue
Total sources27
Academic / standards3
Official documentation18
Vendor engineering blogs4
Security research1
Community guides1
Citation coverage89%
Counter-arguments searchedYes
Research rounds3
Questions emerged9
Questions resolved7
Questions insufficient data2

  1. Model Context Protocol Blog. “The 2026-07-28 Specification.” July 28, 2026. https://blog.modelcontextprotocol.io/posts/2026-07-28/ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  2. Model Context Protocol Blog. “The 2026-07-28 MCP Specification Release Candidate.” 2026. https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  3. Hefner J., Roth M., Smith S., Tuch H., Van Gent K. “SEP-1442: Make MCP Stateless (by default), issue #1442.” GitHub, modelcontextprotocol/modelcontextprotocol. https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1442 ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  4. Model Context Protocol. “Specification 2026-07-28.” 2026. https://modelcontextprotocol.io/specification/2026-07-28 ↩︎

  5. Ulili S. “MCP Goes Stateless: What the 2026-07-28 Spec Changes and How to Migrate.” Better Stack, August 10, 2026. https://betterstack.com/community/guides/ai/mcp-stateless/ ↩︎ ↩︎ ↩︎

  6. Model Context Protocol. “Key Changes (changelog) 2026-07-28.” 2026. https://modelcontextprotocol.io/specification/2026-07-28/changelog ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  7. Model Context Protocol. “Base Protocol, revision 2026-07-28.” 2026. https://modelcontextprotocol.io/specification/2026-07-28/basic/index ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  8. Model Context Protocol. “Discovery (server/discover).” 2026. https://modelcontextprotocol.io/specification/2026-07-28/server/discover ↩︎ ↩︎

  9. Model Context Protocol. “Versioning and Compatibility.” 2026. https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  10. Levan M. “MCP Stateless Spec Changes: The Engineering Details.” Solo.io, July 27, 2026. https://www.solo.io/blog/mcp-stateless-spec-changes-the-engineering-details ↩︎ ↩︎

  11. Model Context Protocol. “Multi Round-Trip Requests.” 2026. https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  12. Model Context Protocol. “Caching.” 2026. https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  13. Model Context Protocol. “Streamable HTTP transport, revision 2026-07-28.” 2026. https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  14. Model Context Protocol. “SEP-2243: HTTP Header Standardization for Streamable HTTP Transport.” 2026. https://modelcontextprotocol.io/seps/2243-http-standardization ↩︎ ↩︎ ↩︎

  15. Tigera. “The New MCP Headers Are a Gift to Gateways.” August 6, 2026. https://www.tigera.io/blog/the-new-mcp-headers-are-a-gift-to-gateways/ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  16. Model Context Protocol. “Releases: modelcontextprotocol/python-sdk (v2.3.0).” 2026. https://github.com/modelcontextprotocol/python-sdk/releases ↩︎ ↩︎ ↩︎

  17. Posta C. “MCP goes stateless with headers. Do you need an MCP-native data plane?” agentgateway, July 21, 2026. https://agentgateway.dev/blog/2026-07-21-stateless-mcp-still-needs-mcp-native-dataplane/ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  18. Gorgiev Z., Dalla Piazza A. “Stateless MCP: What the 2026-07-28 specification changes for security.” Equixly, August 5, 2026. https://equixly.com/blog/2026/08/05/stateless-mcp/ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  19. Model Context Protocol. “Subscriptions (subscriptions/listen).” 2026. https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions ↩︎ ↩︎ ↩︎

  20. Model Context Protocol. “Tasks extension (io.modelcontextprotocol/tasks).” 2026. https://modelcontextprotocol.io/extensions/tasks/overview ↩︎ ↩︎ ↩︎ ↩︎

  21. Model Context Protocol. “Authorization.” 2026. https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/index ↩︎ ↩︎ ↩︎

  22. Meyer zu Selhausen K., Fett D. “RFC 9207: OAuth 2.0 Authorization Server Issuer Identification.” IETF, March 2022. https://www.rfc-editor.org/rfc/rfc9207 ↩︎ ↩︎

  23. Model Context Protocol. “Deprecated Features.” 2026. https://modelcontextprotocol.io/specification/2026-07-28/deprecated ↩︎ ↩︎ ↩︎ ↩︎

  24. Model Context Protocol. “Client Registration.” 2026. https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration ↩︎ ↩︎

  25. Model Context Protocol. “Security Best Practices.” 2026. https://modelcontextprotocol.io/docs/2026-07-28/tutorials/security/security_best_practices ↩︎

  26. Model Context Protocol. “MCP TypeScript SDK v2 — Migration Guides.” 2026. https://ts.sdk.modelcontextprotocol.io/v2/migration/ ↩︎ ↩︎

  27. Cloudflare. “Agents SDK adds MCP Specification 2026-07-28 support (v0.20.0).” Changelog, July 2026. https://developers.cloudflare.com/changelog/post/2026-07-27-agents-sdk-v0.20.0-mcp-sdk-v2/ ↩︎ ↩︎