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

> Multi Round-Trip Requests в MCP 2026-07-28 - как сервер запрашивает у клиента дополнительные данные через InputRequiredResult, inputRequests, inputResponses и requestState

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

Сервер MCP не может сам отправить запрос клиенту. Если для выполнения ему нужно что-то ещё - ответ пользователя, например, - он возвращает результат «нужны данные» со списком вопросов. Клиент собирает ответы и повторяет исходный запрос вместе с ними. Этот порядок называется Multi Round-Trip Requests, сокращённо MRTR.

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

Источник - страница [Multi Round-Trip Requests](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr) спецификации. Порядок введён изменением [SEP-2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322).

## Что он заменил

До редакции `2026-07-28` сервер отправлял клиенту собственные запросы: `elicitation/create`, `sampling/createMessage`, `roots/list`. Когда сервер работает в нескольких экземплярах, для этого требовалось общее хранилище или привязка клиента к одному экземпляру. Теперь сервер обязан использовать MRTR; прежний способ не поддерживается. Спецификация прямо называет это несовместимым изменением.

## Четыре шага

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

    C->>S: tools/call (id 1)
    S-->>C: результат input_required: inputRequests, requestState
    Note over C: клиент собирает ответы
    C->>S: tools/call (id 2): inputResponses, requestState
    S-->>C: результат complete
```

1. Клиент отправляет обычный запрос.
2. Сервер понимает, что данных не хватает, и отвечает результатом с `resultType: "input_required"`.
3. Клиент получает нужное у пользователя или из других источников и повторяет исходный запрос, добавив ответы.
4. Сервер выполняет запрос и возвращает итог.

Два запроса полностью независимы. Серверу, который обрабатывает повтор, не нужно ничего, кроме самого повтора. Поэтому повтор может попасть на другой экземпляр сервера.

## Где это разрешено

Сервер может вернуть «нужны данные» только на три запроса клиента.

| Запрос | Можно |
|---|---|
| `tools/call` | да |
| `resources/read` | да |
| `prompts/get` | да |
| любой другой | нет |

## Первый ответ сервера

```json title="Результат «нужны данные»"
{
  "jsonrpc": "2.0",
  "id": 1,
  "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": "eyJzdGVwIjoxfQ"
  }
}
```

| Поле | Что это |
|---|---|
| `inputRequests` | набор вопросов к клиенту; ключи придумывает сервер, они уникальны в пределах запроса |
| `requestState` | непрозрачная строка, понятная только серверу |

В ответе обязано быть хотя бы одно из двух полей.

Вопросом может быть один из трёх запросов: `elicitation/create` ([вопрос пользователю](https://mcpdoc.ru/protocol/elicitation/)), `sampling/createMessage` или `roots/list`. Последние два относятся к функциям, которые [объявлены устаревшими](https://mcpdoc.ru/protocol/deprecations/). Сервер не должен задавать вопрос, поддержку которого клиент не объявил в своих возможностях.

## Повтор от клиента

```json title="Повтор исходного запроса"
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": { "location": "New York" },
    "inputResponses": {
      "github_login": {
        "action": "accept",
        "content": { "name": "octocat" }
      }
    },
    "requestState": "eyJzdGVwIjoxfQ"
  }
}
```

Требования к клиенту:

- если в ответе есть `inputRequests`, клиент обязан собрать ответы до повтора; если нет - может повторить сразу;
- `requestState` возвращается точно таким, каким пришёл; разбирать и менять его нельзя; если сервер его не присылал, добавлять его в повтор нельзя;
- у повтора обязан быть другой `id`: это отдельный запрос;
- `inputRequests` и `requestState` относятся только к повтору этого запроса, в других запросах их использовать нельзя.

Сервер не должен рассчитывать, что клиент обязательно ответит или повторит запрос. Если в повторе не хватает нужных данных, серверу следует снова вернуть «нужны данные», а не ошибку.

## `requestState` - данные от возможного злоумышленника

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

- Если от `requestState` зависят права, доступ к ресурсам или логика, сервер обязан защитить её целостность (например, HMAC) и отклонять строку, не прошедшую проверку.
- От повторного использования серверу следует защищаться, включив в защищённую часть: кто сделал запрос, короткий срок действия и признак исходного запроса.
- Эти меры сокращают окно для повтора, но не гарантируют одноразовость. Если строка должна сработать ровно один раз, сервер обязан обеспечить это сам.

Защиту целостности можно не делать только тогда, когда подделка не даёт ничего, кроме отказа запроса.

## Кэш

Результат «нужны данные» не кэшируется. Итог запроса, полученный после повтора с `inputResponses` или `requestState`, кэшировать тоже нельзя.

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

- [Elicitation](https://mcpdoc.ru/protocol/elicitation/) - самый частый вопрос сервера: спросить пользователя.
- [Ядро без состояния](https://mcpdoc.ru/protocol/stateless/) - почему протокол отказался от запросов со стороны сервера.
- [Переход на 2026-07-28](https://mcpdoc.ru/protocol/migration/) - что менять в сервере, который раньше сам отправлял запросы.
