Agents Talking to Agents
The A2A protocol.
Velo Supply's Juno needs to book a courier. The courier company has its own agent, built by another team, using other tools. Juno can't see inside it, and doesn't need to. They just need a common language, in the way that two companies can exchange an invoice.

- Juno needs a courier
- The courier has its own agent
- They need a common language
MCP and A2A
Here's how the two standards fit together. MCP connects an agent to tools and data. It's vertical. A two A, or Agent to Agent, connects one agent to another. It's horizontal. Google introduced it in twenty twenty five, and it now lives under the Linux Foundation, alongside MCP. They're complements, not rivals. A tool does exactly what it's told. An agent is given a goal, and decides how to reach it.
MCP
- Agent to tool
- Exact function calls
- You control each step
A2A
- Agent to agent
- Delegate a goal
- The other agent decides how
The agent card
How does one agent find out what another can do? Every A two A agent publishes an agent card, a small JSON document, usually at a well known web address. It gives a name, a description, and a list of skills. It's like a business card for software. Check the spec for the exact fields, as they've changed between versions.
{
"name": "Velo Supply Returns Agent",
"description": "Handles returns and refunds for Velo Supply orders.",
"version": "1.0.0",
"capabilities": {"streaming": true},
"skills": [
{
"id": "start-return",
"name": "Start a return",
"description": "Checks an order and creates a return label."
}
]
}Long-running tasks
Delegated work can take minutes, or days. So A two A is built around tasks, which move through states. Submitted, working, maybe waiting for more input, and then completed. Here's a small model of that. Run it. The task needed a photo along the way, and it paused, just like our human in the loop graph did. Same idea, across company boundaries.
STATES = ["submitted", "working", "input-required", "working", "completed"]
class Task:
def __init__(self, task_id):
self.id, self.history = task_id, []
def move(self, state, note=""):
self.history.append(state)
print(f"{self.id}: {state:<16} {note}")
t = Task("return-881")
notes = ["received", "checking the order", "needs a photo of the damage",
"photo received", "label created"]
for state, note in zip(STATES, notes):
t.move(state, note)return-881: submitted received return-881: working checking the order return-881: input-required needs a photo of the damage return-881: working photo received return-881: completed label created
Summary
MCP for tools, and A two A for other agents. Together, they're becoming the plumbing of the agent world. Next, a map of the frameworks that you'll hear about.
Key takeaways- MCP is vertical, A2A is horizontal
- Agent cards describe skills
- Tasks can run for days