Google a fait d'API Gateway un MCP Server distant le 24/09/2026, en Public Preview. La doc officielle a été mise à jour le même jour. Ce texte est du 30/09/2026. On lit le Developers Blog, MCP overview, MCP configure. Conclusion à figer : la passerelle n'écrit pas d'autre outil. Elle transcode l'OpenAPI 3.x déjà déployé en tools/list et tools/call. Le contrat que l'Agent voit reste les paramètres de chemin, query, body et JSON Schema. Home MCP est une autre ligne produit : Home MCP. Comment Harness et MCP se partagent le travail : Agents API vs MCP.
L'utilisateur dit à l'Agent : « où en est la commande A-1042 ? » Le Host n'envoie pas cette phrase directement à Cloud Run. Il envoie d'abord un JSON-RPC tools/call, dont le nom est le get_order_status cloué dans votre OpenAPI, avec les arguments {"orderId":"A-1042"}. La passerelle en fait un GET /orders/A-1042. JWT, quotas et journaux restent sur le chemin REST d'origine. La requête transcodée et le REST direct se ressemblent côté backend. Pourquoi la couche contrat est un objet : Pourquoi l'IA aime JSON.
Ce que la passerelle ouvre vraiment
Au 30/09/2026, le matériau public se coupe en trois paquets, à ne pas mélanger avec Home MCP, Apigee, Agent Gateway :
- Produit : Google Cloud API Gateway comme MCP Server distant. Public Preview. L'officiel le nomme : un service sur Cloud Run, à doter en quelques minutes d'authentification et de quotas, puis à exposer à un Agent, passe par cette entrée légère. Cycle de vie complet, politiques de trafic, monétisation : Apigee. Piloter les appels qu'un Agent lance vers l'extérieur : Agent Gateway.
- Protocole : le client
POSTvers/mcpde la passerelle (avec préfixe de version :/v1/mcp). Supportés :initialize,notifications/initialized,tools/list,tools/call. Les autres méthodes, y comprisresources/*,prompts/*,ping, renvoient JSON-RPC-32601. Pas de stdio, pas de streaming, pas de tâche longue. - Source : l'inventaire d'outils est généré depuis OpenAPI 3.0.x / 3.1.x. L'annotation document
x-google-api-management.mcpouvre l'interrupteur global. L'annotation opérationx-google-mcp-toolchange le nom, la description, ou vautfalsepour sortir. OpenAPI 2.0 n'est pas supporté.
Après la poignée de main, le client doit porter MCP-Protocol-Version sur chaque requête. L'exemple officiel utilise 2025-11-25. Sans cet en-tête, la passerelle retombe sur 2025-03-26. initialize et notifications/initialized n'authentifient pas. Une fois branché sur API Hub, une passerelle MCP entre au catalogue avec ses métadonnées MCP, et apparaît automatiquement dans Agent Registry.
En une phrase. La passerelle est un transcodeur. L'opération REST reste une opération REST. L'Agent gagne un /mcp. Les deux côtés partagent le même OpenAPI, et le même quota.
Le contrat est dans OpenAPI, pas dans un MCP Server à part
Avant, pour qu'un Agent voie l'interface commandes, l'équipe réécrivait souvent un MCP Server, et refaisait routes, authentification, quotas. Maintenant on annote le spec déjà déployé, on déploie la config API, /mcp commence à servir. L'exemple commandes du blog officiel :
openapi: 3.0.4
info:
title: Order Service
version: 1.0.0
x-google-api-management:
mcp: true
backends:
orders-backend:
address: https://orders-a1b2c3-uc.a.run.app
paths:
/orders/{orderId}:
get:
operationId: getOrderStatus
description: Returns the current status, carrier, and ETA for an order.
x-google-backend: orders-backend
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
Avec mcp: true au global, toutes les opérations éligibles deviennent des outils. Le nom d'outil par défaut est operationId, la description vient de description ou summary. Une opération sans description parsable est refusée. Le nom d'outil doit matcher [A-Za-z0-9_.-]{1,128}, et être unique dans tout le spec. Seuls GET / POST / PUT / PATCH / DELETE peuvent être exposés. Chaque opération doit encore avoir un backend.
La description est le signal principal qui dit au modèle quand tendre la main. L'officiel demande d'écrire clairement « quand l'utiliser, pourquoi l'utiliser », pas seulement ce qui est renvoyé. Les écritures, remboursements, suppressions qui ne doivent pas sortir du même spec : x-google-mcp-tool: false pour sortir. Permissions trop larges : MCP malveillant / Fake Skills.
Comment arguments retombe sur REST
Le mapping officiel fige trois couches :
- path / query : deviennent des clés de premier niveau dans
arguments, le nom de clé est le nom de paramètre OpenAPI. - Corps de requête : niché sous l'unique clé
body. Pour créer une ressource, passer{"body":{"fieldName":"value"}}, ne pas étaler les champs au premier niveau. - header : aussi des clés de premier niveau. La passerelle les injecte en en-têtes HTTP backend. On ne peut pas lier un en-tête réservé système, ni un en-tête qui commence par
x-google-.
La lecture de commande est un paramètre path, tools/call ressemble à ceci :
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_order_status",
"arguments": {
"orderId": "A-1042"
}
}
}
Si le même service crée aussi des commandes, arguments doit envelopper les champs métier dans body. La forme ci-dessous passe ; la version aplatie doit être refusée à la passerelle :
{
"ok_shape": {
"body": {
"sku": "mug-blue",
"qty": 2
}
},
"flat_body": {
"sku": "mug-blue",
"qty": 2
},
"wrong_type": {
"body": {
"sku": "mug-blue",
"qty": "两件"
}
},
"extra_field": {
"body": {
"sku": "mug-blue",
"qty": 2,
"extra_cmd": "skip_confirm"
}
}
}
Seul ok_shape peut devenir un body REST. flat_body n'a pas la clé body, l'officiel mappe ça sur JSON-RPC -32602 (Invalid tool arguments). "两件" et extra_cmd doivent déjà être refusés par votre Schema, pas attendre une erreur métier du backend. Le contrat d'entrée correspondant peut d'abord être cloué ainsi :
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"additionalProperties": false,
"required": ["body"],
"properties": {
"body": {
"type": "object",
"additionalProperties": false,
"required": ["sku", "qty"],
"properties": {
"sku": { "type": "string", "pattern": "^[a-z0-9-]+$" },
"qty": { "type": "integer", "minimum": 1, "maximum": 99 }
}
}
}
}
body, le backend ne voit pas les champs. Un Schema trop large à gauche, tools/list diffuse des capacités en trop.tools/list est public par défaut
L'officiel coupe l'authentification en trois couches :
initialize/notifications/initialized: pas d'authentification.tools/call: réutilise la politique de l'opération REST sous-jacente. Si REST veut un JWT ou une API key, l'appel MCP aussi.tools/list: pas d'authentification par défaut. Pratique en debug local, ça veut aussi dire que quiconque demande récupère les noms d'outils et l'inputSchema.
En production, protégez la surface de découverte avec un JWT. L'écriture transforme mcp d'un booléen en objet, tout en ouvrant MCP au global :
x-google-api-management:
mcp:
tools-list:
security:
orderServiceJwt: []
On ne peut nommer qu'un scheme JWT de components.securitySchemes. En Public Preview, une API key ne protège pas tools/list. La forme objet de mcp expose toutes les opérations éligibles ; pour n'en publier qu'une partie, les autres doivent explicitement porter x-google-mcp-tool: false. Une fois la surface de découverte publique, un Host malveillant sait quels endpoints d'écriture vous avez. C'est le même type de problème que Fake Skills : l'inventaire d'outils est lui-même une surface d'attaque.
Ce que la Preview a coupé
Le blog officiel et la doc écrivent la frontière dans le même paragraphe. Au 30/09/2026 :
- Une réponse vide (par exemple HTTP 204) n'est pas exposée comme outil.
- Un object schema très imbriqué peut ne pas se déployer entièrement dans
tools/list. - Une passerelle : 1000 outils au plus.
- Une même API config ne peut pas ouvrir MCP et Model Routing en même temps. Si
x-google-api-management.mcpest ouvert,x-google-model-routerne peut pas servir. resources/*,prompts/*, stdio, streaming, tâches longues : non supportés. Sur la feuille de route : MCP resources / prompts, flux de réponse, inspection de charge Model Armor.
Ces limites se voient directement dans le JSON. Une opération 204 disparaît de l'inventaire, ce n'est pas un oubli d'abonnement côté client. Quand un champ profond est tronqué dans tools/list, le modèle remplit arguments d'après un Schema incomplet, et omet plus facilement body ou invente des clés en trop. À la recette, c'est l'OpenAPI original qui fait foi, pas seulement l'inventaire renvoyé par la passerelle.
Ne mélangez pas erreur de protocole et erreur HTTP
MCP sépare échec de transport et échec de protocole. Beaucoup de clients traitent un non-200 comme un crash de transport. Donc, pour une erreur de protocole ou d'application, la passerelle renvoie souvent HTTP 200, puis explique dans l'objet d'erreur JSON-RPC. Dans le tableau officiel, les lignes où les développeurs trébuchent le plus :
- Autre chose que
POSTvers/mcp: HTTP 405. - Le corps n'est pas du JSON :
-32700, HTTP 400. - JSON valide mais pas JSON-RPC :
-32600, HTTP 200. Vérifierjsonrpc,method,id. - Méthode non supportée :
-32601, HTTP 200. - Mauvaise version de protocole, ou
initializesans chaîneprotocolVersion:-32602. - Outil inconnu, paramètre manquant,
bodypas nested :-32602. - Échec d'authentification : HTTP 401 / 403, avec
WWW-Authenticate.
Une erreur métier backend reste en général un JSON-RPC de succès en HTTP 200, result.isError à true, et le corps d'erreur backend est dedans. Ne prenez pas isError: true pour « le protocole est passé, on peut tendre la main suivante ». Si l'objet rate le Schema, la main suivante ne doit pas partir. Échange d'objets entre Agents : Claude Agent échange du JSON.
Recetter dans la Boîte à outils JSON
- Collez les exemples lecture et création de commande dans le formatage JSON, confirmez que ça parse.
- Avec JSON → Schema, remontez le contrat d'arguments depuis
ok_shape, puis ajoutezbody,additionalProperties,pattern. - Les mêmes champs via MCP Tool. S'il faut aussi les donner au modèle en Function Calling, encore Function Calling.
- Vous avez déjà une réponse REST, pas encore d'OpenAPI 3.x : d'abord JSON → OpenAPI, puis complétez à la main
x-google-api-management.mcpet les descriptions. - Jetez
flat_body,"两件",extra_cmddans la validation Schema, confirmez le refus.
Tout se traite dans le navigateur, rien n'est envoyé. D'abord un objet capable de refuser un body aplati et trop d'outils publics, ensuite seulement on branche la passerelle sur le McpToolset d'ADK.
FAQ
Est-ce le même produit que Google Home MCP ?
Non. Home MCP, ce sont cinq outils maison. API Gateway transforme votre propre REST en MCP Server distant.
OpenAPI 2.0 peut-il activer MCP directement ?
Non. Il faut 3.0.x ou 3.1.x. Migrer d'abord.
tools/list exige-t-il une authentification par défaut ?
Par défaut, non. En production, un JWT. Une API key ne protège pas la surface de découverte. tools/call suit encore l'authentification REST.
Pourquoi le corps de requête doit-il être dans body ?
La passerelle mappe selon OpenAPI. path / query / header au premier niveau, le corps ne reconnaît que body. Sans ça : -32602.
Est-ce le même article que « Agents API vs MCP » ?
Non. Celui-là écrit le Harness OpenAI. Celui-ci ne traite que le transcodage API Gateway depuis OpenAPI.
En résumé
La Public Preview d'API Gateway rentre MCP dans la passerelle déjà là : annoter OpenAPI 3.x, /mcp commence à transcoder. Ça ne remplace pas REST, et ça n'invente pas un second inventaire d'outils. L'Agent voit encore vos noms de paramètres, le body imbriqué et le Schema. tools/list est public par défaut, une réponse vide n'apparaît pas, un schema profond peut être tronqué, une passerelle : mille outils au plus. Ce que le développeur doit tenir : quelles opérations exposer, si arguments est nested selon le mapping, si la surface de découverte a un JWT. La suite n'est pas d'abord de brancher ADK. C'est d'abord de refuser flat_body et une écriture sans description.