Почему после того как Google положил REST на API Gateway MCP, обнаружение всё ещё JSON: OpenAPI 3.x до tools/list

На 30 сентября 2026: Public Preview API Gateway (блог 24 сент.) превращает операции OpenAPI 3.x в удалённые MCP-инструменты. tools/list — JSON Schema и по умолчанию открыт; tools/call остаётся JSON-RPC. Проверьте спецификацию до mcp: true.

Сразу вывод: шлюз сыграет роль MCP Server. Контракт обнаружения — по-прежнему JSON-документ. 24 сентября 2026 блог разработчиков Google написал: Cloud API Gateway в Public Preview может выставить уже развёрнутые операции OpenAPI 3.x как удалённые MCP-инструменты — без отдельного MCP Server, который нужно писать и хостить. Документация вышла раньше: в release notes от 11 сентября уже стоит Enable MCP. Шлюз принимает стандартный JSON-RPC на /mcp, транскодирует tools/call в существующий REST-запрос и держит JWT, API Key, квоты и логи на одном пути политик. Агент видит не «REST стал магией». Он видит имена инструментов и input schema из tools/list — всё ещё JSON.

Текст актуален на 30 сентября 2026, по тому посту и документации API Gateway, которые в тот день ещё действовали. На сайте уже есть что такое MCP, почему обнаружение Skill всё ещё JSON и вредоносный JSON и Tool Calling. Этот текст только отвечает: какой слой JSON проверять первым, когда OpenAPI сел на шлюз, и какой слой по умолчанию открыт.

Что на самом деле вышло как «шлюз как MCP Server»

Официальная формулировка короткая: большая часть корпоративных возможностей сидит за REST; агенты её не видят. Обычно команды поднимают второй MCP Server и заново реализуют маршрутизацию, auth и квоты. API Gateway — лёгкий вход в линейке шлюзов Google Cloud. Сервис на Cloud Run, который нужно за минуты взять под управление и отдать агентам, идёт сюда. Полный жизненный цикл, тяжёлые политики трафика и монетизация остаются на Apigee. Исходящие вызовы агента, включая такие MCP Server, идут через Agent Gateway. Исходящая маршрутизация модели — другое направление, и её нельзя писать в одном API config с MCP.

Поддерживаются только четыре метода жизненного цикла: initialize, notifications/initialized, tools/list и tools/call. Всё остальное (resources/*, prompts/*) возвращает JSON-RPC -32601. Транспорт — HTTP POST. stdio нет. Пример заголовка — MCP-Protocol-Version: 2025-11-25. Сама спецификация сдвинула рукопожатие в 2026-07-28; этот preview фиксирует 2025-11-25. Даже строка версии — поле, которое сначала выравнивают в JSON-конверте.

Это не писать ещё один MCP Server

Транскодированный REST-запрос неотличим от вызова из браузера или SDK. Квота считается по операции; MCP и REST делят один лимит. Бэкенд не растит второй интерфейс для агентов. Меняется обнаружение: раньше люди читали OpenAPI; теперь модель читает JSON Schema внутри tools/list.

СлойРаньшеПосле Gateway MCP
Человеческий контрактOpenAPI 2.0 / 3.x, часто YAMLСначала нужно поднять до OpenAPI 3.0.x или 3.1.x
Обнаружение агентомСвой hosted tools/listШлюз собирает tools/list из той же спецификации
ВызовREST или свой tools/callJSON-RPC tools/call → исходный REST
Auth / квотаПолитика шлюза, иногда написанная дваждыПо-прежнему политика шлюза; обнаружение — отдельный дефолт

Так что «не нужно держать MCP Server» — не «не нужно держать JSON-контракт». Пустые описания, глубокие объекты и остатки 2.0 всплывают на обнаружении или при транскодинге. См. что такое MCP.

Контракт вырастает из OpenAPI 3.x

MCP включают на уровне документа через x-google-api-management.mcp. На отдельной операции x-google-mcp-tool может переименовать, переписать описание или поставить false, чтобы выйти. Каждая выставляемая операция нужна с бэкендом и непустым description. Подходят только GET / POST / PUT / PATCH / DELETE. Имена инструментов должны совпадать с [A-Za-z0-9_.-]{1,128} и быть уникальными на всём шлюзе.

Официальная минимальная форма (на странице YAML; семантика — JSON-объект):

x-google-api-management:
  mcp: true
paths:
  /orders/{orderId}:
    get:
      operationId: getOrderStatus
      description: Returns the current status, carrier, and ETA for an order.
      x-google-mcp-tool:
        name: get_order_status
        description: "Look up the delivery status and ETA of a customer order."
      parameters:
        - name: orderId
          in: path
          required: true
          schema:
            type: string

Описание — главный сигнал, по которому модель решает, когда вызывать. Google просит when / why, а не только что возвращается. Schema пути, query, body и заголовков становятся arguments инструмента. Вложенные объекты в tools/list могут раскрыться не полностью — задокументированное ограничение preview, не сломанный валидатор. Сначала разгладьте OpenAPI локально, затем сделайте Diff с input schema шлюза.

tools/list по умолчанию без аутентификации

По умолчанию кто угодно может сделать POST /mcp и получить каталог: имена, описания, input schema. Для разработки удобно. В продакшене это публикует контракт параметров. Google рекомендует JWT на tools/list. В Public Preview API Key этот метод не защитит. Объектная форма тоже включает MCP глобально; операции, которые не хотите выставлять, нужно пометить x-google-mcp-tool: false.

x-google-api-management:
  mcp:
    tools-list:
      security:
        orderServiceJwt: []

tools/call всегда применяет auth нижележащего REST — заперто обнаружение или нет. Открытый каталог и запертый вызов — разные вещи. Если имена инструментов и schema — секрет, заприте tools/list до выкладки. Это тот же слой, что гайд по вредоносному JSON: чем шире контракт, который видит модель, тем шире поверхность инъекции.

tools/call по-прежнему JSON-RPC

На проводе официальная форма такая:

{"jsonrpc":"2.0","id":1,"method":"tools/call",
 "params":{"name":"get_order_status","arguments":{"orderId":"A-1042"}}}

Шлюз раскладывает arguments обратно в path / query / body / header, прогоняет политику и заворачивает ответ бэкенда в MCP result. При отладке разделяйте слои: внешний конверт — JSON-RPC; внутренняя нагрузка — бизнес-JSON. Ошибка parse принадлежит одному слою или другому. Пример ADK направляет Streamable HTTP на …/mcp и по-прежнему может слать те credentials, которые шлюз уже ждёт.

Подключите шлюз к API hub — конфиг с включённым MCP публикуется с MCP-метаданными и появляется в Agent Registry. Каталог обнаружения сменился. Полевой контракт — нет: это всё та же schema, выросшая из вашего OpenAPI. Обнаружение Skill — другой JSON-документ; см. SEP-2640 и skill://index.json. Не сливайте эти два каталога в одну таблицу.

Ограничения, которые стоит прочитать в Public Preview

  • OpenAPI 2.0 не поддерживается. Сначала поднимите до 3.x.
  • Операции с пустым телом (HTTP 204) не выставляются как инструменты.
  • Слишком глубокие object schema в tools/list могут обрезаться.
  • Один шлюз отдаёт примерно до 1 000 инструментов.
  • MCP и маршрутизация модели не делят один API config.
  • resources / prompts, потоковые ответы и проверки Model Armor ещё на roadmap.

Это не «потом отполируем». Операция с 204 исчезает из каталога, и модель вызовет что-то другое. Обрезанная schema не сойдётся со строгим валидатором и с настоящим бэкендом. Гайд миграции MCP 2026 про версии протокола. Эта статья добавляет: список, который генерирует шлюз, может не равняться полному OpenAPI в репозитории.

Четыре JSON-документа до включения тумблера

  1. OpenAPI 3.x в репозитории. Сначала поднимите 2.0. У каждой выставляемой операции — непустой description, бэкенд и допустимое имя инструмента.
  2. tools/list шлюза. Смотрите, не обрезана ли input schema и не утекли ли лишние операции.
  3. Один настоящий tools/call. Раскладываются ли arguments обратно в REST? Конверт — JSON-RPC 2.0?
  4. Объект безопасности обнаружения. Не выкатывайте с открытым tools/list. Имя JWT-схемы должно уже быть в components.securitySchemes.

Смотреть спецификацию локальными JSON-инструментами

Прежде чем включать MCP, разложите в браузере три текста: OpenAPI (YAML сначала в JSON), один ответ tools/list и объект arguments, который отправите в tools/call.

  • Валидатор JSON — легальна ли грамматика; если есть Schema — сразу required и лишние ключи.
  • JSON ↔ YAML — большинство OpenAPI лежит YAML; сначала конвертируйте, потом Diff с list.
  • JSON Diff — сравните parameters schema в репозитории с inputSchema, который вернул шлюз.

Ничего не уходит из браузера. Разгладьте контракт, потом включайте тумблер шлюза. Шлюз транскодирует. Имена полей и список required не должны разъезжаться вместе с обрезкой preview.

FAQ

Это GA? Свой MCP Server всё ещё нужен?

На 30 сентября 2026 это Public Preview. REST плюс OpenAPI 3.x и четыре метода жизненного цикла можно посадить на шлюз. Resources, prompts, стриминг, stdio или больше примерно 1 000 инструментов — по-прежнему свой сервер.

Если tools/list открыт, разве API Key не защищает вызовы?

Вызовы идут по политике REST. Каталог по умолчанию публикует имена и input schema. API Key не защитит tools/list. В продакшене заприте обнаружение JWT.

Спецификация всё ещё OpenAPI 2.0 / Swagger. Можно включить?

Нет. Сначала поднимите до 3.0.x или 3.1.x, затем добавьте расширение mcp.

Это то же самое, что обнаружение Skill по SEP-2640 в сентябре?

Нет. Обнаружение Skill — skill://index.json или skills/list. Путь шлюза превращает REST-операции в tools/list. Два JSON-документа, два набора полей.

Почему schema в tools/list мельче, чем в OpenAPI?

Preview пишет: глубокие объекты могут раскрыться не полностью. Верьте ответу шлюза. Diff с спецификацией в репозитории покажет, какие required пропали.

Куда делся DELETE, который возвращает 204?

Операции с пустым телом не выставляются как инструменты. Модель не увидит это имя и не вызовет его.

Итог

API Gateway забирает процесс MCP Server. JSON-контракт он не забирает. OpenAPI 3.x вырастает в tools/list. tools/call остаётся JSON-RPC. Политика — та же REST, что уже есть. Открытый каталог, обрезанная вложенная schema и пропавшая операция с 204 — проверки до запуска, не «preview включили и готово».

Сначала разгладьте OpenAPI, ответ list и образец call локально, потом ставьте mcp: true. Шлюз транскодирует. Полевой контракт не должен разъезжаться вместе с ограничениями preview.