Votre carte Agent A2A nécessite une URL publique : tester les notifications push A2A sur localhost
Votre carte Agent A2A nécessite une URL publique. Découvrez comment tester les notifications push sur localhost avec un tunnel stable et une inscription webhook résistante à SSRF.

Quick answer
Test des notifications push A2A sur localhost (URL de la carte Agent): quick comparison answer
Choose the tunnel tool based on the network model: public HTTPS URLs for webhooks and demos, private mesh access for internal apps, and managed infrastructure when policy controls matter most.
Which tunnel tool is best for public webhook testing?
Use a public HTTPS localhost tunnel with stable URLs. InstaTunnel focuses on webhook testing, demos, OAuth callbacks, and MCP endpoint workflows.
When should I choose a private network tool instead?
Choose a private mesh or Zero Trust tool when every user and service should stay inside a controlled private network.
Le protocole Agent2Agent (A2A) a rapidement grandi. Google l’a annoncé en avril 2025, la Linux Foundation l’a pris en charge en juin 2025, et la spécification stable v1.0 est sortie le 12 mars 2026. En août 2026, il est devenu un projet hébergé par l’Agentic AI Foundation (AAIF). Deux de ses blocs de construction sont importants pour le développement local. Notifications push sont de simples webhooks : le serveur agent envoie un HTTP POST à une URL enregistrée par le client. La carte Agent est un document JSON servi depuis un chemin bien connu.
Les deux rencontrent le même obstacle sur un ordinateur portable. Des pairs distants ne peuvent pas atteindre localhost, et un serveur agent bien conçu peut refuser d’envoyer un POST vers celui-ci. Ce guide explique pourquoi, comment tester les notifications push A2A depuis votre machine via un tunnel public, et comment enregistrer des webhooks sans ouvrir une faille SSRF.
Il s’agit des callbacks agent-à-agent et d’un enregistrement webhook sûr. Il omet délibérément les flux de découverte OAuth et d’autorisation-serveur.
Où en est A2A en novembre 2026
- v1.0 a été livré le 12 mars 2026. Le blog du projet et le guide Turing Post l’attribuent à cette date, et Turing Post mentionne un correctif v1.0.1 en mai. La version 1.0 était la première spécification stable et prête pour la production. Sa définition protobuf,
a2a.proto, est la source normative, et les formes JSON, gRPC et REST en sont générées. - La gouvernance a évolué en deux étapes. Google a donné A2A à la Linux Foundation en juin 2025. Le 17 août 2026, il a été annoncé comme un projet hébergé par l’AAIF, l’organisme de la Linux Foundation lancé en décembre 2025 autour de MCP, goose et AGENTS.md. L’annonce du projet A2A est datée du 27 août 2026 et décrit A2A comme un projet Growth Stage de l’AAIF. La couverture presse de ce déménagement s’est étendue du 17 au 20 août. Aucun contrôle n’a changé de mains. Google avait déjà donné la spec, et chaque projet AAIF conserve ses propres mainteneurs et son calendrier de versions.
- L’écosystème est large. La Linux Foundation a enregistré plus de 150 organisations de soutien au cap d’un an du projet en avril 2026. Des SDK officiels existent pour Python, Go, JavaScript, Java, .NET et Rust. Le SDK JavaScript (
@a2a-js/sdk) est passé en disponibilité générale 1.0.0 le 22 juillet 2026, avec une compatibilité opt-in v0.3 pour des migrations par étapes. - v1.0 définit trois liaisons standard du protocole : JSON-RPC 2.0 sur HTTP(S), gRPC et HTTP+JSON/REST.
L’issue pratique est que la spec est suffisamment stable pour investir dans des outils et des travaux de sécurité. Mais de nombreux agents déployés servent encore des formes de carte pré-1.0, il faut donc vérifier la version de chaque pair avant de tester contre lui.
Deux URLs publiques, pas une
Le titre dit « votre carte Agent a besoin d’une URL publique ». C’est vrai, mais seule la moitié d’un test A2A local en a besoin, et mélanger les deux moitiés provoque la plupart des confusions.
1. L’URL de la carte agent (l’adresse du serveur). Les serveurs A2A publient leur carte à l’adresse https://{server_domain}/.well-known/agent-card.json. Le chemin well-known suit la RFC 8615. Les anciens serveurs pré-1.0 utilisaient couramment /.well-known/agent.json, et des outils tels que a2aops reviennent à ce chemin historique lorsqu’ils vérifient une carte.
La carte répertorie les points de terminaison que les clients doivent appeler dans supportedInterfaces. Il s’agit d’un tableau ordonné dont la première entrée est l’interface préférée. Chaque entrée porte un url, un protocolBinding (JSONRPC, GRPC ou HTTP+JSON) et une protocolVersion, avec un champ optionnel tenant. La spec indique qu’une URL d’interface doit être une URL HTTPS absolue en production.
Si votre serveur tourne localement et qu’un client distant doit y accéder, comme un orchestrateur hébergé, l’agent d’un collègue ou une démonstration cloud, la carte et ses URL d’interface doivent être résolubles publiquement.
2. L’URL du webhook (l’adresse du client). Les notifications push circulent dans l’autre sens. Le client enregistre un webhook et le serveur y POST. Si vous développez le client localement et que vous testez contre un agent distant, votre webhook doit avoir une adresse publique.
Si vous exécutez deux agents locaux qui communiquent entre eux depuis des réseaux différents, vous avez besoin des deux : deux noms d’hôtes publics stables.
Comment fonctionnent les push notifications A2A
Les notifications push existent pour des tâches très longues (minutes, heures ou jours) et pour les clients qui ne peuvent pas maintenir une connexion de streaming ouverte, comme les applications mobiles ou les fonctions serverless. L’agent indique le support avec capabilities.pushNotifications: true dans sa carte. Si le drapeau est faux ou absent, les opérations de configuration push doivent retourner PushNotificationNotSupportedError.
- Enregistrer une configuration. Le client envoie un
TaskPushNotificationConfigsoit en ligne dans la requêteSendMessage(sousconfiguration, l’ID de tâche laissé vide) soit séparément via l’opération de création sur une tâche existante. La spécification v1.0 définit les opérations Create, Get, List et Delete. En JSON-RPC ce sontCreateTaskPushNotificationConfig,GetTaskPushNotificationConfig,ListTaskPushNotificationConfigsetDeleteTaskPushNotificationConfig. En REST, elles se trouvent sous/tasks/{id}/pushNotificationConfigs. - Ce que porte la configuration. Elle contient une
urlde webhook, untokenoptionnel pour la validation côté client, et des détails d’authentication(schemeetcredentials) qui indiquent au serveur comment s’authentifier vers votre webhook. Elle porte également unidoptionnel et letaskId. - Le serveur POST sur les changements d’état. Le corps est un
StreamResponse, la même forme utilisée en streaming. Il contient exactement l’un des élémentstask,message,statusUpdateouartifactUpdate. - Votre récepteur le vérifie. L’exemple du guide montre que le serveur envoie un en-tête
Authorizationconstruit à partir de vos réglagesauthentication, plusX-A2A-Notification-Tokenportant letokenque vous avez fourni.
La spec n’est pas d’accord sur chaque détail, alors concevez le récepteur de manière défensive :
- Le texte normatif ne nomme pas d’en-tête de token. L’exemple montre
X-A2A-Notification-Token. D’autres implémentations diffèrent : la crate Rusta2a-protocol-serverenvoie à la foisX-A2A-Notification-Tokenet unA2A-Notification-Tokensans préfixe, acceptez donc les deux. - Les exemples dans la spec montrent le
Content-Typedu webhook commeapplication/a2a+jsonà un endroit etapplication/jsonà un autre. Analysez le corps JSON sans insister sur un seul type de média.
Une inscription ressemble à ceci, de manière approximative. Elle est simplifiée, alors confirmez la disposition exacte des champs avec a2a.proto pour votre version du SDK :
{
"jsonrpc": "2.0",
"id": "1",
"method": "CreateTaskPushNotificationConfig",
"params": {
"taskId": "task-123",
"url": "https://a2a-client-dev.example.com/webhooks/a2a",
"token": "per-task-secret-value",
"authentication": { "scheme": "Bearer", "credentials": "webhook-credential" }
}
}
Envoyez l’en-tête A2A-Version: 1.0 à chaque requête. La spec exige que les clients l’envoient afin qu’un agent qui met à jour plus tard ne change pas silencieusement le comportement.
Un fragment minimal de carte au style v1.0 montre où se situe l’adresse publique. Une carte complète nécessite également defaultInputModes, defaultOutputModes et skills :
{
"name": "Flight Booking Agent",
"description": "Handles flight reservations.",
"version": "1.0.0",
"supportedInterfaces": [
{
"url": "https://a2a-agent-dev.example.com/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
],
"capabilities": { "streaming": true, "pushNotifications": true }
}
Ce que la spec demande des expéditeurs et des destinataires
- Les serveurs doivent tenter la livraison au moins une fois et peuvent réessayer avec un backoff exponentiel. Ils devraient utiliser un délai d’attente du webhook d’environ 10 à 30 secondes et peuvent s’arrêter après des échecs répétés.
- Les destinataires doivent répondre avec un statut 2xx pour accuser réception, doivent traiter les notifications de manière idempotente car des duplications peuvent survenir, et doivent vérifier que le task ID correspond à une tâche attendue.
- Le guide asynchrone d’A2A indique qu’après avoir vérifié l’authenticité d’une notification, un client appelle généralement
GetTaskavec l’ID de la notification pour obtenir l’état complet et actuel. Considérez la charge utile comme un déclencheur et réinterrogez la tâche avant d’agir sur quoi que ce soit d’important.
Pourquoi localhost casse les push notifications A2A
Trois échecs distincts se cachent derrière « ça marche sur ma machine ».
La carte publie une adresse que personne d’autre ne peut atteindre. De nombreux cadres construisent la carte à partir de l’adresse de liaison, donc la carte affiche http://localhost:8000/a2a. Un client distant récupère la carte (si elle est atteignable), puis suit supportedInterfaces[0].url vers sa propre interface de loopback. La solution est de définir explicitement l’URL publique de base du serveur afin que la carte reflète le nom d’hôte du tunnel.
Le agent ne peut pas atteindre votre webhook. Si votre webhook est http://localhost:9000/hook, l’agent distant résout cela vers lui-même, et rien n’arrive.
Un serveur bien construit peut refuser d’essayer. La spec indique que les serveurs ne doivent pas poster simplement à n’importe quelle URL fournie par le client, car cela ouvre des attaques SSRF et d’amplification DDoS. Les implémentations réelles répondent à cela de différentes manières :
- La crate Rust
a2a-protocol-server(0.15.0) valide les URLs webhook lors de la création de la config et à nouveau lors de la livraison. Elle rejette les cibles loopback, privées et link-local, ainsi quelocalhost,.localet.internal. Son échappatoireallow_private_urls()est documentée comme destinée aux tests et comme désactivant la protection SSRF. - Une pull request visant le SDK Python officiel (#1164) décrit le problème clairement. L’expéditeur a utilisé
push_info.urlexactement tel quel, sans vérifications. La PR ajoute une validation à l’envoi concernant le schéma, la résolution DNS et les destinations publiques uniquement, avec une option d’exclusionallow_private_push_urlspour les opérateurs dont les webhooks résident sur des réseaux privés. Une PR chevauchante (#1169) couvre le même terrain, et je ne peux pas confirmer si l’une ou l’autre a été fusionnée. Vérifiez la version du SDK que vous utilisez.
Ainsi, savoir si localhost fonctionne comme webhook dépend du SDK et de la version de votre serveur. Là où cela fonctionne, c’est parce que la garde manque. Désactiver la garde pour que 127.0.0.1 passe les tests est une voie de code que vous n’useriez pas en production. Un tunnel public donne à votre webhook une adresse HTTPS publique réelle et globale qui passe la même validation qu’une endpoint de production.
Le contexte de sécurité : SSRF et webhook
Le webhook est une entrée influençable par définition. Quiconque enregistre une configuration push choisit où votre serveur envoie des requêtes HTTP. Le guide de sécurité A2A (juin 2026) appelle l’URL du webhook sa propre surface d’attaque, avec SSRF si les destinations sortants ne sont pas autorisées et usurpation si le destinataire n’authentifie pas les notifications.
La documentation A2A énumère des mitigations pour les serveurs : autorisation des domaines de confiance (allowlisting), vérification de possession telle que challenge-réponse, et contrôles réseau tels que des pare-feu de sortie. Pour les destinataires, elle indique que le point de terminaison doit vérifier que les notifications proviennent réellement du serveur légitime, en utilisant des signatures, des tokens ou le token enregistré. Elle indique également que les notifications doivent comporter un horodatage afin de rejeter les anciennes, et recommande des IDs uniques pour les événements critiques afin d’attraper les replays. La documentation décrit aussi une procédure optionnelle JWT+JWKS pour la vérification asymétrique.
L’avis Apache Camel montre comment un validateur peut mal tourner :
- CVE-2026-71569 (Apache Camel, publié le 29 octobre 2026). Le composant
camel-a2aWebhookUrlValidatorclassifiait des hôtes en deux endroits qui n’étaient pas d’accord. Un hôte écrit sous forme d’adresse IP littérale était apparié à des préfixes de chaîne qui incluaient l’intervalle unique-localfc00::/7. Un nom d’hôte résolu et vérifié avec des prédicats JDK (isLoopbackAddress,isSiteLocalAddress, etc.) ne couvrait pasfc00::/7. Un nom résolu enfc00::/7a donc franchi une garde qui refusait l’identique littéral.- Le répartiteur envoyait aussi tout en-tête
Authorizationconfiguré à cette adresse. L’attaquant fournit le schéma et les informations d’identification, ce qui n’est pas une fuite des secrets de la victime. - Cela concerne la version 4.21.0 jusqu’à 4.22.2. Les correctifs arrivent dans 4.22.2 et 4.23.0, et la ligne 4.21.x est en fin de vie sans correctif. Le composant a été introduit en 4.21.0 et est marqué comme Prévisualisation.
- Le score est Medium (CVSS 3.1 score 4.8). La requête est aveugle, car la réponse n’est pas relayée au caller. L’exploitation nécessite aussi que le nom se résolve en
fc00::/7, un service HTTPS écoutant là-bas, et une poignée TLS réussie pour ce nom. - La pré-vérification de chaîne était également erronée dans l’autre sens. Elle correspondait au nom d’hôte brut sans vérifier d’abord s’il s’agissait d’une IP littérale, donc des noms légitimes commençant par
fcoufd, tels quefcm.googleapis.com, ont été refusés.
- Le répartiteur envoyait aussi tout en-tête
- Le SDK Python officiel. La PR #1164 indique deux risques résiduels. Le rebinding DNS entre la validation et le POST reste possible, car la résolution et la connexion résolvent le nom séparément. Un relecteur a également noté que les redirections ne sont pas revalidées, donc le client HTTP doit maintenir
follow_redirects=False, ce qui est la valeur par défaut de httpx.
Une checklist d’inscription webhook SSRF-safe
Si vous construisez ou exploitez un serveur A2A, validez par couches :
- HTTPS uniquement. Rejetez d’autres schémas et URL portant des identifiants intégrés. Certains garde-fous SDK permettent aussi
httpen clair. Renforcez cela en production. - Restreindre les ports. Autoriser 443 sauf raison documentée.
- Résoudre puis classer chaque adresse. Une mauvaise réponse suffit à faire échouer l’URL entière. La résolution capture aussi les écritures décimales, hexadécimales et octales des hôtes comme
2130706433, que la correspondance de chaînes manquerait. Dépliez les adresses IPv4 imbriquées dans IPv6, NAT64 et 6to4 avant de les classer, et assurez-vous quefc00::/7et100.64.0.0/10soient couverts. - Valider à l’enregistrement et à la livraison. Les configurations peuvent arriver par plusieurs chemins (en ligne dans une requête Send ou via l’opération dédiée), et le DNS peut changer entre les deux instants.
- Fermer la fenêtre de rebinding. Là où votre client HTTP le permet, connectez-vous à l’adresse que vous avez validée tout en conservant le nom d’hôte d’origine pour TLS et l’en-tête
Host. La crate Rust suit une voie différente pour les cibleshttps://. Elle ne lie pas l’adresse IP et explique qu’un rebinding vers une adresse privée échoue la négociation TLS parce que l’attaquant ne peut pas présenter un certificat valide pour votre nom d’hôte. Choisissez délibérément une approche. - N’en faites jamais suivre des redirections lors de la livraison des push.
- Vérifiez la propriété avec un challenge avant d’envoyer de vrais événements.
- N’attachez pas d’identifiants à des destinations non validées. Ajoutez un proxy de sortie ou une politique réseau comme défense en profondeur.
- Refuser l’injection d’en-têtes. Refusez les caractères CR ou LF dans les valeurs
tokenetauthenticationavant de les mettre dans les en-têtes.
Un point de départ Python pour les étapes 1 à 3 suit. Je l’ai exécuté sur Python 3.13. Il rejette les cibles loopback, privées, link-local, CGNAT et unique-local, les hôtes codés en entier, localhost, IPv4-mappés et IPv4-compatibles IPv6, NAT64 et adresses 6to4 enveloppant des IPv4 privés, les ports mauvais et les informations d’identification intégrées. Il accepte les hôtes publics. Les règles is_global de Python ont changé entre les versions, donc retestez sur votre propre version :
import ipaddress
import socket
from urllib.parse import urlsplit
ALLOWED_PORTS = {443}
NAT64 = ipaddress.ip_network("64:ff9b::/96")
def unwrap(ip):
"""Return the IPv4 hidden inside an IPv6 address, if there is one."""
if isinstance(ip, ipaddress.IPv6Address):
if ip.ipv4_mapped: # ::ffff:a.b.c.d
return ip.ipv4_mapped
if ip in NAT64: # 64:ff9b::/96
return ipaddress.IPv4Address(int(ip) 0xFFFFFFFF)
if ip.sixtofour: # 2002::/16
return ip.sixtofour
if int(ip) 32 == 0 and int(ip) 1: # deprecated ::a.b.c.d
return ipaddress.IPv4Address(int(ip) FFFFFFFF)
return ip
def check_webhook_url(url: str) -> list[str]:
parts = urlsplit(url)
if parts.scheme != "https" or not parts.hostname:
raise ValueError("webhook must be an https URL with a host")
if parts.username or parts.password:
raise ValueError("credentials in the URL are not allowed")
try:
port = parts.port or 443
except ValueError:
raise ValueError("invalid port")
if port not in ALLOWED_PORTS:
raise ValueError("port not allowed")
public_ips = []
for *_, sockaddr in socket.getaddrinfo(parts.hostname, port, type=socket.SOCK_STREAM):
ip = ipaddress.ip_address(sockaddr[0].split("%")[0])
# is_global rejects private, loopback, link-local, unique-local and CGNAT.
if not unwrap(ip).is_global:
raise ValueError(f"{ip} is not a public address")
public_ips.append(str(ip))
return public_ips # connect to one of these, not to a fresh DNS lookup
Sur le côté récepteur, comparez le token en temps constant, acceptez les deux orthographes d’en-tête, répondez rapidement et récupérez l’état séparément. J’ai testé ce gestionnaire FastAPI. Il renvoie 401 pour un token manquant ou incorrect et 200 pour l’un des noms d’en-tête :
import hmac
import os
from fastapi import FastAPI, Header, HTTPException, Request
app = FastAPI()
EXPECTED = os.environ["A2A_WEBHOOK_TOKEN"]
@app.post("/webhooks/a2a")
async def a2a_webhook(
request: Request,
x_a2a_notification_token: str = Header(default=""),
a2a_notification_token: str = Header(default=""),
):
token = x_a2a_notification_token or a2a_notification_token
if not hmac.compare_digest(token.encode(), EXPECTED.encode()):
raise HTTPException(status_code=401)
event = await request.json() # accepts application/json or application/a2a+json
# enqueue event; re-fetch the task with GetTask before acting on it
return {"received": True}
Si votre serveur envoie aussi un en-tête Authorization issu de authentication, vérifiez-le aussi. Le token seul prouve seulement que l’expéditeur connaissait un secret par tâche.
Tester les notifications push A2A sur localhost avec un tunnel
Un tunnel donne à votre port local un nom d’hôte HTTPS public, vous permettant d’exécuter le flux réel. N’importe quel outil de tunnels fonctionne. Les propriétés importantes sont HTTPS, un nom d’hôte stable, et le support des requêtes POST simples et non interactives.
Étape 1 : Réserver un nom d’hôte stable. Des URL aléatoires de session cassent les tests A2A. Les clients mettent en cache les cartes, et la spec indique que les serveurs doivent envoyer les en-têtes Cache-Control et ETag, et que les clients doivent les respecter. Les configurations push enregistrées contiennent l’URL de votre webhook. Lorsque le nom d’hôte change, elles ne pointent sur rien.
Un tunnel jetable est suffisant pour un premier test rapide. cloudflared tunnel --url http://localhost:8000 crée une URL aléatoire trycloudflare.com sans compte. Cloudflare documente plusieurs limites pour ces Quick Tunnels :
- Il n’y a aucune garantie de disponibilité.
- Chaque tunnel prend en charge jusqu’à 200 requêtes en vol, et les requêtes supplémentaires renvoient un 429.
- Le nom d’hôte change à chaque fois.
- Server-Sent Events ne sont pas pris en charge. Les opérations de streaming A2A (
SendStreamingMessage,SubscribeToTask) utilisent SSE, donc un Quick Tunnel peut transporter les webhooks push et les appels plain request/response mais pas les tests de streaming. - Quick Tunnels ne fonctionnent pas si un
config.yamlexiste dans~/.cloudflared. - Quick Tunnels disposent désormais d’un drapeau optionnel
--allowed-mailqui restreint l’URL derrière un PIN à usage unique par e-mail. Cloudflare indique qu’il nécessite une session de navigateur interactive et ne prend pas en charge les clients non interactifs. Un serveur agent POSTant vers votre webhook ne peut pas accomplir cela, donc désactivez-le pour les callbacks A2A.
Pour tout test itératif, utilisez un tunnel nommé ou le sous-domaine réservé par un autre fournisseur.
Étape 2 : Faites dire à la carte l’adresse publique. Configurez l’URL publique de base de votre agent à partir d’une variable d’environnement et reconstruisez la carte à partir de celle-ci. Puis vérifiez-la depuis l’extérieur de votre réseau :
curl -s https://a2a-agent-dev.example.com/.well-known/agent-card.json | jq '.supportedInterfaces'
Vous devriez voir le nom d’hôte du tunnel, pas localhost. Si un pair utilise une carte au format pré-1.0, a2aops compat <base-url> imprime une checklist de migration v0.x vers v1.0. C’est un petit outil bêta tiers, traitez donc sa sortie comme une indication.
Étape 3 : Tunneliser le récepteur webhook. Exécutez le récepteur ci-dessus sur son propre port avec son propre nom d’hôte public, ou sur un chemin acheminé.
Étape 4 : Enregistrer et déclencher. Créez la configuration push pour une tâche longue, puis lancez la tâche. Observez l’inspecteur de requêtes du tunnel (la plupart des outils en proposent un) pour les en-têtes exacts et le corps que le serveur envoie.
Étape 5 : Exécuter les tests négatifs. Ils comptent autant que le chemin heureux :
- Enregistrez
https://127.0.0.1/hookethttps://localhost/hook. Un serveur durci devrait rejeter les deux. - Enregistrez un nom d’hôte que vous contrôlez qui résout une adresse privée, et un hôte boucle décimale tel que
https://2130706433/hook. Les deux devraient être rejetés. - Envoyez une requête avec un token wrong ou manquant. Votre récepteur devrait renvoyer 401.
- Répétez une notification capturée ancienne. Votre récepteur devrait la rejeter comme périmée ou en double.
- Retournez un 5xx depuis le récepteur une fois et confirmez que le serveur réessaie. Puis retournez un 401 et voyez s’il s’arrête. Le comportement de réessai varie, et la crate Rust ne réessaie que les 408, 429 et 5xx.
Pièges courants
- Dérive de la carte et du tunnel. Vous redémarrez le tunnel, le nom d’hôte change, et la carte (et chaque configuration push enregistrée) affiche toujours l’ancien.
- Cartes pré-1.0. Un pair peut servir
/.well-known/agent.jsonou un schéma plus ancien. La v1.0 a introduit des changements importants, y compris une structurePartunifiée, des méthodes renommées et de nouveaux champs d’interface de carte. - Tunnel public, agent public. Un tunnel expose votre serveur de développement à Internet. Ne mettez pas de secrets dans la carte, ne mettez pas de données de production derrière un agent de développement, et fermez le tunnel lorsque vous avez fini.
- Gestionnaires de webhooks lents. Accusez réception rapidement et traitez de façon asynchrone. La crate Rust par défaut donne un délai d’attente de 10 secondes pour les requêtes, et la spec recommande 10 à 30 secondes. Un gestionnaire lent invite les réessais et les livraisons en double.
- Jetons partagés. Utilisez un jeton unique et à usage unique par configuration push.
FAQ
Une carte Agent A2A doit-elle être à une URL publique ? Oui, pour la découverte par des clients distants. Elle est servie à /.well-known/agent-card.json sur le domaine de l’agent, et les URL d’interface intérieures doivent être atteignables par quiconque vous appellera. Les cartes peuvent également être récupérées à partir d’un registre ou configurées directement.
Pourquoi mon serveur A2A rejette-t-il mon webhook localhost ? C’est presque certainement une protection SSRF. Les serveurs durcis bloquent par défaut les destinations privées, loopback et link-local. Utilisez un tunnel HTTPS public plutôt que de désactiver la garde.
Quel en-tête porte le jeton de notification push A2A ? L’exemple du guide utilise X-A2A-Notification-Token, alimenté par le token que vous avez fourni lors de l’enregistrement. Le texte normatif ne nomme pas d’en-tête, et certaines implémentations envoient aussi A2A-Notification-Token, donc acceptez les deux.
Puis-je tester le streaming A2A via un Cloudflare Quick Tunnel ? Non. Cloudflare indique que les Quick Tunnels ne prennent pas en charge les Server-Sent Events, utilisées par le streaming A2A. Les webhooks push fonctionnent correctement via l’un d’eux.
A2A est-il assez stable pour construire dessus ? v1.0 est la spécification stable actuelle, gouvernée par la Linux Foundation et hébergée par l’AAIF depuis août 2026. Les SDK et les intégrations sont encore en maturation, alors testez le support des versions, les capacités optionnelles et l’authentification de bout en bout avec chaque pair.
Points clés
- Un test local A2A peut nécessiter deux adresses publiques : l’URL d’interface de la carte pour le serveur, et l’URL du webhook pour le client.
- Le fait qu’un webhook localhost fonctionne dépend du SDK de votre serveur. Les serveurs durcis refusent intentionnellement les cibles privées, et un tunnel teste le chemin réaliste où désactiver la protection ne fonctionnera pas.
- L’enregistrement du webhook est une surface SSRF. Résolvez et classez chaque adresse avec un seul classificateur partagé, validez à l’enregistrement et à la livraison, décidez comment vous allez fermer la fenêtre de rebinding et refusez les redirections.
- Utilisez un nom d’hôte de tunnel stable, authentifiez chaque notification, traitez la charge utile comme un déclencheur pour appeler
GetTask, et effectuez les tests négatifs.
Sources
- A2A Protocol Specification v1.0.0
- Streaming and Asynchronous Operations (A2A docs)
- A New Chapter for A2A: Joining the Agentic AI Foundation (A2A blog, Aug 27, 2026)
- A2A Protocol Surpasses 150 Organizations (Linux Foundation, Apr 9, 2026)
- A2A Joins AAIF: The 2026 Agent Protocol Consolidation (NerdLevelTech)
- Agent2Agent (A2A) Protocol: v1.0 Guide for 2026 (Turing Post)
- A2A security: The developer’s complete guide (Tyk)
- CVE-2026-71569, Apache Camel A2A webhook SSRF et le Apache Camel advisory
- a2a-python PR #1164, validate push-notification URLs before dispatch
- a2a-protocol-server push sender (docs.rs)
- a2a-js v1.0.0 release
- a2aops on PyPI
- Cloudflare Quick Tunnels documentation
Related InstaTunnel pages
Continue from this article into the most relevant product guides and workflows.
Related Topics
Keep building with InstaTunnel
Read the docs for implementation details or compare plans before you ship.