MCP is agent-to-tool. A2A (Agent2Agent) is agent-to-agent — an open protocol for letting opaque agents built on different frameworks collaborate. Released by Google in April 2025, donated to the Linux Foundation in June 2025, reaching v1.0 in April 2026 with 150+ supporters including AWS, Cisco, Microsoft, Salesforce, SAP, and ServiceNow. It absorbed IBM's ACP and added the AP2 payments extension. This lesson walks the Agent Card, Task lifecycle, and the three protocol bindings, using the A2A 1.0.1 wire names.
Type: Build Languages: Python (stdlib, Agent Card + Task harness) Prerequisites: Phase 13 · 06 (MCP fundamentals), Phase 13 · 08 (MCP client) Time: ~75 minutes
Learning Objectives
- Distinguish agent-to-tool (MCP) from agent-to-agent (A2A) use cases.
- Publish an Agent Card at
/.well-known/agent-card.jsonwith skills andsupportedInterfacesmetadata. - Walk the Task lifecycle:
TASK_STATE_SUBMITTED,TASK_STATE_WORKING,TASK_STATE_INPUT_REQUIRED, and the terminal statesTASK_STATE_COMPLETED,TASK_STATE_FAILED,TASK_STATE_CANCELED,TASK_STATE_REJECTED. - Use Messages whose Parts each hold one of
text,raw,url, ordata, and Artifacts as outputs.
The Problem
A customer-service agent needs to delegate report-writing to a specialized writer agent. Options pre-A2A:
- Custom REST API. Works but every pairing is a one-off.
- Shared codebase. Requires the two agents to run the same framework.
- MCP. Doesn't fit: MCP is for calling tools, not for two agents collaborating while preserving each agent's opaque internal reasoning.
A2A fills the gap. It models the interaction as one agent sending a Task to another, with a lifecycle, messages, and artifacts. The called agent's internal state stays opaque — the caller sees only task state transitions and eventual outputs.
A2A is the "let agents across frameworks talk to each other" protocol. It does not replace MCP; the two are complementary.
The Concept
Agent Card
Every A2A-compliant agent publishes a card at /.well-known/agent-card.json:
{
"name": "research-agent",
"description": "Summarizes academic papers and drafts citations.",
"version": "1.2.0",
"supportedInterfaces": [
{
"url": "https://research.example.com/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
],
"capabilities": {"streaming": true, "pushNotifications": true},
"securitySchemes": {
"bearer": {"httpAuthSecurityScheme": {"scheme": "Bearer"}}
},
"securityRequirements": [{"schemes": {"bearer": {"list": []}}}],
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/markdown"],
"skills": [
{
"id": "summarize_paper",
"name": "Summarize a paper",
"description": "Read a paper PDF and produce a 3-paragraph summary.",
"tags": ["research", "summarization"],
"inputModes": ["text/plain", "application/pdf"],
"outputModes": ["text/markdown"]
}
]
}
Discovery is URL-based: fetch the card, pick the first supportedInterfaces entry whose protocolBinding your client speaks, and enumerate skills. Input and output modes are media types.
Signed Agent Cards
A card can carry a signatures array. Each entry is a JWS (RFC 7515) computed over the card's RFC 8785 canonical JSON, with the signatures field left out. Consumers canonicalize the card the same way and verify. Prevents impersonation.
Task lifecycle
TASK_STATE_SUBMITTED
-> TASK_STATE_WORKING
-> TASK_STATE_COMPLETED | TASK_STATE_FAILED | TASK_STATE_CANCELED | TASK_STATE_REJECTED
TASK_STATE_WORKING
-> TASK_STATE_INPUT_REQUIRED
-> TASK_STATE_WORKING (the client sends a message with the same taskId)
Clients initiate with SendMessage, and the server creates the Task. The called agent transitions through states; clients poll with GetTask or stream over SSE with SendStreamingMessage and SubscribeToTask. A stream carries statusUpdate and artifactUpdate events and closes when the task reaches a terminal state. There is no final flag.
Messages and Parts
A message has a messageId, a role (ROLE_USER or ROLE_AGENT), and one or more Parts. Each Part holds exactly one content field, and that field name is the type. There is no kind field.
text: plain content.raw: file bytes, base64 in JSON, usually withfilenameandmediaType.url: a link to file content.data: structured JSON payload (structured input for the called agent).
Example:
{
"messageId": "msg-001",
"role": "ROLE_USER",
"parts": [
{"text": "Summarize this paper."},
{"raw": "...", "filename": "paper.pdf", "mediaType": "application/pdf"},
{"data": {"targetLength": "3 paragraphs"}, "mediaType": "application/json"}
]
}
Artifacts
Outputs are Artifacts, not raw strings. An Artifact is a named, typed output:
{
"artifactId": "art-001",
"name": "summary",
"parts": [{"text": "...", "mediaType": "text/markdown"}]
}
Artifacts can be streamed as chunks. Each artifactUpdate event carries the artifact plus append and lastChunk. The caller accumulates.
Three protocol bindings
- JSON-RPC 2.0 over HTTP (
JSONRPC). POST for requests, SSE for streaming. Methods are PascalCase:SendMessage,SendStreamingMessage,GetTask,ListTasks,CancelTask,SubscribeToTask,CreateTaskPushNotificationConfig,GetTaskPushNotificationConfig,ListTaskPushNotificationConfigs,DeleteTaskPushNotificationConfig, andGetExtendedAgentCard. - gRPC (
GRPC). For enterprise environments where gRPC is native. Same method names. - HTTP+JSON/REST (
HTTP+JSON). Resource URLs such asPOST /message:sendandGET /tasks/{id}.
All three bindings carry the same data model. Each supportedInterfaces entry names one binding and its protocolVersion. Clients send the header A2A-Version: 1.0 on every request, because a server reads a request without it as version 0.3.
POST /a2a HTTP/1.1
Host: research.example.com
Content-Type: application/json
A2A-Version: 1.0
{
"jsonrpc": "2.0",
"id": 1,
"method": "SendMessage",
"params": {
"message": {
"messageId": "msg-001",
"role": "ROLE_USER",
"parts": [{"text": "Summarize this paper."}]
}
}
}
Opacity preservation
A key design principle: the called agent's internal state is opaque. The caller sees task state and artifacts. The called agent's chain-of-thought, its tool calls, its sub-agent delegation — all invisible. This is different from MCP, where tool calls are transparent.
Rationale: A2A enables competitors to collaborate without revealing internals. A2A can be "call this customer-service agent" without the caller learning how that agent implements the service.
Timeline
- 2025-04-09. Google announces A2A.
- 2025-06-23. Donated to Linux Foundation.
- 2025-08. Absorbs IBM's ACP.
- 2025-09. AP2 extension (Agent Payments) ships.
- 2026-04. v1.0 released with 150+ supporting organizations.
Relationship to MCP
| Dimension | MCP | A2A |
|---|---|---|
| Use case | Agent-to-tool | Agent-to-agent |
| Opacity | Transparent tool calls | Opaque inner reasoning |
| Typical caller | Agent runtime | Another agent |
| State | Tool-call result | Task with lifecycle |
| Authorization | OAuth 2.1 (Phase 13 · 16) | Agent Card securitySchemes + securityRequirements |
| Transport | Stdio / Streamable HTTP | JSON-RPC / gRPC / HTTP+JSON |
Use MCP when you want to invoke a specific tool. Use A2A when you want to delegate a whole task to another agent. Many production systems use both: an agent uses MCP for its tool layer and A2A for its collaboration layer.
a2a-task-lifecycleUse It
code/main.py implements a minimal A2A harness: the writer agent publishes its card, the research agent sends it a SendMessage request with a PDF part and a text instruction, and the task moves through TASK_STATE_WORKING → TASK_STATE_INPUT_REQUIRED → TASK_STATE_WORKING → TASK_STATE_COMPLETED before returning a text artifact. All stdlib; uses an in-memory transport to focus on message shapes.
What to look at:
- Agent Card JSON shape.
- Server-side task id assignment and state transitions.
- Parts typed by which content field is present.
TASK_STATE_INPUT_REQUIREDbranch mid-task.- Artifact return on completion.
Ship It
This lesson produces outputs/skill-a2a-agent-spec.md. Given a new agent that should be callable by other agents, the skill produces the Agent Card JSON, skills schema, and endpoint blueprint.
Exercises
-
Run
code/main.py. Trace the full Task lifecycle, including theTASK_STATE_INPUT_REQUIREDpause where the called agent asks for a clarification. -
Add a signed Agent Card. Put one JWS entry in
signatureswithalgset toHS256, signing the card's canonical JSON without thesignaturesfield. Write a verifier and confirm it fails on a mutated card. -
Implement task streaming with
SendStreamingMessage: the writer agent emits thetask, threeartifactUpdatechunks, and astatusUpdatewithTASK_STATE_COMPLETED, then closes the stream. The caller accumulates the chunks. -
Design an A2A agent that wraps an MCP server. Map each MCP tool to an A2A skill. Note the trade-offs — what opacity is lost?
-
Read the A2A v1.0 announcement and identify the one feature that is not yet implemented by any framework as of April 2026. (Hint: it relates to multi-hop task delegation.)
Key Terms
| Term | What people say | What it actually means |
|---|---|---|
| A2A | "Agent-to-Agent protocol" | Open protocol for opaque agent collaboration |
| Agent Card | "/.well-known/agent-card.json" | Published metadata describing an agent's skills and supportedInterfaces |
| Skill | "A callable unit" | A named operation the agent supports (analog to MCP tool) |
| Task | "Unit of delegation" | A work item with a lifecycle and final artifact |
| Message | "Task input" | Carries Parts (text, raw, url, data) |
| Part | "Typed chunk" | Exactly one of text / raw / url / data, plus optional mediaType; no kind field |
| Artifact | "Task output" | Named, typed output returned on completion |
| AP2 | "Agent Payments Protocol" | Payments extension built on A2A; card signing is core A2A (signatures) |
| Opacity | "Black-box collaboration" | Called agent's internals are hidden from caller |
TASK_STATE_INPUT_REQUIRED | "Task pause" | Interrupted state when the agent needs more info |
Further Reading
- a2a-protocol.org — canonical A2A specification
- a2aproject/A2A — GitHub — reference implementations and SDKs
- A2A v1.0.1 release: the tagged
docs/specification.mdand the normativespecification/a2a.protothis lesson follows - Linux Foundation — A2A launch press release — June 2025 governance transfer
- Google Cloud — A2A protocol upgrade — roadmap and partner momentum
- Google Dev — A2A 1.0 milestone — v1.0 release notes and backward-compat guidance