A2A Protocol in Practice: When AI Agents Start Talking to Each Other, Things Get Interesting
Last month I wrote about What the Heck is MCP? A Full-Stack Dev's Practical Take — the protocol that lets AI agents call external tools. Someone in the comments asked a natural follow-up: "Can agents call other agents?" Like, if I have a coding agent and a testing agent, can they just figure things out between themselves without me playing telephone operator?
Honestly, I didn't know enough to answer at the time. So I went digging, and discovered that Google dropped the A2A (Agent-to-Agent) protocol back in April 2025 specifically for this use case. I've been tinkering with it for a couple weeks now, hit plenty of walls, and figured it was time to write up what I learned.
A2A vs MCP: The Question Everyone Asks
Let's get this out of the way first because it's the number one thing people get confused about.
MCP (Model Context Protocol) handles how an agent calls tools. Your agent wants to query a database, call an API, read a file — that's all MCP territory. The agent is the boss, the tool is the servant. Clean relationship.
A2A handles how agents talk to other agents. Your agent isn't calling a dumb tool — it's collaborating with another agent that has its own intelligence, its own reasoning, its own capabilities. Neither side knows how the other one works internally. They just communicate through a standard interface.
Think of it this way: MCP is you ordering at a restaurant (you tell the waiter what you want). A2A is two chefs in the kitchen coordinating on a complex meal (each has their own specialty, they negotiate and collaborate).
They're not competing — they're complementary. A single agent can use MCP to call tools AND use A2A to collaborate with other agents at the same time.
The Core Concepts
A2A 1.0 shipped in 2025, built on JSON-RPC 2.0 over HTTP(S). The design is surprisingly clean. Let me walk through the key pieces.
Agent Card
This is probably the most important concept. Every A2A Server publishes an Agent Card — basically a self-description. It tells you:
- Who you are (name, description)
- What you can do (skills list)
- Where to reach you (service URL)
- How to authenticate
It lives at /.well-known/agent.json. When another agent wants to collaborate with you, it reads your Agent Card first to see if you're a good fit.
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
Task
The fundamental work unit in A2A. You send a message to another agent, it creates a Task to track the request. Tasks have a lifecycle:
submitted→ just arrivedworking→ being processedinput-required→ needs more info from youcompleted→ donefailed→ blew upcanceled→ you gave up waiting
This is clever because agent collaboration can be long-running — nothing like a simple REST API call. Tasks let you track progress asynchronously.
Message and Part
The communication units. A Message has a role (user or agent) and contains one or more Parts.
Parts come in three flavors:
- TextPart: plain text
- FilePart: a file (URL reference or inline base64)
- DataPart: structured JSON data
This flexibility means A2A isn't just about passing text — you can exchange files, structured data, even binary blobs.
Artifact
The output an agent produces after completing a task. If you asked it to write code, the artifact is the code file. If you asked it to analyze something, the artifact is the report.
Building an A2A Server: Let's Actually Code This
Enough theory. Let me show you how to build a real A2A Server using the Python SDK.
Setup
| 1 | |
| 2 | |
| 3 | |
First gotcha I hit: the SDK requires Python 3.10+. My server defaulted to 3.9 and I got cryptic syntax errors. Had to switch to 3.11 with pyenv. Classic.
A Simple Translation Agent Server
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | |
| 38 | |
| 39 | |
| 40 | |
| 41 | |
| 42 | |
| 43 | |
| 44 | |
| 45 | |
| 46 | |
| 47 | |
| 48 | |
| 49 | |
| 50 | |
| 51 | |
| 52 | |
| 53 | |
| 54 | |
Fire it up:
| 1 | |
Test the Agent Card endpoint:
| 1 | |
If you get the JSON back, you're good.
Writing a Client
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | |
The client reads the Agent Card, sends a message, and gets back the translation. Simple enough.
When I first ran this, I got a ConnectionRefusedError. Took me 20 minutes to figure out that port 8000 was already taken by something else. Switched to 8001 and it worked. These little environment issues are the bane of trying new tools.
Streaming: Real-Time Progress Updates
The synchronous example works fine, but what if your agent takes 30 seconds to process? You can't just sit there with a spinning cursor. A2A supports SSE (Server-Sent Events) streaming for real-time progress.
On the server side, you yield events as you go:
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
On the client side, you iterate over the stream:
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
The upside: much better UX. The downside: significantly more complex to implement, and debugging SSE streams is a pain. The logs are messy and breakpoints don't work as cleanly as with synchronous code.
Multi-Agent Orchestration: Where A2A Really Shines
Single-agent examples can be done with a plain REST API. A2A's real value emerges when you have multiple agents collaborating.
Picture this: you have a Requirements Analyst Agent, a Code Generator Agent, and a Test Runner Agent. A user describes a feature, and the three agents work together to deliver working, tested code.
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | |
| 38 | |
| 39 | |
| 40 | |
| 41 | |
| 42 | |
| 43 | |
| 44 | |
| 45 | |
| 46 | |
| 47 | |
| 48 | |
| 49 | |
| 50 | |
| 51 | |
| 52 | |
| 53 | |
| 54 | |
| 55 | |
| 56 | |
| 57 | |
| 58 | |
| 59 | |
| 60 | |
| 61 | |
| 62 | |
| 63 | |
| 64 | |
| 65 | |
| 66 | |
| 67 | |
| 68 | |
| 69 | |
The orchestrator chains three agents together, feeding each one's output to the next. In a real project you'd add error handling, retries, maybe parallel execution for independent steps.
When to Use What
Since there's already an MCP article on this site, here's a practical decision framework:
Use MCP when:
- Your agent needs to query a database
- Your agent calls external APIs
- Your agent reads/writes files
- Your agent uses search engines
- The "tool" is stateless — one call, one result
Use A2A when:
- Multiple agents collaborate on a complex task
- Tasks run for a long time (minutes or hours)
- Agents need to exchange context and negotiate
- Different teams/companies built the agents
- You need to preserve agent "opacity" (no internal state exposed)
Real-world example:
You're building an automated code review system:
- MCP connects to GitHub API (read PRs, post comments)
- MCP connects to SonarQube (code quality checks)
- A2A connects to an independent "Security Review Agent" (has its own knowledge base and reasoning)
- A2A connects to an independent "Performance Analysis Agent" (has its own benchmarks)
MCP handles tool calls. A2A handles agent collaboration. Clean separation.
Pitfalls I Hit (So You Don't Have To)
Pitfall 1: Agent Card URLs Must Be Absolute
I initially wrote the URL as a relative path /api/agent. The client choked on it. A2A spec requires full absolute URLs with protocol and domain.
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
Pitfall 2: Task States Can't Skip Steps
Task state transitions are strict. You can't jump from submitted directly to completed — you must go through working first. I tried to be clever and shortcut this once. The client parser broke.
Valid transitions:
submitted→working→completedsubmitted→working→failedsubmitted→working→input-required→working→completed- Any non-terminal state →
canceled
Pitfall 3: JSON-RPC ID Must Match
A2A uses JSON-RPC 2.0. The id field in request and response must match. The SDK handles this for you, but if you're testing with raw HTTP/curl, watch out.
Pitfall 4: SSE Timeout Through Proxies
Streaming responses use Server-Sent Events. If your agent takes longer than 30 seconds, intermediate proxies (nginx, load balancers) might kill the connection.
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
Pitfall 5: Don't Skip Auth
A2A supports standard HTTP auth (Bearer Token, OAuth2). In my test environment I ran without auth for a week — everything worked. When I moved to production, nginx's security module blocked every request because there was no auth header. Added Bearer Token and it was fine. Don't be lazy like me.
Integrating With Existing Frameworks
A2A isn't trying to replace your existing agent framework. It gives them a common communication layer.
Google ADK: Native A2A support. Wrapping an ADK agent as an A2A Server is nearly zero-cost.
LangGraph: Works through adapters. Wrap your LangGraph agent as an A2A Server and it becomes callable by any A2A Client.
CrewAI: Natural fit. Each Crew can expose itself as an A2A Agent, and multiple Crews collaborate through A2A.
Roll your own: If your agent is custom-built (say, calling OpenAI API directly), you implement the A2A protocol manually:
- HTTP Server exposing
/.well-known/agent.jsonand JSON-RPC endpoints - Handle
message/sendrequests - Return A2A-compliant Task or Message responses
Security: The Big Concern
Agents talking to each other raises serious security questions. A2A addresses several:
Opacity
The most important security principle. Agents collaborate without exposing their internals. The other agent doesn't know what model you're using, what tools you have, or what you've memorized. Unlike traditional APIs where you need to know the interface spec, A2A only uses the public information in the Agent Card.
Auth
A2A supports standard HTTP auth mechanisms. The Agent Card declares what authentication is required. The client provides credentials with each request.
Input Validation
Never trust another agent's output. Even "trusted" agents can produce malicious content (prompt injection attacks). Always validate and sanitize A2A responses before processing them.
Performance Tips
Connection Reuse
If you're calling the same agent frequently, keep HTTP connections alive. The Python SDK uses httpx under the hood which supports this by default.
Parallel Calls
If multiple agents need to be called and they're independent, use asyncio.gather:
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
I tested this with three agents. Parallel execution took about as long as the slowest individual agent — roughly 3x faster than serial execution.
Cache Agent Cards
Agent Cards don't change often. Cache them client-side instead of fetching every time. The spec recommends supporting HTTP caching headers (ETag, Last-Modified) on the Agent Card endpoint.
Current State of the Ecosystem
Let's be real: A2A is still early. It shipped in April 2025, so it's been about a year. The ecosystem is growing but not mature.
What's good:
- Google is behind it with real engineering investment
- DeepLearning.AI released a dedicated course
- Multiple major agent frameworks are integrating
- Spec is at v1.0 and relatively stable
What's not there yet:
- Production case studies are sparse
- SDK docs and examples need more love
- Community size lags behind MCP
- Debugging and observability tools are limited
My take: A2A and MCP will become the two foundational protocols of the AI agent ecosystem. MCP for tool calls, A2A for agent collaboration. Like HTTP and WebSocket — different protocols for different needs, both essential.
What's Next
I'm planning to integrate A2A into Hermes Agent (Hermes Agent vs OpenClaw Architecture Security and Use Cases Compared):
- Wrap Hermes as an A2A Server so its skills are callable by other agents
- Build an orchestrator that coordinates multiple A2A agents on complex tasks
- Explore A2A's push notification mechanism for long-running workflows
Will write a follow-up when that's done. Questions? Drop them in the comments.
Resources:
- A2A Protocol Docs: https://a2a-protocol.org/
- A2A GitHub: https://github.com/a2aproject/A2A
- A2A Python SDK: https://github.com/a2aproject/a2a-python
- DeepLearning.AI A2A Course: https://www.deeplearning.ai/