# Транспорты MCP

> Как сообщения MCP передаются в редакции 2026-07-28 - stdio и Streamable HTTP, обязательные заголовки, статусы ответов, отмена запроса и статус устаревшего HTTP+SSE

Страница: https://mcpdoc.ru/protocol/transports/
Указатель сайта: https://mcpdoc.ru/llms.txt

В спецификации два стандартных транспорта: stdio для сервера, который клиент запускает как локальный процесс, и Streamable HTTP для сервера, работающего как самостоятельный сервис. Смысл сообщений на обоих одинаков, различается только способ доставки.

Старый транспорт HTTP+SSE устарел, но из спецификации не удалён.

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

## Статус транспортов

| Транспорт | Статус | Где описан |
|---|---|---|
| stdio | действует | [stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio) |
| Streamable HTTP в форме `2026-07-28` | действует | [Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http) |
| Streamable HTTP в форме `2025-03-26` - `2025-11-25` (сессии, поток по GET) | Legacy: описан в своих редакциях, в текущую не входит | раздел Backward Compatibility той же страницы |
| HTTP+SSE из редакции `2024-11-05` | устарел с `2025-03-26`, не удалён | [реестр устаревшего](https://modelcontextprotocol.io/specification/2026-07-28/deprecated) |
| свой транспорт | разрешён | [обзор транспортов](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports) |

Транспорта на WebSocket в спецификации `2026-07-28` нет.

Свой транспорт обязан сохранить формат JSON-RPC, шаблоны обмена и поля `_meta`. Если он работает поверх надёжного потока байтов (сокет Unix, TCP), спецификация рекомендует взять правила stdio: одно сообщение на строку.

## stdio

Клиент запускает сервер как дочерний процесс и общается с ним через стандартные потоки.

- Сервер читает сообщения из `stdin` и пишет в `stdout`.
- Одно сообщение - одна строка. Переводов строки внутри сообщения быть не должно.
- В `stdout` сервер не должен писать ничего, кроме сообщений MCP.
- В `stderr` сервер может писать что угодно: журнал, отладку, ошибки. Клиенту не следует считать вывод в `stderr` признаком сбоя.
- Сервер не отправляет запросы. Клиент не отправляет ответы.

```json title="Две строки обмена по stdio"
{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}
{"jsonrpc":"2.0","id":1,"result":{"resultType":"complete","tools":[],"ttlMs":0,"cacheScope":"private"}}
```

**Отмена.** Клиент отправляет уведомление `notifications/cancelled` с номером запроса. Серверу следует остановить работу как можно скорее. Присылать по этому запросу новые сообщения он не должен.

**Завершение.** Клиенту следует закрыть `stdin` сервера и подождать выхода процесса. Если процесс не вышел за разумное время, клиент завершает его принудительно: в POSIX это обычно `SIGTERM`, затем `SIGKILL`. Серверу следует выходить сразу, как только `stdin` закрыт.

**Сбой процесса.** Клиенту следует перезапустить сервер. Незавершённые запросы теряются, их можно повторить.

## Streamable HTTP

Сервер работает как отдельный сервис и даёт один адрес, например `https://example.com/mcp`. Этот адрес принимает POST.

- Каждое сообщение клиента - отдельный POST.
- Клиент обязан указать в `Accept` оба типа: `application/json` и `text/event-stream`.
- На запрос сервер отвечает либо одним объектом JSON, либо потоком SSE, привязанным к этому запросу. Клиент обязан понимать оба варианта.
- В потоке сервер может прислать уведомления по этому запросу, например о ходе выполнения, а затем итоговый ответ.
- Сервер не отправляет по потоку собственные запросы.

```mermaid
sequenceDiagram
    participant C as Клиент
    participant S as Сервер

    C->>S: POST /mcp (запрос)
    alt короткий ответ
        S-->>C: 200, application/json
    else ответ потоком
        S-->>C: 200, text/event-stream
        S--)C: уведомления по этому запросу
        S-->>C: итоговый ответ, поток закрыт
    end
```

### Обязательные заголовки

| Заголовок | Откуда значение | Когда нужен |
|---|---|---|
| `MCP-Protocol-Version` | версия из `_meta` запроса | в каждом POST |
| `Mcp-Method` | поле `method` | в каждом запросе |
| `Mcp-Name` | `params.name` или `params.uri` | для `tools/call`, `resources/read`, `prompts/get` |
| `Mcp-Param-{имя}` | аргумент инструмента, помеченный в схеме свойством `x-mcp-header` | когда сервер так пометил параметр |

Заголовки повторяют тело запроса, чтобы балансировщики и шлюзы могли направлять запросы, не разбирая JSON. Источником истины остаётся тело.

```http title="Вызов инструмента по HTTP"
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": { "location": "Seattle, WA" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}
```

Если значение нельзя записать обычными символами ASCII (например, в нём кириллица), клиент обязан закодировать его в Base64 и обернуть так: `=?base64?ЗНАЧЕНИЕ?=`. Правило действует для `Mcp-Name` и `Mcp-Param-{имя}`.

### Статусы ответов

| Ситуация | Статус HTTP | Ошибка JSON-RPC |
|---|---|---|
| заголовок не совпал с телом, отсутствует или содержит недопустимые символы | `400` | `-32020` `HeaderMismatch` |
| сервер не поддерживает запрошенную версию | `400` | `-32022` `UnsupportedProtocolVersion` |
| клиент не объявил нужную возможность | `400` | `-32021` `MissingRequiredClientCapability` |
| сервер не знает такого метода | `404` | `-32601` |
| заголовок `Origin` есть и он недопустим | `403` | необязательно |
| принято уведомление | `202` | тела нет |

### Отмена и обрыв

Клиент отменяет запрос, закрывая поток ответа. Отдельное уведомление на HTTP не нужно.

Возобновить оборванный поток нельзя: заголовок `Last-Event-ID` не поддерживается. Клиент отправляет запрос заново с новым `id`.

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

### Защита адреса

Три требования из раздела Security & Endpoint.

1. Сервер обязан проверять заголовок `Origin` во всех входящих соединениях. Это защита от подмены DNS (DNS rebinding).
2. Локально запущенному серверу следует слушать только `127.0.0.1`, а не все интерфейсы.
3. Серверу следует проверять подлинность всех соединений. Как устроена авторизация, описано в разделе [«Модель авторизации»](https://mcpdoc.ru/auth/).

Авторизация из спецификации относится к HTTP. На stdio учётные данные берутся из окружения процесса.

## Что отвечает новый сервер старому клиенту

Серверу, который поддерживает только `2026-07-28`, спецификация рекомендует:

- на GET и DELETE по своему адресу отвечать `405`;
- заголовок `Mcp-Session-Id` игнорировать и номера сессий не выдавать;
- заголовок `Last-Event-ID` игнорировать.

## HTTP+SSE: устарел, но не удалён

HTTP+SSE из редакции `2024-11-05` устарел с редакции `2025-03-26`. В `2026-07-28` он отнесён к состоянию Deprecated по правилам жизненного цикла ([SEP-2596](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2596)). Замена - Streamable HTTP.

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

Срок в реестре - это момент, с которого функцию можно удалить, а не дата удаления. Само удаление - отдельное решение ведущих разработчиков при подготовке очередной редакции. Новым реализациям HTTP+SSE использовать не следует, существующим следует перейти на Streamable HTTP.

Как клиенту работать и со старым, и с новым сервером, спецификация описывает так: отправить POST с новым набором заголовков; если пришёл ответ `400`, `404` или `405` и в теле нет распознанной ошибки Modern, отправить GET и ждать событие `endpoint` - это признак сервера на HTTP+SSE.

## Что читать дальше

- [Редакции и версии](https://mcpdoc.ru/protocol/versions/) - как определить эпоху сервера.
- [Что устарело](https://mcpdoc.ru/protocol/deprecations/) - полный реестр и сроки.
- [HTTP-развёртывание](https://mcpdoc.ru/deployment/http-sse/) - практическая сторона: прокси, сертификаты, запуск.
