3.A2A
👉 #AI #LLM #Agent #SystemDesign #Security
I. A2A (Agent-to-Agent Protocol)
📅 2026-04-28 CDT; Claude Opus 4.6 📎 A2A Official Specification 📎 A2A GitHub Repository 📎 A2A Python SDK 📎 Google Codelab: A2A Purchasing Concierge 📎 A2A Protocol Guide (codilime) 📎 A2A Protocol Guide (letsdatascience) 📎 AWS Bedrock A2A Contract 📎 Microsoft Semantic Kernel + A2A
1. Overview
1.1. Definition & Why
- A2A (Agent-to-Agent) is an open protocol that lets AI Agents built by different vendors and frameworks discover, communicate, and collaborate with each other.
- Released by Google at Google Cloud Next '25 on April 9, 2025 with 50+ launch partners; donated to the Linux Foundation in June 2025; by mid-2026 it has 150+ supporting organizations (AWS, Microsoft, Cisco, Salesforce, SAP, ServiceNow, etc.).
- Core metaphor: the "HTTP of AI Agents". Just as HTTP standardized browser-server communication, A2A standardizes Agent-to-Agent communication.
- Pain solved: the Agent-silo problem.
- Without A2A: every Agent is a black box; you can't know what other Agents can do; every integration is custom engineering.
- With A2A: Agents declare capabilities via an Agent Card and delegate tasks via a standard protocol — cross-organization, cross-vendor collaboration becomes possible.
- Analogy: before HTTP, every networked application had a custom protocol. After HTTP, any browser could access any website.
- Technical essence: a stateful task protocol over JSON-RPC 2.0 + HTTP/HTTPS, with SSE streaming and Push Notification asynchronous callbacks.
- Relationship with MCP — complementary, not competitive:
- MCP: vertical integration (Agent ↔ Tool) — solves "how does an Agent use tools".
- A2A: horizontal integration (Agent ↔ Agent) — solves "how does an Agent collaborate with other Agents".
- Both are now under the Linux Foundation Agentic AI Foundation (AAIF); production systems typically use both.
1.2. Features & Use Cases
(1) Core Features
| Feature | Description |
|---|---|
| Opaque Agents | Internals not exposed; Agents interact as black boxes via standard interfaces |
| Agent Card | A JSON "business card" declaring skills, input/output formats, and authentication |
| Task Lifecycle | Standard state machine (submitted → working → completed/failed); supports long-running tasks |
| Streaming | Real-time progress updates and incremental results via SSE |
| Push Notification | Webhook-based notifications after disconnection |
| Multi-modal | Text, images, audio, video, files — multiple content types supported |
| Enterprise Security | OAuth 2.0, API Key, JWT, OpenID Connect — enterprise-grade auth |
| Vendor Neutral | Linux Foundation governance, 150+ organizations |
(2) Typical Use Cases
- Cross-department workflow orchestration: a Sales Agent delegates contract review to a Legal Agent, then payment processing to a Finance Agent.
- Multi-Agent collaborative analysis: a Data Agent collects data, a Stats Agent models, a Visualization Agent produces the report.
- Enterprise service integration: HR Agent + IT Agent collaborate on new-hire onboarding (account creation, equipment, permissions).
- Supply-chain coordination: Procurement Agent negotiates with a Supplier Agent on price; a Logistics Agent arranges delivery.
- Customer-service escalation: when a frontline customer-service Agent can't resolve, delegate to a specialist Agent.
- Code-development collaboration: Coding Agent writes code, Testing Agent runs tests, Deploy Agent ships to production.
1.3. Competitors & Alternatives
| Protocol/Approach | Sponsor | Position | Pros | Cons |
|---|---|---|---|---|
| A2A | Google → AAIF | Agent ↔ Agent (horizontal) | 150+ orgs, enterprise security, task lifecycle | New (2025-04); production deployment still early |
| MCP | Anthropic → AAIF | Agent ↔ Tool (vertical) | De-facto standard, 97M+ downloads, 10K+ Servers | Doesn't handle Agent-to-Agent comms |
| ACP (Agent Communication) | IBM and community | Agent-to-Agent comms | Community-driven, flexible | Low adoption; no big-vendor backing |
| ANP (Agent Network Protocol) | Community | Decentralized Agent network | Decentralized, DID identity | Experimental; tiny ecosystem |
| LangGraph / CrewAI | Frameworks | In-framework multi-Agent orchestration | Smooth dev experience, fast prototyping | Framework-locked; not cross-vendor |
| Custom REST/gRPC | Each team | Point-to-point integration | Full control | Every integration is custom; doesn't scale |
- Key distinctions:
- A2A vs MCP: A2A is the diplomatic protocol between Agents; MCP is the driver an Agent uses to operate tools. See
4.Protocol/2.MCP.md§1.3. - A2A vs ACP: similar position, but A2A has Google + 150 orgs behind it; ACP is more of a community experiment.
- A2A vs in-framework orchestration: LangGraph/CrewAI work best for multi-Agent setups inside the same framework; A2A works best across frameworks, organizations, and vendors.
2. Concept, Component, & Architecture
2.1. Key Concepts
(1) Agent Card — the Agent's "business card"
- Every A2A Server must expose an Agent Card at
/.well-known/agent.json. - The Agent Card is a JSON capability declaration: name, description, skills, input/output formats, auth.
- The Client reads the Agent Card to discover and select an Agent — like a fusion of DNS and API documentation.
- Core fields:
json { "name": "Recipe Agent", "description": "Helps users find and customize recipes", "url": "https://recipe-agent.example.com", "version": "1.0.0", "provider": { "organization": "FoodTech Inc" }, "capabilities": { "streaming": true, "pushNotifications": true }, "authentication": { "schemes": ["OAuth2"] }, "defaultInputModes": ["text/plain", "application/json"], "defaultOutputModes": ["text/plain", "image/png"], "skills": [ { "id": "find-recipe", "name": "Find Recipe", "description": "Search recipes by ingredients or cuisine", "tags": ["cooking", "search"], "examples": ["Find Italian pasta recipes with mushrooms"] } ] } - Design philosophy: Agents are opaque. The Client doesn't need to know which framework or LLM is inside — it only needs the Agent Card.
(2) Task — the unit of collaboration
- The most central concept in A2A: a unit of work delegated from a Client to a Server.
- Every Task has a unique ID and follows a standard state machine.
- Task state machine:
submitted → working → completed ↓ ↑ input-required ─────┘ ↓ failed / canceled / rejected - States:
| State | Description |
|---|---|
| submitted | Task submitted, waiting to be processed |
| working | Task is processing |
| input-required | Server needs additional input from the Client (multi-turn) |
| auth-required | Additional authentication needed |
| completed | Successfully completed |
| failed | Execution failed |
| canceled | Canceled by the Client |
| rejected | Rejected by the Server |
(3) Message & Part — the communication content
- Message: an exchange between Client and Server, with
role(user/agent) andpartsarray. - Part: the content units of a Message; supports multiple types:
| Part type | Description | Example |
|---|---|---|
| TextPart | Plain text | Natural-language message |
| FilePart | File content (inline bytes or URI) | Image, PDF, source file |
| DataPart | Structured JSON data | Form data, API response |
- Multi-modal: a single Message can contain multiple Parts of different types — text + image + structured data combined.
(4) Artifact — the task output
- An Artifact is a result produced during Task execution, stored separately from Messages.
- A single Task can produce multiple Artifacts (e.g., a report + a chart + a data file).
- Artifacts are also composed of Parts; multi-modal supported.
- Design intent: separate "the conversation" (Message) from "the deliverable" (Artifact) for clean result extraction.
(5) Streaming & Async — Two delivery modes
- Streaming (SSE): Client holds an HTTP connection; Server pushes progress updates and incremental results via Server-Sent Events.
- Best for: short-to-medium tasks where the Client is actively waiting.
- Event types:
TaskStatusUpdateEvent,TaskArtifactUpdateEvent. - Push Notification (Webhook): Client disconnects; Server calls back via webhook on status change.
- Best for: long-running tasks (minutes to hours); Client doesn't need to stay online.
- Flow: Client sets a
pushNotificationURL → Server POSTs to it on completion.
(6) Five Design Principles
- Agentic Capabilities: don't degrade to simple APIs — support multi-turn negotiation, long tasks, multi-modality.
- Opaque Agents: don't require exposing internals; Agents interact as black boxes.
- Built on Existing Standards: HTTP, JSON-RPC 2.0, SSE, OAuth — no reinventing wheels.
- Security First: enterprise-grade auth, authorization, audit.
- Long-Running Tasks: tasks may run seconds to hours, with full lifecycle management.
2.2. Core Components
(1) A2A Client
- The party initiating task requests — typically an "orchestrator Agent" or a "user proxy".
- Responsibilities: discover Agents (read Agent Cards), send tasks, receive results, handle multi-turn interaction.
- A single Client can interact with many Servers simultaneously to orchestrate multi-Agent workflows.
(2) A2A Server
- The party that receives and executes tasks — an Agent with specific capabilities.
- Responsibilities: expose an Agent Card, accept tasks, execute, return results / request input.
- The Server can use any framework internally (LangChain, CrewAI, AutoGen, custom, etc.) — opaque to the Client.
(3) Agent Card
- The capability-declaration file, hosted at
/.well-known/agent.json. - Includes name, description, skill list, I/O formats, auth, capability flags (streaming, pushNotifications).
- The basis for Agent discovery and selection.
(4) Task Manager
- The Server-side component managing Task lifecycles.
- Responsibilities: create Tasks, transition states, store Messages and Artifacts, handle cancellations.
(5) JSON-RPC Methods (API endpoints)
| Method | Description |
|---|---|
message/send |
Send message and create/continue a Task (sync) |
message/stream |
Send message and receive responses via SSE |
tasks/get |
Query current state and history of a Task |
tasks/cancel |
Cancel a running Task |
tasks/pushNotification/set |
Set the Push Notification webhook |
tasks/pushNotification/get |
Query current Push Notification config |
tasks/resubscribe |
Re-subscribe to a Task's SSE stream |
2.3. Architecture & Design
(1) Overall Architecture
graph TB
subgraph Client["Orchestrator / User Agent (A2A Client)"]
CC1["Agent Card Cache"]
CC2["Agent Card Cache"]
CC3["Agent Card Cache"]
CC4["Agent Card Cache"]
end
subgraph SA["A2A Server A (Sales)"]
TA["Agent Executor"]
end
subgraph SB["A2A Server B (Legal)"]
TB["Agent Executor"]
end
subgraph SC["A2A Server C (Finance)"]
TC["Agent Executor"]
end
subgraph SD["A2A Server D (HR)"]
TD["Agent Executor"]
end
CC1 -->|HTTPS| SA
CC2 -->|HTTPS| SB
CC3 -->|HTTPS| SC
CC4 -->|HTTPS| SD
SA --> CRM["CRM System"]
SB --> CDB["Contract DB"]
SC --> PAY["Payment API"]
SD --> HR["HR System"]
(2) Task Interaction Flow
sequenceDiagram
participant C as A2A Client (Orchestrator)
participant S as A2A Server (Specialist Agent)
C->>S: GET /.well-known/agent.json
S-->>C: Agent Card (skills, auth, capabilities)
C->>S: message/send {task_id, message: "Analyze Q3 sales data"}
S-->>C: Task {id, status: "working"}
Note over S: Agent is processing...
S-->>C: Task {status: "input-required", message: "Please specify the region"}
C->>S: message/send {task_id, message: "APAC"}
Note over S: Continuing...
S-->>C: Task {status: "completed", artifacts: [report, chart]}
(3) Streaming Flow
sequenceDiagram
participant C as A2A Client
participant S as A2A Server
C->>S: message/stream {message: "Generate the quarterly report"}
Note over C,S: SSE connection established
S-->>C: SSE: TaskStatusUpdateEvent {state: "working"}
S-->>C: SSE: TaskArtifactUpdateEvent {part: "Chapter 1..."}
S-->>C: SSE: TaskArtifactUpdateEvent {part: "Chapter 2..."}
S-->>C: SSE: TaskStatusUpdateEvent {state: "completed"}
Note over C,S: SSE connection closed
(4) A2A and MCP Co-architecture
graph TB
User["User / Application"]
User --> Orch
subgraph Orch["Orchestrator Agent"]
A2AClient["A2A Client (delegates tasks)"]
MCPClient1["MCP Client (calls tools)"]
end
subgraph Specialist["Specialist Agent (A2A Server)"]
MCPClient2["MCP Client"]
MCPClient2 -->|MCP| MCPDB["MCP Server (Database)"]
end
MCPServer["MCP Server (GitHub)"]
A2AClient -->|A2A| Specialist
MCPClient1 -->|MCP| MCPServer
- The Orchestrator delegates high-level tasks to Specialist Agents over A2A.
- The Specialist Agent uses MCP internally to call concrete tools (DB, APIs).
- Two protocols, distinct responsibilities: A2A handles "who does it"; MCP handles "how it's done".
2.4. Eco-system
(1) Official SDKs
| Language | Repo | Install |
|---|---|---|
| Python | github.com/google/a2a-python | pip install a2a-sdk |
| TypeScript | Community implementations | npm install a2a-sdk |
| Go | Official SDK | go get |
| Java | Official SDK | Maven/Gradle |
| JavaScript | Official SDK | npm install |
(2) Supported Platforms & Frameworks
| Platform / Framework | Integration |
|---|---|
| Google ADK (Agent Dev Kit) | Native, first-class support |
| Google Cloud Agent Engine | Hosted A2A Server |
| Amazon Bedrock AgentCore | Native A2A support (Runtime layer) |
| Microsoft Semantic Kernel | Plugin integration |
| LangChain / LangGraph | Community adapter |
| CrewAI | Community adapter |
| AutoGen | Community adapter |
(3) Governance & Community
| Org / Resource | Description |
|---|---|
| Linux Foundation AAIF | Governance body; same as MCP |
| 150+ supporting organizations | AWS, Microsoft, Cisco, Salesforce, SAP, etc. |
| Agent Payments Protocol (AP2) | A2A's commercial extension; 60+ payment orgs (Mastercard etc.) |
| Google Agent Registry | Agent Card registration and discovery |
| a2a-protocol.org | Official spec website |
3. Install, Configure, Secure, & Cheatsheets
3.1. A2A Server Development — Python
(1) Install
# Official SDK
pip install a2a-sdk
# Community library (simpler API)
pip install python-a2a
# Google ADK (includes A2A)
pip install google-adk
(2) Minimal Server (Official SDK)
# server.py
import uvicorn
from a2a.server.apps import A2AStarletteApplication
from a2a.server.agent_execution import AgentExecutor
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.types import AgentCard, AgentSkill, TaskState, Message, Part, TextPart
# Define the Agent Card
agent_card = AgentCard(
name="Echo Agent",
description="A simple agent that echoes back messages",
url="http://localhost:9000",
version="1.0.0",
skills=[
AgentSkill(
id="echo",
name="Echo",
description="Echoes back the user's message",
tags=["demo", "echo"],
examples=["Say hello"]
)
],
defaultInputModes=["text/plain"],
defaultOutputModes=["text/plain"],
capabilities={"streaming": False, "pushNotifications": False}
)
# Implement Agent logic
class EchoAgentExecutor(AgentExecutor):
async def execute(self, context, event_queue):
# Get user input
user_message = context.get_user_input()
# Return result
await event_queue.enqueue_event(
TaskState.completed,
message=Message(
role="agent",
parts=[TextPart(text=f"Echo: {user_message}")]
)
)
# Build the app
handler = DefaultRequestHandler(
agent_card=agent_card,
agent_executor_factory=lambda: EchoAgentExecutor()
)
app = A2AStarletteApplication(agent_card=agent_card, http_handler=handler)
if __name__ == "__main__":
uvicorn.run(app.build(), host="0.0.0.0", port=9000)
# Run
python server.py
# Verify Agent Card
curl http://localhost:9000/.well-known/agent.json | python -m json.tool
# Send a Task
curl -X POST http://localhost:9000/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [{"type": "text", "text": "Hello A2A!"}]
}
}
}'
(3) Simplified Community Library (python-a2a)
# simple_server.py
from python_a2a import A2AServer, AgentCard, skill, run_server
class MyAgent(A2AServer):
def get_agent_card(self) -> AgentCard:
return AgentCard(
name="Helper Agent",
description="A helpful assistant agent",
skills=[
skill(
id="answer",
name="Answer Questions",
description="Answers general questions"
)
]
)
def handle_task(self, task):
user_msg = task.get_user_message()
task.complete(f"You said: {user_msg}")
return task
if __name__ == "__main__":
run_server(MyAgent(), port=9000)
3.2. A2A Client Development — Python
# client.py
import httpx
import json
A2A_SERVER_URL = "http://localhost:9000"
# 1. Discover Agent (read Agent Card)
async def discover_agent():
async with httpx.AsyncClient() as client:
resp = await client.get(f"{A2A_SERVER_URL}/.well-known/agent.json")
agent_card = resp.json()
print(f"Agent: {agent_card['name']}")
print(f"Skills: {[s['name'] for s in agent_card['skills']]}")
return agent_card
# 2. Send a Task
async def send_task(message: str):
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [{"type": "text", "text": message}]
}
}
}
async with httpx.AsyncClient() as client:
resp = await client.post(A2A_SERVER_URL, json=payload)
result = resp.json()
return result
# 3. Streaming receive (SSE)
async def stream_task(message: str):
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "message/stream",
"params": {
"message": {
"role": "user",
"parts": [{"type": "text", "text": message}]
}
}
}
async with httpx.AsyncClient() as client:
async with client.stream("POST", A2A_SERVER_URL, json=payload) as resp:
async for line in resp.aiter_lines():
if line.startswith("data:"):
event = json.loads(line[5:])
print(f"Event: {event}")
3.3. Google ADK Integration
# adk_a2a_server.py
from google.adk.agents import Agent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
# Define an Agent
agent = Agent(
name="research_agent",
model="gemini-2.5-pro",
instruction="You are a research assistant. Help users find information.",
tools=[] # Add MCP Tools here
)
# Create the Runner (auto-exposes the A2A endpoints)
runner = Runner(
agent=agent,
app_name="research-app",
session_service=InMemorySessionService()
)
# The runner auto-publishes the Agent Card at /.well-known/agent.json
# and handles message/send, message/stream, etc.
3.4. Scripts & Tools
(1) Agent Card Validator
#!/bin/bash
# validate_agent_card.sh -- validate an A2A Server's Agent Card
SERVER_URL=${1:-"http://localhost:9000"}
echo "=== Fetching Agent Card ==="
CARD=$(curl -s "${SERVER_URL}/.well-known/agent.json")
if [ $? -ne 0 ]; then
echo "ERROR: Cannot reach ${SERVER_URL}"
exit 1
fi
echo "$CARD" | python3 -c "
import json, sys
card = json.load(sys.stdin)
print(f'Name: {card.get(\"name\", \"MISSING\")}')
print(f'URL: {card.get(\"url\", \"MISSING\")}')
print(f'Skills: {len(card.get(\"skills\", []))}')
for s in card.get('skills', []):
print(f' - {s[\"name\"]}: {s[\"description\"]}')
print(f'Streaming: {card.get(\"capabilities\", {}).get(\"streaming\", False)}')
print(f'Push: {card.get(\"capabilities\", {}).get(\"pushNotifications\", False)}')
print(f'Auth: {[s for s in card.get(\"authentication\", {}).get(\"schemes\", [])]}')
"
(2) Quick Task Test
# test_a2a_task.py
import asyncio
import httpx
async def test_task(server_url: str, message: str):
"""Quickly test an A2A Server's Task handling."""
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [{"type": "text", "text": message}]
}
}
}
async with httpx.AsyncClient(timeout=30) as client:
resp = await client.post(server_url, json=payload)
result = resp.json()
if "error" in result:
print(f"ERROR: {result['error']}")
else:
task = result.get("result", {})
print(f"Task ID: {task.get('id')}")
print(f"Status: {task.get('status', {}).get('state')}")
artifacts = task.get("artifacts", [])
for a in artifacts:
for p in a.get("parts", []):
if p.get("type") == "text":
print(f"Result: {p['text'][:200]}")
if __name__ == "__main__":
asyncio.run(test_task("http://localhost:9000", "Hello A2A!"))
(3) Common Tools and Platforms
| Tool / Platform | Use | Link |
|---|---|---|
| Google ADK | Agent dev framework, native A2A | github.com/google/adk-python |
| Google Agent Registry | Agent Card registration & discovery | docs.cloud.google.com/agent-registry |
| AWS Bedrock AgentCore | Hosted A2A Server | docs.aws.amazon.com/bedrock-agentcore |
| python-a2a | Community Python lib, simpler API | github.com/themanojdesai/python-a2a |
| A2A Protocol Playground | Online A2A interaction testing | a2a.plus |
3.5. Security Best Practices
(1) Authentication Methods
A2A reuses standard enterprise authentication mechanisms — no new ones invented. | Method | Best fit | Notes | | :---------------- | :----------------------------- | :----------------------------------- | | OAuth 2.0 | Enterprise, cross-organization | Recommended; fine-grained permissions | | API Key | Internal services, quick integration | Simple but less secure | | JWT Bearer Token | Microservice-to-microservice | Stateless; carries claims | | OpenID Connect | Identity-verification needed | Identity layer on top of OAuth 2.0 | | mTLS | High-security needs | Mutual certificate authentication |
(2) Security Checklist
- [ ] Agent Card declares supported auth schemes (
authentication.schemes) - [ ] HTTPS enforced in production
- [ ] Verify Client identity before executing tasks
- [ ] Don't leak internal implementation details in Task results
- [ ] Validate and filter user input on
input-required - [ ] Push Notification webhook URL validation (prevent SSRF)
- [ ] Limit Task concurrency and execution time to prevent resource exhaustion
- [ ] Audit logs: record creation, state changes, and completion of every Task
(3) Common Attack Vectors
| Attack | Description | Defense |
|---|---|---|
| Agent Card forgery | Malicious Agent impersonating a trusted Agent | Card signature verification, registry whitelist |
| Task injection | Malicious instructions injected via messages | Input validation, Prompt isolation |
| Webhook SSRF | Push Notification used to attack internal services | URL allowlist, outbound traffic limits |
| Denial of Service | Flood of Task requests exhausts resources | Rate limiting, auth-first |
| Data exfiltration | Sensitive data leaked via Artifacts | Output filtering, DLP policies |
3.6. Cheatsheets
(1) Development Workflow
# 1. Install SDK
pip install a2a-sdk
# or
pip install python-a2a
# 2. Define Agent Card (name, skills, auth)
# 3. Implement AgentExecutor (Task logic)
# 4. Start the Server
python server.py
# 5. Verify
curl http://localhost:9000/.well-known/agent.json
# 6. Test a Task
curl -X POST http://localhost:9000/ \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"message/send","params":{"message":{"role":"user","parts":[{"type":"text","text":"test"}]}}}'
(2) JSON-RPC Method Quick Reference
// Send (sync)
{"jsonrpc":"2.0","id":1,"method":"message/send","params":{"message":{"role":"user","parts":[{"type":"text","text":"..."}]}}}
// Send (streaming)
{"jsonrpc":"2.0","id":1,"method":"message/stream","params":{"message":{"role":"user","parts":[{"type":"text","text":"..."}]}}}
// Query Task state
{"jsonrpc":"2.0","id":2,"method":"tasks/get","params":{"id":"task-123"}}
// Cancel Task
{"jsonrpc":"2.0","id":3,"method":"tasks/cancel","params":{"id":"task-123"}}
// Set Push Notification
{"jsonrpc":"2.0","id":4,"method":"tasks/pushNotification/set","params":{"id":"task-123","pushNotificationConfig":{"url":"https://my-webhook.example.com/callback"}}}
(3) Task State Quick Reference
submitted ──→ working ──→ completed (normal flow)
│
├──→ input-required ──→ working (additional input needed)
├──→ auth-required ──→ working (auth needed)
├──→ failed (execution failed)
└──→ canceled (canceled)
submitted ──→ rejected (rejected by Server)
(4) A2A vs MCP Quick Reference
| Dimension | A2A | MCP |
|---|---|---|
| Direction | Agent ↔ Agent (horizontal) | Agent ↔ Tool (vertical) |
| Protocol | JSON-RPC + HTTP + SSE | JSON-RPC + stdio/HTTP |
| Discovery | Agent Card (/.well-known/) |
Capability Negotiation |
| Core unit | Task (stateful lifecycle) | Tool Call (request-response) |
| Async | Push Notification + SSE | Sampling + Elicitation |
| Typical scenario | Multi-Agent orchestration, cross-org collaboration | Tool calls, data-source connections |
| Used together | Orchestrator delegates tasks | Agent calls tools internally |
4. Bootcamp & Workshops
4.1. Learning Resources
| Resource | Type | Audience |
|---|---|---|
| A2A Official Spec | Spec | Everyone |
| A2A GitHub Repo | Source + samples | Engineers |
| Google Codelab: A2A Purchasing Concierge | Tutorial | Beginners |
| A2A Protocol Guide (codilime) | Deep dive | Architects |
| A2A Multi-Agent Guide (letsdatascience) | Guide | Full-stack |
| Microsoft Semantic Kernel + A2A | Integration | .NET developers |
| AWS Bedrock A2A Contract | AWS | AWS users |
| A2A Python Tutorial (kanaries) | Tutorial | Python developers |
| A2A TypeScript Guide | Tutorial | TS developers |
| A2A Security (Red Hat) | Security | Security engineers |
4.2. Trouble Shooting
(1) Agent Card not reachable
- Symptom:
GET /.well-known/agent.jsonreturns 404. - Diagnostics: confirm the Server registered the route correctly.
- Common causes: missing route in framework config; Server not running on the expected port.
(2) Task stuck in working forever
- Cause: Agent execution didn't transition state correctly (no complete/fail).
- Fix: ensure all paths end in a terminal state (completed/failed); add timeouts.
- Recommendation: enforce a max execution time and auto-fail.
(3) SSE stream disconnects
- Cause: middle proxy (Nginx, ALB) closes long-lived connections.
- Fix: configure proxy timeouts (Nginx
proxy_read_timeout 3600s). - Alternative: use Push Notification instead of SSE for long tasks.
(4) Multi-turn (input-required) doesn't work
- Cause: Client doesn't handle
input-requiredcorrectly, or doesn't passtask_idwhen continuing. - Fix: on
input-required, the Client must send the nextmessage/sendwith the sametask_id. - Note: every
message/sendmust include thetask_idto continue the same Task.
(5) Authentication failure
- Cause: Agent Card declares an auth scheme that doesn't match Server-side middleware.
- Fix: ensure
authentication.schemesmatches Server-side configuration. - Common pitfalls: expired OAuth token, API key not properly passed in headers.
(6) CORS issues
- Symptom: browser-side Client can't access the A2A Server.
- Fix: configure CORS headers (
Access-Control-Allow-Origin, etc.) on the Server. - Note:
/.well-known/agent.jsonalso needs CORS configuration.
4.3. Q & A
- How exactly do A2A and MCP work together?
- Short answer: A2A handles "who does it" (Agent-to-Agent delegation); MCP handles "how it's done" (Agent calls tools).
- Typical architecture: an Orchestrator Agent delegates tasks via A2A to Specialist Agents; each Specialist uses MCP internally to call DBs, APIs, etc.
- Both are governed by the Linux Foundation AAIF — they are not competing.
-
See
4.Protocol/2.MCP.md§1.3 and Q&A items 5, 7. -
When do I need A2A and when don't I?
- Need A2A: multiple independent Agents need to collaborate, especially across teams, organizations, or vendors.
- Don't need A2A: a single Agent + MCP Tools is enough; multi-Agent within the same framework (use LangGraph/CrewAI — simpler).
-
Test: if your Agent needs to "delegate to another Agent you don't control", you need A2A.
-
What's the difference between an A2A Server and an MCP Server?
- MCP Server: exposes Tools/Resources/Prompts; used by an Agent as a tool; no autonomous decision-making.
- A2A Server: itself an Agent with autonomous decisions, multi-turn, can reject tasks.
-
Analogy: MCP Server is "a hammer in the toolbox"; A2A Server is "a colleague you can delegate to".
-
Difference between Agent Card and an MCP Tool Schema?
- Agent Card: describes the Agent's overall capabilities (skills) — high-level "what can I do".
- Tool Schema: describes a single tool's I/O — low-level "how to call this function".
-
Agent Card is more like a resume; Tool Schema is more like API documentation.
-
How is an A2A Task different from a normal API call?
- API call: synchronous, stateless, request-response, milliseconds.
- A2A Task: asynchronous, stateful, multi-turn, runs seconds to hours.
-
A2A Task can pause (
input-required) to wait for human input — API calls cannot. -
How mature is A2A as of mid-2026?
- Spec: stable; v0.3+ supports gRPC and signed agent cards.
- SDKs: official Python/Go/Java/JS SDKs available.
- Production: still early; mostly PoCs and pilot projects.
- Ecosystem: 150+ orgs support it, but the count of production-grade A2A Servers is far fewer than MCP Servers.
-
Recommendation: track and learn it; pilot in suitable scenarios (cross-org multi-Agent); don't roll out broadly yet.
-
When do you write a Skill, install an MCP, or use A2A?
- Skill: teach an Agent how to do something — workflows, conventions, templates (see
4.Protocol/1.Skill.md). - MCP: give an Agent "hands and feet" — connect tools, data sources, external systems (see
4.Protocol/2.MCP.md). - A2A: let an Agent "find a colleague" — delegate tasks to other Agents; cross-organization collaboration.
- The three are complementary: Skills define the flow; MCP provides the tools; A2A coordinates the division of labor.
- Heuristic: "I want to teach the Agent a process" → Skill; "I want the Agent to query a database" → MCP; "I want the Agent to hand a task to another Agent" → A2A.