1️⃣ Introduction
Agent-to-Agent (A2A) Protocol is an open standard that enables independent AI agents to discover each other, share capabilities, and collaborate on tasks in a secure and interoperable way. Instead of building one monolithic agent, A2A allows specialized agents—such as a planner, researcher, or executor—to communicate seamlessly across different frameworks and organizations. By defining a common structure for discovery (Agent Cards), task management (Task lifecycle), and communication (messages & parts), A2A provides the foundation for scalable, multi-agent ecosystems where agents can work together much like microservices do in modern software architectures.
2️⃣ Agent Cards
- A small, self-describing JSON document that advertises an agent’s identity, capabilities, and how to interact with it.
- It typically lives at a well-known URL like
https://yourdomain.com/.well-known/agent.json
(oragent-card.json
). - It enables automated discovery and interoperability so other agents can safely submit tasks and receive updates without custom integrations.
- A consuming agent fetches and parses the card → learns endpoints, formats, and auth → submits tasks accordingly.
🔹 Agent Card Keys
id
- A globally unique identifier (URN/UUID) for the agent (e.g.,
urn:agent:example:researcher-1
).
name
- Human-readable name for UIs and logs.
description
- Short summary of the agent’s purpose and domain.
version
- Semantic version of the agent service; helps with change management and client compatibility.
endpoints/task_submit
- HTTP endpoint where other agents POST tasks for execution.
- Accepts a task object (JSON). Returns task acceptance/ID and may start processing asynchronously.
endpoints/events
- Endpoint to stream progress updates (SSE/webhooks) or poll for status/results.
- Clients subscribe or query using the previously returned task ID.
capabilities
- A list describing actions/skills (e.g.,
web.search
,summarize
). - Lets peers quickly assess whether this agent can fulfill a requested task.
modalities
- Supported input/output formats (e.g.,
text/plain
,application/json
). - Ensures payload compatibility between agents.
auth
- Required authentication scheme(s) (e.g., OAuth2 scopes, mTLS, API keys).
- Enforces secure, auditable access aligned with enterprise policies.
skills (optional)
- Richer, structured descriptions of capabilities with tags and examples.
- Improves automated routing/selection among multiple candidate agents.
protocolVersion (optional)
- The A2A protocol version implemented.
- Helps clients negotiate behavior and avoid drift.
🔹 Example Agent Card
{
"a2a_version": "1.0",
"id": "urn:agent:example:researcher-1",
"name": "Researcher Agent",
"description": "Finds sources on the web and summarizes them.",
"version": "1.0.0",
"endpoints": {
"task_submit": "https://researcher.example.com/a2a/tasks",
"events": "https://researcher.example.com/a2a/events"
},
"capabilities": ["web.search", "summarize"],
"modalities": ["text/plain", "application/json"],
"auth": {
"type": "oauth2",
"scopes": ["a2a.tasks.write", "a2a.events.read"]
}
}
3️⃣ Discovery Directory
- A shared registry service where agents publish their Agent Cards so others can find them dynamically.
- Acts as the DNS + service registry of the A2A ecosystem — but instead of just resolving network addresses, it resolves capabilities.
- Allows agents to query by capability, version, or metadata to locate the right peer for a task.
- Enables dynamic, loosely coupled ecosystems where agents can join/leave without manual wiring.
- ADK provides a Discovery Directory out of the box, so developers can immediately register and look up agents. For advanced use cases, teams can swap in custom registries with richer policies or scaling behavior.
🔹 Discovery Directory Keys
url
- Base URL of the directory service (e.g.,
https://directory.example.com/a2a
). - Agents register their cards here and consumers query it for matches.
query
- API to request available agents by criteria (capabilities, region, trust level, version).
- Returns one or more Agent Cards that match.
registration
- Endpoint for an agent to register or update its Agent Card.
- Typically authenticated to prevent rogue entries.
metadata
- Optional performance/health data stored alongside each entry.
- Examples: uptime, SLA, latency profiles, trust scores.
- Helps consumers select among multiple candidates.
🔹 Example Directory Query
GET https://directory.example.com/a2a/agents?capability=web.search
Accept: application/json
🔹 Example Directory Response
[
{
"id": "urn:agent:example:researcher-1",
"name": "Researcher Agent",
"capabilities": ["web.search", "summarize"],
"endpoints": {
"task_submit": "https://researcher.example.com/a2a/tasks",
"events": "https://researcher.example.com/a2a/events"
},
"metadata": {
"region": "us-east1",
"sla": "99.9%",
"trustLevel": "verified"
}
}
]
4️⃣ Task Submission (A2A)
🔹 Key Points
- Submit work to another agent via its
task_submit
endpoint (from the Agent Card). -
Async-first: server returns immediately with
{ id, status: "submitted", links: { self, events } }
. - Track progress using events (SSE/webhook) for real-time updates until terminal status:
completed
orfailed
. - Use a client-generated task ID for idempotency; retries with the same ID should not duplicate execution.
- Final output is received via the events stream.
🔹 Example Flow (High-Level)
- Discover receiver’s
task_submit
from its Agent Card. - Build task payload:
id
,requester
, andpayload
(type
+ args). -
POST
it totask_submit
→ receive async ack withlinks.events
. - Subscribe to the events endpoint to get status updates and results.
- Print the final status and artifacts when the task is completed.
🔹 Example Task Submit in Python (Async with SSE)
# Brief, happy-path example: async task submission + SSE event subscription
# Focused on clarity, with inline comments explaining each step.
import asyncio, json, uuid, httpx
# Endpoint for submitting tasks — discovered from the Agent Card
TASK_SUBMIT_URL = "https://receiver.example.com/a2a/tasks"
# Access token (OAuth2 bearer, API key, or other scheme from Agent Card auth section)
ACCESS_TOKEN = "<TOKEN>"
async def main():
# Step 1: Generate a unique task ID for idempotency
# Using UUID ensures retries with the same ID won't duplicate execution if the server deduplicates
task_id = f"task-{uuid.uuid4()}"
# Step 2: Build the payload
# Includes:
# - id: chosen by the client
# - requester: who is submitting (URN or URL)
# - payload: actual work request (type + arguments)
payload = {
"id": task_id,
"requester": "urn:agent:example:planner-1",
"payload": {
"type": "web.search",
"query": "Latest AI conferences in 2025"
}
}
async with httpx.AsyncClient() as client:
# Step 3: Submit the task
# POST returns quickly with async acknowledgment (id, status=submitted, links)
ack = (await client.post(
TASK_SUBMIT_URL,
headers={
"Authorization": f"Bearer {ACCESS_TOKEN}", # auth as required by Agent Card
"Accept": "application/json" # we want JSON back
},
json=payload,
)).json()
print("Submitted", ack["id"], "status=", ack["status"])
# ack contains "links": { "self": ..., "events": ... }
# - links.self: poll for updates
# - links.events: subscribe for streaming updates (preferred)
# Step 4: Subscribe to events stream (SSE)
# Server sends progress + final results as "data: {...}" lines
events_url = ack["links"]["events"]
async with client.stream(
"GET",
events_url,
headers={
"Authorization": f"Bearer {ACCESS_TOKEN}",
"Accept": "text/event-stream"
}
) as resp:
# Loop over incoming SSE lines until we see a terminal status
async for line in resp.aiter_lines():
if not line or not line.startswith("data:"):
continue # ignore comments/keepalives
evt = json.loads(line[5:].strip()) # strip "data:" prefix, parse JSON
if "status" in evt:
print("[event] status=", evt["status"])
# Break once we hit completed/failed — final output is available
if evt["status"] in {"completed", "failed"}:
final = evt
break
else:
# Could be partial result or log message
print("[event]", evt)
# Step 5: Print final output
print("Final status:", final["status"])
for a in final.get("artifacts", []):
# Artifacts may have inline content (text) or links (href)
print("-", a.get("type"), a.get("content", a.get("href", "<no content>")))
if __name__ == "__main__":
asyncio.run(main())
🔹 Example Output
Submitted: {"id": "task-123", "status": "submitted", "links": {"events": "..."}}
[event] {"status": "working"}
[event] {"status": "completed", "artifacts": [{"type": "text/plain", "content": "Upcoming AI conferences: NeurIPS 2025, ICML 2025..."}]}
Final output: {"status": "completed", "artifacts": [{"type": "text/plain", "content": "Upcoming AI conferences: NeurIPS 2025, ICML 2025..."}]}
5️⃣ Messages & Parts
🔹 Key Points
- Messages are a general-purpose communication channel between agents, outside of task submission.
- Each message has metadata (id, sender, recipient, timestamp) and a list of parts.
- Typed payloads such as text, JSON, image, or file references. Each part has a
type
and eithercontent
orhref
. - Share context, logs, prompts, human-in-the-loop requests, or supporting artifacts.
- Messages are POSTed to the
messages
endpoint advertised in the Agent Card. - Typed parts let heterogeneous agents parse what they understand and ignore the rest.
🔹 Example Flow
- Agent A POSTs a message to Agent B’s
messages
endpoint. - The message contains metadata plus one or more typed parts.
- Agent B processes each part as appropriate (display, parse JSON, fetch URI, etc.).
🔹 Example Message (JSON)
{
"id": "msg-42",
"sender": "urn:agent:example:planner-1",
"recipient": "urn:agent:example:researcher-1",
"timestamp": "2025-08-28T12:00:00Z",
"parts": [
{
"type": "text/plain",
"content": "Please summarize this document."
},
{
"type": "application/json",
"content": { "docId": "abc123", "priority": "high" }
},
{
"type": "text/uri-list",
"href": "https://example.com/docs/abc123.pdf"
}
]
}
🔹 Example Server Response
{
"id": "msg-3f1e3f7b-2c58-42ab-94cd-fc22e3b1687a",
"status": "ok",
"received_at": "2025-08-28T12:34:56Z",
"echo": {
"parts": [
{ "type": "text/plain", "content": "Please summarize this document." },
{ "type": "text/uri-list", "href": "https://example.com/docs/abc123.pdf" }
]
}
}
Top comments (1)
Agent Cards + async events feels like OpenAPI + webhooks for agents. As the industry moves toward interoperable, composable AI stacks, could A2A become the standard layer for federated agent marketplaces, observability, and policy‑aware routing?