applied-ai2026-08-0424 minNikolay Angelov

MCP and A2A

Two protocols for agentic systems — what each one solves, when you need one, the other, or both together.

MCP inward, A2A between agents

Two protocols, announced within months of each other, both built for agentic systems. This article looks at what each of them is, when you need one, when you need the other, and when you need both.

To make things concrete, I'll use two examples. One is a software example that will stay with us for the whole article — two systems inside one organization:

  • Leave calendar (HR unit) — owns the knowledge about vacations, balances, public holidays, team coverage rules, approval policy.
  • Staffing / Scoping (Delivery unit) — owns the knowledge about people, skills, seniority, rates, project commitments.

The other example is there purely for intuition. We'll get to it in a minute.


Before we talk about the protocols, let's establish one idea. An agent has two fundamentally different directions of communication:

  • inward — toward its own tools and data
  • outward — toward people or other agents

The first direction is about access to capabilities. The second is about delegating work. That's exactly where the split between MCP and A2A comes from.

How an Agent Uses Its Own Tools

Every agent needs tools: databases, internal APIs, documents, external services, file systems, calculators, and search engines. The problem is how to present all of these capabilities in a unified way, so the model can discover and use them. That is the problem MCP solves.

MCP (Model Context Protocol) — announced by Anthropic in late 2024 — provides a unified way for a language model to get access to tools and data. A server exposes tools; the client — the agent — calls them. The interaction is synchronous, request/response, within a single session.

The leave calendar exposes a dozen or so tools: get_leave_balance, who_is_out, team_coverage, list_holidays, request_leave, and so on. Each has a name, a description, and a JSON schema for its input.

It Looks Like OpenAPI, but It Isn't

OpenAPI describes an interface for code. MCP describes an interface for reasoning.

OpenAPI vs MCP: machine-readable vs model-readable

The resemblance is real. Both describe, in machine-readable form, what a system can do, so that someone who hasn't read the code can use it. In both cases there's a name, parameters, types.

The difference is a single one, but it's essential.

An OpenAPI spec is read by a client generator or by a programmer. Then the programmer writes code. The code is deterministic: exactly what the human decided to call gets called, exactly when they decided. The spec is documentation about the interface — the real interface is the code someone wrote after reading it.

An MCP description is read by a model that decides on its own whether, when, and with what arguments to call. There is no compilation. There is no programmer in the middle who made the decisions in advance. The description is not documentation about the interface.

To the agent, the description is the interface.

Everything else follows from that. The description field carries a weight that summary in OpenAPI never carried, because it is the only thing the model sees — not the code, not the database, not the business logic. That's why good descriptions say when to use something, not just what it does:

{
  "name": "get_leave_balance",
  "description": "How many days of paid annual leave an employee has left for a given year. Use this BEFORE submitting a request, to check whether it fits within the quota.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "employee": {
        "type": "string",
        "description": "Employee — a name (or part of one), an email, or a numeric id. E.g. \"Georgi\", \"maria@example.com\", \"4\"."
      },
      "year": {
        "type": "integer",
        "description": "Year; defaults to the current one."
      }
    },
    "required": ["employee"]
  }
}

The second sentence in description doesn't describe functionality. It's an instruction about calling order. Without it, the model submits the request and learns about the quota from the error.

Look at employee too. It accepts a name, an email, or an id — not employeeId: number. The schema is written for something that talks to a human and has "Georgi" to work with, not for code that holds a primary key. Resolution is the server's job.

That's the whole difference on one screen: the schema describes the shape, the description carries the decision. In OpenAPI the second one doesn't exist, because a programmer already made the decision.

The Deal

If all of this sounds too abstract, let's set software aside for a moment.

Here is the other example.

You're buying an apartment. You know what's needed — more or less everyone does. You need a plot sketch from the cadastre. A tax valuation from the municipality. A certificate of encumbrances from the property registry. An appraisal, if there's a mortgage. A preliminary contract, a deposit, a notarial deed.

The procedures are public. The counters are open. Nobody is hiding anything from you. You could do it all yourself — some people do.

And yet you hire a broker.

Not because you can't walk to the cadastre. But because you don't know what gets issued before what, which document has a validity period and will expire while you wait for another, which one is only possible after you have a third — and what to do when the clerk at the counter turns you down. You also don't know which of all these documents even apply to your case.

The institutions are your API. The counters already work. The broker doesn't replace them, doesn't build a second municipality, doesn't keep his own copy of the cadastre. He sits on top and knows when, what, and why.

Notice something important. The whole time, the broker does the work himself. He simply uses the various institutions as his tools.

That is MCP. Not a second implementation of your business logic, but a layer that describes the API you already have in a way a language model can use.

And that's exactly why the description "Use this BEFORE submitting a request" is worth more than the description "returns a number." A broker who lists the counters for you but won't tell you in what order to visit them isn't a broker — he's a directory sign.

Now swap the broker for an agent and the institutions for tools. Everything else is the same.

The Limits of MCP

Three things follow from the nature of a tool.

A tool is transparent. You see the schema, you see what it returns, you know what will happen before you call it. That is a strength — and a boundary.

A tool carries no judgment. team_coverage returns numbers. Whether "two on duty out of a team of five during the week of September 22" is acceptable is decided by whoever asked. The counter hands you the document; whether the deal is good is not its business.

The initiative always belongs to the client. A request is submitted and the answer is awaited, within the session. Nobody notifies the client later — the cadastre doesn't call you.


How an Agent Collaborates with People and Other Agents

Sometimes, though, tools are not enough. There are tasks you don't want to solve yourself, because someone else already owns the knowledge, the context, or the responsibility. That is the problem A2A solves.

A2A (Agent2Agent) is a protocol for communication between autonomous agents. Announced by Google in April 2025, later donated to the Linux Foundation. Instead of calling a function, you delegate a task.

The Deal, Continued

So far the story had one broker — yours. But the apartment has an owner, and the owner has a broker too.

And the two brokers start talking.

What they say to each other does not look like a function call.

"Could your client vacate the property by September 15?"

That is not a lookup. The other broker doesn't know the answer at the moment he hears the question. He'll have to check, call his client, maybe wait for the client to talk it over with his wife. He'll come back two days later with "yes, but he wants the deposit a week earlier."

Notice what does not happen along the way.

Your broker doesn't get access to the drawer with the seller's documents. He doesn't learn that the seller is in a hurry because of a divorce or a tax problem. He doesn't find out whether the person across the table has thirty years of experience or is a rookie, or whether they work out of a notebook or a million-dollar software suite.

He gets an answer. And that is entirely sufficient for the deal to move forward.

And most importantly — the part that usually gets missed: the seller's broker has his own counters. His own notary, his own bank, his own cadastre. Nobody sends your broker to dig through the seller's documents, and nobody sends the seller to your bank.

Here's the whole picture in one sentence: each broker walks his own counters, and the two brokers talk to each other.

Here comes the essential difference. The broker is no longer touring institutions — he is talking to other experts, who make their own decisions and carry responsibility for them.

That is A2A.

MCP inward, A2A outward.

MCP: institutions as tools — you expect a lookup. A2A: a conversation with experts who decide and take responsibility — you expect a judgment

What This Looks Like as a Protocol

The analogy translates almost literally.

Where MCP has a Tool Description, A2A has an Agent Card. But an Agent Card doesn't describe a tool. It describes an expert.

An Agent Card is the broker's business card — a JSON document at a well-known address (/.well-known/agent-card.json) that says what this agent takes on, what skills it offers, where to find it, and what authentication it requires. The same rule from the previous chapter applies here: this is everything the other side sees. A business card that just says "broker" is useless.

In our example, the two cards look like this.

Leave Planner Agent is the agentic side of the leave calendar. Its card doesn't say "returns balances," and the ten tools from earlier are not listed — they stay inside, hidden behind it. It says something else: that it assesses leave risk for a given set of employees and a period, and that it proposes a lower-risk window for an engagement of a given length. Two skills, phrased as judgments, not as lookups. On the inside it is a perfectly ordinary agent — it uses its own MCP server over the same API that serves HR's internal web UI — but none of that is visible from the outside. What's visible is a broker responsible for his side of the deal.

Staffing Agent sits on the other side of the table. It serves the account managers: it knows who has what skills, who is committed to which projects and until when, what the rates are, and it assembles proposals for client teams — through its own MCP server, over its own database, in its own unit. When the question comes down to availability, it doesn't reach into someone else's data and doesn't form its own opinion about vacations. It asks. In this pair it is the client: the one that delegates the task and waits for the answer.

The leave agent's card looks roughly like this:

{
  "protocolVersion": "0.3.0",
  "name": "Leave Planner Agent",
  "description": "Answers questions about people's availability with respect to leave, public holidays, and team coverage rules.",
  "url": "https://leave-agent.internal/a2a",
  "version": "1.0.0",
  "capabilities": { "streaming": true, "pushNotifications": true },
  "defaultInputModes": ["text/plain", "application/json"],
  "defaultOutputModes": ["text/plain", "application/json"],
  "skills": [
    {
      "id": "assess_leave_risk",
      "name": "Leave risk assessment",
      "description": "For a given list of employees and a period, returns who is away when, which days are critical for coverage, and the overall confidence that the team will be available.",
      "tags": ["hr", "availability", "risk"]
    },
    {
      "id": "propose_staffing_window",
      "name": "Window proposal",
      "description": "Proposes an alternative start period with minimal leave risk for an engagement of a given length.",
      "tags": ["hr", "planning"]
    }
  ]
}

Notice what's missing. No get_leave_balance, no team_coverage, no trace of the ten tools. They are behind the boundary. Two skills are exposed, both phrased as judgments.

A Task is the engagement, not the question. Unlike an MCP call, a task has a lifecycle:

submitted → working → [ input-required ] → completed / failed / canceled

input-required is literally "let me ask my client and get back to you." The task doesn't fail and doesn't time out — it waits. Designed for things that take minutes or hours.

The artifact is what the broker brings you at the end: not the seller's raw documents, but an answer — with terms, deadlines, and sometimes a proposal you didn't ask for.

The spec moves fast — the path used to be agent.json, then agent-card.json; the transport used to be JSON-RPC only, then others were added. Check the field names against the version you're targeting.

Opacity Is a Decision, Not an Omission

The fact that you can't see the other agent's internal tools is not a flaw in the protocol. It is the point of it. Two agents from different teams or companies can work together without revealing their implementations — exactly like two brokers closing a deal without showing each other their notebooks.

In our software example this is literal: the leave agent can be built on one framework and one language, the staffing agent on an entirely different one, on different models, in different clouds. The boundary doesn't change because of any of that. Swap out the internal systems and tools on one side, and the other side never knows.

The Same Question, Posed as a Task

Back to the two systems. An account manager asks:

"Client X wants a team of three — one senior backend, one frontend, one QA — for 6 weeks starting September 15. Can we commit, and what's the risk?"

With A2A, the staffing agent doesn't crawl someone else's calendar. It delegates a goal:

Staffing ──► Leave    task: assess the risk for these candidates in this period
Staffing ◄── Leave    working    "checking balances…"
Staffing ◄── Leave    working    "computing coverage for Platform…"
Staffing ◄── Leave    input-required
                      "Two candidates have PENDING requests for Sep 22–26.
                       Conservative (treat as busy) or optimistic (treat as free)?"
Staffing ──► Leave    "conservative"
Staffing ◄── Leave    completed
                      artifact: risk assessment + a proposed alternative window

That's the broker calling back: "I checked, but one question — how do you want me to count the two pending ones?"

Here's what the pause for clarification looks like:

{
  "id": "task-7f3a91",
  "status": {
    "state": "input-required",
    "message": {
      "role": "agent",
      "parts": [{
        "kind": "text",
        "text": "Two candidates have pending requests for Sep 22–26. Should I treat them as busy (conservative) or as free (optimistic)?"
      }]
    }
  }
}

The task doesn't end and doesn't fail. It sits in this state until the staffing agent sends an answer under the same id — and that holds even if the connection dropped in the meantime or the process on the other side was restarted. This is exactly where it differs from a tool call, which would simply have returned an error or timed out.

Finally, the artifact comes back:

{
  "window": { "start": "2026-09-15", "end": "2026-10-27" },
  "assumption": "pending_treated_as_busy",
  "candidates": [
    { "employee": "Georgi Ivanov", "role": "senior backend",
      "availableWorkingDays": 26, "totalWorkingDays": 30, "risk": "low" }
  ],
  "criticalDays": [
    { "date": "2026-09-24", "team": "Platform", "onDuty": 1, "threshold": 2 }
  ],
  "holidays": [{ "date": "2026-09-22", "name": "Independence Day" }],
  "overallRisk": "medium",
  "narrative": "The engagement can be taken on, but coverage is thin in the week of Sep 21–25",
  "alternative": {
    "start": "2026-10-06",
    "overallRisk": "low",
    "why": "Leave requests cluster around Independence Day."
  }
}

There's the whole argument in one JSON. overallRisk, criticalDays, and threshold were computed inside the leave agent, by the team that owns the rules. Staffing receives a verdict, not raw material from which to derive its own verdict.

With an exposed MCP, those three fields would not exist anywhere. They would be reasoning inside someone else's system prompt.

The leave calendar has stopped being a database with an API and has become an expert with an opinion — including proposing a window nobody asked about.


Which One When

By this point the intuition has probably taken shape. Let's boil it down to a few simple rules.

Ask yourself... If the answer is "yes"
Does the other side need to know something? MCP
Does the other side need to decide something? A2A
Should the other side use your tools? MCP
Should the other side use its own tools? A2A
Are you expecting a lookup? MCP
Are you expecting an expert opinion? A2A
Will the same reasoning live in two places? A2A — that's the threshold
Does the interaction take time and possibly ask back? A2A
Is the other side actually a database? neither — that's an API

In the language of the deal: "get me the tax valuation" is a lookup. "Can it be done by September 15" is a judgment. The first is a job for a counter. The second needs someone who knows their client, their deadlines, and their constraints — and who has the right to answer on their behalf.

The choice comes down to four things:

Where the business logic lives. With an exposed MCP, the reasoning "what does this calendar mean for the project's risk" happens in the staffing agent's prompt. The HR team's rules — that pending requests don't count as certain, what the coverage threshold is, that holidays are not working days — live in someone else's system prompt, get versioned with someone else's deploys, and get tested by someone else's team. HR owns the data, but not the verdict on it.

The number of consumers. As long as there is a single one asking, MCP could well be entirely sufficient. With a second consumer, things change. There's a whole chapter on that below.

Context and quality. With MCP, the staffing agent has to load all the raw calendar data into its own context and reason over it. With seven people, that's irrelevant. With two hundred, it drowns — and quality drops exactly where it's needed most.

The shape of the interaction. Synchronous request/response, or a task that runs for a while, asks back, and can deliver an answer even a week later? The second has no place to live in MCP.

MCP A2A
Connects agent → tools agent → agent
Transparency the schema is visible black box
Interaction request/response task with a lifecycle
Duration milliseconds–seconds minutes–hours
Initiative always the client both sides
Unit of work many calls, each small one task — the whole thing
Who reasons the consumer the provider

When Both

In a normal system the question is almost never "which of the two."

Staffing Agent  ──── MCP ────► [people / skills / commitments]
      │
      │  A2A  (one task instead of dozens of calls)
      ▼
Leave Agent     ──── MCP ────► [leave calendar]

Each agent uses MCP for its own tools, within its own boundary. A2A crosses the boundary between the units. Each broker walks his own counters.

Where the Boundary Runs

It's not the legal one — not "different companies," the way it's usually explained. The real criteria are four:

  • Who releases independently. If Delivery deploys without asking HR, there needs to be a versioning contract between the two sides, not shared code.
  • Is the boundary a network boundary anyway. Different clouds means the cost of the protocol is already paid — the round-trip exists regardless of what travels over it.
  • What is the shape of the interaction. A synchronous lookup, or a task that runs and asks back.
  • Is there something to hide. Not intellectual property, but implementation — so one side can swap it without the other ever noticing.

Why Distance Changes the Answer

If an agent in one cloud gets wired to an MCP server in another, every tool call is a round-trip over the internet. The agentic loop makes dozens of those per task, and the latency accumulates.

Picture a broker who picks up the phone to the other office for every single question. "Is your client free on Tuesday? What about Wednesday? Thursday?" Fifty calls instead of one conversation.

The A2A model works wholesale by design: the whole task is delegated once, the remote agent calls its own tools locally, and an artifact comes back.

Authentication is the other topic. A2A deliberately doesn't invent its own mechanism — the Agent Card declares which standard variant it wants, and you use OIDC, workload identity federation, or mTLS. Good news, because this is a solved problem. Bad news: this is the bulk of the integration work, and no SDK will do it for you.

The Order of Magnitude

With MCP, the staffing agent assembles the picture itself. For each candidate it asks for the balance, for the absences in the period, for the coverage of the candidate's team, and then for the public holidays. Three candidates, a six-week window, several tools per candidate — the total quickly reaches dozens of calls, each with its own round-trip and its own portion of raw data that enters the context and stays there.

With A2A, the traversal doesn't disappear. It happens on the other side of the boundary, local to the data, and only the verdict travels back over the network.

MCP only:  dozens of calls · the leave logic lives in someone else's prompt
A2A:       one task · a few messages · the leave logic stayed home

The difference that matters, though, is not in the left column. If the problem were just speed, it could be solved with a cache. The right column cannot be solved with a cache.


MCP Is Defensible — Here Is the Moment It Stops Being

For the scenario described, MCP alone is a perfectly defensible choice. The staffing agent mounts the leave MCP server, walks the calendar, assembles the picture, answers. It works. In a production environment this would do fine. If someone tells you that you need A2A here, they're selling a protocol, not solving a problem.

The question is not whether MCP works. The question is when it stops working.

The Moment: The Second Consumer

As long as staffing is the only one asking "who is available," everything is fine. The logic lives in one place — its prompt — and that place is exactly one.

Then a second consumer appears. Finance wants to know whether it can commit to an engagement in Q4. Recruitment wants to know when there's capacity for onboarding. All three systems need the same thing: what does "available" mean.

With an exposed MCP, each of them defines it for itself. And the three definitions drift apart in small ways:

Question Staffing decides Finance decides Recruitment decides
A pending, unapproved request? busy (conservative) free (optimistic) busy
Coverage threshold? at least two people 50% of the team doesn't check it
September 22? holiday, doesn't count counts holiday

Nobody made a mistake. Each made a reasonable decision in its own context.

But now, at the leadership meeting, three systems give three different answers to "can we take on client X" — and nobody can say which one is right, because the definition of "risky" doesn't exist anywhere as a definition. It is scattered across three system prompts, maintained by three teams, versioned in three deploy cycles.

Worse: when HR changes the policy — raises the coverage threshold, changes how pending requests are treated — the three systems have to be updated separately. In practice they won't be updated at the same time. One gets updated, a second a month later, and the third keeps giving the old answer until someone happens to notice.

That is the moment. It's not the number of employees, not the volume of data, not the complexity of the calendar. The architectural threshold is not the number of requests. The architectural threshold is the number of places where the same reasoning lives. One is fine. Two is already a defect that hasn't shown itself yet.

A2A solves it the only way it can be solved: "risky" is computed in one place, by the team that owns the domain, and returned as a verdict. The three systems get the same answer, because there is only one answer.

If you need an image: it's the difference between a deal where one party is responsible for the condition of the property, and a deal where the buyer, the bank, and the notary each run their own inspection against their own criteria and then argue at the table about whose is correct.

Three Smaller Thresholds

The same turn, in weaker forms. When the reasoning starts changing without you — if HR touches the rules more often than staffing touches its prompt, you're already in debt. When the question stops fitting in a single call — an assessment that takes time, needs clarification, or has to get back to you later. And when the data outgrows the context — at two hundred people, the consumer drowns exactly on the questions where it most needs quality.

The Price of Switching to A2A

You lose debugging transparency — when the answer is wrong, you can't see why, because of someone else's team, someone else's cloud, and an overall black box. You add another LLM loop — cost, latency, and one more place where hallucination can happen. You work with a less mature ecosystem than the one around a plain REST API. And you freeze a boundary that will later be hard to move — organizationally, not technically.

So you switch when the threshold is reached. Not in advance, "just in case."

If the "agent" on the other side is actually doing a database lookup, that's an API. Wrapping it in a task lifecycle adds no value — like hiring a broker to fetch you a single plot sketch.

If the interaction really is "give me the data, I'll judge for myself" — and you are the only one judging — MCP is the more correct answer.


What Fails Either Way

Three things don't depend on the choice of protocol.

The description is the contract, at every level. With MCP the other side sees the tool description. With A2A it sees the Agent Card. In both cases, that is literally all it sees. Write them as if for a new colleague who has access only to them — no access to the code, no way to ask questions, and who will act immediately.

Opacity has a price during an incident. A black box plus someone else's team plus someone else's cloud means that without a trace you have no chance of debugging a wrong answer. Agree on trace context propagation and correlation IDs before the first integration, not after the first incident. Half an hour up front saves weeks later.

Validate on your own side. Descriptions and cards are an entry point for prompt injection. The server has to enforce its own rules, rather than trusting the model to follow what's written. "Only a manager can approve" is a check in code, not a sentence in a description.


Closing Words

MCP and A2A are not competing technologies. They solve different problems, and in most real architectures they work together.

MCP gives an agent access to its tools, data, and capabilities. A2A lets it delegate tasks to people or other agents who own their own context, knowledge, and responsibilities.

As long as a system has one consumer and one place where decisions are made, MCP is often entirely sufficient. As the number of independent participants grows, a new architectural question emerges — not where the data lives, but where the reasoning should live.

When the same reasoning starts being copied into several different systems, divergence inevitably follows. Not because the data differs, but because different participants begin maintaining their own interpretations of the same rules.

That's why the choice between MCP and A2A rarely starts from the protocols themselves. It starts from a more fundamental architectural question:

Who should make this decision?

If the decision belongs to the agent and it uses its own tools, MCP is the natural choice. If it belongs to another expert — human or agent — then A2A lets it stay where it belongs.

Protocols connect systems. Architecture decides where the reasoning lives.