A fully working demonstration of the LAD-A2A discovery protocol with two AI agents communicating via Google's A2A (Agent-to-Agent) protocol.
- Real mDNS Discovery - The user agent scans for
_a2a._tcp.localservices - LAD-A2A Protocol - Discovery via
/.well-known/lad/agentsendpoint - A2A Protocol - JSON-RPC 2.0 communication between agents
- LLM-Based Routing - AI decides when to query the remote agent
┌─────────────────────────────────────────────────────────────────┐
│ User's Device │
│ ┌─────────────┐ WebSocket ┌───────────────────────┐ │
│ │ Browser UI │◄───────────────────►│ User Agent (Aria) │ │
│ │ index.html │ │ - OpenAI GPT-4o │ │
│ └─────────────┘ │ - LAD-A2A Client │ │
│ │ - A2A Client │ │
│ └───────────┬───────────┘ │
└──────────────────────────────────────────────────┼──────────────┘
│
┌──────────────────────────────┼──────────────┐
│ Local Network │ │
│ │ │
│ 1. mDNS Discovery │ │
│ _a2a._tcp.local ─────────┤ │
│ │ │
│ 2. LAD-A2A │ │
│ /.well-known/lad/agents │ │
│ │ │
│ 3. A2A JSON-RPC 2.0 │ │
│ SendMessage ─────────────┤ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ Hotel Agent │ │
│ │ (Grand Azure) │ │
│ │ - OpenAI GPT-4o │ │
│ │ - LAD-A2A Server │ │
│ │ - A2A Server │ │
│ └─────────────────────┘ │
└─────────────────────────────────────────────┘
| Feature | Implementation |
|---|---|
| mDNS Service Type | _a2a._tcp.local |
| TXT Records | path, v, org |
| Discovery Endpoint | /.well-known/lad/agents |
| Response Format | JSON with version, network, agents[] |
| Agent Card Reference | Points to A2A /.well-known/agent.json |
| Feature | Implementation |
|---|---|
| Transport | JSON-RPC 2.0 over HTTP |
| Agent Card | /.well-known/agent.json with skills, capabilities |
| SendMessage | ✅ Implemented |
| GetTask | ✅ Implemented |
| CancelTask | ✅ Implemented |
| Task Model | Returns Task with status, history |
| Message Format | role + parts[] with TextPart |
- Python 3.9+
- OpenAI API key
-
Configure your API key:
cp .env.example .env # Edit .env and add your OpenAI API key -
Run the demo:
./run_demo.sh
-
Open in browser: Navigate to http://localhost:8000
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Terminal 1: Start Hotel Agent
python hotel_agent.py
# Terminal 2: Start User Agent
python user_agent.py
# Open http://localhost:8000When you open the browser, Aria (user agent) performs real mDNS discovery:
📡 Starting mDNS discovery for _a2a._tcp.local...
🔍 mDNS: Found service Grand Azure Hotel at http://127.0.0.1:8001
Aria fetches the discovery endpoint to get agent metadata:
GET http://localhost:8001/.well-known/lad/agents
{
"version": "1.0",
"network": {"ssid": "GrandAzure-Guest", "realm": "grandazurehotel.local"},
"agents": [{
"name": "Grand Azure Hotel",
"agent_card_url": "http://localhost:8001/.well-known/agent.json",
"capabilities_preview": ["room-service", "spa-booking", "dining"]
}]
}Aria fetches the full A2A AgentCard:
GET http://localhost:8001/.well-known/agent.json
{
"name": "Grand Azure Hotel",
"url": "http://localhost:8001",
"protocolVersions": ["1.0"],
"capabilities": {"streaming": false, "pushNotifications": false},
"skills": [
{"id": "spa-wellness", "name": "Spa & Wellness", "tags": ["spa", "massage"]},
{"id": "dining", "name": "Dining & Restaurants", "tags": ["food", "breakfast"]}
]
}The UI prompts the user to connect to the discovered agent.
When you send a message, the LLM decides if it should query the hotel agent:
User: "What time does the spa open?"
🧠 Routing decision: Query Grand Azure Hotel
Aria sends a JSON-RPC 2.0 request to the hotel agent:
POST http://localhost:8001/
Content-Type: application/json
{
"jsonrpc": "2.0",
"method": "SendMessage",
"params": {
"message": {
"role": "user",
"parts": [{"type": "text", "text": "What time does the spa open?"}]
}
},
"id": "uuid"
}Response:
{
"jsonrpc": "2.0",
"result": {
"id": "task-uuid",
"status": {
"state": "completed",
"message": {
"role": "agent",
"parts": [{"type": "text", "text": "The spa opens at 7:00 AM..."}]
}
}
}
}demo/
├── hotel_agent.py # Hotel concierge (LAD-A2A server + A2A server)
├── user_agent.py # Personal assistant (LAD-A2A client + A2A client)
├── index.html # Web interface
├── requirements.txt # Python dependencies
├── .env.example # Environment template
├── .env # Your API key (gitignored)
└── run_demo.sh # Startup script
| Endpoint | Method | Protocol | Description |
|---|---|---|---|
/.well-known/lad/agents |
GET | LAD-A2A | Discovery endpoint |
/.well-known/agent.json |
GET | A2A | Agent card |
/ |
POST | A2A | JSON-RPC 2.0 endpoint |
/health |
GET | - | Health check |
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Web interface |
/ws |
WebSocket | Real-time chat |
/health |
GET | Health check |
Routed to Hotel Agent:
- "What time does the spa open?"
- "What's for breakfast?"
- "Can I get a late checkout?"
- "Any restaurant recommendations nearby?"
- "Is there a gym?"
Handled by Aria (not routed):
- "What's the weather like?"
- "Tell me a joke"
- "What's 2 + 2?"
- "Who won the World Cup?"
- Make sure the hotel agent is running on port 8001
- Check if mDNS is working:
dns-sd -B _a2a._tcp local - Check the hotel agent logs for mDNS registration
- Verify your OpenAI API key in
.env - Check both agents are running
- Look at terminal output for errors
On some systems, mDNS may be blocked. The demo will fall back to direct HTTP discovery if mDNS fails.