Глава 17

Моделируйте дополнительный ввод и долгую работу явно

Современный MCP различает два вида "незавершённости". Когда операции не хватает данных, используется resultType: input_required - Multi Round-Trip Request. Когда работа по-настоящему долгая и асинхронная, она выносится в официальное tasks-extension. Оба механизма внешне похожи на A2A lifecycle, но остаются capability-oriented контрактом, а не делегацией.

Сам круг Multi Round-Trip выглядит как короткая последовательность.

  1. tools/call
  2. input_required
  3. User input
  4. Retry (new id)
  5. Result

Сервер сообщает, что ему нужен ввод, отдельным результатом с описанием формы этого ввода.

JSON
{
  "jsonrpc": "2.0",
  "id": 20,
  "result": {
    "resultType": "input_required",
    "inputRequests": {
      "approval": {
        "method": "elicitation/create",
        "params": {
          "mode": "form",
          "message": "Подтвердите окно выпуска",
          "requestedSchema": {
            "type": "object",
            "properties": {
              "window": {
                "type": "string"
              }
            },
            "required": [
              "window"
            ]
          }
        }
      }
    },
    "requestState": "opaque-signed-state"
  }
}

Клиент дополняет исходную операцию ответом пользователя и повторяет её - уже с новым JSON-RPC id.

JSON
{
  "jsonrpc": "2.0",
  "id": 21,
  "method": "tools/call",
  "params": {
    "name": "schedule_release",
    "arguments": {
      "service": "web-portal"
    },
    "inputResponses": {
      "approval": {
        "action": "accept",
        "content": {
          "window": "2026-08-02T02:00:00Z"
        }
      }
    },
    "requestState": "opaque-signed-state",
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28"
    }
  }
}

У этого цикла есть несколько инвариантов, нарушение которых ломает безопасность.

  • Retry получает новый JSON-RPC id.
  • requestState непрозрачен для клиента, связан с исходными аргументами и защищён от подмены.
  • Клиент объявляет поддерживаемые input modes в capabilities.
  • Отказ пользователя - нормальный исход, а не infrastructure error.
  • Не запрашивайте пароль или долгоживущий secret через произвольную форму.

Tasks-extension нужен, когда capability запускает работу, которую надо poll-ить, обновлять или продолжать после разрыва запроса. Но здесь проходит важная граница: если публичный контракт уже является делегацией независимому агенту с Agent Card, multimodal-сообщениями и artifacts - вероятно, эту границу честнее выразить через A2A, а не натягивать на неё MCP-tasks.

Не копируйте старый sampling flow. Roots, sampling и прежние server-initiated паттерны помечены deprecated в 2026-07-28. Проверяйте deprecated-registry и migration guide до реализации client capabilities - иначе рискуете построить систему на том, что уже уходит.

Функциональность удалённого MCP собрана. Прежде чем выпускать его в сеть, нужно закрыть главный вопрос - кто и на что имеет право.

Ссылки