Passa al contenuto principale

A2A: il protocollo Agent-to-Agent

Avanzato

Entro metà 2026, la maggior parte del lavoro non banale degli agenti è svolto da più agenti che cooperano — un agente di ricerca passa il lavoro a uno scrittore, un agente di fatturazione parla con un agente di supporto di un altro vendor, un orchestratore delega a uno specialista dentro il cloud di un'altra organizzazione. A2A (Agent-to-Agent) è il protocollo aperto che permette a quegli agenti di trovarsi a vicenda, descrivere cosa sanno fare, e passarsi task avanti e indietro — anche quando sono stati costruiti su framework diversi da team diversi. Dove MCP collega un agente ai suoi strumenti e dati, A2A collega un agente a un altro agente. Si compongono; non competono.

What you'll learn
  • Enunciare esattamente a cosa serve A2A — e dove sta il confine con MCP
  • Leggere un'Agent Card e sapere cosa ne farà un agente ricevente
  • Percorrere un task attraverso tutti e otto gli stati del ciclo di vita, compresi i due che sono interrotti anziché terminali
  • Scegliere tra streaming SSE e push webhook per task a lunga esecuzione
  • Riconoscere le funzionalità meno ovvie: card firmate, endpoint multi-tenant e parti di dati strutturati

Perché esiste A2A

Ogni framework di agenti — LangGraph, CrewAI, il Claude Agent SDK, l'OpenAI Agents SDK, il Microsoft Agent Framework, i loop custom in casa — ha risolto il tool use appoggiandosi al tool calling nativo del modello e, sempre più, a MCP come connettore universale per strumenti e dati. Questo ci ha dato agente ↔ strumento.

Quello che nessuno di loro ha risolto da solo è agente ↔ agente attraverso un confine. Due problemi ricorrenti:

  • Discovery. Come fa l'agente A a sapere che l'agente B esiste, cosa sa fare, come autenticarsi verso di lui e se supporta lo streaming? Un README scritto a mano non è un protocollo.
  • Passaggio di task. Una volta che A vuole che B faccia qualcosa, come si scambiano il lavoro (non la chat del modello) — inclusi file, dati strutturati, aggiornamenti di progresso, e il fatto che B potrebbe dover fermarsi e chiedere input ad A?

Le risposte specifiche di ciascun framework (subgraph di LangGraph, crew di CrewAI, subagenti dentro un singolo runtime) funzionano benissimo dentro un solo processo. Si fermano al confine dell'organizzazione. A2A è il pezzo che permette a un agente nel tuo prodotto di delegare a un agente nel prodotto di qualcun altro senza che nessuna delle due parti sveli le proprie interiora — Todd Segal di Google lo definisce "la base sicura per far collaborare senza soluzione di continuità agenti personali, di team e di dominio su qualsiasi piattaforma." La governance è affidata alla Linux Foundation, e ad aprile 2026 il progetto contava oltre 150 organizzazioni che lo supportano, tra cui AWS, Microsoft, Salesforce, SAP, ServiceNow e IBM.

MCP vs. A2A — il modello mentale

Entrambi sono protocolli aperti. Entrambi usano JSON su HTTP. Risolvono problemi diversi e sono progettati per comporsi:

  • MCP = agente-verso-strumento. Un server MCP espone strumenti (search, read_file, run_query) e risorse (documenti, prompt) a un client guidato dal modello. Il client è un agente; il server è un fornitore passivo di capacità. Vedi MCP & connessione agli strumenti per come Claude lo usa.
  • A2A = agente-verso-agente. Un endpoint A2A espone un agente — un'entità con il proprio loop di ragionamento che deciderà come risolvere un task delegato. Entrambe le parti sono agenti; ciascuna può chiamare l'altra.

La differenza concreta emerge nel formato del wire. Una tools/call di MCP restituisce un risultato e chiude. Un SendMessage di A2A apre un task — una cosa con stato e ciclo di vita proprio, che può inviare aggiornamenti in streaming, chiedere chiarimenti, o girare per ore in background. Se la risposta del tuo endpoint è sempre "ecco il risultato di una funzione", è uno strumento — pubblicalo via MCP. Se è "fammi ragionare e torno da te, e potrei doverti fare una domanda di follow-up", è un agente — pubblicalo via A2A.

La maggior parte dei sistemi seri gestirà entrambi: un agente che all'interno usa MCP per raggiungere gli strumenti, e che all'esterno parla A2A perché i peer possano passargli lavoro.

L'Agent Card — il pezzo della spec che conta di più

Un'Agent Card è un documento JSON servito a un URL well-known che dice a qualsiasi potenziale chiamante tutto quello che serve per parlare col tuo agente. Pensala come OpenAPI + robots.txt, per agenti. Ogni interazione A2A comincia recuperandone una.

La card include:

  • Identitàid, name, description, provider (dettagli dell'organizzazione).
  • Endpoint — gli URL del servizio e quali binding di protocollo (JSON-RPC, gRPC, REST) sono disponibili.
  • Capabilities — feature flag: streaming, pushNotifications, extendedAgentCard.
  • Skills — funzioni dichiarate dell'agente con schemi di input/output (qui B dichiara cosa sa fare).
  • Schemi di sicurezza — uno o più tra APIKey, HTTPAuth (Basic/Bearer), OAuth2 (Authorization Code, Client Credentials, Device Code), OpenIdConnect, MutualTLS. Il chiamante legge questo per sapere quali credenziali portare prima della prima chiamata.
  • Firma — una firma crittografica opzionale sulla card.

È l'ultimo campo su cui vale la pena fermarsi. Una Signed Agent Card permette a un agente ricevente di verificare che la card sia stata davvero emessa dal proprietario del dominio — l'equivalente DNS/PKI di "sì, questo è davvero agents.acme.com, non qualcosa piantato lì da un attaccante." Combinato con l'autenticazione mTLS, chiude la porta a Agent Card canaglie servite da host contraffatti, che sarebbe altrimenti il modo di ottenere una prompt injection al livello della discovery: un'Agent Card di un attaccante che mente sugli strumenti che espone e sui dati che vuole.

Gli otto stati del ciclo di vita di un task

Una volta che fai SendMessage a un agente A2A, il lavoro diventa un Task — un oggetto di prima classe con un ID che puoi interrogare, sottoscrivere, cancellare o elencare. Il task attraversa otto stati, ed è interessante notare che solo cinque sono terminali:

  • SUBMITTED — il server ha preso in carico il task.
  • WORKING — elaborazione attiva.
  • INPUT_REQUIREDinterrotto: l'agente ha bisogno di altre informazioni dal chiamante. Non è un errore; è previsto nei workflow reali.
  • AUTH_REQUIREDinterrotto: l'agente ha bisogno che il chiamante si autentichi (o si ri-autentichi) prima di poter continuare.
  • COMPLETED — successo. Terminale.
  • FAILED — errore. Terminale.
  • CANCELED — cancellazione avviata dal chiamante. Terminale.
  • REJECTED — l'agente ha rifiutato il task (policy, capacità, quota). Terminale.

Gli stati interrotti sono il punto chiave. L'RPC classico assume una chiamata → un risultato. Il lavoro reale di un agente somiglia a "avvia l'analisi, torna un'ora dopo, accorgiti che devo farti una domanda di chiarimento, aspetta la risposta, riprendi, finisci." A2A lo modella nativamente. Il tuo codice chiamante deve essere una piccola macchina a stati, non un await sincrono.

Streaming vs. push notification

I task a lunga esecuzione hanno bisogno di un modo per consegnare gli aggiornamenti. A2A ti dà due modelli asincroni — scegli per task, non per agente:

  • Streaming (SendStreamingMessage / SubscribeToTask). Server-Sent Events sopra la connessione HTTP aperta. Il client resta connesso, riceve TaskStatusUpdateEvent e TaskArtifactUpdateEvent in ordine. Ottimo per UI interattive e task da corti a medi. Cade se il client non riesce a tenere aperta una connessione (mobile, serverless, tab del browser che vanno in sleep).
  • Push notification (config webhook). Il client registra un webhook via CreateTaskPushNotificationConfig. Il server fa POST degli aggiornamenti a quell'URL man mano che accadono. Il client può essere totalmente offline nel frattempo. È la modalità per task che sopravvivono a una connessione HTTP — pensa "esegui questo per tutta la notte" o "richiamami quando il batch job finisce."

Entrambi richiedono che l'agente dichiari il supporto nella sua Agent Card (capabilities.streaming: true e/o capabilities.pushNotifications: true). Un chiamante conforme controlla prima e ripiega in modo pulito.

Parti del messaggio — non solo chat

Un Message A2A è composto da uno o più Parts. Ogni Part può essere:

  • text — contenuto stringa (la parte da chat).
  • raw — file binario, codificato in base64 nel JSON.
  • url — un riferimento a un file esterno (evita di inlinare blob enormi).
  • data — un oggetto o array JSON strutturato, con una mappa metadata opzionale.

La parte data è ciò che rende A2A utile per il lavoro machine-to-machine. Due agenti possono scambiare payload tipizzati — un ordine, una spec di acquisto, un diff JSON — senza fingere di avere una conversazione in linguaggio naturale su quello. È anche ciò che permette a protocolli come Agent Payments (AP2) di posarsi in modo pulito sopra A2A: l'intent di pagamento viaggia in una parte data con uno schema noto.

Endpoint multi-tenant — un URL, molti agenti

Questo è facile da mancare. Un singolo endpoint A2A può ospitare molti agenti, serviti tramite il metodo GetExtendedAgentCard dopo l'autenticazione. Un vendor SaaS può offrire un solo URL e restituire Agent Card diverse, specifiche per tenant, a seconda di quale API key o scope OAuth il chiamante presenta. Dal lato del chiamante sembra un endpoint per agente; dal lato del vendor è un solo deployment. Se stai costruendo infrastruttura che serve agenti, questo è il pattern che ti permette di scalare senza un hostname per tenant.

Un'interazione end-to-end minima

Il protocollo completo ha molta superficie, ma il flusso happy-path è breve:

Guided walkthrough1 of 5
  1. Recupera l'Agent Card da un URL well-known. Verifica la firma se presente. Leggi `capabilities`, `skills` e `securitySchemes` per decidere se questo agente può fare ciò che ti serve e quale auth porterai.

Recuperare un'Agent Card (concetto)

La discovery è solo un HTTP GET. Questa è la forma di una richiesta che un client farebbe per ispezionare un agente candidato prima ancora di mandargli lavoro:

Recupera e ispeziona un'Agent Card

GET https://agents.example.com/.well-known/agent.json
Accept: application/json

# Response (abbreviated):
# {
#   "id": "acme/support-router",
#   "name": "Acme Support Router",
#   "provider": {"organization": "Acme, Inc."},
#   "endpoints": [
#     {"url": "https://agents.example.com/a2a", "protocol": "jsonrpc"}
#   ],
#   "capabilities": {
#     "streaming": true,
#     "pushNotifications": true,
#     "extendedAgentCard": true
#   },
#   "skills": [
#     {"id": "route_ticket", "inputSchema": {...}, "outputSchema": {...}}
#   ],
#   "securitySchemes": {
#     "primary": {"type": "oauth2", "flows": {...}}
#   },
#   "signature": {"alg": "EdDSA", "value": "..."}
# }

Nota cosa non c'è nella card: nulla sul modello dietro l'agente, sul suo prompt, sui suoi strumenti o sul suo stato privato. Quell'opacità è deliberata — A2A tratta un agente peer come una black box a cui deleghi lavoro, non come un sistema da ispezionare.

Trappole comuni

  • Trattare INPUT_REQUIRED come un errore. Non lo è; è il protocollo che chiede al tuo codice di rispondere. Se il tuo codice chiamante ramifica solo su "è riuscito o è fallito", romperai ogni workflow interattivo.
  • Ignorare le capabilities dell'Agent Card. Mandare una richiesta di streaming a un agente che non ha dichiarato streaming: true ti fa ottenere un UnsupportedOperationError. Leggi la card, ripiega in modo pulito.
  • Assumere che la connessione di streaming sia durevole. Client mobili, runtime serverless, tab del browser — tutti droppano la connessione SSE. Per qualsiasi cosa più lunga di "un turno di chat", preferisci le push notification.
  • Saltare la verifica della firma perché è opzionale. Se stai consumando Agent Card da fuori la tua organizzazione, verifica la firma — altrimenti hai creato un vettore di prompt injection al livello della discovery.
  • Confondere A2A con MCP. Pubblicare un endpoint A2A per una funzione stateless one-shot è eccessivo; quello è uno strumento, e MCP è il protocollo giusto. Pubblicare uno strumento MCP per qualcosa che ci mette minuti e deve chiedere chiarimenti è sotto-ingegnerizzare; quello è un agente, e A2A è il protocollo giusto.

Check yourself

0/4
  1. Quale di questi è compito di A2A — la cosa per cui MCP *non* è progettato?
  2. A2A definisce otto stati del task. Quali due sono *interrotti* anziché terminali?
  3. Devi far girare un task A2A che durerà un'ora. Il client è una funzione serverless che non può tenere aperta una connessione HTTP. Qual è il modello di consegna giusto?
  4. Da cosa ti protegge un'Agent Card *firmata*?

Dove si colloca A2A nel tuo stack

Messo insieme al resto del quadro sugli agenti:

  • Dentro un agente, MCP è come raggiungi strumenti e dati — inclusi server MCP remoti che non hai scritto tu.
  • Tra agenti in un solo framework, usi quello che il framework ti dà — subagenti in Claude Code, subgraph di LangGraph, crew di CrewAI, ecc. È il più veloce ma ti lega a un solo runtime.
  • Tra agenti tra framework, team o vendor diversi, A2A è quello a cui ricorri. Leggi Framework open source per agenti AI per il lato runtime; A2A è il filo tra quei runtime.

La regola pratica: se il confine è un confine di processo, i passaggi nativi del framework vanno bene. Se è un confine di organizzazione, cloud o fiducia, usa A2A.

Fonti e approfondimenti