AIProtocollo A2A: come progettare un agente che altri agenti chiamano
A2A v1.0 è uscito a marzo 2026. Sei passi per progettare un server A2A: Agent Card, skill per risultato, otto stati dei task, binding, auth e versioni.

Alla fine di questa guida avrai il progetto di un server A2A per un agente che hai già in produzione: un'Agent Card pubblicata, skill tra cui il modello di un altro agente sa scegliere, un ciclo di vita dei task allineato agli stati dei tuoi job, un canale di aggiornamento adatto alla tua infrastruttura, l'autorizzazione su ogni chiamata e un piano per le versioni. Il protocollo Agent2Agent (A2A) è uno standard aperto con cui un agente AI trova un altro agente, gli delega un compito e ne raccoglie il risultato, senza che nessuno dei due veda prompt, memoria o strumenti dell'altro.
A2A è arrivato alla prima versione stabile, la 1.0, a marzo 2026. Google l'ha annunciato ad aprile 2025 e l'ha affidato alla Linux Foundation a giugno 2025. Ad agosto 2026 è diventato un progetto ospitato dall'Agentic AI Foundation, la stessa casa neutrale di MCP. La Linux Foundation conta più di 150 organizzazioni che lo sostengono e installazioni in produzione dentro Azure AI Foundry e Amazon Bedrock AgentCore. Il protocollo è abbastanza stabile per progettarci sopra. Le scelte di progetto restano tue, e sono il tema di questa guida.
Dove si colloca A2A rispetto a MCP?
La documentazione di A2A descrive MCP come verticale e A2A come orizzontale. MCP dà a un agente più strumenti: un database, l'API di un calendario, un archivio di file. A2A collega quell'agente ad altri agenti che non controlli. Un agente di pianificazione dentro il tuo SaaS usa MCP per leggere il servizio calendario e A2A per ricevere lavoro dall'agente acquisti di un cliente. Quasi tutti i prodotti che espongono un agente useranno entrambi.
Per il progetto conta l'opacità. Un client MCP chiama i tuoi strumenti uno per uno e vede ogni risultato. Un client A2A ti affida un obiettivo e riceve un task, aggiornamenti di stato e artifact. Prompt, catena di strumenti e ragionamenti intermedi restano privati. Se la parte MCP non c'è ancora, parti da cosa fa un server MCP per un SaaS.
Cosa serve prima di cominciare
- Un agente che già porta a termine un lavoro completo dentro il prodotto, con i suoi strumenti.
- Un archivio dei job che sopravvive ai riavvii, una tabella o una coda. Un task A2A può durare ore, e chi lo ha chiesto lo rilegge per id.
- Un identity provider che parla OAuth 2.0 o OpenID Connect. Le Agent Card dichiarano schemi con API key, autenticazione HTTP, OAuth 2.0, OpenID Connect e TLS reciproco.
- Uno degli SDK ufficiali: Python, Go, Java, JavaScript, C#/.NET o Rust. La specifica chiede agli SDK di gestire la negoziazione della versione, cioè la parte che meno conviene scrivere a mano.
Passo 1: descrivi ogni skill come il risultato che il chiamante cerca
Le skill sono ciò che il modello dell'agente chiamante legge per decidere se delegarti il lavoro. Ogni skill nell'Agent Card ha un id, un name, una description, dei tags, degli examples e i formati che accetta e restituisce. Quel testo è un prompt per un modello che non hai mai visto. Scrivilo come documentazione per un estraneo: cosa fa la skill, cosa le serve, cosa restituisce.
Raggruppa le skill per risultato. «Riconcilia una fattura con il suo ordine d'acquisto» è una skill. Le funzioni che ci stanno dietro (recuperare la fattura, abbinare le righe, segnalare lo scostamento) sono la tua implementazione, e l'esecuzione opaca di A2A le tiene fuori dalla card. Tieni la lista corta: ogni skill in più è una scelta in più su cui il modello del chiamante può sbagliare. Dai a ogni skill almeno un esempio in linguaggio naturale e, quando l'input è strutturato, uno in JSON, come fa la card di esempio della specifica.
Passo 2: pubblica l'Agent Card all'indirizzo well-known
Un server A2A deve pubblicare un'Agent Card. Il posto standard è https://tuo-dominio/.well-known/agent-card.json; funzionano anche i registri e la configurazione diretta. Una card minima in v1.0, con una sola skill, è fatta così:
{
"name": "Invoice Reconciliation Agent",
"description": "Matches supplier invoices against purchase orders and flags variances.",
"version": "2.1.0",
"provider": { "organization": "Example SaaS", "url": "https://example.com" },
"supportedInterfaces": [
{ "url": "https://agents.example.com/a2a/v1", "protocolBinding": "JSONRPC", "protocolVersion": "1.0" }
],
"capabilities": { "streaming": true, "pushNotifications": true, "extendedAgentCard": true },
"securitySchemes": {
"oidc": { "openIdConnectSecurityScheme": { "openIdConnectUrl": "https://auth.example.com/.well-known/openid-configuration" } }
},
"securityRequirements": [{ "schemes": { "oidc": { "list": ["openid"] } } }],
"defaultInputModes": ["application/json", "text/plain"],
"defaultOutputModes": ["application/json"],
"skills": [
{
"id": "reconcile-invoice",
"name": "Reconcile an invoice",
"description": "Compares one supplier invoice with its purchase order. Returns matched lines, variances and a pass or hold decision.",
"tags": ["finance", "invoices", "reconciliation"],
"examples": ["Reconcile invoice INV-2291 against PO-7781."],
"inputModes": ["application/json", "application/pdf"],
"outputModes": ["application/json"]
}
]
}Quattro campi portano quasi tutto il peso del progetto.
supportedInterfaceselenca gli endpoint in ordine di preferenza. Il client prende il primo che sa usare, quindi metti in cima il binding che hai provato di più.capabilitiesdeve dire il vero. Se un client chiama una funzione opzionale che la card non dichiara, il server deve rispondere con un errore. Dichiara lo streaming solo quando lo streaming funziona.securitySchemesdice a chi chiama come ottenere un token prima della prima richiesta.extendedAgentCardti lascia una card pubblica corta e mostra le skill specifiche di un tenant solo a chi è autenticato, conGetExtendedAgentCard.
Servi la card con Cache-Control e un ETag ricavato dalla sua versione, come raccomanda la specifica. Quando chi chiama deve verificare da dove arriva la card, firmala con JSON Web Signature sulla sua forma JSON canonica (RFC 7515 e RFC 8785).
Passo 3: fai corrispondere gli stati dei job al ciclo di vita del task
In A2A v1.0 un task attraversa otto stati. Prima di scrivere un solo handler, annota quale stato interno dei tuoi job finisce in ciascuno.
- Submitted e working: accettato, poi in lavorazione.
- Input-required: l'agente ha bisogno di altre informazioni. Il chiamante risponde con un nuovo messaggio che porta lo stesso id del task.
- Auth-required: all'agente servono una credenziale o l'approvazione di una persona per andare avanti.
- Completed, failed, canceled e rejected: stati finali. Un task in uno stato finale non accetta altri messaggi.
Tre regole della specifica danno forma al resto. Gli id dei task li genera il server, e un client non può creare un task con un id suo. I risultati vanno negli artifact; i messaggi portano conversazione e stato, quindi chi cerca l'output legge gli artifact. E una risposta rapida che non ha bisogno di essere tracciata può tornare come un singolo messaggio, senza task. Usiamo rejected per il lavoro che l'agente decide di non fare (fuori ambito, contro una regola) e teniamo failed per il lavoro che si è interrotto per un errore, perché la mossa successiva del chiamante cambia: riprovare altrove, o riprovare più tardi.
Il contextId raggruppa i task collegati in un'unica conversazione. Un agente può far scadere i contesti, e la specifica chiede di documentare questa regola. Scrivi la scadenza nelle descrizioni delle skill o nella documentazione collegata, così il chiamante sa per quanto tempo una richiesta successiva resta valida.
Passo 4: scegli un binding e un canale di aggiornamento
La v1.0 definisce tre binding che devono comportarsi allo stesso modo: JSON-RPC 2.0, gRPC e HTTP+JSON. Le operazioni hanno gli stessi nomi in tutti e tre: SendMessage, SendStreamingMessage, GetTask, ListTasks, CancelTask, SubscribeToTask. Nel binding REST diventano percorsi come POST /message:send e GET /tasks/{id}. Scegli il binding che il tuo gateway e il tuo sistema di osservabilità gestiscono già. Su uno stack web di solito vuol dire JSON-RPC o HTTP+JSON su HTTPS.
Chi chiama può seguire un task in tre modi: interrogando GetTask a intervalli, con lo streaming, o con notifiche push verso un webhook che registra. La nostra scelta predefinita è lo streaming per i task che finiscono mentre il chiamante aspetta, e il push per quelli abbastanza lunghi da far cadere la connessione. Sul push la specifica è molto precisa in fatto di sicurezza:
- Invia le credenziali configurate con ogni chiamata al webhook.
- Chiudi le richieste al webhook dopo 10-30 secondi e riprova con un backoff esponenziale.
- Rifiuta gli URL di webhook che puntano a localhost, a indirizzi link-local o a reti private come 10.0.0.0/8 e 192.168.0.0/16. Senza questo controllo l'agente diventa uno strumento di request forgery contro la sua stessa rete.
- Dal lato di chi riceve, elabora le notifiche in modo idempotente: i duplicati sono previsti.
Passo 5: autorizza ogni chiamata in base a chi chiama
La specifica chiede un controllo di autorizzazione su ogni operazione, prima di qualsiasi query che possa rivelare se una risorsa esiste. ListTasks restituisce solo i task che il chiamante può vedere, anche quando la richiesta non ha filtri. GetTask sul task di un altro tenant risponde come se il task non esistesse. Ricava il tenant dal token del chiamante all'ingresso e passalo a ogni lettura dell'archivio.
Usa lo stato auth-required per i permessi che l'agente non ha ancora: un token OAuth verso un servizio a valle, o il via libera di una persona prima di un rimborso sopra una certa soglia. Il task si ferma, il chiamante procura la credenziale e il lavoro riprende.
Considera inaffidabile ogni parte che arriva. Il testo di un agente che ti delega un lavoro raggiunge il tuo modello, quindi valgono le stesse difese contro la prompt injection che usi sull'input degli utenti. I riferimenti a file vanno controllati prima di scaricarli, per lo stesso rischio di request forgery dei webhook. I controlli descritti per blindare un server MCP per l'enterprise (SSO, registro di audit, un gateway davanti) valgono quasi senza modifiche.
Passo 6: tieni separate la versione del protocollo e quella della card
In un'installazione A2A convivono due numeri di versione. La versione del protocollo è Major.Minor: il client la manda nell'header A2A-Version e la card la dichiara per ogni interfaccia. Il campo version della card è invece la release del tuo agente, e cambia ogni volta che cambiano le skill.
Una richiesta con l'header A2A-Version vuoto va trattata come 0.3, e una versione che l'interfaccia non serve riceve VersionNotSupportedError. Conta perché la v1.0 ha rotto la compatibilità con la 0.3: message/send è diventato SendMessage, i valori degli enum sono passati a SCREAMING_SNAKE_CASE e protocolVersion si è spostato dalla card alle singole interfacce. Se hai già client 0.3, servi le due versioni come interfacce separate e dismetti la 0.3 a una data che pubblichi.
Come verificare che funzioni
- Scarica la card con
curl. Ti aspetti 200, JSON valido,Cache-Controle unETag. - Manda un messaggio senza token. Ti aspetti un errore di autenticazione, non un task.
- Manda un messaggio valido. Ti aspetti un task con un id generato dal server, in stato submitted o working.
- Leggi quel task con il token di un altro tenant. Ti aspetti un errore di task non trovato.
- Annulla lo stesso task due volte. Le due chiamate devono lasciare lo stesso stato.
- Apri uno stream e controlla che si chiuda quando il task arriva a uno stato finale.
- Manda
A2A-Version: 9.9. Ti aspettiVersionNotSupportedError. - Registra un webhook su
http://127.0.0.1. Ti aspetti un rifiuto.
Errori frequenti e come correggerli
- Skill con il nome delle funzioni interne. Il chiamante sceglie quella sbagliata, o nessuna. Rinominale in base al risultato e aggiungi esempi.
- Output dentro i messaggi di stato. Chi legge gli artifact non trova niente. Sposta i risultati negli artifact e lascia ai messaggi domande e avanzamento.
- Capability dichiarate prima che funzionino. Una card con
streaming: truesenza unSubscribeToTaskfunzionante manda in errore i client che si fidano. Attiva il flag il giorno in cui la funzione è online. - Nomi 0.3 e 1.0 mescolati sullo stesso endpoint. Il client negozia una versione per interfaccia. Separa le interfacce.
- contextId usato come identità. Raggruppa le conversazioni e non dice nulla su chi chiama. L'autorizzazione viene dal token.
Per andare oltre
A2A copre il dialogo tra agenti; ogni agente ha comunque bisogno dei suoi strumenti e delle sue regole. Per la governance leggi cosa cambia per MCP con la Linux Foundation, e per quello che si inceppa quando più agenti si dividono il lavoro i 12 errori dei team al primo sistema multi-agent.
Domande frequenti
Risolvono problemi diversi, quindi uno non sostituisce l'altro. Un server MCP fa chiamare a un agente AI gli strumenti del tuo prodotto uno alla volta, e la pianificazione la fa il modello di chi chiama. Un server A2A fa sì che un altro agente affidi al tuo un obiettivo intero e riceva un task tracciato con i suoi risultati, mentre prompt e strumenti restano privati. Se agli agenti dei clienti serve soprattutto leggere e scrivere dati, MCP basta. Aggiungi A2A quando il tuo agente fa un lavoro che vale la pena delegare, come una riconciliazione in più passaggi o una revisione che può fermarsi in attesa dell'approvazione di una persona.
No. Google ha creato A2A e l'ha annunciato ad aprile 2025, poi l'ha donato alla Linux Foundation a giugno 2025 con AWS, Cisco, Microsoft, Salesforce, SAP e ServiceNow come membri fondatori. Da agosto 2026 è un progetto ospitato dall'Agentic AI Foundation, che ospita anche MCP. La definizione normativa è un file Protocol Buffers in un repository pubblico con licenza Apache 2.0, e le modifiche passano dalla governance aperta del progetto.
No. Un'API REST è deterministica: la stessa richiesta restituisce sempre la stessa struttura, ed è su questo che contano integrazioni, report e fatturazione. Un agente A2A risponde a obiettivi espressi in linguaggio naturale o in dati strutturati, e il percorso con cui arriva alla risposta può cambiare da una versione del modello all'altra. Tieni l'API REST come contratto per i sistemi e affianca l'agente A2A per i lavori che richiedono giudizio. Molti agenti A2A, dietro le quinte, chiamano proprio quella API REST con i loro strumenti.
Sì. Un server A2A può fare da client verso agenti a valle, e le catene di agenti sono uno schema normale. Tre aspetti vanno progettati. Le credenziali: il tuo agente chiama il successivo con il proprio token, non con quello del chiamante originale, e registra per conto di chi lavora. I tempi: ogni passaggio aggiunge latenza, quindi le catene lunghe dovrebbero usare le notifiche push invece di tenere aperti gli stream. I cicli: metti un limite di passaggi o un id di traccia nei metadati del messaggio, così due agenti non si rimbalzano lo stesso task all'infinito.
Servizi correlati
Articoli correlati
AI
AIWebMCP nel 2026: l'API con cui gli agenti usano il tuo SaaS
Con WebMCP una pagina registra gli strumenti che un agente AI del browser può chiamare. Chrome 149 lo prova in origin trial. Cosa cambia per le interfacce SaaS.
AI