The A2A protocol: how it works, step by step, and how it compares with MCP
AI systems are no longer just a single model answering questions. We now build specialised agents (an HR agent, a booking agent, a code-review agent), often developed by different teams, on different frameworks (LangGrap
AI systems are no longer just a single model answering questions. We now build specialised agents (an HR agent, a booking agent, a code-review agent), often developed by different teams, on different frameworks (LangGraph, CrewAI, ADK, OpenAI Agents SDKβ¦), and hosted by different providers. That raises a new question: how do these agents talk to each other?
That is the question A2A (Agent2Agent) answers. This article introduces the protocol, walks through how it works step by step, and then compares it with MCP (Model Context Protocol), with which it is often confused.
Contents
- What is A2A?
- History and governance
- Key concepts
- A three-layer architecture
- How it works, step by step
- Task lifecycle
- Security
- A2A vs MCP
- Using A2A and MCP together
- Current limitations and best practices
- Conclusion
1. What is A2A?
A2A is an open specification that defines how independent AI agents:
- discover each other (who can do what, and how to reach them),
- delegate tasks to one another, including long-running, multi-step ones,
- exchange data (text, JSON, files) securely,
- track progress on work in flight (streaming, notifications).
The core idea: every agent is treated as a black box. A client agent does not need to know the remote agent's model, prompt, tools or memory. It hands over a task, the way you would hand a file to a colleague in another department, and gets a result back.
In one sentence: MCP connects an agent to its tools; A2A connects an agent to other agents.
2. History and governance
| Date | Milestone |
|---|---|
| April 2025 | Protocol announced by Google, with around fifty partners |
| June 2025 | Project donated to the Linux Foundation, which now provides neutral governance |
| Summer 2025 | Version 0.3: gRPC binding added, Agent Card signatures |
| March 2026 | Stable version 1.0 |
| 2026 | Production support in several platforms (Microsoft Copilot Studio, Azure AI Foundry, Amazon Bedrock AgentCore, ServiceNow, Salesforceβ¦) |
Version 1.0 introduced several breaking changes compared with 0.x (method names, state names, removed fields). If you are reading tutorials from 2025, check which version they target.
3. Key concepts
A2A relies on a small vocabulary:
| Concept | Role |
|---|---|
| Client agent | The agent that initiates the request (often an orchestrator). |
| Remote agent (A2A server) | The agent that receives and executes the task. Roles are fluid: an agent can be the client in one interaction and the server in another. |
| Agent Card | The agent's public JSON identity card: name, description, version, skills, endpoints, authentication methods. |
| Skill | A capability declared in the Agent Card (e.g. book_flight), with a description, tags, examples and accepted formats. |
| Task | A unit of work with an identifier and a state, generated by the server. It can last a few milliseconds or several days. |
| Message | One turn of conversation, carried by a role (user or agent). |
| Part | A piece of content inside a message: text, structured JSON data, a URL to a file, or raw bytes. |
| Artifact | The deliverable produced by the task (a report, a JSON itinerary, a PDFβ¦), also made of Parts. |
| Context | An identifier used to group several tasks and messages belonging to the same conversation. |
4. A three-layer architecture
The v1.0 specification is split into three layers, so you can change transport without rewriting the agent's logic:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 3 β Protocol bindings β
β JSON-RPC 2.0 over HTTPS β gRPC β HTTP+JSON (REST) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Layer 2 β Abstract operations β
β SendMessage, SendStreamingMessage, GetTask, β
β ListTasks, CancelTask, SubscribeToTask, β
β push notification config, Agent Card retrieval β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Layer 1 β Canonical data model β
β AgentCard, AgentSkill, Task, Message, Part, β
β Artifact, Extension (Protocol Buffers + JSON Schema) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Each agent advertises the binding(s) it supports in its Agent Card (the supportedInterfaces field). JSON-RPC is the most common for publicly exposed agents; gRPC is attractive for low-latency internal traffic.
5. How it works, step by step
Let's take a concrete scenario: an HR agent needs to organise an interview and delegates the booking to a travel agent run by another team.
![A2A task delegation sequence: discovery, authentication, sending, tracking, multi-turn exchange and result]
Step 1 β Discovery via the Agent Card
The remote agent publishes its card at a standard URL: https://<domain>/.well-known/agent-card.json (an RFC 8615 convention). A simplified, v1.0-compliant example:
{
"name": "Travel booking agent",
"description": "Books flights and hotels for employees.",
"version": "1.2.0",
"provider": {
"organization": "MyCompany",
"url": "https://mycompany.example"
},
"supportedInterfaces": [
{
"url": "https://travel.mycompany.example/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
],
"capabilities": {
"streaming": true,
"pushNotifications": true,
"extendedAgentCard": false
},
"defaultInputModes": ["text/plain", "application/json"],
"defaultOutputModes": ["application/json"],
"skills": [
{
"id": "book_flight",
"name": "Book a flight",
"description": "Books a flight given an origin, a destination and dates.",
"tags": ["travel", "booking"],
"examples": [
"Book a ParisβLyon flight on 12 November for employee 4432"
]
}
],
"securitySchemes": {
"corp_oauth": {
"type": "oauth2",
"flows": {
"clientCredentials": {
"tokenUrl": "https://auth.mycompany.example/token",
"scopes": { "flights:write": "Book flights" }
}
}
}
},
"security": [{ "corp_oauth": ["flights:write"] }]
}
The client reads the card, checks that the book_flight skill exists, picks an interface and identifies the expected authentication method.
Discovery can also go through an internal registry (a catalogue of vetted agents) or direct configuration (a hard-coded URL) for tightly coupled systems.
Step 2 β Authentication
Credentials never travel in the body of the A2A message: they are sent in HTTP headers (Authorization: Bearer β¦). Here, the client runs an OAuth2 client credentials flow against the declared tokenUrl.
Step 3 β Sending the task (SendMessage)
POST /a2a HTTP/1.1
Host: travel.mycompany.example
Authorization: Bearer eyJhbGciOi...
Content-Type: application/json
Accept: application/json, text/event-stream
{
"jsonrpc": "2.0",
"id": 1,
"method": "SendMessage",
"params": {
"message": {
"role": "ROLE_USER",
"parts": [
{
"text": "Book a direct ParisβLyon flight on 12 November for employee 4432."
}
]
},
"configuration": { "returnImmediately": true }
}
}
Things to note:
- The client does not supply a task identifier: the server generates it and returns it.
- For a trivial answer, the server can return a
Messagedirectly instead of creating aTask. -
returnImmediately: trueasks the server to hand back the newly created task right away, so the client can follow progress in parallel (in v1.0 the default behaviour is blocking).
Step 4 β Tracking progress
Three mechanisms, depending on duration and topology:
| Mechanism | When to use it | Operations |
|---|---|---|
| Polling | Short tasks, simple client |
GetTask at regular intervals |
| SSE streaming | The client stays connected and wants real-time updates |
SendStreamingMessage (send + stream) or SubscribeToTask (subscribe to an existing task) |
| Push notifications | Very long tasks, disconnected client (mobile, serverless) | The client registers a webhook; the server POSTs updates to it, authenticated (signed JWT, HMAC or mTLS) |
Example of a received SSE stream:
data: {"task": {"id": "task-9876", "status": {"state": "TASK_STATE_SUBMITTED"}}}
data: {"statusUpdate": {"taskId": "task-9876", "status": {"state": "TASK_STATE_WORKING"}}}
data: {"artifactUpdate": {"taskId": "task-9876", "artifact": {"artifactId": "a1", "name": "itinerary", "parts": [ ... ]}}}
data: {"statusUpdate": {"taskId": "task-9876", "status": {"state": "TASK_STATE_COMPLETED"}}}
The stream closes automatically when the task reaches a terminal state.
Step 5 β Multi-turn exchange (if needed)
If the remote agent needs clarification ("economy or business class?"), the task moves to INPUT_REQUIRED. The client replies with a new SendMessage carrying the same task identifier, and work resumes.
Step 6 β Retrieving the result
Artifacts hold the final deliverable. A client that missed the stream can always call GetTask to fetch the full task, with its history and artifacts.
Bonus: a minimal Python client
import requests
BASE = "https://travel.mycompany.example"
# 1. Discovery
card = requests.get(f"{BASE}/.well-known/agent-card.json", timeout=10).json()
if "book_flight" not in {s["id"] for s in card.get("skills", [])}:
raise RuntimeError("The agent does not offer the book_flight skill")
endpoint = card["supportedInterfaces"][0]["url"]
headers = {"Authorization": "Bearer <token>", "Content-Type": "application/json"}
# 2. Send the task
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "SendMessage",
"params": {
"message": {
"role": "ROLE_USER",
"parts": [{"text": "Book a ParisβLyon flight on 12/11 for employee 4432."}],
},
"configuration": {"returnImmediately": True},
},
}
task = requests.post(endpoint, json=payload, headers=headers, timeout=30).json()["result"]
# 3. Read the state (simple polling)
status = requests.post(
endpoint,
json={"jsonrpc": "2.0", "id": 2, "method": "GetTask",
"params": {"taskId": task["task"]["id"]}},
headers=headers, timeout=30,
).json()
print(status)
In production, prefer the official SDKs (Python, JavaScript, Java, Go, .NET) published by the A2A project over hand-written HTTP calls. The exact shape of
resultdepends on the server's response (taskormessage).
6. Task lifecycle
![A2A task lifecycle: in-progress, interrupted and terminal states]
| State (v1.0) | Category | Meaning |
|---|---|---|
TASK_STATE_SUBMITTED |
in progress | Accepted, not yet started |
TASK_STATE_WORKING |
in progress | Actively being processed |
TASK_STATE_INPUT_REQUIRED |
interrupted | Waiting for information from the client |
TASK_STATE_AUTH_REQUIRED |
interrupted | The client must provide additional credentials |
TASK_STATE_COMPLETED |
terminal | Finished successfully |
TASK_STATE_FAILED |
terminal | Unrecoverable error |
TASK_STATE_CANCELED |
terminal | Cancelled (often via CancelTask) |
TASK_STATE_REJECTED |
terminal | Refused by the agent (policy, quota, capability) |
7. Security
A2A builds on web standards rather than inventing its own:
- Encrypted transport: HTTPS (TLS 1.2 minimum) is mandatory in production.
-
Authentication schemes aligned with OpenAPI: OAuth 2.0, OpenID Connect, API key, mTLS. Declared in
securitySchemesand required viasecurity. - Signed Agent Cards: a JWS signature (RFC 7515) computed over a canonical form of the card (RFC 8785) makes any tampering detectable. Otherwise, a modified card could redirect calls or inject malicious content into the client agent's prompt.
- Extended Agent Card: an agent can expose a minimal public card and a more detailed one, available only after authentication.
-
Traceability: the specification recommends OpenTelemetry and propagating W3C Trace Context headers (
traceparent) to follow a request across the whole chain of agents.
For high assurance: combine mTLS and OAuth2, or use sender-constrained tokens (DPoP, RFC 9449), so that a stolen token is useless from another machine.
8. A2A vs MCP
Reminder: what is MCP?
MCP (Model Context Protocol), launched by Anthropic in late 2024 and now widely adopted, standardises the connection between an AI application (the client/host) and servers that expose tools, resources (data) and prompts. It runs on JSON-RPC 2.0, locally over stdio or remotely over HTTP. Its specifications are named by date; the 2026-07-28 revision notably made the protocol stateless (sessions and the initialisation handshake were removed), which makes horizontal scaling of servers easier.
Comparison table
| Criterion | A2A | MCP |
|---|---|---|
| Purpose | Make autonomous agents collaborate | Give an agent access to tools and data |
| Analogy | A colleague you delegate a file to | A toolbox you use yourself |
| Nature of the counterpart | Opaque, autonomous, reasons on its own | A deterministic function or exposed data source |
| Unit of exchange | A task (Task) with a state and a lifecycle |
A tool call / resource read |
| Typical duration | Seconds to days, multi-turn | Usually short, request/response |
| Interaction | Negotiation possible (INPUT_REQUIRED, AUTH_REQUIRED) |
The model calls, the tool answers |
| Discovery | Public Agent Card (/.well-known/agent-card.json), registries |
Listing tools/resources on the connected server |
| Transports | JSON-RPC 2.0, gRPC, HTTP+JSON | JSON-RPC 2.0 over stdio or HTTP |
| Async / long-running | Native: SSE, webhook push notifications | Possible but less central |
| Content | Multimodal via Parts (text, JSON, files, bytes) | Structured results, text, images, resources |
| Topology | Peer-to-peer, interchangeable client/server roles | Host β client β server |
| Origin / governance | Google β Linux Foundation | Anthropic β open governance by the MCP community |
| Maturity (Oct. 2026) | v1.0 stable (March 2026) | 2026-07-28 revision stable |
The right question to ask
"Do I want to perform a precise action, or hand over a goal to someone who will figure out how to reach it?"
- A precise, deterministic action (an SQL query, reading a file, calling a weather API) β MCP.
- A goal to reach by a system that reasons, can ask questions, and whose implementation you don't want to know about β A2A.
There is a grey area: you can expose a whole agent as an MCP "tool". That works for simple cases, but you lose what makes A2A strong: state tracking, multi-turn exchanges, long-running tasks and cross-organisation discovery.
9. Using A2A and MCP together
The two protocols are complementary and together form the communication stack of multi-agent systems:
Scenario:
- The user asks the orchestrator: "Organise Marie's interview in Lyon on Thursday."
- The orchestrator delegates via A2A to the HR agent ("schedule the interview") and to the travel agent ("book the trip").
- Each of these agents uses MCP internally to query its own tools: calendar, HRIS, booking API.
- The agents return their artifacts (confirmed slot, ticket) to the orchestrator via A2A.
Rule of thumb: A2A between agents, MCP between an agent and its tools.
10. Current limitations and best practices
Limitations to be aware of:
-
Per-skill data schema: a skill declares that it accepts
application/json, but the specification does not standardise the exact schema expected. Workaround: publish a JSON Schema in the skill description or through an Extension declared in the Agent Card. - Downscoping across delegation chains: A2A says how to pass credentials, not how to narrow them when a highly privileged orchestrator delegates to a less privileged agent. Workaround: OAuth 2.0 Token Exchange (RFC 8693) to issue short-lived, narrowly scoped tokens.
- No standard registry: discovery through a central catalogue is still something you build yourself.
-
Migrating from 0.x to 1.0: method names (
message/sendβSendMessage), prefixed state names, removal of thekindandfinalfields.
Best practices:
- Treat the Agent Card as a contract: any change to a skill, URL or capability must bump the version.
- Sign Agent Cards and verify signatures on the client side.
- Serve the card with
Content-Type: application/json. - Put an API gateway in front of agents to centralise authentication, quotas, logging and long-lived connection handling.
- Instrument with OpenTelemetry from day one: debugging a chain of five agents without distributed traces is painful.
- Never blindly trust content received from another agent: it is data, not instructions (prompt-injection risk).
11. Conclusion
A2A does for agents what HTTP did for documents or SMTP for email: it provides a common, neutral language that lets heterogeneous systems cooperate without bespoke integration. With a stable v1.0, Linux Foundation governance and adoption by the major platforms, it is now ready for production use.
MCP and A2A are not competitors: MCP gives an agent hands; A2A gives it colleagues. A modern multi-agent architecture uses both.
Further reading
- Official A2A specification
- A2A and MCP: how the two protocols relate (official A2A site)
- MCP specification
- A2A v1.0 technical guide β Tyk
- MCP vs A2A β Metorial
Originally published on my blog. Une version franΓ§aise est disponible ici.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.
