TL;DR: The “MCP vs A2A” framing is a category error. They sit on different axes of an agent system: MCP is the vertical protocol connecting one agent down to its tools and data, while A2A is the horizontal protocol connecting agents across each other [4]. An implementation-grounded study from the University of York (arXiv 2607.23884, July 2026) built the same four-agent coordination loop twice — once on MCP, once on A2A — and found MCP delivers a lighter coordination model (1,255 vs 1,898 lines of code, 4 vs 10 coordination primitives, 2 vs 6 coordination stages per interaction) while A2A’s long-lived Task abstraction buys native multi-turn, stateful coordination at the cost of substantially more machinery [1]. The emerging production answer is not either/or: MCP inside each agent, A2A between agents [4].
The one-axis model: capabilities below, collaborators beside
Every operational difference between the two protocols traces back to a single assumption about the other side of the connection. MCP assumes the other end is a capability the agent controls — a database, an API, a deterministic service. A2A assumes the other end is a peer that reasons independently, refuses requests, and asks clarifying questions [4]. MCP describes capabilities; A2A describes collaborators [4].
MCP’s architecture is strictly client–server: a host (the LLM application) instantiates one client per server, and servers expose three first-class primitives — resources (data), tools (executable functions), and prompts (templates) — negotiated over JSON-RPC 2.0 [3]. A2A is peer-oriented: a client agent submits work to a remote agent that hosts its own reasoning, state, and opaque internals [1][2].
flowchart TB
User((User)) --> AgentA[Orchestrator agent]
AgentA -->|"A2A · tasks/send"| AgentB[Peer agent B]
AgentA -->|"A2A · tasks/send"| AgentC[Peer agent C]
AgentB -->|"A2A · tasks/send"| AgentC
AgentA -->|"MCP · tools/call"| T1[Tool: SQL database]
AgentA -->|"MCP · tools/call"| T2[Tool: external API]
AgentB -->|"MCP · tools/call"| T3[Tool: code sandbox]
style AgentA fill:#0f766e,stroke:#2dd4bf,color:#fff
style AgentB fill:#0f766e,stroke:#2dd4bf,color:#fff
style AgentC fill:#0f766e,stroke:#2dd4bf,color:#fff
style T1 fill:#1e293b,stroke:#334155,color:#cbd5e1
style T2 fill:#1e293b,stroke:#334155,color:#cbd5e1
style T3 fill:#1e293b,stroke:#334155,color:#cbd5e1
The A2A protocol itself is explicit about the division: “MCP is for agent-to-tool communication… A2A is for agent-to-agent communication” — and “not a replacement for MCP” [2]. The protocol docs’ own canonical build recipe is: build with any framework, equip with MCP (or any tool layer), communicate with A2A [2].
Wire-level transports: one RPC dialect, different binding strategies
Both protocols speak JSON-RPC 2.0 at the application layer, but they bind to the wire differently.
MCP defines two standard transports — stdio for local subprocesses and Streamable HTTP for remote servers [4]. Since the 2026-07-28 revision, Streamable HTTP is deliberately stateless: a single POST-only endpoint, no protocol-level sessions, no Mcp-Session-Id header, no initialize handshake [4]. Every request is self-describing — version and capabilities ride in _meta, and routing metadata is mirrored into MCP-Protocol-Version, Mcp-Method, and Mcp-Name headers so intermediaries can inspect traffic without parsing bodies [4]. A conforming tools/call is a plain, cacheable-looking POST [3][4]:
POST /mcp HTTP/1.1
Host: mcp.example.com
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": { "city": "London" }
}
}
A2A takes the opposite approach to binding: the application protocol is defined transport-agnostically (protobuf is the source of truth), with three normative bindings — JSON-RPC 2.0 over HTTP, gRPC over HTTP/2, and HTTP+JSON/REST — and updates delivered by polling, SSE, or webhooks [4][6]. A task submission over the JSON-RPC binding looks like [1][6]:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tasks/send",
"params": {
"id": "task-7f3a",
"contextId": "thread-42",
"message": {
"role": "user",
"parts": [
{ "kind": "text", "text": "Generate a domain model for a library system" }
]
}
}
}
The binding multiplicity is a real operational cost. Polling, SSE, and webhooks are all valid per spec, so you must verify which update-delivery mechanism a given remote agent actually implements before building against it [4]. MCP’s single-POST statelessness, by contrast, means load balancers, CDNs, and gateways can treat agent traffic like ordinary HTTP — the very property that motivated the rewrite [4].
State: the Task is the atom of A2A; statelessness is the point of MCP
This is the deepest divergence. A2A’s core abstraction is the Task — a stateful, long-running unit of work tracked by both sides from submission to a terminal state, grouped into logical threads by contextId, and producing Artifacts that can stream incrementally as work progresses [4]. Messages, by contrast, are the lightweight path for trivial interactions that need no tracking [4]. The task lifecycle is protocol-level, not application-level [1]:
stateDiagram-v2
[*] --> submitted
submitted --> working
working --> input-required
input-required --> working
working --> auth-required
auth-required --> working
working --> completed
working --> canceled
working --> failed
working --> rejected
completed --> [*]
canceled --> [*]
failed --> [*]
rejected --> [*]
The paused states are the tell. input-required exists specifically so a remote agent can halt mid-task, ask for clarification, and resume without losing task identity — a negotiation pattern a stateless function call cannot represent [1][4]. The A2A-based implementation in the York study leans on exactly this: a constant task ID and context ID persist across retry cycles, letting artifacts and status events reconstruct the entire interaction history [1].
MCP’s 2026-07-28 rewrite is deliberately the opposite: stateless by design, with any server instance able to serve any request [4]. Task semantics did briefly appear in MCP core (November 2025 revision: tasks/get, tasks/cancel, status notifications) but were moved out of core into an official extension in the July 2026 revision — a signal to pin your spec revision if you build on them [4]. The York paper found the practical consequence: in the MCP-based system, conversational state and task lifecycle must be “implemented explicitly at the application layer,” whereas A2A provides them natively [1].
Discovery: tools/list versus the well-known card
Discovery encodes the trust boundary each protocol assumes [4]:
- MCP — servers are client-configured (out of band), and capabilities are enumerated per-connection via listing methods like
tools/list[3][4]. There is no spec-defined pre-connection discovery document; a “well-known server card” remains an open proposal and the separate MCP Registry is in preview rather than part of the spec [4]. - A2A — every agent publishes an Agent Card, a JSON document at the well-known URI
/.well-known/agent-card.json, advertising name, description, version, service endpoint, supported modalities, authentication requirements, and skills [4]. Signed Agent Cards have been available since v0.3.0 [4].
{
"name": "Semantic Reviewer",
"description": "Validates generated models against a requirements description",
"url": "https://agents.example.com/semantic-reviewer",
"version": "1.2.0",
"skills": [
{ "id": "validate-model", "name": "Validate domain model" }
],
"capabilities": { "streaming": true, "pushNotifications": false },
"security": { "authenticationSchemes": ["bearer"] }
}
Note the asymmetry: A2A’s card solves discovery, not selection. It is registry-light — finding the right remote agent still depends on knowing where to look, and credentials are exchanged out of band, declared but not delivered by the protocol [4].
What the empirical study actually measured
arXiv 2607.23884 (submitted 26 July 2026, University of York) is the first implementation-grounded comparison of MCP and A2A used for inter-agent coordination rather than tool access [1]. The setup: a fixed four-agent collaboration — a collaboration agent orchestrating a solution agent plus syntactic and semantic supervisor agents — solving a software engineering task (generate an Emfatic/EMF domain model from a natural-language prompt), with both implementations sharing the same coordination algorithm and the same LLM (qwen2.5-coder:32b), differing only in protocol [1]. Validation ran on 30 prompts, 10 straightforward and 20 of higher complexity [1]. Real output from the solution agent, validated end-to-end [1]:
class Library {
attr String name;
val Book[*] books;
val Author[*] authors;
}
class Book {
attr String title;
attr int pageCount;
ref Author author;
}
The complexity delta is stark — measured with cloc, excluding config [1]:
| Metric | MCP | A2A | Delta |
|---|---|---|---|
| Lines of code | 1,255 | 1,898 | +51% |
| Coordination primitives | 4 | 10 | +150% |
| Coordination stages per interaction | 2 | 6 | +200% |
A2A’s six stages (agent discovery, task creation, message dispatch, task state progression, artifact propagation, completion handling) versus MCP’s two (transport initialisation, tool invocation) reflect “the richer protocol-level workflow semantics and lifecycle management capabilities provided by A2A” — and correspondingly a larger coordination failure surface [1].
Against the seven requirements derived from prior literature and industry partners (banking, aerospace, immersive tech, IoT), the scores were [1]:
| Requirement | MCP | A2A |
|---|---|---|
| R1: Agent discoverability | ✓ | ✓ |
| R2: Multi-part messaging | ✓ | ✓ |
| R3: Multi-turn conversations | ✗ | ✓ |
| R4: Asynchronous and streaming | ✓ | ✓ |
| R5: Agent observability | ~ | ~ |
| R6: Interoperability | ✓ | ✓ |
| R7: Access control | ✓ | ✓ |
Two findings deserve emphasis. First, R3 is the only differentiator: A2A natively supports multi-turn clarification via input-required; MCP requires servers to implement their own context tracking [1]. Second, neither protocol solves observability natively — no protocol-level tracing, no super-task IDs to correlate a tree of tasks and sub-tasks; both implementations had to bolt on Langfuse/Phoenix-style OpenTelemetry instrumentation at the application layer [1]. MCP’s 2026-07-28 revision does now document traceparent/tracestate propagation in _meta, which narrows but does not close that gap [4]. The authors are careful to frame the results as “design observations from an empirical experience report rather than general claims of protocol suitability” — the coordination pattern evaluated is deliberately narrow [1].
The production pattern: both protocols, one architecture
Every row of the comparison traces back to the same design decision, and so does the architecture that is emerging in production: MCP manages each agent’s access to tools and data; A2A coordinates between agents [4]. The A2A project itself ships this as the reference mental model — “MCP is for agent-to-tool communication… A2A is for agent-to-agent communication” — and the majority of application-oriented work combining both protocols follows exactly this layered structure [1][2].
flowchart LR
subgraph OrgA[Organization A]
direction TB
CA[Client agent] -->|"MCP tools/call"| M1[MCP server: internal DB]
CA -->|"MCP tools/call"| M2[MCP server: analytics API]
end
subgraph OrgB[Organization B]
direction TB
RA[Remote agent] -->|"MCP tools/call"| M3[MCP server: proprietary service]
end
CA <-->|"A2A tasks/send · Agent Card discovery"| RA
style CA fill:#0f766e,stroke:#2dd4bf,color:#fff
style RA fill:#0f766e,stroke:#2dd4bf,color:#fff
style M1 fill:#1e293b,stroke:#334155,color:#cbd5e1
style M2 fill:#1e293b,stroke:#334155,color:#cbd5e1
style M3 fill:#1e293b,stroke:#334155,color:#cbd5e1
That architecture obliges you to operate: durable HTTPS endpoints (A2A’s long-lived endpoint per remote agent, not short-lived functions), published Agent Cards, out-of-band credential infrastructure, task lifecycle state, one MCP server per tool or data source, and correlated logging across every A2A message and MCP call [4]. Treat those as first-class infrastructure, not afterthoughts [4].
Decision rules that fall out of the protocol analysis and the empirical results:
- Everything in one codebase, one team — skip both protocols. Framework-native subagents or plain function calls add less serialization and no interoperability tax [4].
- The remote side is deterministic (same input → same output) — expose it as an MCP tool. Keep reasoning in the calling agent [4].
- The remote side reasons autonomously, runs long, needs back-and-forth, or crosses an organizational boundary — that is a peer, not a tool; use A2A [4].
- You need cross-boundary delegation and tool access — run both: A2A between agents, MCP inside each [4].
- Coordination is constrained and in-process — the York results show MCP can carry it with ~51% fewer lines of code and a far smaller coordination surface, at the price of hand-rolled conversation state and lifecycle handling [1].
- Multi-turn negotiation is the core interaction — reach for A2A’s Task lifecycle; MCP will make you rebuild
input-requiredat the application layer [1].
Governance: two foundations, one trajectory
Both protocols now live under neutral open governance. Anthropic donated MCP to the Linux Foundation on 9 December 2025 as a founding project of the new Agentic AI Foundation (AAIF), alongside Block’s goose and OpenAI’s AGENTS.md, with platinum members including AWS, Anthropic, Bloomberg, Cloudflare, Google, Microsoft, and OpenAI — MCP alone counted more than 10,000 published servers at the time [5]. A2A, originally developed by Google and donated to the Linux Foundation, is Apache-2.0 licensed, maintained by a technical steering committee with seats at AWS, Cisco, Google, IBM Research, Microsoft, Salesforce, SAP, and ServiceNow, and reached 1.0 stable in March 2026 with public support from 150+ organizations [2][4][6]. IBM Research’s ACP (Agent Communication Protocol) merged into A2A under LF AI & Data in August 2025, consolidating the agent-to-agent layer further [4]. Maturity-wise: A2A 1.0 adds multi-tenancy and a web-aligned architecture built for the load balancers and gateways teams already run [4]; MCP’s surface is stable but its task semantics are settling inside an official extension, its registry is in preview, and it still has no memory primitive — plan around those gaps [4].
Bottom line
MCP and A2A are not competing standards; they are two orthogonal layers of the same stack, and the empirical record now backs that up [1][2][4]. MCP wins where the other side is a deterministic capability and the priority is a small coordination surface; A2A wins where the other side is an autonomous peer and the priority is stateful, multi-turn negotiation [1][4]. The protocol-level question to ask before reaching for either is the one Vercel’s guide leads with: what does your architecture assume about the other side of the connection? [4]
Sources:
- [1] A Comparative Study of MCP and A2A for Inter-Agent Coordination in LLM-Based Systems — arXiv:2607.23884
- [2] A2A Protocol documentation — a2a-protocol.org
- [3] Model Context Protocol Specification (2025-06-18) — modelcontextprotocol.io
- [4] A2A vs MCP: Key Differences for Agent System Architects — Vercel
- [5] Linux Foundation Announces the Formation of the Agentic AI Foundation — linuxfoundation.org
- [6] a2aproject/A2A — GitHub
📖 Related Reads
- Hermes Tutorials — Hermes Agent setup, configuration, and advanced workflows
- ToolBrain — tool reviews, LLM comparisons, and AI workflow guides
- NoCode Insider — AI workflow automation with no-code tools, agents, and APIs
Cross-links automatically generated from NiteAgent.
← Back to all posts


