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 клиент не отправляет.
Заголовки и правило 400
Заголовок раздела «Заголовки и правило 400»В редакции 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-*: незнакомый заголовок посредник обязан передать дальше. Посреднику, который принимает решения по этим заголовкам, следует отклонять запрос, если заголовка версии нет или версия старше.
Как клиент распознаёт старый сервер HTTP+SSE
Заголовок раздела «Как клиент распознаёт старый сервер HTTP+SSE»Спецификация 2026-07-28 описывает порядок для клиента, который хочет работать и со старыми серверами. Это описание, а не обязательное требование.
- Клиент принимает от пользователя адрес сервера. Адрес может вести и на старый, и на новый транспорт.
- Клиент отправляет на этот адрес POST с заголовком
Accept. - Если запрос удался, перед ним сервер на Streamable HTTP.
- Если пришёл статус
400,404или405и в теле нет распознанной ошибки Modern, клиент отправляет GET на тот же адрес. - Если в ответ открылся поток и первым пришло событие
endpoint, перед ним сервер на HTTP+SSE. Дальше клиент работает с ним по старому транспорту.
Условие про тело ответа появилось в редакции 2026-07-28. Сервер Modern тоже отвечает 400 и 404, но с ошибкой JSON-RPC в теле: неподдерживаемая версия, неизвестный метод, ошибка заголовков. Такой ответ означает сервер Modern, и переходить на старый транспорт клиенту не нужно. В редакции 2025-11-25 этого условия не было, а первым запросом был initialize.
Выполняет ли этот порядок конкретная программа-клиент, зависит от неё самой. Спецификация этого не гарантирует.
Статус HTTP+SSE
Заголовок раздела «Статус HTTP+SSE»В реестре устаревшего самый ранний срок удаления записан словами: «через три месяца после того, как SEP-2596 получит статус Final». Календарной даты в реестре нет. Раздел «Removed» того же реестра пуст.
Этот срок - момент, начиная с которого транспорт можно удалить из спецификации. Это не дата, когда перестанут работать ваши серверы и клиенты: они работают, пока их поддерживают программы на обеих сторонах. Подробнее - на странице «Что устарело в MCP».
Как перевести сервер с HTTP+SSE
Заголовок раздела «Как перевести сервер с HTTP+SSE»Шаги 1 и 2 следуют спецификации. Остальные - практика, а не правило MCP.
- Добавьте адрес Streamable HTTP рядом со старыми. Спецификация описывает именно такой путь: сервер, которому нужны старые клиенты, продолжает держать оба адреса HTTP+SSE и добавляет новый адрес MCP. Совместить старый адрес для POST с новым адресом можно, но спецификация предупреждает о лишней сложности.
- Решите, какие редакции обслуживает новый адрес. Только
2026-07-28или ещё и Legacy сinitialize. Второй вариант описан на странице «Сервер для двух эпох». - Возьмите транспорт из выпущенной версии SDK. Что умеет каждый SDK, записано на его странице в разделе «SDK». Не переносите старый код с двумя адресами в новый обработчик.
- Уберите зависимость от сессий, если идёте в Modern. В редакции
2026-07-28запрос может прийти на любой экземпляр сервера. Состояние между вызовами передаётся явно - см. «Ядро без состояния». - Проверьте оба адреса. Новый - запросом curl с заголовками Modern, старый - прежним клиентом.
- Смотрите, кто ещё ходит на старые адреса. В журнале сервера это запросы GET на адрес потока.
- Отключите старые адреса, когда решите сами. Спецификация срока не назначает. Это решение владельца сервера.
Что не должен делать обратный прокси
Заголовок раздела «Что не должен делать обратный прокси»Этот раздел - практика, а не правило 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.
location /mcp { proxy_pass http://127.0.0.1:3000; proxy_buffering off;}Пример схематичный, составлен по документации nginx и здесь не запускался. Адрес и порт условные.
Отдельно от прокси действуют требования спецификации к самому серверу: он обязан проверять заголовок Origin, при локальном запуске ему следует слушать только 127.0.0.1, и ему следует проверять подлинность соединений. Об авторизации - раздел «Модель авторизации».
Удалённому серверу нужна машина с постоянным адресом и сертификатом. Виртуальный сервер можно арендовать у FirstVDS или Aéza.
Что читать дальше
Заголовок раздела «Что читать дальше»- Транспорты - полное описание stdio и Streamable HTTP редакции
2026-07-28. - Сервер для двух эпох - как одним адресом отвечать клиентам Legacy и Modern.
- Что устарело в MCP - реестр устаревшего и сроки.
- Ядро без состояния - как работать без сессий.