Short answers to what readers ask most about this topic.
01What is the difference between A2A and MCP?
MCP (Model Context Protocol) standardises how an AI agent connects to tools, APIs and data sources with defined inputs and outputs. A2A (Agent2Agent) standardises how independent, opaque agents discover each other, delegate tasks and exchange results as peers. In short, MCP is agent-to-tool and A2A is agent-to-agent.
02Do I need both A2A and MCP in the same system?
Often, yes. A typical design uses MCP below an orchestrator agent to reach tools you control, such as ERP read and draft tools, and A2A sideways to delegate work to agents owned by another team or company. The A2A specification itself describes the two as complementary rather than competing.
03Is MCP still stateful after the 2026-07-28 specification?
No. The 2026-07-28 release removed the initialize handshake and the Mcp-Session-Id header, so every request carries its protocol version, client info and capabilities in _meta. Any request can be served by any instance behind a round-robin load balancer. Servers that need continuity are told to return an explicit handle from a tool that the model passes back as an argument.
04How are MCP Tasks different from A2A tasks?
MCP Tasks are an extension, io.modelcontextprotocol/tasks, that lets a server return a durable handle for a slow tool call, which the client polls with tasks/get and answers with tasks/update. A2A tasks are a core protocol object for delegated work, with states such as TASK_STATE_INPUT_REQUIRED and TASK_STATE_AUTH_REQUIRED, plus streaming and push-notification webhooks. Use MCP Tasks for a slow but well-defined operation and A2A tasks when another agent must reason, ask questions or seek approval.
05Who governs A2A and MCP?
Both are projects of the Agentic AI Foundation at the Linux Foundation. MCP was a founding project when the foundation was announced in December 2025, and A2A became a hosted project on 17 August 2026 after moving to the Linux Foundation in June 2025. Each keeps its own maintainers and specification process.
MCP connects one AI agent to tools and data; A2A connects independent agents to each other. Since the 2026-07-28 spec, MCP requests are stateless and long jobs use the Tasks extension, while A2A 1.0 keeps server-owned tasks, Agent Cards and an AUTH_REQUIRED state. Most production systems need both, at different layers.
A2A vs MCP is the question I now hear in almost every agent design review, usually phrased as a choice: which one should we standardise on? It is the wrong question. MCP, the Model Context Protocol, is how an agent reaches tools and data it is allowed to use. A2A, the Agent2Agent protocol, is how one agent hands work to another agent it cannot see inside. A procurement agent reading stock levels from your ERP is an MCP problem. The same agent asking a supplier's agent for a quote is an A2A problem, and it is common for one system to need both in the same afternoon.
What changed this year is that the old shorthand stopped being accurate. MCP used to be the stateful one, with a handshake and a session; the 2026-07-28 specification removed both. A2A reached a stable 1.0 and, on 17 August 2026, moved into the Agentic AI Foundation alongside MCP. This post compares the two on what actually decides an architecture: who is on the other end, discovery, state, long-running work, auth and governance. Every method name, field and date below comes from the two specifications, the MCP release post and the foundation's announcement, as of 1 October 2026. The earlier post on MCP versus function calling compared MCP with in-process tools; this one is about the protocol layer above it.
A2A vs MCP in One Line Each: Agent-to-Tool and Agent-to-Agent
The A2A specification puts the line in its own appendix: MCP standardises how agents connect to tools, APIs, data sources and other resources, while A2A standardises how independent, often opaque agents communicate as peers. The word that matters is opaque. With MCP you see a tool's name, its input schema and its result. With A2A you see an Agent Card listing skills, and nothing about the prompts, tools or memory behind them. Three questions settle which side of the line a capability sits on.
Does the caller know exactly which operation it wants, with typed arguments? Then it is a tool, and MCP fits. Get stock level for a SKU in a warehouse is a tool call.
Does the other side need to reason, ask clarifying questions or negotiate before it can answer? Then it is an agent, and A2A fits. Find me the cheapest delivered price for 400 units is a task for an agent.
Is the other side owned by a different team or company that will not hand you its tool list or its credentials? Then you want A2A even when the work looks simple, because the boundary is organisational rather than technical.
That third question is the one teams skip. A finance team's credit-check agent inside your own company is still a separately owned agent with its own release cycle and its own access to data. Wrapping it as an MCP tool means freezing its behaviour into one schema and borrowing its credentials, which is exactly the coupling A2A exists to avoid.
The A2A vs MCP Comparison Table
This is the table I wanted when I started, filled in from MCP 2026-07-28 and A2A 1.0. The rows that changed most this year are state and long-running work, so read those two before trusting any comparison written in 2025.
Dimension
MCP (2026-07-28)
A2A (1.0)
What is on the other end
A server exposing tools, resources and prompts with defined inputs and structured outputs
Another agent, deliberately opaque: you see its skills, not its prompts, tools or memory
Direction
Vertical: one agent reaching down into systems it may use
Horizontal: peers delegating work, often across a company boundary
Discovery
Optional server/discover call, then tools/list; list results carry ttlMs and cacheScope hints
Agent Card at /.well-known/agent-card.json, plus an authenticated extended card when capabilities.extendedAgentCard is true
Protocol state
None: no initialize handshake and no Mcp-Session-Id; each request carries version, client info and capabilities in _meta
Server-owned tasks, with a contextId that groups related tasks and messages
Application state
An explicit handle returned by one tool and passed back by the model as an argument
Built in: a follow-up message references the taskId it continues
Long-running work
io.modelcontextprotocol/tasks extension: tasks/get to poll, tasks/update to answer, tasks/cancel
Core: GetTask, ListTasks, CancelTask, SubscribeToTask streaming and push-notification webhooks
Needing input mid-call
Multi Round-Trip Requests: resultType input_required, client retries with inputResponses
TASK_STATE_INPUT_REQUIRED; the client replies with a new message carrying the taskId
Wire format
JSON-RPC over stdio or Streamable HTTP; HTTP requests must send Mcp-Method and Mcp-Name headers
Three bindings, JSON-RPC, gRPC and HTTP+JSON/REST, declared in supportedInterfaces
Auth
Optional; over HTTP the server is an OAuth 2.1 resource server with Protected Resource Metadata and audience-bound tokens
Card declares securitySchemes: API key, HTTP auth, OAuth 2.0, OpenID Connect or mutual TLS; plus TASK_STATE_AUTH_REQUIRED
Governance
Founding project of the Agentic AI Foundation, announced December 2025
Linux Foundation project from June 2025; Agentic AI Foundation hosted project since 17 August 2026
Read across the rows and a pattern appears. MCP has spent this year removing anything that ties a request to a connection, so a tool server behaves like any other stateless HTTP service. A2A went the other way on purpose: the task is a durable object the remote agent owns, because delegating to an agent is a conversation, not a function call. Neither design is better. They fit different jobs.
Discovery: An Agent Card Is a Résumé, a Tool List Is a Contract
The two discovery mechanisms tell you a lot about the intended relationship. An MCP client asks a server what it can call and gets typed tool definitions it can hand straight to a model. An A2A client fetches a public JSON document that describes an agent's identity, endpoints, auth requirements and skills, and then decides whether to trust it.
# MCP 2026-07-28 — no initialize, no Mcp-Session-Id.
# Every request carries its own version, client info and capabilities,
# so it can land on any instance behind a plain round-robin balancer.
POST /mcp HTTP/1.1
Host: erp-tools.internal.example
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call # gateways route and meter on these two
Mcp-Name: get_stock_level # headers without parsing the JSON body
{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"get_stock_level","arguments":{"sku":"BRG-0042","warehouse":"SBY"},
"_meta":{"io.modelcontextprotocol/clientInfo":{"name":"procurement-agent","version":"3.1"}}}}
# A2A 1.0 — you are not calling a function, you are reading a résumé.
GET /.well-known/agent-card.json HTTP/1.1
Host: agents.supplier.example
{
"name": "Supplier Quote Agent",
"description": "Quotes price and lead time for bulk orders",
"version": "2.0.0",
"supportedInterfaces": [
{"url": "https://agents.supplier.example/a2a/v1",
"protocolBinding": "JSONRPC", "protocolVersion": "1.0"}
],
"capabilities": {"streaming": true, "pushNotifications": true,
"extendedAgentCard": true},
"securitySchemes": {"partnerOAuth": {"oauth2SecurityScheme": {"...": "flows"}}},
"securityRequirements": [{"schemes": {"partnerOAuth": {"list": ["quotes"]}}}],
"defaultInputModes": ["text/plain", "application/json"],
"defaultOutputModes": ["application/json"],
"skills": [{"id": "bulk-quote", "name": "Bulk order quote",
"description": "Negotiates a quote for 100+ units",
"tags": ["quote", "procurement"]}]
}
# Note what is missing: no tool list, no input schema per call.
# The partner's tools stay private — that opacity is the point of A2A.
Two details from the specifications matter in practice. On the MCP side, tools/list, prompts/list, resources/list and resources/read responses now carry ttlMs and cacheScope, and list order is deterministic, so a client can cache the tool catalogue and keep an upstream prompt cache stable across reconnects. On the A2A side, Agent Cards may be signed with JSON Web Signature, and a public card can advertise an extended card that only authenticated clients receive. That is how a partner can show a general skill list to the world and a fuller one to you.
The consequence for design: an MCP tool list is a contract you program against, so changing a tool's schema is a breaking change for every client. An Agent Card is closer to a résumé. Skills carry descriptions, tags and examples rather than strict schemas, and the remote agent is expected to cope with varied requests and ask when it needs more.
State After MCP Went Stateless
The 2026-07-28 release retired the initialize and initialized exchange and the Mcp-Session-Id header. Each request now carries its protocol version, client identity and capabilities in _meta, and the release post says plainly why: any request can land on any server instance behind a plain round-robin load balancer, without shared storage. Server-initiated requests such as elicitation and sampling are replaced by Multi Round-Trip Requests, where the server returns input_required and the client retries the original call with the answers attached. Roots, Sampling and Logging are deprecated with at least twelve months of support, and so is the legacy HTTP+SSE transport.
Stateless protocol does not mean stateless application. The release post recommends that a server needing continuity mint an explicit handle from a tool and have the model pass it back as an argument. A2A never had that problem to solve, because state is its subject matter. A task has an id, a status and artifacts, and the contextId lets the remote agent keep a multi-turn thread together across several tasks. If you catch yourself building conversation memory on top of MCP handles so that two agents can talk, that is the moment to switch protocols.
A quick test for an existing design: list everything your MCP server stores between calls. If it is a cache, a draft document id or a cursor, keep MCP and pass it as a handle. If it is the other party's half of a conversation, you have built an agent behind a tool interface, and A2A will model it more honestly.
Long-Running Work: MCP Tasks Versus A2A Tasks
Both protocols now have something called a task, which is where most confusion starts. In MCP it is an extension, io.modelcontextprotocol/tasks, that the client opts into per request and the server applies per request: when it judges a call will be slow, it returns a durable task handle instead of the result. In A2A the task is the core object every non-trivial interaction produces. Here is the same shape of job in each.
# ── MCP: tools/call with the io.modelcontextprotocol/tasks extension ──
# Client opted in via _meta clientCapabilities.extensions. The SERVER decides
# per request whether to return a task instead of the result.
-> tools/call {"name": "rebuild_stock_valuation", "arguments": {"period": "2026-09"}}
<- {"resultType": "task", "taskId": "t-81f2", "status": "working",
"ttlMs": 86400000, "pollIntervalMs": 5000} # abbreviated
-> tasks/get {"taskId": "t-81f2"} # store taskId durably:
<- {"status": "input_required", "inputRequests": {...}} # a restart resumes polling
-> tasks/update {"taskId": "t-81f2", "inputResponses": {...}}
-> tasks/get {"taskId": "t-81f2"}
<- {"status": "completed", "result": {...}} # what tools/call would
# have returned inline
# ── A2A: the task IS the protocol, not an extension ──
-> SendMessage {"message": {"role": "ROLE_USER", "messageId": "m-1",
"parts": [{"text": "Quote 400 units of BRG-0042, delivery Surabaya"}]}}
<- {"task": {"id": "q-77", "contextId": "ctx-9",
"status": {"state": "TASK_STATE_INPUT_REQUIRED",
"message": {"role": "ROLE_AGENT",
"parts": [{"text": "Incoterm? FOB or delivered?"}]}}}}
-> SendMessage {"message": {"taskId": "q-77", "role": "ROLE_USER",
"messageId": "m-2", "parts": [{"text": "Delivered"}]}}
# Then poll GetTask, hold a SubscribeToTask stream, or register a webhook
# with CreateTaskPushNotificationConfig and stop holding connections at all.
The state names line up more closely than the designs do, and the gaps are instructive.
MCP Tasks status
A2A TaskState
What the difference means
working
TASK_STATE_SUBMITTED, TASK_STATE_WORKING
A2A separates accepted from started, which matters when the remote side queues work
input_required
TASK_STATE_INPUT_REQUIRED
MCP answers through tasks/update with inputResponses; A2A answers with a new message that references the taskId
no equivalent
TASK_STATE_AUTH_REQUIRED
MCP handles missing permission at the HTTP layer with 401 or 403 and step-up authorization, not as a task state
completed
TASK_STATE_COMPLETED
In MCP the result is exactly what the original call would have returned inline
failed
TASK_STATE_FAILED, TASK_STATE_REJECTED
A2A distinguishes an agent that refused the work from one that broke while doing it
cancelled
TASK_STATE_CANCELED
MCP documents cancellation as cooperative: the server may still finish the work
The rule I use: MCP Tasks are for a tool that is slow, such as a stock revaluation, a report export or a CI run. The caller still knows exactly what it asked for and only needs to wait. A2A tasks are for work that is delegated, where the remote agent may ask questions, need approval and produce several artifacts along the way. MCP polls by default and can push through an opt-in subscriptions/listen stream; A2A offers polling, streaming over Server-Sent Events and webhooks, which suits a partner that may take hours to answer.
Auth and Governance: Who You Trust, and Who Owns the Spec
MCP's authorization is optional, and for stdio servers the spec says to take credentials from the environment instead. Over HTTP it is precise: the MCP server is an OAuth 2.1 resource server, it must publish Protected Resource Metadata, clients must send a resource indicator naming the server, and the server must reject any token not issued for it as the audience. The 2026-07-28 revision adds RFC 9207 issuer validation, binds client credentials to the issuer that minted them and formally deprecates Dynamic Client Registration in favour of Client ID Metadata Documents.
A2A treats an agent as an ordinary enterprise application. The Agent Card declares securitySchemes and securityRequirements, credentials are obtained out of band, and the server must authenticate every request. The interesting part is in-task authorization. When a remote agent needs a new permission halfway through, it moves the task to TASK_STATE_AUTH_REQUIRED and the client resolves it, by delegating up its own chain if necessary. The spec is explicit that this state by itself authorises nothing; what the resulting credential covers is for the implementation to define.
The expensive mistake in a multi-agent chain is forwarding the user's token. MCP forbids it outright: a server must not accept or pass on tokens issued for anything else. A2A warns that in-band credentials can be exposed to every agent in a chain, and recommends binding them to the requesting agent and encrypting them. Give each hop its own audience-bound credential.
Governance is the one dimension where the two have converged. MCP was a founding project of the Agentic AI Foundation, announced by the Linux Foundation in December 2025 with Anthropic contributing MCP, Block contributing goose and OpenAI contributing AGENTS.md. A2A started at Google in April 2025, went to the Linux Foundation in June 2025, reached its stable 1.0 in March 2026 and became an AAIF hosted project on 17 August 2026. Each keeps its own maintainers and specification process, but choosing one is no longer a bet on a single vendor.
A Layered Reference Architecture: Where Each Protocol Sits
Here is how I lay out one system that needs both, using an ERP procurement assistant as the example. Each arrow is labelled with the protocol it uses, and the point of the drawing is that the protocols never compete for the same arrow.
Layer 4 Surfaces web chat · WhatsApp · ERP side panel
│ (your own app API — neither A2A nor MCP)
▼
Layer 3 Orchestrator procurement agent: owns the conversation and the plan
│ │ │
│ MCP │ A2A │ A2A
│ tools/call, stateless │ SendMessage, task │ (internal, but
▼ ▼ ▼ separately owned)
Layer 2 MCP gateway partner endpoint finance team's agent
routes on supplier quote agent credit-limit check
Mcp-Method/Mcp-Name (its tools are invisible (it keeps its own MCP
│ to you; it may use MCP) servers behind it)
▼
MCP tool servers
erp-read: stock, price, PO status ← safe, cacheable lists
erp-draft: create draft PO, draft GRN ← writes, idempotency key
erp-post: NOT exposed to any agent ← humans post documents
│
▼
Layer 1 Systems of record ERP database · document store · approval queue
Read it from the middle. The orchestrator owns the user's conversation and the plan. Everything it can call with known arguments goes down through MCP to tool servers you run: read tools for stock, price and purchase order status, and draft tools that create documents a human then reviews. Posting tools are not exposed to any agent at all. Everything that needs another party's judgement goes sideways over A2A: the supplier's quote agent outside the company, and the finance team's credit-limit agent inside it, which keeps its own MCP servers behind it.
Two operational benefits come from keeping the layers clean. Because MCP requests now carry Mcp-Method and Mcp-Name headers, the gateway in layer 2 can rate-limit, log and authorise per tool without parsing bodies, and scale horizontally with no sticky sessions. Because A2A sits only at ownership boundaries, every A2A endpoint corresponds to a real contract with another team or company, which is the right granularity for audit and for deciding whose credentials are used where.
Choosing Between Them, and the Two Ways to Get It Wrong
In practice the decision falls out of four questions, asked in this order for every integration in the design.
Do you control both sides and know the exact operation? Use an MCP tool, and keep it narrow and typed.
Is the operation slow but still well defined? Keep MCP and let the server return a task through the Tasks extension, if your client supports it.
Does the other side reason, ask questions or need its own approvals? Use A2A and treat the result as a task with a lifecycle, not a return value.
Is the other side owned by someone else? Use A2A at that boundary even for simple requests, and let the owner decide what tools sit behind it.
The two failure modes mirror each other. Wrapping a remote agent as one MCP tool loses INPUT_REQUIRED, AUTH_REQUIRED and multi-turn context, so the agent either guesses or fails silently. Wrapping every database query as an A2A agent adds an extra model call, latency and cost to work a typed function would do deterministically.
The useful rule is about boundaries, not brands: MCP below the agent, A2A between agents. MCP's move to a stateless core made it an even cleaner tool layer, and A2A's server-owned tasks are what delegation needs. Since August 2026 both sit in the same foundation, so the only real decision left is which arrow in your design is which.