# Шаблоны обмена

Запрос и ответ, многошаговые запросы, подписки

> Страница сайта MCP Docs — неофициального перевода документации Model Context Protocol (https://mcpdocs.ru/protocol/patterns/). Тип: Перевод и пересказ. Основа: Спецификация, раздел «Message patterns»; список изменений 2026-07-28 (https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/index). Ревизия спецификации 2026-07-28, сверено 05.10.2026.

Базовый протокол поддерживает три шаблона обмена. Они заменили механизмы, которые зависели от долгого открытого соединения, и поэтому подходят для протокола без состояния.

## Запрос и ответ

Клиент отправляет запрос, сервер возвращает результат или ошибку. По Streamable HTTP каждый запрос — отдельный POST, а ответ — один объект JSON или поток SSE, привязанный к запросу. Запросы, которые идут по потоку, могут нести уведомления о ходе выполнения до итогового ответа.

## Многошаговые запросы (MRTR)

Многошаговый запрос (Multi Round-Trip Requests, MRTR) заменил прежний подход, где сервер сам посылал клиенту запросы `roots/list`, `sampling/createMessage` и `elicitation/create`. Такие запросы требовали открытого потока от сервера к клиенту, а протокол без состояния его не предоставляет.

Работает это так.

1. Клиент отправляет обычный запрос, например `tools/call`.
2. Если серверу нужны дополнительные данные, он возвращает не итог, а результат с `resultType: "input_required"`. Это объект `InputRequiredResult`. В поле `inputRequests` лежат запросы на недостающую информацию, каждому присвоен ключ.
3. Клиент собирает данные (например, спрашивает пользователя) и **повторяет исходный запрос** с новым идентификатором JSON-RPC, добавив `inputResponses` и, если сервер прислал, `requestState`.
4. Сервер возвращает итоговый результат или снова `input_required`.

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "resultType": "input_required",
    "inputRequests": {
      "github_login": {
        "method": "elicitation/create",
        "params": {
          "mode": "form",
          "message": "Please provide your GitHub username",
          "requestedSchema": {
            "type": "object",
            "properties": { "name": { "type": "string" } },
            "required": ["name"]
          }
        }
      }
    },
    "requestState": "eyJsb2NhdGlvbiI6Ik5ldyBZb3JrIn0..."
  }
}
```

Повтор запроса с ответами:

```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": { "location": "New York" },
    "inputResponses": {
      "github_login": { "action": "accept", "content": { "name": "octocat" } }
    },
    "requestState": "eyJsb2NhdGlvbiI6Ik5ldyBZb3JrIn0..."
  }
}
```

Идентификатор JSON-RPC повторного запроса ДОЛЖЕН отличаться от идентификатора первого. Поле `requestState` непрозрачно для клиента: сервер кладёт в него то, что нужно для продолжения, и получает обратно.

> **Заметка переводчика.** Уведомление `notifications/elicitation/complete` и поле `elicitationId` у запросов элицитации в режиме URL (они появились в 2025-11-25) в ревизии 2026-07-28 удалены. Клиент узнаёт итог внешнего взаимодействия, когда повторяет исходный запрос. Если серверу нужно связать несколько повторов, свой идентификатор он кодирует в `requestState`.

## Подписка на изменения (subscriptions/listen)

Уведомления об изменениях подписочные: клиент заранее выбирает, какие из них хочет получать. Для этого он отправляет запрос `subscriptions/listen` с фильтром `notifications`. Ответ на него — долгий поток, который остаётся открытым.

Типы уведомлений, которые клиент может выбрать:

| Фильтр | Что присылает сервер |
| --- | --- |
| `toolsListChanged` | `notifications/tools/list_changed` при изменении перечня инструментов. |
| `promptsListChanged` | Уведомление при изменении перечня шаблонов запросов. |
| `resourcesListChanged` | Уведомление при изменении перечня ресурсов. |
| `resourceSubscriptions` | `notifications/resources/updated` по перечисленным URI. |

Запрос:

```json
{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "subscriptions/listen",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "example-client", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": { "elicitation": {} }
    },
    "notifications": { "toolsListChanged": true }
  }
}
```

Сервер подтверждает подписку уведомлением `notifications/subscriptions/acknowledged`: оно первое в потоке с идентификатором подписки в `_meta`, а в его поле `notifications` указана та часть фильтра, которую сервер согласен выполнять (неподдерживаемые типы пропущены). Дальше каждое уведомление в потоке несёт `io.modelcontextprotocol/subscriptionId` в `_meta`. Значение равно идентификатору запроса `subscriptions/listen`, поэтому клиент сопоставляет уведомление с подпиской.

- Уведомление доступно, только если сервер объявил соответствующую возможность, например `"listChanged": true` у `tools`.
- Доставка «по возможности»: нет гарантии, что каждое уведомление будет отправлено или получено, особенно при переподключении. Свежесть результатов клиентам СЛЕДУЕТ дополнительно поддерживать опросом.
- Уведомления, привязанные к запросу, такие как `notifications/progress` и `notifications/message`, идут в потоке ответа на тот запрос, к которому относятся, а не в потоке подписки.
- Получив уведомление, клиент обычно запрашивает обновлённый перечень (`tools/list`).

## Отмена

По Streamable HTTP закрытие потока ответа SSE — это отмена запроса. По stdio используется уведомление `notifications/cancelled`. Подробности: [«Транспорты»](https://mcpdocs.ru/protocol/transports/#otmena).

## Прогресс

Клиент может подписать запрос на уведомления о ходе выполнения, передав `progressToken` в `_meta`. Сервер присылает `notifications/progress` в потоке ответа на этот запрос. Подробное описание: [оригинал](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/progress).
