La question revient souvent : « peut-on vraiment connecter un agent IA à Google Ad Manager, et le faire dialoguer avec d'autres agents ? » La réponse est oui, et ça ne demande pas de réécrire quoi que ce soit. Tout tient dans une seule chose qu'il faut réussir : la connexion. Le reste — exposer l'agent, le déployer, l'orchestrer — est de la plomberie standard que les frameworks d'agents savent déjà faire.
Cet article (1/4 de la série « OrbiAds en A2A ») montre, pas à pas, comment un agent parle à Google Ad Manager via OrbiAds, et comment l'authentification fonctionne réellement.
MCP et A2A : deux protocoles complémentaires
On confond souvent les deux. La distinction est pourtant simple — et c'est elle qui structure toute la suite.
Agent ↔ outils. Le canal par lequel un agent appelle des outils et des données. Le serveur MCP d'OrbiAds expose 290+ opérations Google Ad Manager derrière un seul endpoint.
Agent ↔ agent. Le canal par lequel un agent en découvre un autre et lui délègue une tâche.
Notre approche n'invente rien : on emballe le MCP OrbiAds existant dans un petit agent, puis on expose cet agent en A2A. Un agent A2A se comporte alors comme un agent-CLI : un runtime, une instruction (le « skill »), des outils (le MCP), et une boucle.
L'agent GAM minimal
Avec l'Agent
Development Kit (ADK) de Google, l'agent tient en quelques lignes : un LlmAgent, un MCPToolset pointé sur OrbiAds, et un tool_filter qui borne les outils exposés. to_a2a() transforme l'agent en service A2A et génère sa carte automatiquement.
from google.adk.agents import LlmAgent
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
from google.adk.a2a.utils.agent_to_a2a import to_a2a
orbiads_mcp = MCPToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://orbiads.com/mcp",
headers={"Authorization": f"Bearer {TOKEN}"},
),
tool_filter=["check_credentials", "select_gam_network", "inventory"],
)
root_agent = LlmAgent(
name="gam_inventory_sentinel",
model="gemini-2.5-flash", # MODEL = your choice
instruction="You are a READ-ONLY GAM inventory sentinel. ...",
tools=[orbiads_mcp],
)
a2a_app = to_a2a(root_agent, port=10000) # serves /.well-known/agent-card.json Détail important : to_a2a() expose l'agent comme un skill (pas
un par outil). Le tool_filter borne les capacités en interne — l'angle
est l'encapsulation (un agent métier net), pas « moins de tokens ».
Le cœur : la connexion OAuth
C'est ici que tout se joue. OrbiAds fonctionne en OAuth délégué utilisateur : l'utilisateur autorise une fois, OrbiAds garde un refresh token chiffré par tenant et rafraîchit les jetons d'accès.
Point clé : OrbiAds n'accepte que authorization_code + refresh_token — pas de client_credentials (pas de
machine-to-machine sans humain). D'où trois cas d'usage :
Ex. Claude Desktop : connexion OAuth native, rien à coder.
Bootstrap d'un jeton une fois via get_token.py, puis le refresh token prend le relais.
Connecteur Agent Identity 3LO managé (article 2).
Au consentement, Google demande quel compte autorise l'application — c'est l'utilisateur qui autorise, jamais l'agent tout seul :
Astuce qui sauve des heures : ADK charge le .env du dossier de l'agent, pas les variables du shell — c'est là qu'il faut mettre le jeton écrit par get_token.py.
L'Agent Card : ce que voit le monde A2A
Dès que l'agent tourne, il sert sa carte sur /.well-known/agent-card.json — le contrat
public A2A : nom, description, skills, URL. C'est exactement ce qu'un autre agent
lit pour décider de déléguer. (L'ancien chemin /.well-known/agent.json reste servi en alias rétro-compatible par le SDK A2A.)
{
"protocolVersion": "0.3.0",
"name": "GAM Inventory Sentinel",
"description": "Read-only Google Ad Manager agent (via OrbiAds).",
"url": "https://your-agent-endpoint/a2a",
"version": "1.0.0",
"provider": { "organization": "OrbiAds", "url": "https://orbiads.com" },
"capabilities": { "streaming": true },
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain"],
"skills": [
{
"id": "inventory_health",
"name": "GAM inventory monitoring",
"description": "Checks the OrbiAds->GAM connection and reports inventory availability (read-only).",
"tags": ["gam", "inventory", "adops", "read-only"]
}
]
}L'Agent Card servie par to_a2a() : nom, description, skills, URL — exactement ce qu'un autre agent lit pour décider de déléguer.
Lancer l'agent en local
Deux façons de l'exécuter, selon ce qu'on veut voir :
# serve the agent over A2A (card at :10000/.well-known/agent-card.json)
uvicorn gam_sentinel.agent:a2a_app --port 10000
# or the ADK dev UI to chat and inspect the trace
adk web . # http://127.0.0.1:8000 Garde-fou indispensable : reste sur un réseau GAM de test (jamais un réseau client réel). Le réseau actif est un état serveur, basculé via network(action='switch_network', …). Nos agents affichent le réseau actif et s'arrêtent s'il est inattendu.
La suite
La connexion est faite et prouvée. Dans l'article 2, on déploie cet agent sur Vertex Agent Engine et on le rend découvrable en A2A.
