The A2A Protocol: Powering the Next Generation of Multi-Agent Systems
Wednesday Deep Dive In Code
Follow me: π¦ Xβ|βπΌ LinkedInβ|βπ¬ Substackβ|βπ Medium (with voiceover)
TL;DR
Starting today, a set of posts for my more technical readers with code and a deep dive. They will always happen on Wednesday, but not necessarily every week.
A2A (Agent-to-Agent) is an open protocol developed by Google that enables direct communication between AI agents built on different frameworks
It functions as a horizontal integration layer that complements the vertical integration provided by Model Context Protocol (MCP)
Key features include dynamic agent discovery via AgentCards, rich content types, formalized task lifecycle, and enterprise-grade security
The protocol is framework-agnostic and can be used for general microservices communication beyond AI
Our implementation demonstrates how A2A enables seamless collaboration between specialized agents while each can still use MCP for tool access
In the rapidly evolving landscape of AI systems, we're witnessing a significant shift from single-agent models to complex multi-agent ecosystems. These systems leverage specialized agents for different tasks, working together to solve complex problems. But how do these agents communicate effectively? Enter the Agent-to-Agent (A2A) protocol β a promising solution that addresses many challenges in building robust multi-agent systems.
Important Note: The implementation we're exploring is a protocol demonstration that uses mock agents rather than actual LLM implementations. This approach was intentionally chosen to focus on protocol communication, discovery, and orchestration patterns. While the project includes all the setup necessary to use Ollama and real LLMs, the mocked components help isolate and showcase the protocol mechanics. In many ways, A2A functions as a protocol for microservices in general, not just AI-specific applications.
The Emerging Protocol Ecosystem: Where A2A Fits
We're currently witnessing what some industry observers have dubbed the "protocol wars" in the AI space β a race to establish standards for how intelligent systems communicate. Three major protocols have emerged, each tackling different aspects of the AI communication challenge:
Model Context Protocol (MCP) β Developed by Anthropic, MCP standardizes how AI models connect with tools and data sources. Think of it as a "universal adapter" that gives AI secure access to external resources.
Agent-to-Agent Protocol (A2A) β Google's contribution focuses on agent-to-agent communication, allowing different AI agents to discover each other's capabilities and collaborate effectively.
Agent Communication Protocol (ACP) β An open source protocol now under the Linux Foundation, ACP also addresses agent communication between AI systems. We'll explore ACP in more detail in another article, potentially comparing it with A2A.
Why so many protocols? Each addresses a different slice of the AI communication puzzle. If I were to use a simple metaphor: MCP is like the socket wrench that connects agents to tools, while A2A is the conversation between mechanics discussing how to fix the car. They're not competing but complementary β solving different parts of the same problem.
This article focuses primarily on A2A, but understanding its relationship with MCP is crucial to seeing the complete picture of modern multi-agent architectures.
The Problem: Limitations of Current Agent Communication
Before we explore A2A, let's understand the challenges in current multi-agent systems:
Siloed Agents: Agents often operate in isolation, unaware of each other's capabilities
Communication Bottlenecks: Intermediaries are required to facilitate agent interactions
Message Format Restrictions: Limited support for rich content types
Stateless Interactions: Difficulty tracking long-running tasks
Framework Lock-in: Agents built with different frameworks struggle to interact
Traditional approaches like the Message Context Protocol (MCP) work well for tool calling within a single agent but face limitations when scaling to multi-agent architectures where diverse agents need to collaborate on complex tasks.
Enter A2A: Agent-to-Agent Protocol
A2A addresses these challenges with a protocol specifically designed for direct agent-to-agent communication. Key features include:
Dynamic Agent Discovery: Agents advertise their capabilities through standardized AgentCards
Direct Communication: Agents communicate directly without intermediaries
Rich Content Types: Support for various content formats through the Part system
Task Management: Built-in task lifecycle with well-defined states
Streaming & Push Notifications: Real-time updates for long-running tasks
Formalized Artifacts: Structured output beyond simple text responses
Let's see how these features come together in a practical implementation.
Understanding the "Protocol Bus" Architecture
To grasp how A2A fits into the broader ecosystem of agent communication, it's helpful to think about what some experts call the "dual-bus architecture" for AI systems:
Vertical Integration Bus (MCP) - Connects agents vertically to their tools, data sources, and external systems. This is where MCP excels, providing standardized ways for agents to access resources.
Horizontal Integration Bus (A2A) - Connects agents horizontally to other agents, enabling peer-to-peer collaboration. This is A2A's domain, facilitating direct agent-to-agent communication.
These buses aren't competing - they're complementary layers in a complete agent architecture. Using another metaphor: if MCP is the brain function of individual agents, A2A is how multiple brains talk to each other. An effective multi-agent system needs both.
In this architecture, A2A handles the horizontal connections between agents, while MCP manages the vertical connections from agents to their tools and resources. This separation of concerns leads to more modular, maintainable, and extensible agent ecosystems.
Security Considerations: Enterprise-Ready by Design
When it comes to agent communication, security isn't just a featureβit's a foundation. A2A was designed from the ground up with a "secure by default" philosophy that makes it particularly well-suited for enterprise environments. Let's dive into how A2A handles security concerns:
π Authentication & Identity
Ever wondered how agents can trust each other in a distributed system? A2A leverages well-established web security standards rather than reinventing the wheel:
OpenAPI Authentication Support: A2A embraces standard authentication schemes like OAuth, API keys, and OpenID Connect. This means organizations can integrate A2A into existing security infrastructure without creating custom solutions.
Agent Identity Verification: In production environments, A2A servers present digital certificates signed by trusted certificate authorities as part of TLS negotiation. This ensures that agents can verify who they're talking toβcritical for maintaining trust in multi-agent ecosystems.
# Example of how authentication requirements are specified in an AgentCard
agent_card = AgentCard(
# ... other fields ...
authentication_requirements={
"type": "oauth2",
"flows": {
"authorizationCode": {
"authorizationUrl": "https://auth.example.com/authorize",
"tokenUrl": "https://auth.example.com/token",
"scopes": {
"agent.read": "Read-only access to agent capabilities",
"agent.write": "Full access to agent capabilities"
}
}
}
}
)
π‘οΈ Authorization & Access Control
Authentication tells you who someone isβauthorization decides what they're allowed to do. A2A handles this elegantly:
Per-Skill Authorization: The protocol recommends implementing authorization at the skill level, enabling fine-grained access control. For example, an OAuth scope like 'data-analysis-read' might limit access to only specific agent capabilities.
Opaque Agents Pattern: One of A2A's most powerful security features is its embrace of "opaque agents"βagents that collaborate without revealing their internal logic or implementation details. This protects proprietary algorithms and sensitive data while still enabling effective collaboration.
π Transport Security & Rate Limiting
The foundation of any secure communication protocol is secure transport:
HTTPS Requirement: While A2A can technically work over HTTP for development, any production implementation should require HTTPS with modern TLS ciphers.
Protection Against Abuse: The protocol includes provisions for rate limiting using strategies like token bucket algorithm and geographic restrictions to prevent abuse and DDoS attacks.
The security features of A2A reflect its enterprise originsβdesigned by Google based on experience deploying large-scale, multi-agent systems for customers. By addressing security at the protocol level rather than leaving it as an implementation detail, A2A provides a solid foundation for building trustworthy agent ecosystems in environments where data sensitivity and compliance are paramount.
In our implementation example, we've focused on the communication aspects rather than security for simplicity, but in a production environment, you'd want to implement proper authentication and authorization as described above.
System Architecture
Our implementation follows this architecture:
The system consists of:
Web UI: A Gradio-based interface for user interaction
Host Agent: Orchestrates the system using Google ADK
Specialized Agents:
Data Analysis Agent: Uses LangGraph and MCP for tool calling
Planning Agent: Built with CrewAI for task decomposition
Creative Agent: Specializes in content generation
This architecture demonstrates how A2A enables communication between agents built on different frameworks, showcasing its interoperability benefits.
Agent Discovery: The Foundation of A2A
One of A2A's most powerful features is dynamic agent discovery. Each agent exposes a standardized AgentCard through a .well-known/agent.json
endpoint:
# Example implementation from the Creative Agent
agent_card = AgentCard(
name="Creative Agent",
description="Generates creative content based on prompts",
url=f"http://{host}:{port}",
version="1.0.0",
capabilities=Capabilities(
streaming=True,
pushNotifications=True
),
defaultInputModes=["text"],
defaultOutputModes=["text"],
skills=[
Skill(
id="text_generation",
name="Text Generation",
description="Generates creative text content"
),
Skill(
id="story_creation",
name="Story Creation",
description="Creates compelling stories"
),
Skill(
id="content_formatting",
name="Content Formatting",
description="Formats content for various purposes"
)
]
)
In our demo system, when we run the agents, the Host Agent discovers all available agents at startup by querying their AgentCards:
async def startup(self):
"""Discover available agents on startup."""
for agent_type, url in self.agent_urls.items():
try:
agent_card = await self.client.discover_agent(url)
self.agent_capabilities[agent_type] = agent_card
print(f"Discovered {agent_type} agent at {url}")
except Exception as e:
print(f"Error discovering {agent_type} agent: {e}")
Here's the agent discovery information from our running system:
This dynamic discovery mechanism enables:
Automatic capability detection without hard-coding
Runtime agent addition or removal
Framework-agnostic agent integration
Self-documented agent interfaces
Task Lifecycle Management
A2A introduces a formalized task lifecycle with well-defined states:
class TaskState(str, Enum):
"""States for A2A tasks."""
SUBMITTED = "submitted"
WORKING = "working"
INPUT_REQUIRED = "input-required"
COMPLETED = "completed"
FAILED = "failed"
CANCELLED = "cancelled"
When a user submits a request like "write an email," the system creates a task in the SUBMITTED
state, then transitions it through various states as it's processed:
SUBMITTED
: Initial state when task is createdWORKING
: Agent is actively processing the taskCOMPLETED
: Task successfully completedFAILED
: Task failed to completeINPUT_REQUIRED
: Agent needs additional input to continueCANCELLED
: Task cancelled by the requester
Let's look at the raw task data from our "write an email" example:
{
"id": "cb01f996-5866-4b9d-990c-3a03c5140192",
"status": {
"state": "completed",
"message": {
"parts": [
{
"type": "text",
"text": "Here's what I found: **Creative Agent**: I've created a email titled \"Follow-up: Project Proposal Discussion\" based on your request. *1 artifacts produced*"
}
]
},
"reason": null
},
"artifacts": [
{
"id": "b546752d-4b7f-4c8c-bfb5-96d03818e471",
"type": "document",
"name": "Follow-up: Project Proposal Discussion",
"description": "Business email follow-up after meeting",
"content": {
"content_type": "email",
"full_text": "Dear Marcus, I hope this email finds you well...",
"sections": {
"greeting": "Dear Marcus,",
"body": "I hope this email finds you well. I wanted to thank you for taking the time to meet...",
"closing": "Best regards, Sarah Johnson Project Director"
}
}
}
],
"metadata": {}
}
This structured task representation enables:
Long-running task management
Stateful multi-turn conversations
Proper error handling and recovery
Cancellation support
Progress tracking for complex workflows
Rich Content Types & Artifacts
A2A supports rich content types through its Part system and formalized artifacts. In our email example, the Creative Agent returned not just text but a structured document artifact:
# Creative Agent artifact creation
artifact = Artifact(
id=artifact_id,
type=ArtifactType.DOCUMENT,
name=content.get("title", "Generated Content"),
description=content.get("description", "Creative content based on your prompt"),
content={
"content_type": content_type,
"full_text": content.get("full_text", ""),
"sections": content.get("sections", {})
}
)
This structured output allows:
Semantic understanding of content types
Consistent handling across different agents
Multiple output formats (documents, data, visualizations)
Structured content with sections and metadata
Real-time Communication with WebSockets
A2A supports streaming updates and push notifications through WebSockets, enabling real-time visibility into task progress:
# Client-side subscription to task updates
async def subscribe_to_task(self, agent_url: str, task_id: str) -> AsyncIterator[Task]:
"""Subscribe to real-time updates for a task."""
ws_url = f"{agent_url.rstrip('/')}/tasks/{task_id}/subscribe".replace("http", "ws")
async with connect(ws_url) as websocket:
while True:
try:
message = await websocket.recv()
task_update = Task.model_validate(json.loads(message))
yield task_update
# If task reached terminal state, exit
if task_update.status.state in [
TaskState.COMPLETED,
TaskState.FAILED,
TaskState.CANCELLED
]:
break
except asyncio.CancelledError:
break
This enables:
Progress visibility for long-running tasks
Real-time UI updates without polling
Efficiency for compute-intensive operations
Better user experience for tasks that take time
A2A + MCP: The Best of Both Worlds
One of the most interesting aspects of our implementation is how it combines A2A with MCP. The Data Analysis Agent uses A2A for agent-to-agent communication but MCP for tool calling:
class DataAnalysisAgent(A2ABaseServer):
"""Data Analysis Agent that uses MCP for tool calling."""
# A2A for agent communication
async def handle_task(self, task: Task) -> Task:
# Process A2A task
# ...
# Call MCP for tool usage
result = await self._process_with_mcp(task_data)
# Create response and artifacts for A2A
# ...
return task
# MCP for tool calling
def _create_tools(self) -> List[Tool]:
"""Create tools for data analysis."""
tools = [
Tool.from_function(
func=self._load_csv,
name="load_csv",
description="Load a CSV file for analysis"
),
# More tools...
]
return tools
This hybrid approach demonstrates:
A2A for macro-level agent orchestration
MCP for micro-level tool calling within agents
Framework interoperability (A2A works with any agent framework)
Separation of concerns between inter-agent and intra-agent operations
Real-World Integration Examples
To better understand how A2A and MCP work together in practice, let's explore a few real-world scenarios:
Example 1: Enterprise Customer Support System
Imagine a customer support system with multiple specialized agents:
Intake Agent: Receives customer queries and determines which specialized agent to route to
Knowledge Base Agent: Searches documentation and previous cases. This is an agentic RAG
Troubleshooting Agent: Analyzes errors and generates solutions
Account Management Agent: Handles billing and subscription issues
When a customer submits a technical issue with billing implications:
All agents communicate with each other via A2A, passing tasks and context
Each agent uses MCP internally to access its specific tools (knowledge base, diagnostic tools, billing system)
The system preserves context across agent boundaries via structured artifacts
The orchestrator maintains a coherent conversation with the customer while specialized agents work behind the scenes
This architecture provides both:
Horizontal integration: Agents collaborate seamlessly via A2A
Vertical integration: Each agent accesses its specific tools via MCP
Example 2: Automated Research Workflow
Consider a research assistant system with specialized agents:
Research Planner: Plans the research approach
Data Collector: Gathers relevant sources and data
Analysis Agent: Performs quantitative/qualitative analysis
Report Generator: Creates final deliverables
When tasked with researching a market opportunity:
The Planner uses A2A to delegate specific research tasks to other agents
The Data Collector uses MCP to search databases, APIs, and web sources
The Analysis Agent uses MCP to run statistical tools on collected data
The Report Generator receives analysis artifacts via A2A and creates reports
This separation of concerns leads to a more modular, extensible system where specialized agents can evolve independently while maintaining seamless collaboration.
Why A2A Matters: The Big Picture
After exploring the implementation, let's zoom out and consider why A2A represents a significant advancement for multi-agent systems:
1. Framework Interoperability
A2A enables agents built on different frameworks (ADK, LangGraph, CrewAI, etc.) to communicate seamlessly, breaking down framework silos. Each agent can use the most suitable framework for its specific task while maintaining compatibility with the broader system.
2. Polyglot Agent Ecosystems
Beyond frameworks, A2A could enable cross-language agent ecosystems. Since the protocol is language-agnostic, agents written in Python could communicate with those in JavaScript, Java, or any other language, as long as they implement the A2A protocol.
3. Agent Composition & Specialization
A2A encourages specialized agents that excel at specific tasks, which can then be composed into more complex systems. This specialization leads to better performance, easier maintenance, and clearer separation of concerns.
4. Autonomous Agent Discovery
With dynamic agent discovery, A2A enables more autonomous systems where agents can discover and leverage each other's capabilities without explicit programming. This opens the door to emergent behaviors and more adaptable AI systems.
5. Scalable Multi-Agent Architectures
The formal task lifecycle and stateful communication model make A2A well-suited for complex, distributed multi-agent systems that need to manage many concurrent tasks and agent interactions.
Building Your Own A2A-Powered System
Want to explore A2A yourself? The implementation we've discussed is available on GitHub:
A2A Multi-Agent System Repository
To get started:
# Clone the repository
git clone https://github.com/yourusername/a2a-multi-agent-system.git
cd a2a-multi-agent-system
# Setup with uv (recommended)
chmod +x setup_uv.sh
./setup_uv.sh
Next, run each agent in a separate console window:
Console 1 - Data Analysis Agent:
python -m main --agent data --host localhost --port 8001
Console 2 - Planning Agent:
python -m main --agent planning --host localhost --port 8002
Console 3 - Creative Agent:
python -m main --agent creative --host localhost --port 8003
Console 4 - Host Agent:
python -m main --agent host --host localhost --port 8000
Console 5 - Web UI:
python run_ui.py
Running each agent in its own console gives you visibility into individual agent logs and operations, which is extremely helpful for understanding the communication patterns between agents.
You can then interact with the system through the web UI, trying different requests like:
"Analyze this sales data for trends" (Data Agent)
"Create a project plan for launching a new app" (Planning Agent)
"Write a blog post about AI" (Creative Agent)
"Analyze this data and create a marketing plan" (Combined)
Conclusion: The Future of Agent Communication
A2A represents a significant step forward in how we design and implement multi-agent systems. By providing a standardized communication protocol with rich features like agent discovery, task lifecycle management, and structured artifacts, A2A enables more interoperable, scalable, and capable agent ecosystems.
As AI systems continue to grow in complexity, protocols like A2A will become increasingly important for building coherent, reliable multi-agent architectures that leverage specialized components while maintaining system-level integrity.
The combination of A2A for agent-to-agent communication and MCP for tool calling demonstrates how these protocols can complement each other, providing a comprehensive solution for building the next generation of AI systems.
What multi-agent systems will you build with A2A?
Follow me: π¦ Xβ|βπΌ LinkedInβ|βπ¬ Substackβ|βπ Medium (with voiceover)