A2A — Agent-to-Agent Protocol

muLLM implements an HTTP A2A-style registry for federated multi-agent coordination. Agents register capabilities, discover each other, and queue tasks via HTTP or JSON-RPC 2.0.

Agent A → JSON-RPC 2.0 → muLLM Registry ← discovery ← Agent B
Agent A → queue task → muLLM Registry → route → Best Agent

How It Works

API Endpoints

Register an agent

httpPOST /api/agents/register
Content-Type: application/json

{"agent_id":"my-translator","capabilities":["translate","summarize"],"endpoint":"https://my-agent:9000","name":"Translator Agent"}

List registered agents

httpGET /api/agents

Add a task

httpPOST /api/agents/{agent_id}/task
Content-Type: application/json

{"content":"Translate this to French: Hello world"}

Get agent's task queue

httpGET /api/agents/{agent_id}/tasks

Usage Examples

curl
Python
Node.js

Register an agent

bash# Register a custom agent with muLLM
curl -s -X POST https://localhost:6856/api/agents/register \
  -H 'Content-Type: application/json' \
  -d '{"agent_id":"my-code-agent","capabilities":["code","debug","refactor"],"endpoint":"https://my-agent:9000","name":"Code Specialist"}'

List agents

bashcurl -s https://localhost:6856/api/agents | jq

Add a task

bash# Queue a task for a registered agent
curl -s -X POST https://localhost:6856/api/agents/my-code-agent/task \
  -H 'Content-Type: application/json' \
  -d '{"content":"Explain the difference between async and threads"}'

Check task results

bashcurl -s https://localhost:6856/api/agents/my-code-agent/tasks | jq

Full A2A workflow

pythonimport httpx, time

client = httpx.Client(base_url="https://localhost:6856", verify=False)

# 1. Register our agent
client.post("/api/agents/register", json={
    "agent_id": "my-analyzer",
    "capabilities": ["analyze", "summarize"],
    "endpoint": "https://my-agent:9000",
    "name": "Analysis Agent"
})

# 2. Discover available agents
agents = client.get("/api/agents").json()["agents"]
for a in agents:
    print(f"  {a['agent_id']}: {a.get('capabilities', [])}")

# 3. Queue a task for the registered agent
client.post("/api/agents/my-analyzer/task", json={
    "content": "Analyze this code for performance issues: def fib(n): return fib(n-1)+fib(n-2) if n>1 else n"
})

# 4. Poll for results (in production, use webhooks)
time.sleep(5)
tasks = client.get("/api/agents/my-analyzer/tasks").json()
for task in tasks:
    print(f"  Status: {task.get('status')}")
    print(f"  Content: {task.get('content', '')[:100]}")

Full A2A workflow

javascriptconst BASE = 'https://localhost:6856';

// 1. Register agent
await fetch(`${BASE}/api/agents/register`, {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({agent_id: 'my-agent', capabilities: ['code', 'test'], endpoint: 'https://my-agent:9000', name: 'Test Agent'})
});

// 2. List agents
const agents = await fetch(`${BASE}/api/agents`).then(r => r.json());
console.log('Registered agents:', agents.agents.map(a => a.agent_id));

// 3. Queue task
await fetch(`${BASE}/api/agents/my-agent/task`, {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({content: 'Write unit tests for a fibonacci function'})
});

// 4. Check results
const tasks = await fetch(`${BASE}/api/agents/my-agent/tasks`).then(r => r.json());
console.log('Tasks:', tasks);

JSON-RPC 2.0 A2A Envelope

The A2A protocol wraps all communication in JSON-RPC 2.0 envelopes. muLLM's /rpc endpoint accepts these directly.

json// Request: register an agent
{
  "jsonrpc": "2.0",
  "id": "agent-001",
  "method": "agents.register",
  "params": {
    "agent_id": "mullm-primary",
    "endpoint": "https://localhost:6856",
    "capabilities": ["query", "code", "classify"]
  }
}

// Response: registered
{
  "jsonrpc": "2.0",
  "id": "agent-001",
  "result": {
    "registered": true,
    "agent": {"agent_id": "mullm-primary"}
  }
}

Agent Card (.well-known/agent.json)

Each A2A agent exposes a discovery card. muLLM's card is available at /.well-known/agent.json.

json{
  "name": "muLLM Primary",
  "description": "Cost-optimized LLM router — routes queries to cheapest capable model",
  "url": "https://localhost:6856",
  "capabilities": ["query", "code", "classify", "cache", "stream"],
  "protocols": ["mcp", "a2a"],
  "version": "0.2.0"
}