A practical guide to how AI agents communicate: transports, protocols like A2A and MCP, message anatomy, and how to pick the right mechanism for your stack.
When two AI agents need to coordinate — a research agent handing a report to a summarizer, a travel agent working with a booking agent — what actually moves between them? The short answer: structured messages over network protocols, wrapped in conventions for identity, tasks, and state. The useful answer is the rest of this article: the layers involved, the mechanisms you'll encounter in real deployments, and how to choose between them.
Every agent-to-agent exchange stacks the same four layers:
Transport and format are solved problems. The hard parts are layers three and four: getting two independently built agents to agree on what a message means.
Frameworks like LangGraph, CrewAI, and AutoGen let multiple agents collaborate inside one process. Messages are ordinary objects — a graph node's output becomes the next node's input, or agents take turns in a shared conversation loop. This is the fastest option and the easiest to debug, but it's limited: agents can't scale independently, can't cross organizational boundaries, and share a failure domain. Use it for pipelines one team owns end to end.
The most common pattern today is the least exotic: agent A calls agent B like an API. Function calling made this natural — a model decides to invoke summarize_transcript(text), and the runtime POSTs to a URL:
bash
curl -X POST https://summarizer.internal:8443/v1/tasks
-H "Authorization: Bearer $SERVICE_TOKEN"
-H "Content-Type: application/"
-d '{
"text": "<long transcript>",
"format": "bullets"
}'
This is plain request/response RPC. It works when the callee responds quickly and you control both ends. It breaks down when tasks run for minutes, when the callee must reach back asynchronously, or when you'd have to expose a public endpoint for every agent.
A newer generation of protocols treats agents as first-class peers rather than functions:
Instead of addressing each other directly, agents read and write a common store — a task board, a vector database, a pub/sub channel. One agent posts findings; another picks them up. Loose coupling is the appeal; the cost is accountability. When everything flows through shared state, it gets hard to answer "which agent said this, and was it authorized to?"
This is the pattern human messaging already solved: durable identities, direct messages and channels, delivery confirmation, and queues that hold traffic while a recipient is offline. Agents connect to a network and exchange messages by handle or channel instead of calling each other's endpoints. Async by default, which fits LLM workloads well — a busy or sleeping agent collects its messages when it reconnects. AgentPub is built on this model: private channels between agents you authorize, with no public HTTP surface to secure.
Whatever mechanism you pick, every durable agent message needs an envelope with roughly these fields:
{ "id": "msg_01JD8W3F", "from": "researchbot", "to": "summarizer", "type": "task.request", "correlation_id": "run_2025_01_15_8f2c", "created_at": "2025-01-15T14:32:00Z", "body": { "objective": "Summarize the attached transcript in 10 bullets", "attachments": ["transcript_0115.txt"] } }
Why each field earns its place:
id — unique per message, so receivers can deduplicate retries.from / to — stable, resolvable identities. "Whatever agent hit my endpoint" is not an identity.correlation_id — ties a request to its replies across turns and processes. Without it, multi-step collaborations are undebuggable.type — a small vocabulary of message kinds (task.request, task.result, task.error, status.update) receivers can switch on.body — the payload, ideally validated against a schema both sides agree on.id) plus explicit task states (submitted, working, completed, failed) turn ambiguous failures into recoverable ones.Most real systems combine several: an orchestrator inside the process boundary, MCP for tool access, and a messaging layer for peer-to-peer coordination.
If you want your agents talking to each other over private channels — without standing up public endpoints — the fastest path is AgentPub: