---
title: "MCP, A2A, and Where ACP Went"
description: "MCP connects an agent to tools, A2A connects agents to each other, and ACP folded into A2A in 2025. Here is the agent protocol stack in 2026, spec-level, and how a gateway governs both."
canonicalUrl: "https://zuplo.com/blog/2026/07/03/agent-protocol-stack-mcp-a2a-acp-2026"
pageType: "blog"
date: "2026-07-03"
authors: "martyn"
tags: "MCP, ai-agents, API Security"
image: "https://zuplo.com/og?text=MCP%2C%20A2A%2C%20and%20Where%20ACP%20Went"
---
Two protocols now define how an AI agent reaches the outside world. The Model
Context Protocol (MCP) connects an agent to tools: a database, a Stripe account,
an internal API. Agent2Agent (A2A) connects agents to each other, so a planning
agent can hand a task to a billing agent without either one exposing its
internal state. They solve different problems and are stewarded by different
standards bodies.

You may also have heard about a third contender, the Agent Communication
Protocol (ACP). Good news: it is no longer a separate thing to track.

If you are deciding what to support, what to secure, and where the gateway sits,
the mid-2026 landscape is more settled than the hype implies. Here is the stack
at spec level, and where the controls go.

<CalloutAudience
  variant="useIf"
  items={[
    `Building or exposing agents that call tools (MCP) or other agents (A2A)`,
    `Deciding which protocols to support and how to secure them`,
    `After the spec-level detail, not another "what is an agent" explainer`,
  ]}
/>

## MCP talks to tools, A2A talks to agents

MCP is agent-to-tool. A client (Claude Desktop, Cursor, your own agent) connects
to an MCP server that exposes tools, resources, and prompts. The server is a
capability provider; the agent is the caller. Our
[what is an MCP server](https://zuplo.com/learning-center/what-is-an-mcp-server)
walkthrough covers the model.

A2A is agent-to-agent. Both ends are autonomous agents. One discovers another,
delegates a task, and the two coordinate over a long-running exchange, streaming
partial results as they go. Neither side hands over its tools or its memory. Our
[A2A protocol guide for API teams](https://zuplo.com/learning-center/agent-to-agent-a2a-protocol-guide)
covers the higher-level model; this post goes a layer deeper into the wire
format.

In a real system you use both: an orchestrator uses A2A to delegate to
specialist agents, and each specialist uses MCP to reach the tools it needs.

## Where ACP went

For most of 2025 there were three protocols in the conversation, not two. ACP,
the Agent Communication Protocol, came out of IBM Research in March 2025 to
power its BeeAI platform. It overlapped heavily with A2A: both described how
autonomous agents discover and talk to each other.

That overlap resolved. In August 2025, LF AI & Data announced that ACP was
joining A2A under the Linux Foundation umbrella. "Merger" undersells it: the ACP
team
[wound down active development](https://lfaidata.foundation/communityblog/2025/08/29/acp-joins-forces-with-a2a-under-the-linux-foundations-lf-ai-data/)
and began contributing its technology directly to A2A.

So in 2026 there is one agent-to-agent standard worth building against: A2A.

A2A itself moved to neutral governance first. Google donated the protocol, its
SDKs, and tooling to the Linux Foundation on June 23, 2025, launching the
Agent2Agent Protocol Project with AWS, Cisco, Google, Microsoft, Salesforce,
SAP, and ServiceNow as founding members. By the time ACP wound down, it was
joining a project that was already vendor-neutral, not handing itself to a
competitor.

## Inside the AgentCard

A2A discovery starts with a public document called an AgentCard, served at a
well-known path. In the
[v1.0 spec](https://a2a-protocol.org/v1.0.0/specification/) that path is
`/.well-known/agent-card.json` (the older `/.well-known/agent.json` you may see
in v0.x examples is out of date).

The card advertises who the agent is, what it can do, and how to authenticate to
it:

```json
{
  "name": "Billing Agent",
  "description": "Issues refunds and answers invoice questions",
  "url": "https://agents.example.com/a2a",
  "provider": { "organization": "Example Corp" },
  "capabilities": {
    "streaming": true,
    "pushNotifications": true
  },
  "securitySchemes": {
    "oauth": {
      "type": "oauth2",
      "flows": {
        "clientCredentials": {
          "tokenUrl": "https://auth.example.com/token",
          "scopes": { "billing:write": "Issue refunds" }
        }
      }
    }
  },
  "security": [{ "oauth": ["billing:write"] }],
  "skills": [
    {
      "id": "refund",
      "name": "Issue a refund",
      "description": "Refunds a charge by transaction ID"
    }
  ]
}
```

`capabilities` tells a caller whether the agent supports streaming and push
notifications (a callback to a webhook so a long-running task can report back
without holding a connection open). `securitySchemes` and `security` describe
how to authenticate, using the same shape as OpenAPI security schemes. `skills`
is the menu of what the agent will do. A calling agent fetches the card, decides
the remote agent is a fit, and starts a task.

The card is a capability grant in document form, which is exactly why it is a
security surface we will come back to.

## Task lifecycle and transports

Work in A2A is modeled as a Task. A caller sends a Message (made up of Parts:
text, files, structured data), and the remote agent does the work and streams
back Messages and Artifacts. The task moves through a defined set of states:

| State            | Meaning                                    |
| ---------------- | ------------------------------------------ |
| `submitted`      | The task has been accepted but not started |
| `working`        | The agent is actively processing           |
| `input-required` | The agent is blocked waiting on the caller |
| `auth-required`  | The agent needs additional authentication  |
| `completed`      | The task finished successfully             |
| `failed`         | The task errored                           |
| `canceled`       | The caller or agent stopped the task       |
| `rejected`       | The agent declined the task                |

The `input-required` and `auth-required` states are what make A2A a coordination
protocol rather than a request/response API: a task can pause mid-flight, ask
the caller for more, and resume.

A2A v1.0 defines three transport bindings: JSON-RPC 2.0 over HTTP, gRPC, and
HTTP+JSON/REST. Streaming updates ride Server-Sent Events. Over the JSON-RPC
binding, delegating a task is a single POST to the agent's URL:

```http
POST /a2a HTTP/1.1
Host: agents.example.com
Authorization: Bearer <token>
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "message/send",
  "params": {
    "message": {
      "role": "user",
      "parts": [{ "kind": "text", "text": "Refund charge ch_3Nk for $40" }]
    }
  }
}
```

The agent replies with a Task object carrying an `id` and a `status.state` of
`submitted` or `working`, then streams updates over SSE as that state advances.
For a gateway operator this is the headline: A2A traffic is HTTP plus JSON plus
SSE, with no exotic transport to learn. Zuplo's runtime is web-standard down to
streams, so the SSE leg rides the same engine that handles your other streaming
responses.

## How A2A authenticates

A2A does not invent an auth scheme. The `securitySchemes` field on the AgentCard
reuses the OpenAPI vocabulary, so an agent can declare API keys
(`APIKeySecurityScheme`), HTTP auth, OAuth 2 (`OAuth2SecurityScheme`), OpenID
Connect, or mutual TLS.

A calling agent reads the scheme, obtains a matching credential (usually
authenticating as itself with a machine identity, though a scheme can carry a
user's delegated token), and presents it on every task request.

Because the AgentCard is a public document that drives trust decisions, the spec
also defines signed agent cards so a caller can verify the card has not been
tampered with before acting on it. If you can poison an agent's card, you can
redirect or escalate everything that trusts it.

That puts A2A on familiar ground for anyone who runs API infrastructure: HTTP
with OAuth-style auth and a discovery document. The controls you already apply
to APIs (token validation, rate limiting, observability) apply directly, which
is why a standard gateway can govern A2A without a dedicated handler.

## Threats when agents call agents

Adding agents to the call graph adds attack surface that traditional API
security models do not fully cover, and the threats are increasingly catalogued.

- **Tool poisoning.** A malicious or compromised tool returns content crafted to
  manipulate the calling model. It is item #3 in the
  [OWASP MCP Top 10](https://owasp.org/www-project-mcp-top-10/), currently an
  incubator project, alongside rug pulls and tool shadowing.
- **Prompt injection.** Untrusted content reaches the model as instructions.
  This is LLM01 in the
  [OWASP Top 10 for LLM Applications](https://owasp.org/www-project-top-10-for-large-language-model-applications/).
  It flows backwards through tool and agent responses, so the boundary has to
  inspect what comes back, not only what goes out.
- **Excessive agency.** An agent is granted more capability than the task needs
  and acts on it. That is LLM06 in the same OWASP list, the failure mode that
  makes least-privilege grants non-negotiable.
- **Agent-card and confused-deputy attacks.** A poisoned AgentCard or a token
  replayed at the wrong server lets a compromised component act with another's
  authority. (A confused deputy is a privileged component tricked into misusing
  its authority on an attacker's behalf.) The MCP authorization spec names the
  confused-deputy attack explicitly in its security considerations.

OWASP now ships a dedicated
[Top 10 for Agentic Applications for 2026](https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/),
the list to design against if your system has agents calling agents. The common
thread: the model layer cannot be the sole enforcement point. Model-side
guardrails help, but they are probabilistic and never catch everything, so a
deterministic boundary has to sit between the agent and whatever it is reaching.

## MCP in 2026

MCP grew up over the last year. In December 2025 Anthropic
[donated MCP to the Agentic AI Foundation](https://www.anthropic.com/news/donating-the-model-context-protocol-and-establishing-of-the-agentic-ai-foundation),
a Linux Foundation directed fund it co-founded with Block and OpenAI, so it is
no longer an Anthropic project the rest of the industry consumes; it is
community-governed, with working groups and a formal proposal process. Both
protocols in this post now sit under the Linux Foundation, the clearest signal
yet that the agent stack is standardizing rather than fragmenting.

The spec hardened alongside that governance shift. The current stable revision
is dated `2025-11-25`, with the next version (`2026-07-28`) in release candidate
as of this writing. The authorization model got strict: MCP servers **MUST**
implement OAuth 2.0 Protected Resource Metadata
([RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728)) and MCP clients
**MUST** implement Resource Indicators
([RFC 8707](https://datatracker.ietf.org/doc/html/rfc8707)), binding every token
to the specific server it was issued for. Dynamic client registration, once the
expected path, is now optional.

<CalloutTip variant="mistake">
  If you implemented MCP auth in early 2025, do not assume it still conforms.
  The token-binding and Resource Indicator requirements became **MUST** since,
  and dynamic client registration is no longer the expected path. Re-read the
  current spec before you ship against it.
</CalloutTip>

After a long stretch of people wondering whether MCP would stick, it has settled
into something normal. As teams landed on their preferred AI setups, adoption
turned routine rather than experimental. That maturity is not the same as a free
pass. A critical command-injection vulnerability disclosed in April 2026
([CVE-2026-30623](https://docs.litellm.ai/blog/mcp-stdio-command-injection-april-2026))
let LiteLLM's MCP server-creation feature run config commands without
validation. The lesson is boring, but very real: a maturing protocol needs a
governed path, not blind trust in every server you connect to. Ungoverned
servers are exactly the
[shadow MCP](https://zuplo.com/learning-center/shadow-mcp-ungoverned-ai-agent-security)
problem.

## One gateway for both

Both protocols ride HTTP, both use OAuth-style auth, and both put untrusted
content in front of a model. That is why the same gateway can govern both, with
one asymmetry in how much it does for each:

| Concern           | MCP                                        | A2A                                          |
| ----------------- | ------------------------------------------ | -------------------------------------------- |
| Gateway's job     | Issues tokens (full OAuth 2.1 auth server) | Validates tokens (each agent brings its own) |
| Dedicated handler | Yes, the MCP Gateway                       | No, front it like any HTTP API               |
| Transport         | HTTP, JSON-RPC, SSE, stdio                 | HTTP, JSON-RPC, SSE                          |
| Extra controls    | Capability filtering, no token passthrough | Per-agent rate limiting, request logging     |

The split: MCP needs the gateway to mint and bind credentials, while A2A only
needs it to validate the credentials agents already carry.

For MCP, Zuplo ships a dedicated
[MCP Gateway](https://zuplo.com/blog/introducing-zuplo-mcp-gateway): a full
OAuth 2.1 authorization server in front of your MCP servers, implementing the
authorization-server metadata (RFC 8414), protected-resource metadata (RFC
9728), and dynamic client registration (RFC 7591) surfaces.

Each upstream you front is published as a virtual server, its own gateway route
with its own OAuth resource. With PKCE and a required `resource` parameter (RFC
8707), a token issued for one virtual server is rejected at another, closing the
confused-deputy gap: a token minted for `/mcp/linear-v1` cannot be replayed
against `/mcp/stripe-v1`.

Two more controls matter:

- **No token passthrough.** Passthrough is forbidden by the MCP spec, and the
  gateway enforces it. Inbound auth headers never leak to the upstream; the
  gateway resolves the user's credential server-side and attaches it, storing
  upstream tokens encrypted at rest. The reasoning behind binding a token to one
  server is in
  [bind MCP tokens to one server](https://zuplo.com/blog/bind-mcp-tokens-to-one-server).
- **Capability filtering.** A policy filters the upstream's `tools/list`,
  `prompts/list`, and `resources/list` responses and blocks calls to anything
  hidden, returning `MethodNotFound` even to an agent that already knows or
  guesses the tool name. You publish a read-only or hand-picked subset of a
  server's tools rather than handing the agent everything.

For A2A there is no dedicated handler, and there does not need to be. Each agent
presents its own credential, so the gateway validates rather than issues tokens,
the lighter job. A2A is HTTP plus JSON-RPC plus SSE, so you front it the way you
front any API: JWT or OpenID Connect validation, per-agent rate limiting, and
full request logging. Same boundary, applied to agent-to-agent traffic. Our
[AI gateway comparison for MCP, A2A, and agent governance](https://zuplo.com/learning-center/ai-gateway-comparison-mcp-a2a-agent-governance)
lays out where each vendor sits on native A2A support today.

An AgentCard describes one agent, but a caller still has to discover which
servers and agents an organization publishes in the first place. Because the
gateway already sits in front of all of them, it is the natural place to publish
that catalog, kept in sync with what is actually deployed rather than a manifest
that drifts on its own. We cover the mechanics in
[serving an agentic resource discovery manifest from the gateway](https://zuplo.com/blog/agentic-resource-discovery).

<CalloutDoc
  title="MCP Gateway Quickstart"
  description="Build a virtual MCP server in the browser: pick an upstream, wire up OAuth, curate the tools, and point an agent at it."
  href="https://zuplo.com/docs/mcp-gateway/quickstart"
  icon="book"
/>

In not much more than a year, the agent protocol stack has grown clear and
settled. MCP for tools, A2A for agents, both under the Linux Foundation, both
spec-hardened on auth. The work now is not picking a protocol but putting a
governed boundary in front of the ones you already have, so the next disclosed
vulnerability is something your gateway absorbs instead of something your agents
inherit.