Перейти к содержимому
Выберите тему

Streamable HTTP и переход с HTTP+SSE

Чем старый транспорт HTTP+SSE отличается от Streamable HTTP двух редакций, как клиент распознаёт старый сервер, как перевести сервер и что не должен делать обратный прокси

описана редакция 2026-07-28, сверено со спецификацией 4 октября 2026

Под словами «сервер на SSE» скрываются три разных устройства.

1. HTTP+SSE из редакции 2024-11-05. У сервера два адреса. По первому клиент открывает поток SSE и получает сообщения сервера. По второму клиент отправляет свои сообщения запросами POST. Адрес для POST сервер сообщает первым событием потока, оно называется endpoint. Этот транспорт устарел.

2. Streamable HTTP редакций 2025-03-26 - 2025-11-25. Адрес один, он принимает POST и GET. Сервер может выдать номер сессии, клиент может открыть отдельный поток запросом GET, оборванный поток можно возобновить. Это Legacy.

3. Streamable HTTP редакции 2026-07-28. Адрес один, он принимает только POST. Сессий, потока по GET, запроса DELETE и возобновления потока нет. Это Modern.

Полное описание действующего транспорта - на странице «Транспорты». Здесь только то, что нужно для перехода и развёртывания.

Свойство HTTP+SSE, 2024-11-05 Streamable HTTP, 2025-11-25 Streamable HTTP, 2026-07-28
адреса два: поток SSE и адрес для POST один один
методы HTTP GET для потока, POST для сообщений POST и GET только POST
начало работы GET, затем событие endpoint POST с initialize любой запрос, рукопожатия нет
сессии в описании транспорта заголовка сессии нет необязательны, заголовок MCP-Session-Id удалены
отдельный поток от сервера весь обмен идёт по одному потоку клиент может открыть его запросом GET нет, вместо него subscriptions/listen
собственные запросы сервера в потоке - разрешены запрещены
завершение сессии - клиенту следует отправить DELETE нет, на DELETE сервер отвечает 405
возобновление потока - необязательно, через GET и Last-Event-ID нет
обрыв потока ответа - не считается отменой запроса считается отменой запроса
статус в спецификации Deprecated Legacy действует

Прочерк означает, что в описании транспорта 2024-11-05 этого вопроса нет.

Источники строк: транспорты 2024-11-05, транспорты 2025-11-25, Streamable HTTP 2026-07-28 и перечень изменений 2026-07-28.

Что изменилось между двумя формами Streamable HTTP

Заголовок раздела «Что изменилось между двумя формами Streamable HTTP»
  • Удалены сессии на уровне протокола и заголовок Mcp-Session-Id.
  • Удалён поток по GET. Долгий поток уведомлений клиент получает запросом subscriptions/listen: ответ на этот POST и есть поток, который остаётся открытым.
  • Удалено возобновление потока. Оборванный поток означает потерянный запрос. Клиент обязан отправить его заново с новым номером запроса.
  • Сервер не должен отправлять в потоке собственные запросы. В редакциях 2025-03-26 - 2025-11-25 это было разрешено.
  • Закрытие потока ответа сервер обязан считать отменой запроса. В редакции 2025-11-25 было наоборот: обрыв не следовало считать отменой.
  • В теле POST теперь может быть только запрос или уведомление. Ответы JSON-RPC клиент не отправляет.

В редакции 2026-07-28 клиент обязан указывать:

Заголовок Когда
Accept с обоими типами, application/json и text/event-stream в каждом POST
MCP-Protocol-Version в каждом POST
Mcp-Method в каждом запросе
Mcp-Name в запросах tools/call, resources/read, prompts/get

Значение MCP-Protocol-Version обязано совпадать с версией в поле _meta тела запроса.

Правило проверки одно. Если обязательного заголовка нет, если он не совпал с телом или содержит недопустимые символы, сервер обязан ответить статусом 400 и ошибкой JSON-RPC -32020 (HeaderMismatch).

Ещё три ответа, которые полезно различать:

  • версия не поддерживается - 400 и ошибка -32022 со списком поддерживаемых версий;
  • метод серверу неизвестен - 404 и ошибка -32601;
  • принято уведомление - 202 без тела.

Для обратного прокси из этого следует практический вывод: перечисленные заголовки нужно пропускать без изменений, иначе сервер отклонит запрос. Прямое требование к посредникам спецификация записывает только для заголовков Mcp-Param-*: незнакомый заголовок посредник обязан передать дальше. Посреднику, который принимает решения по этим заголовкам, следует отклонять запрос, если заголовка версии нет или версия старше.

Спецификация 2026-07-28 описывает порядок для клиента, который хочет работать и со старыми серверами. Это описание, а не обязательное требование.

  1. Клиент принимает от пользователя адрес сервера. Адрес может вести и на старый, и на новый транспорт.
  2. Клиент отправляет на этот адрес POST с заголовком Accept.
  3. Если запрос удался, перед ним сервер на Streamable HTTP.
  4. Если пришёл статус 400, 404 или 405 и в теле нет распознанной ошибки Modern, клиент отправляет GET на тот же адрес.
  5. Если в ответ открылся поток и первым пришло событие endpoint, перед ним сервер на HTTP+SSE. Дальше клиент работает с ним по старому транспорту.

Условие про тело ответа появилось в редакции 2026-07-28. Сервер Modern тоже отвечает 400 и 404, но с ошибкой JSON-RPC в теле: неподдерживаемая версия, неизвестный метод, ошибка заголовков. Такой ответ означает сервер Modern, и переходить на старый транспорт клиенту не нужно. В редакции 2025-11-25 этого условия не было, а первым запросом был initialize.

Выполняет ли этот порядок конкретная программа-клиент, зависит от неё самой. Спецификация этого не гарантирует.

В реестре устаревшего самый ранний срок удаления записан словами: «через три месяца после того, как SEP-2596 получит статус Final». Календарной даты в реестре нет. Раздел «Removed» того же реестра пуст.

Этот срок - момент, начиная с которого транспорт можно удалить из спецификации. Это не дата, когда перестанут работать ваши серверы и клиенты: они работают, пока их поддерживают программы на обеих сторонах. Подробнее - на странице «Что устарело в MCP».

Шаги 1 и 2 следуют спецификации. Остальные - практика, а не правило MCP.

  1. Добавьте адрес Streamable HTTP рядом со старыми. Спецификация описывает именно такой путь: сервер, которому нужны старые клиенты, продолжает держать оба адреса HTTP+SSE и добавляет новый адрес MCP. Совместить старый адрес для POST с новым адресом можно, но спецификация предупреждает о лишней сложности.
  2. Решите, какие редакции обслуживает новый адрес. Только 2026-07-28 или ещё и Legacy с initialize. Второй вариант описан на странице «Сервер для двух эпох».
  3. Возьмите транспорт из выпущенной версии SDK. Что умеет каждый SDK, записано на его странице в разделе «SDK». Не переносите старый код с двумя адресами в новый обработчик.
  4. Уберите зависимость от сессий, если идёте в Modern. В редакции 2026-07-28 запрос может прийти на любой экземпляр сервера. Состояние между вызовами передаётся явно - см. «Ядро без состояния».
  5. Проверьте оба адреса. Новый - запросом curl с заголовками Modern, старый - прежним клиентом.
  6. Смотрите, кто ещё ходит на старые адреса. В журнале сервера это запросы GET на адрес потока.
  7. Отключите старые адреса, когда решите сами. Спецификация срока не назначает. Это решение владельца сервера.

Этот раздел - практика, а не правило MCP. Сведения о поведении nginx взяты из документации модуля ngx_http_proxy_module.

Не накапливать поток ответа. В nginx директива proxy_buffering по умолчанию включена. При выключенной буферизации ответ передаётся клиенту сразу, по мере получения. Иначе события потока придут клиенту пачкой или с задержкой.

Здесь спецификация и nginx сходятся. Спецификация говорит, что серверу следует добавлять к потоку SSE заголовок X-Accel-Buffering: no. Документация nginx подтверждает: значение no в этом заголовке ответа отключает буферизацию. Но это работает, только пока заголовок не отключён директивой proxy_ignore_headers.

Не обрывать тихий поток раньше времени. Директива proxy_read_timeout по умолчанию равна 60 секундам. Это время между двумя чтениями, а не на весь ответ: если сервер молчит дольше, nginx закроет соединение. Спецификация советует серверу время от времени отправлять в долгий поток строку-комментарий SSE. Какой промежуток выбрать и нужно ли менять срок ожидания, решаете вы.

Не забывать, что обрыв теперь означает отмену. В редакции 2026-07-28 сервер обязан считать закрытие потока отменой запроса. Если соединение закрыл прокси, запрос для клиента потерян, и отправлять его придётся заново с новым номером.

Не менять и не удалять заголовки MCP. Без MCP-Protocol-Version и Mcp-Method сервер Modern обязан ответить 400.

Схема: проксирование адреса MCP
location /mcp {
proxy_pass http://127.0.0.1:3000;
proxy_buffering off;
}

Пример схематичный, составлен по документации nginx и здесь не запускался. Адрес и порт условные.

Отдельно от прокси действуют требования спецификации к самому серверу: он обязан проверять заголовок Origin, при локальном запуске ему следует слушать только 127.0.0.1, и ему следует проверять подлинность соединений. Об авторизации - раздел «Модель авторизации».

Удалённому серверу нужна машина с постоянным адресом и сертификатом. Виртуальный сервер можно арендовать у FirstVDS или Aéza.