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

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

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

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

Источник - страница Multi Round-Trip Requests спецификации. Порядок введён изменением SEP-2322.

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

СерверКлиентСерверКлиентклиент собирает ответыtools/call (id 1)результат input_required: inputRequests, requestStatetools/call (id 2): inputResponses, requestStateрезультат complete
  1. Клиент отправляет обычный запрос.
  2. Сервер понимает, что данных не хватает, и отвечает результатом с resultType: "input_required".
  3. Клиент получает нужное у пользователя или из других источников и повторяет исходный запрос, добавив ответы.
  4. Сервер выполняет запрос и возвращает итог.

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

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

Запрос Можно
tools/call да
resources/read да
prompts/get да
любой другой нет
Результат «нужны данные»
{
"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 (вопрос пользователю), sampling/createMessage или roots/list. Последние два относятся к функциям, которые объявлены устаревшими. Сервер не должен задавать вопрос, поддержку которого клиент не объявил в своих возможностях.

Повтор исходного запроса
{
"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 - данные от возможного злоумышленника»

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

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

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

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

  • Elicitation - самый частый вопрос сервера: спросить пользователя.
  • Ядро без состояния - почему протокол отказался от запросов со стороны сервера.
  • Переход на 2026-07-28 - что менять в сервере, который раньше сам отправлял запросы.