Skip to main content
Version: 1.0.4

Building Multi-Agent Systems with A2A Inbound Adapter

What We're Building​

In this hands-on guide, we'll build a multi-agent system that exposes specialized Agentverse uAgents through the A2A protocol. By the end, you'll have:

  • Multiple A2A endpoints running on different ports
  • Specialized agents accessible to A2A clients
  • Real-world examples of agent coordination and discovery
  • Production-ready configuration for deployment

We'll create two specialized agents:

  1. Perplexity Search Agent - AI-powered web search and research
  2. Finance Q&A Agent - Financial analysis and planning assistance

Architecture​

a2a-inbound-adapter-example

Each agent will run as a separate A2A server, allowing A2A clients to discover and use them independently or in coordination.

šŸ› ļø Step 1: Installation​

Install the A2A Inbound adapter package:

pip install "uagents-adapter[a2a-inbound]"

This installs all required dependencies including:

  • a2a-sdk[all,sqlite]>=0.2.11 - A2A SDK with all features + SQLite support
  • uvicorn>=0.27.0 - ASGI server for running the A2A bridge server
  • httpx>=0.25.0 - Async HTTP client
  • click>=8.0.0 - CLI framework for command-line interface
  • python-dotenv>=1.0.0 - Environment variable management

Step 2: Choose Your Agents​

You have two options for agents:

Option A: Use Existing Agents from Agentverse Marketplace​

  1. Visit Agentverse.ai
  2. Browse the marketplace for agents that match your needs
  3. Copy the agent address from the agent's profile page
  4. Ensure the agent is active and responding to messages

Option B: Build Your Own Agents​

  1. Create uAgents using the uAgents framework
  2. Register on Agentverse and get them running
  3. Copy the agent addresses from your agent profiles
  4. Test that they respond to chat messages

For this tutorial, we'll use pre-configured agents from the marketplace:

  • Perplexity Search Agent: agent1qgzd0c60d4c5n37m4pzuclv5p9vwsftmfkznksec3drux8qnhmvuymsmshp
  • Finance Q&A Agent: agent1qdv2qgxucvqatam6nv28qp202f3pw8xqpfm8man6zyegztuzd2t6yem9evl

Step 3: Build the Multi-Agent System​

Agent 1: Perplexity Search Agent​

Create a file called perplexity_adapter.py:

import os
import sys
import time
from uagents_adapter.a2a_inbound.adapter import A2ARegisterTool

def main():
"""Start A2A bridge for Perplexity Search Agent."""

# Set bridge seed for consistent agent identity (required in production)
os.environ["UAGENTS_BRIDGE_SEED"] = "perplexity_bridge_seed_2024"

# Configure the bridge
config = {
"agent_address": "agent1qgzd0c60d4c5n37m4pzuclv5p9vwsftmfkznksec3drux8qnhmvuymsmshp",
"name": "Perplexity Search Agent",
"description": "AI-powered web search and research assistant with real-time information access",
"skill_tags": ["search", "research", "web", "ai", "information", "news"],
"skill_examples": ["Search for latest AI news", "Research quantum computing trends", "Find information about climate change"],
"port": 9002,
"bridge_port": 8002,
"host": "localhost"
}

# Start the A2A bridge
adapter = A2ARegisterTool()

try:
result = adapter.invoke(config)

if result.get("success"):
# Keep the server running
while True:
time.sleep(1)
else:
print(f"āŒ Failed to start bridge: {result}")
return 1

except KeyboardInterrupt:
print("\nšŸ‘‹ Shutting down Perplexity bridge...")
return 0
except Exception as e:
print(f"āŒ Error: {e}")
return 1

if __name__ == "__main__":
sys.exit(main())

Agent 2: Finance Q&A Agent​

Create a file called finance_adapter.py:

import os
import sys
import time
from uagents_adapter.a2a_inbound.adapter import A2ARegisterTool

def main():
"""Start A2A bridge for Finance Q&A Agent."""

# Set bridge seed for consistent agent identity (required in production)
os.environ["UAGENTS_BRIDGE_SEED"] = "finance_bridge_seed_2024"

# Configure the bridge
config = {
"agent_address": "agent1qdv2qgxucvqatam6nv28qp202f3pw8xqpfm8man6zyegztuzd2t6yem9evl",
"name": "Finance Q&A Agent",
"description": "AI-powered financial advisor and Q&A assistant for investment, budgeting, and financial planning guidance",
"skill_tags": ["finance", "investment", "budgeting", "financial_planning", "assistance"],
"skill_examples": ["Analyze AAPL stock performance", "Compare crypto portfolios", "Budget planning advice"],
"port": 9003,
"bridge_port": 8003,
"host": "localhost"
}

# Start the A2A bridge
adapter = A2ARegisterTool()

try:
result = adapter.invoke(config)

if result.get("success"):
# Keep the server running
while True:
time.sleep(1)
else:
print(f"āŒ Failed to start bridge: {result}")
return 1

except KeyboardInterrupt:
print("\nšŸ‘‹ Shutting down Finance bridge...")
return 0
except Exception as e:
print(f"āŒ Error: {e}")
return 1

if __name__ == "__main__":
sys.exit(main())

Step 4: Run Your Multi-Agent System​

Terminal 1: Start Perplexity Agent​

python perplexity_adapter.py

Expected output:

INFO:root:šŸ”— Using provided bridge port: 8002
INFO:uagents_adapter.a2a_inbound.agentverse_executor:šŸ” Using user-provided bridge seed from environment
INFO: [a2a_agentverse_bridge]: Starting agent with address: agent1qvdrt7kqg2k67czm8wzs724jv63fsq5cr2lq4mymtptj576sdpu9yngzden
INFO:uagents_adapter.a2a_inbound.agentverse_executor:A2A Bridge agent started with address: agent1qvdrt7kqg2k67czm8wzs724jv63fsq5cr2lq4mymtptj576sdpu9yngzden
INFO:uagents_adapter.a2a_inbound.agentverse_executor:Target Agentverse agent: agent1qgzd0c60d4c5n37m4pzuclv5p9vwsftmfkznksec3drux8qnhmvuymsmshp
INFO: [a2a_agentverse_bridge]: Agent inspector available at https://agentverse.ai/inspect/?uri=http%3A//127.0.0.1%3A8002&address=agent1qvdrt7kqg2k67czm8wzs724jv63fsq5cr2lq4mymtptj576sdpu9yngzden
INFO: [a2a_agentverse_bridge]: Starting server on http://0.0.0.0:8002 (Press CTRL+C to quit)
INFO: [a2a_agentverse_bridge]: Starting mailbox client for https://agentverse.ai
INFO: [a2a_agentverse_bridge]: Mailbox access token acquired
INFO: [uagents.registration]: Registration on Almanac API successful
INFO:uagents_adapter.a2a_inbound.agentverse_executor:āœ… A2A Bridge to Agentverse started successfully
INFO:root:šŸš€ A2A server starting on localhost:9002
INFO:root:šŸ”— Bridging to Agentverse agent: agent1qgzd0c60d4c5n37m4pzuclv5p9vwsftmfkznksec3drux8qnhmvuymsmshp
INFO:root:šŸ“‹ Agent name: Perplexity Search Agent
INFO:root:šŸ·ļø Tags: search, research, web, ai, information, news
INFO: Started server process [14746]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://localhost:9002 (Press CTRL+C to quit)
INFO: [uagents.registration]: Almanac contract registration is up to date!

Terminal 2: Start Finance Agent​

python finance_adapter.py

Expected output:

INFO:root:šŸ”— Using provided bridge port: 8003
INFO:uagents_adapter.a2a_inbound.agentverse_executor:šŸ” Using user-provided bridge seed from environment
INFO: [a2a_agentverse_bridge]: Starting agent with address: agent1qdv8n2zucf50mvyzxwswe02swnwzmt5fctyeug6cewdkaz4wjd46qjggnz2
INFO:uagents_adapter.a2a_inbound.agentverse_executor:A2A Bridge agent started with address: agent1qdv8n2zucf50mvyzxwswe02swnwzmt5fctyeug6cewdkaz4wjd46qjggnz2
INFO:uagents_adapter.a2a_inbound.agentverse_executor:Target Agentverse agent: agent1qdv2qgxucvqatam6nv28qp202f3pw8xqpfm8man6zyegztuzd2t6yem9evl
INFO: [a2a_agentverse_bridge]: Agent inspector available at https://agentverse.ai/inspect/?uri=http%3A//127.0.0.1%3A8003&address=agent1qdv8n2zucf50mvyzxwswe02swnwzmt5fctyeug6cewdkaz4wjd46qjggnz2
INFO: [a2a_agentverse_bridge]: Starting server on http://0.0.0.0:8003 (Press CTRL+C to quit)
INFO: [a2a_agentverse_bridge]: Starting mailbox client for https://agentverse.ai
INFO:uagents_adapter.a2a_inbound.agentverse_executor:āœ… A2A Bridge to Agentverse started successfully
INFO:root:šŸš€ A2A server starting on localhost:9003
INFO:root:šŸ”— Bridging to Agentverse agent: agent1qdv2qgxucvqatam6nv28qp202f3pw8xqpfm8man6zyegztuzd2t6yem9evl
INFO:root:šŸ“‹ Agent name: Finance Q&A Agent
INFO:root:šŸ·ļø Tags: finance, investment, budgeting, financial_planning, assistance
INFO: Started server process [14541]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://localhost:9003 (Press CTRL+C to quit)
INFO: [uagents.registration]: Registration on Almanac API successful
INFO: [uagents.registration]: Almanac contract registration is up to date!
INFO: [a2a_agentverse_bridge]: Mailbox access token acquired

šŸ”— IMPORTANT: Connect Bridge Agents to Mailbox​

For each agent you start, you MUST complete this step:

  1. Look for the Inspector Link in the terminal output:

    Agent inspector available at https://agentverse.ai/inspect/?uri=http%3A//127.0.0.1%3A8002&address=agent1q...
  2. Click the Inspector Link - This will open the Agentverse Agent Inspector in your browser

  3. Connect to Mailbox:

    • Click the "Connect" button in the Inspector UI
    • Select "Mailbox" from the connection options
    • Click "Finish" to complete the connection
  4. Repeat for Each Agent - You need to do this for both the Perplexity agent (port 8002) and Finance agent (port 8003)

Why This is Required:

  • The bridge agents need mailbox access to communicate with your target Agentverse agents
  • Without this connection, messages won't reach your target agents
  • This establishes the secure communication channel between the bridge and Agentverse

For detailed mailbox connection instructions, refer to: Mailbox Agents Documentation

Success Indicators: After connecting, you should see these log messages:

INFO: [a2a_agentverse_bridge]: Mailbox access token acquired
INFO: [uagents.registration]: Registration on Almanac API successful

Step 5: Test Your Multi-Agent System​

Test Agent Discovery​

Check that both agents are discoverable:

# Discover Perplexity agent
curl http://localhost:9002/.well-known/agent.json

# Discover Finance agent
curl http://localhost:9003/.well-known/agent.json

Test Perplexity Search Agent​

curl -X POST http://localhost:9002 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [{"kind": "text", "text": "What are the latest developments in AI agents?"}],
"messageId": "search-query-1"
},
"contextId": "search-session-123"
},
"id": "search-request-1"
}'

Test Finance Q&A Agent​

curl -X POST http://localhost:9003 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [{"kind": "text", "text": "How should I diversify my investment portfolio?"}],
"messageId": "finance-query-1"
},
"contextId": "finance-session-456"
},
"id": "finance-request-1"
}'

šŸ”§ Step 6: Configuration Explained​

Key Configuration Parameters​

Agent Address​

"agent_address": "agent1qgzd0c60d4c5n37m4pzuclv5p9vwsftmfkznksec3drux8qnhmvuymsmshp"
  • What it is: Unique identifier for your Agentverse uAgent
  • How to get it: Copy from Agentverse agent profile page
  • Important: Must be an active, running agent

Ports Configuration​

"port": 9002,        # A2A server port (what clients connect to)
"bridge_port": 8002, # Internal bridge uAgent port
  • A2A Port: Where A2A clients send requests
  • Bridge Port: Internal communication with Agentverse
  • Rule: Each agent needs unique ports to avoid conflicts

Bridge Seed​

os.environ["UAGENTS_BRIDGE_SEED"] = "perplexity_bridge_seed_2024"
  • Purpose: Ensures consistent bridge agent addresses
  • Important: Use unique seeds for different agents
  • Production: Always set this in production deployments

Agent Metadata​

"name": "Perplexity Search Agent",
"description": "AI-powered web search and research assistant",
"skill_tags": ["search", "research", "web"],
"skill_examples": ["Search for latest AI news", "Research trends"]
  • Discovery: Helps A2A clients understand agent capabilities
  • Tags: Used for categorization and filtering
  • Examples: Show users what queries work well

Step 7: Build an A2A Client for Multi-Agent Coordination​

Now that your agents are running, let's create a simple A2A client that can discover and coordinate with both agents.

Simple A2A Client​

Create a2a_client_example.py:

import asyncio
import json
from uuid import uuid4
from typing import Dict, Any

import httpx
from a2a.client import A2ACardResolver, A2AClient
from a2a.types import (
AgentCard,
MessageSendParams,
SendMessageRequest,
)

class SimpleA2AClient:
"""Simple A2A client for multi-agent coordination."""

def __init__(self):
self.agents: Dict[str, dict] = {}
self.httpx_client = None

async def __aenter__(self):
"""Async context manager entry."""
self.httpx_client = httpx.AsyncClient(timeout=30)
return self

async def __aexit__(self, exc_type, exc_val, exc_tb):
"""Async context manager exit."""
if self.httpx_client:
await self.httpx_client.aclose()

async def discover_agent(self, url: str, name: str):
"""Discover an agent and add to available agents."""
try:
resolver = A2ACardResolver(self.httpx_client, url)
agent_card = await resolver.get_agent_card()

client = A2AClient(self.httpx_client, agent_card, url=url)

self.agents[name] = {
'card': agent_card,
'client': client,
'url': url
}

print(f"āœ… Discovered {name}: {agent_card.name}")
print(f" Description: {agent_card.description}")
print(f" Skills: {[skill.name for skill in agent_card.skills]}")
return True

except Exception as e:
print(f"āŒ Failed to discover {name} at {url}: {e}")
return False

async def send_to_agent(self, agent_name: str, message: str, context_id: str = None) -> dict:
"""Send a message to a specific agent."""
if agent_name not in self.agents:
raise ValueError(f"Agent {agent_name} not found")

client = self.agents[agent_name]['client']

payload = {
'message': {
'role': 'user',
'parts': [{'kind': 'text', 'text': message}],
'messageId': uuid4().hex,
}
}

if context_id:
payload['message']['contextId'] = context_id

request = SendMessageRequest(
id=str(uuid4()),
params=MessageSendParams(**payload)
)

response = await client.send_message(request)
return response.model_dump(mode='json', exclude_none=True)

def list_agents(self):
"""List all discovered agents."""
print("\nšŸ“‹ Available Agents:")
for name, info in self.agents.items():
card = info['card']
print(f" • {name} ({card.name})")
print(f" URL: {info['url']}")
print(f" Description: {card.description}")
print()

async def main():
"""Demonstrate A2A client with multi-agent coordination."""

async with SimpleA2AClient() as client:
print("šŸ” Discovering agents...")

# Discover both agents
agents_to_discover = [
("perplexity", "http://localhost:9002"),
("finance", "http://localhost:9003"),
]

for name, url in agents_to_discover:
await client.discover_agent(url, name)

# List discovered agents
client.list_agents()

# Example 1: Single agent query
print("🧪 Example 1: Single Agent Query")
print("-" * 40)

try:
response = await client.send_to_agent(
"perplexity",
"What are the latest trends in sustainable investing?",
context_id="search-session-001"
)
print("Perplexity Response:")
print(json.dumps(response, indent=2))
except Exception as e:
print(f"Error querying Perplexity agent: {e}")

print("\n" + "="*50 + "\n")

# Example 2: Coordinated multi-agent query
print("🧪 Example 2: Multi-Agent Coordination")
print("-" * 40)

# Query both agents with related questions
search_task = client.send_to_agent(
"perplexity",
"Find recent news about ESG investment performance in 2025",
context_id="coordination-001"
)

finance_task = client.send_to_agent(
"finance",
"How should I evaluate ESG investment opportunities for my portfolio?",
context_id="coordination-002"
)

try:
# Wait for both responses
search_result, finance_result = await asyncio.gather(search_task, finance_task)

print("šŸ” Search Agent (ESG News):")
print(json.dumps(search_result, indent=2))
print("\n" + "-"*40 + "\n")

print("šŸ’° Finance Agent (ESG Evaluation):")
print(json.dumps(finance_result, indent=2))

except Exception as e:
print(f"Error in multi-agent coordination: {e}")

if __name__ == "__main__":
print("šŸš€ A2A Multi-Agent Client Example")
print("=" * 50)
asyncio.run(main())

Run the A2A Client​

With both agents running (from Step 4), run the client:

python a2a_client_example.py

Expected Output:

šŸš€ A2A Multi-Agent Client Example
==================================================
šŸ” Discovering agents...
āœ… Discovered perplexity: Perplexity Search Agent
Description: AI-powered web search and research assistant with real-time information access
Skills: ['Perplexity Search Agent Bridge']
āœ… Discovered finance: Finance Q&A Agent
Description: AI-powered financial advisor and Q&A assistant for investment, budgeting, and financial planning guidance
Skills: ['Finance Q&A Agent Bridge']

šŸ“‹ Available Agents:
• perplexity (Perplexity Search Agent)
URL: http://localhost:9002
Description: AI-powered web search and research assistant with real-time information access

• finance (Finance Q&A Agent)
URL: http://localhost:9003
Description: AI-powered financial advisor and Q&A assistant for investment, budgeting, and financial planning guidance

🧪 Example 1: Single Agent Query
----------------------------------------
Perplexity Response:
{
"jsonrpc": "2.0",
"id": "abc123...",
"result": {
"id": "task-456...",
"contextId": "search-session-001",
"state": "completed",
"artifacts": [
{
"name": "agentverse_result",
"parts": [
{
"text": "Based on current market analysis, sustainable investing trends in 2025 show..."
}
]
}
]
}
}

==================================================

🧪 Example 2: Multi-Agent Coordination
----------------------------------------
šŸ” Search Agent (ESG News):
{
"jsonrpc": "2.0",
"result": {
"state": "completed",
"artifacts": [
{
"name": "agentverse_result",
"parts": [
{
"text": "Recent ESG investment performance data shows significant growth..."
}
]
}
]
}
}

----------------------------------------

šŸ’° Finance Agent (ESG Evaluation):
{
"jsonrpc": "2.0",
"result": {
"state": "completed",
"artifacts": [
{
"name": "agentverse_result",
"parts": [
{
"text": "To evaluate ESG investments, consider these key criteria: environmental impact metrics..."
}
]
}
]
}
}

šŸ“Š Step 8: Interactive A2A Client​

For a more interactive experience, create interactive_client.py:

import asyncio
import json
from uuid import uuid4

import httpx
from a2a.client import A2ACardResolver, A2AClient
from a2a.types import MessageSendParams, SendMessageRequest

async def interactive_client():
"""Interactive A2A client for testing agents."""

agents = {}

async with httpx.AsyncClient(timeout=30) as client:
# Discover agents
agent_configs = [
("Perplexity Search", "http://localhost:9002"),
("Finance Q&A", "http://localhost:9003"),
]

print("šŸ” Discovering agents...")
for name, url in agent_configs:
try:
resolver = A2ACardResolver(client, url)
card = await resolver.get_agent_card()
a2a_client = A2AClient(client, card, url=url)
agents[name] = a2a_client
print(f"āœ… {name} ready")
except Exception as e:
print(f"āŒ {name} failed: {e}")

if not agents:
print("No agents available. Make sure they're running!")
return

print(f"\nšŸ“‹ Available agents: {list(agents.keys())}")
print("šŸ’” Type 'quit' to exit, 'list' to see agents\n")

context_id = str(uuid4())

while True:
try:
# Get user input
user_input = input("You: ").strip()

if user_input.lower() == 'quit':
break
elif user_input.lower() == 'list':
print(f"Available agents: {list(agents.keys())}")
continue
elif not user_input:
continue

# Route based on keywords
agent_name = None
if any(word in user_input.lower() for word in ['search', 'news', 'research', 'find']):
agent_name = "Perplexity Search"
elif any(word in user_input.lower() for word in ['finance', 'money', 'invest', 'stock', 'budget']):
agent_name = "Finance Q&A"
else:
print("šŸ¤– Which agent should I use?")
for i, name in enumerate(agents.keys(), 1):
print(f" {i}. {name}")

choice = input("Choose (1-2): ").strip()
if choice == '1':
agent_name = list(agents.keys())[0]
elif choice == '2':
agent_name = list(agents.keys())[1]
else:
print("Invalid choice!")
continue

# Send to chosen agent
print(f"šŸ¤– Sending to {agent_name}...")

payload = {
'message': {
'role': 'user',
'parts': [{'kind': 'text', 'text': user_input}],
'messageId': uuid4().hex,
'contextId': context_id
}
}

request = SendMessageRequest(
id=str(uuid4()),
params=MessageSendParams(**payload)
)

response = await agents[agent_name].send_message(request)
result = response.model_dump(mode='json', exclude_none=True)

# Extract and display response
if 'result' in result and 'artifacts' in result['result']:
artifacts = result['result']['artifacts']
for artifact in artifacts:
if 'parts' in artifact:
for part in artifact['parts']:
if 'text' in part:
print(f"šŸ¤– {agent_name}: {part['text']}")
else:
print(f"šŸ¤– Raw response: {json.dumps(result, indent=2)}")

print()

except KeyboardInterrupt:
break
except Exception as e:
print(f"āŒ Error: {e}")

print("šŸ‘‹ Goodbye!")

if __name__ == "__main__":
asyncio.run(interactive_client())

Run the interactive client:

python interactive_client.py

šŸŽÆ Next Steps​

Scaling Your System​

  1. Add More Agents: Follow the same pattern to add specialized agents
  2. Load Balancing: Use nginx or similar for distributing requests
  3. Service Discovery: Implement agent registry for dynamic discovery
  4. Monitoring: Add health checks and metrics collection

Advanced Features​

  1. Agent Orchestration: Build workflows that coordinate multiple agents
  2. Context Sharing: Share conversation context between agents
  3. Fallback Chains: Implement fallback when primary agents are unavailable
  4. Response Aggregation: Combine responses from multiple agents

Customization​

  1. Custom Agents: Build your own specialized uAgents
  2. Business Logic: Add routing logic for complex queries
  3. Integration: Connect to external APIs and services
  4. UI/UX: Build web interfaces for your multi-agent system

šŸŽ‰ Congratulations!​

You've successfully built a multi-agent system with:

  • āœ… Two specialized A2A agents running independently
  • āœ… Standard A2A protocol compatibility for client integration
  • āœ… Production-ready configuration with proper environment management
  • āœ… Testing and monitoring capabilities
  • āœ… Coordination patterns for multi-agent workflows

References


This demonstrates how uAgents adapters can bring collaborative A2A Agent systems into a networked environment, making complex workflows accessible through standardized messaging protocols.Now Agentverse uAgents are now accessible to any A2A-compatible client, opening up possibilities for integration with AI assistants, web applications, and other agent systems!