Beyond the Chat Box:
How Agent-to-Agent Protocol (A2A) Rewires Enterprise AI Collaboration
A practical, opinionated guide to A2A — what it is, why it exists, how it compares to MCP, and what building production-grade multi-agent systems actually looks like.
|
50+ A2A Founding Partners |
3 Transport Bindings |
MCP Complementary Protocol |
HITL Human-in-the-Loop Support |
There is a moment in almost every enterprise AI project when the first agent you built hits its ceiling. It answers questions well. It calls a few tools. Users like it. Then someone asks: ‘Can it also check the payment status? And create the return if the payment is confirmed? And escalate to a human if the order value is above a threshold?’
Each of those capabilities lives in a different system, owned by a different team, built on a different framework. You could keep cramming logic into one agent — but that path leads to a monolith that is brittle, hard to test, and impossible to maintain across teams.
The cleaner answer is: let specialized agents collaborate. And for that to work without every team writing bespoke integration glue, you need a shared protocol. That is exactly what Agent-to-Agent (A2A) is.
“A2A gives agents a shared language without forcing every team to use the same framework, model, memory store, or deployment architecture.” — SAP Community — A2A: From First Principles to Production
- What A2A Actually Is — And Who Built It
A2A is an open protocol that lets AI agents discover and communicate with each other across framework, vendor, and deployment boundaries. Think of it the way you think about HTTP. HTTP doesn’t care whether your server runs Node.js, Go, or Java. A browser sends a request, a server responds, and both sides follow the same rules.
A2A follows the same philosophy — but at the agent layer. A client agent doesn’t need to know whether the remote agent was built with Mastra, LangGraph, CrewAI, Semantic Kernel, or something custom. It only needs to know four things:
- Where the agent lives: its endpoint URL
- What it can do: its declared skills and capabilities
- How to send it work: the message format
- How to track that work: the task lifecycle
A2A was introduced by Google in April 2025 as an open interoperability protocol, with support from more than 50 technology and services partners at launch — including SAP, Salesforce, ServiceNow, Workday, Accenture, Deloitte, Infosys, McKinsey, and many others. It was subsequently contributed to the Linux Foundation, which matters because protocols become more durable when no single vendor controls their roadmap.
|
🚀 Why This Matters → A2A is not a Google product — it is an open standard. SAP is a founding partner, making it natively relevant to the SAP ecosystem → The Linux Foundation contribution means A2A will evolve through community governance, not a vendor’s release cycle → 50+ partner endorsements at launch signal this is the emerging standard for multi-agent interoperability — not one option among many |
- A2A vs MCP — Two Protocols, Two Different Jobs
If you have been following the agentic AI space, you have heard about MCP — Model Context Protocol, introduced by Anthropic. The natural question is whether A2A replaces it. The answer is no, and understanding why reveals something important about how multi-agent architectures are actually structured.
|
The Single-Line Distinction MCP: Agent talks to tools and data sources A2A: Agent talks to another agent |
MCP is the right protocol when an agent needs to reach a tool with clear inputs and outputs — querying a database, reading a file, calling an API. The tool executes and returns a result. There is no lifecycle, no conversation, no task state.
A2A is the right protocol when the other side is not a tool but a worker — an autonomous agent with its own memory, tools, policies, decision-making, and potentially long-running task lifecycle. The calling agent is not executing a function; it is delegating work.
|
Dimension |
MCP vs A2A |
|
Introduced by |
MCP: Anthropic · A2A: Google (open protocol, Linux Foundation) |
|
What it connects |
MCP: Agent ↔ Tools & Data · A2A: Agent ↔ Agent |
|
Interaction model |
MCP: Function call — input in, output out · A2A: Task delegation — work tracked across lifecycle |
|
State management |
MCP: Stateless per call · A2A: Stateful tasks with history and status |
|
Discovery |
MCP: Tool list via tools/list · A2A: Agent card at /.well-known/agent-card.json |
|
Streaming |
MCP: SSE from server to client · A2A: SSE with task status updates |
|
Best for |
MCP: Databases, APIs, file systems, search · A2A: Specialized agents, approval flows, delegation |
In a well-designed multi-agent system, you use both. A product support agent uses A2A to delegate work to an order lookup agent. The order lookup agent uses MCP internally to query the orders database, payment system, and shipping provider. The protocols sit at different layers and do not compete.
- How A2A Works — The Protocol Fundamentals
The Agent Card — Discoverable Identity
Before one agent can work with another, it needs to know what that agent offers. In A2A, this is published as an agent card — a JSON document available at a well-known URL that acts as a public identity for the agent. It describes capabilities, not implementation.
The card tells a client three things: what the agent is, what it can do (its skills), and where to send requests. It deliberately does not expose the agent’s internal prompt, tools, database schema, or memory — the boundary between what is public and what is private is built into the protocol.
|
GET /.well-known/agent-card.json { “name”: “Order Lookup Agent”, “url”: “http://agent-host/a2a/jsonrpc“, “capabilities”: { “streaming”: true }, “skills”: [{ “id”: “lookup_order”, “name”: “Lookup Order”, “description”: “Answer questions about order status, payment, and delivery.” }] } |
|
💡 Key Takeaway The card is public. The execution endpoint is protected. Discovery and authorization are deliberately separated — an agent can be findable without being openly callable. |
Messages and Tasks — The Two Core Primitives
A2A has two building blocks that everything else builds on: messages and tasks. Understanding the distinction between them is the most important conceptual shift when coming from traditional API design.
|
Concept |
What It Is |
|
Message |
One thing said by a user, client, or agent. Contains parts — text, structured data, files. Identified by a messageId. Represents the input. |
|
Task |
The unit of work created when a message arrives. Has its own taskId, a status that moves through a lifecycle (submitted → working → completed/failed/canceled), and a history of messages. Represents the work. |
The separation exists because agent work is rarely instant. An agent might need to call several tools, wait for an external system, request human approval, or stream progress updates over minutes. Modelling the work as a task — rather than a request-response pair — gives both sides a shared way to reason about what is happening, even when the answer comes later.
“Think of it like a support ticket. The ticket is created the moment the question arrives. The answer may come later. In between, the ticket has a status — and anyone who needs to know what’s happening can check it.”
taskId vs contextId — One Identifies Work, One Identifies Conversation
Two identifiers appear throughout A2A, and they are easy to conflate. The distinction matters in practice — especially when building conversational agents that span multiple turns.
|
The Mental Model contextId = the conversation (who is talking to whom, across multiple turns) taskId = one piece of work (one message → one task → one answer) One conversation (one contextId) can contain many tasks (many taskIds). The contextId usually comes from the client. The taskId is created by the server per message. |
This matters most when connecting A2A to an agent memory system. The contextId is the natural key to pass as the conversation thread identifier, so the agent can load previous turns and understand references like ‘it’ or ‘that order’ in follow-up messages.
Sending Messages — Blocking and Streaming
A2A supports two execution modes. Blocking (message/send) waits for the complete answer before returning. Streaming (message/stream) opens an SSE connection and receives task status updates, progress messages, and the final answer as they are produced.
Streaming is the right default for interactive products. If an agent is checking order status, verifying payment, calling a shipping API, and drafting a customer-friendly response, showing ‘Checking order status…’ beats showing nothing for 15 seconds. The user sees progress, not silence.
|
// Streaming — receives events as the agent works for await (const event of client.sendMessageStream({ message: { kind: ‘message’, messageId: ‘msg-002’, role: ‘user’, parts: [{ kind: ‘text’, text: ‘Where is order ORD-1024?’ }] } })) { console.log(event); // submitted, working, completed, final message } |
- Human-in-the-Loop — The Pause-and-Resume Pattern
Not every agent action should complete autonomously. Creating a return, issuing a refund, deleting a record, or sending an email on someone’s behalf are exactly the kinds of actions where you want a human to approve before the agent proceeds. A2A has a built-in mechanism for this — but it works differently from what you might expect if you are coming from MCP’s elicitation model.
|
What A2A HITL Actually Is A2A does not hold a connection open waiting for human input. When an agent needs approval, it publishes a task with state: input-required and the current HTTP request ends. The client receives a paused task with a taskId and contextId it must remember. A human reviews the question. The client sends a brand new message/send call, referencing the same taskId and contextId. The server resumes the paused work from where it left off. It is a stop-flag-resume pattern, not an open-connection elicitation. |
The protocol flow looks like this in practice:
|
// Step 1 — Client sends: ‘Create a return for order ORD-1024’ // Server responds: task-123 in state input-required // { “kind”: “task”, “id”: “task-123”, “contextId”: “ctx-456”, // “status”: { “state”: “input-required”, // “message”: { “parts”: [ // { “kind”: “text”, “text”: “Approve return for ORD-1024?” }, // { “kind”: “data”, “data”: { “question”: “Approve return?” } } // ]}}} // Step 2 — Human approves. Client sends a SECOND message/send: // { taskId: ‘task-123’, contextId: ‘ctx-456’, // parts: [{ kind: ‘data’, data: { approved: true } }] } // Server resumes task-123 from the point it suspended. |
The critical implementation detail: the client is responsible for holding onto taskId and contextId from an input-required response and carrying them into the follow-up request. Drop them, and the paused task becomes unreachable even though it is sitting in the task store waiting.
|
💡 Key Takeaway HITL in A2A is deliberate and clean — but it requires shared task storage in production. If a human takes 30 minutes to approve a return and the approval request lands on a different pod than the one that suspended the task, the resume fails. InMemoryTaskStore works for demos. Shared, durable task storage is required for real HITL workflows. |
- Memory and Task Storage — Why They Are Not the Same Thing
One of the most common architectural mistakes when building multi-agent systems is conflating agent memory with task storage. They solve different problems, and mixing them produces confusing production failures.
|
Store |
Question It Answers |
|
Agent Memory |
What did this user and this agent talk about in previous turns? (Conversation continuity — loads previous messages so the agent understands references like ‘it’ or ‘that order’) |
|
Task Storage |
What happened to this specific A2A request? (Protocol recovery — current status, message history, artifacts, timestamps — for tasks/get and streaming reconnects) |
A concrete example: a user asks ‘Where is order ORD-1024?’ and then follows up with ‘Can it still be returned?’ Agent memory helps the agent understand what ‘it’ refers to — that is conversation history. If the first request took 30 seconds and the browser refreshed after 10, the client may want to call tasks/get for task-123 — that is task state. Same interaction, two different stores, two different purposes.
|
🚀 Why This Matters → The contextId is the natural bridge — pass it as the memory thread ID so both A2A and the agent memory system agree on which conversation they are referencing → For production: both stores must be externalized. In-memory implementations work for demos; they fail silently in multi-pod deployments → Use contextId for conversation continuity, taskId for protocol recovery — never swap them |
- What Actually Changes in Production
Local demos run one process. Production systems run many. The moment you deploy A2A server replicas behind a load balancer, two silent failure modes appear — and both can be hard to debug because they manifest as ‘task not found’ errors rather than obvious crashes.
|
The Two Production Failure Modes Failure Mode 1 — In-memory task store breaks across pods: message/send → pod 1 → task stored in pod 1 memory tasks/get → pod 2 → task not found Failure Mode 2 — In-memory agent memory breaks across pods: turn 1 → pod 1 → conversation stored in pod 1 memory turn 2 → pod 3 → no previous context, agent starts fresh |
The fix is the same in both cases: externalize the store. Every replica must read from and write to the same shared backend. This is not optional — it is the property that makes correctness work. Sticky sessions can be a performance optimization, but they should not be the thing that makes the application correct.
|
💡 Key Takeaway Keep A2A server pods stateless. All task state and conversation memory lives in shared storage. This is the single most important production rule for multi-agent systems built on A2A. |
- What This Means in the SAP Ecosystem
A2A is not an abstract protocol from a distant part of the tech industry. SAP is a founding partner. SAP Integration Suite Enhanced Edition’s MCP Gateway is already designed as the governance layer for agent-tool connectivity. A2A sits directly above it — the layer where Joule Assistants, custom agents, and third-party agents coordinate with each other.
|
SAP Context |
A2A Relevance |
|
Joule Assistants |
Each Joule Assistant is an A2A-capable agent — Finance, HCM, Supply Chain, CX assistants can delegate to each other or receive delegation from orchestrator agents |
|
SAP AI Agent Hub |
The marketplace where A2A-compatible agents are published, discovered, and governed — the agent card model maps directly to Hub discovery |
|
Integration Suite MCP |
MCP handles tool connectivity (APIs, databases, flows). A2A handles agent-to-agent coordination. The two protocols layer cleanly. |
|
Joule Studio 2.0 |
The development environment for building custom A2A-compatible agents — n8n visual workflows + NVIDIA OpenShell + Vercel tooling |
|
RISE & GROW Migrations |
Agent-led migration tooling relies on multiple specialized agents coordinating — A2A is the protocol that makes that coordination governed and auditable |
|
Partner Ecosystem |
SIs and ISVs building on Joule Studio need A2A expertise to connect custom agents to the broader Autonomous Suite — a direct competency opportunity |
|
🚀 Why This Matters → Solution Architects working on Joule implementations need A2A fluency — it is the coordination layer, not just an academic protocol → Partners building agents for the SAP AI Agent Hub will need to publish valid agent cards and implement A2A endpoints — start building that capability now → The combination of MCP (tool governance via Integration Suite) + A2A (agent coordination) is the complete agentic architecture for the SAP enterprise |
- The Mental Model That Makes A2A Click
Strip away the JSON-RPC, the SSE streams, the task stores, and the TypeScript examples, and A2A is a simple set of agreements:
|
Concept |
One-Line Summary |
|
Agent Card |
The agent’s public identity — who it is, what it can do, where to send work |
|
Message |
What someone said — the input |
|
Task |
The work that message created — tracked through a lifecycle |
|
contextId |
The conversation — shared across multiple tasks and turns |
|
taskId |
One unit of work — unique per message, owned by the server |
|
Executor |
Your bridge between A2A protocol and your actual agent code |
|
input-required |
The pause signal — agent needs human input before continuing |
|
Shared storage |
The production requirement — tasks and memory must survive pod restarts |
“Once these concepts click, the rest is normal backend engineering. Choose a framework for the agent runtime, expose it through A2A, persist state when needed, and protect the endpoint like any other API that can touch real systems.” — SAP Community — A2A: From First Principles to Production
The protocols — A2A for agent coordination, MCP for tool access — are not competing for the same role. They solve different problems at different layers of the stack. A mature enterprise agent architecture will use both, and the SAP ecosystem is already building toward exactly that combination.
Read More Technology Blog Posts by Members articles
#abap