MCP (Model Context Protocol) Connects Tools, A2A (Agent-to-Agent Protocol) Connects Agents: Division of Roles and Adoption Criteria in Multi-Agent Architecture
When I first started designing AI agents, I found myself pausing at this very question: "Should I use MCP or A2A?" But once you dig into the specs of both protocols, you realize it's actually the wrong question. Model Context Protocol and Agent-to-Agent Protocol are not competing standards solving the same problem — they are complementary standards each responsible for a different layer.
Here's a simple analogy. MCP gives agents "hands and eyes" — the ability to read the file system, call APIs, and access databases. A2A, on the other hand, lets agents "talk" to each other, enabling a payment agent and a support agent to collaborate even if they're built on different vendors or frameworks. By the end of this article, you'll have concrete criteria for deciding when MCP alone is sufficient and when it makes sense to bring A2A into the picture. We'll look at what problem each protocol solves, how they work together in real architectures, and the common pitfalls you'll want to avoid in practice.
For what it's worth, both protocols are already converging as industry standards. Rather than worrying about which one will "survive," the conversation has moved to figuring out how to use each one in the right role.
Core Concepts
MCP: A Standard Interface Between Agents and Tools
MCP (Model Context Protocol) is an open standard published by Anthropic in November 2024. The core idea is simple: unify the way LLMs access the outside world under a single standard. Before MCP, each agent had its own way of calling APIs or reading files. MCP hides all of that behind a common interface called an "MCP server."
An MCP server exposes three primitives:
| Primitive | Role | Examples |
|---|---|---|
| Resources | Information retrieval (read-only) | File contents, DB records, API responses |
| Tools | Execution with side effects | File writes, API calls, code execution |
| Prompts | Reusable prompt templates | Code review requests, summarization request forms |
A simple Python MCP server makes the structure immediately clear:
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
app = Server("my-tool-server")
@app.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="get_weather",
description="특정 도시의 현재 날씨를 조회합니다",
inputSchema={
"type": "object",
"properties": {
"city": {"type": "string", "description": "도시명"}
},
"required": ["city"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
if name == "get_weather":
city = arguments["city"]
# TODO: 실제 날씨 API 호출로 교체 (예: OpenWeatherMap API)
weather_data = await fetch_weather(city)
return [TextContent(type="text", text=f"{city}의 날씨: {weather_data}")]
async def main():
async with stdio_server() as (read_stream, write_stream):
await app.run(read_stream, write_stream, app.create_initialization_options())Note During local development, you can run quick tests using the
stdiotransport, but for production deployments, the remote approach using OAuth 2.1 and Streamable HTTP is mandatory. This is because stdio only works on the same machine. OAuth 2.1 is a revised standard that addresses security vulnerabilities in OAuth 2.0 and mandates PKCE; it is the recommended choice for authenticating API calls between remote servers.
A2A: A Standard Communication Protocol Between Agents
A2A (Agent-to-Agent Protocol) is an open standard published by Google in April 2025. Built on HTTP + SSE + JSON-RPC 2.0, it allows agents built by different vendors and frameworks to discover each other and delegate or coordinate tasks.
Note JSON-RPC 2.0 is a lightweight remote procedure call protocol that exchanges requests and responses as JSON. Unlike REST, which uses URL paths to distinguish resources, it specifies the action to invoke via the
"method"field in the message body. A2A adopted this approach for agent-to-agent task delegation because it allows diverse task types to be expressed flexibly through a single endpoint.
There are two key concepts:
Agent Card: A JSON document in which an agent advertises its capabilities. It hides the internal implementation and exposes only the interface — "here's what I can do" — to the outside world. It is typically served at /.well-known/agent.json.
{
"name": "payment-agent",
"version": "1.0.0",
"description": "결제 처리 및 환불 담당 에이전트",
"skills": [
{
"id": "process_refund",
"name": "환불 처리",
"description": "주문 ID를 받아 환불 절차를 처리합니다",
"inputModes": ["text"],
"outputModes": ["text"]
}
],
"url": "https://payment-agent.internal/a2a",
"authentication": {
"schemes": ["Bearer"]
}
}Task: The unit of work delegation between agents. A Task has a well-defined lifecycle:
submitted → working → completed
↘ failed
↘ canceledThe orchestrator sends a task to a sub-agent (submitted), the sub-agent begins processing (working), real-time progress updates are streamed via SSE, and finally the result is received (completed or failed). This state management is a fairly important point in real implementations — especially when handling long-running tasks like web research or code execution that can take tens of seconds. Failing to handle state transitions properly makes timeout and duplicate-execution issues very easy to introduce.
SSE (Server-Sent Events) A technology for the server to stream real-time data to the client unidirectionally over a persistent HTTP connection. Unlike WebSocket, it is unidirectional (server → client only), but because it runs over HTTP it has high compatibility with proxies and firewalls. A2A uses it to deliver real-time task progress updates.
The Architecture Created by Two Layers
The layered structure that has emerged as the consensus in today's AI agent ecosystem looks like this:
Agent coordination : A2A ← delegation and collaboration between agents
Tool access : MCP ← connecting agents to tools and dataEach agent exchanges tasks with other agents via A2A, while internally using MCP to access the tools it needs. When these two layers interlock, you can move beyond a structure where a single agent handles everything, and instead scale to a structure where agents each specialized in their own role collaborate — this is what's called multi-agent orchestration.
Security Note For remote MCP deployments, you need to verify that Tool invocation requests come only from authenticated clients. In A2A, before trusting an Agent Card, you must confirm that the card was actually issued by the agent it claims to represent. Signed Agent Cards, introduced in A2A v1.0, partially address this issue. In enterprise environments, it is recommended to add an extra security layer through an internal API gateway or service mesh for both protocols.
Practical Application
Example 1: Single Agent + Multiple Tools (MCP Only)
This is the most commonly encountered pattern. It applies when a single agent — like a coding assistant or an internal AI bot — needs to access multiple tools simultaneously. My own first hands-on experience with MCP was connecting Claude Code to GitHub, and I was surprised by how much simpler the setup was than I expected. If you have one agent with around five tools attached and it's used only within the team, this pattern alone is more than powerful enough without A2A.
Here's an example of connecting a simple MCP client in TypeScript:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["./my-mcp-server.js"],
});
const client = new Client({
name: "my-agent",
version: "1.0.0",
});
await client.connect(transport);
// 사용 가능한 도구 목록 조회
const { tools } = await client.listTools();
console.log("사용 가능한 도구:", tools.map(t => t.name));
// 도구 호출
const result = await client.callTool({
name: "get_weather",
arguments: { city: "서울" },
});
console.log("결과:", result.content);| Code Point | Description |
|---|---|
StdioClientTransport |
stdio transport for local development (replace with HTTP transport in production) |
client.listTools() |
Dynamically queries the list of tools exposed by the MCP server |
client.callTool() |
Invokes a tool and receives the result |
Example 2: Multi-Agent Orchestration (MCP + A2A Hybrid)
As the system grows, there comes a moment when "this single agent is just too complex." For me, that moment arrived when a single agent had more than twelve tools and the logic for payments, customer support, and inventory lookup all started getting tangled together. As the context grew longer and tool-selection errors became more frequent, the conclusion to "split up the roles" came naturally. Let's use a customer service refund scenario as an example:
[User request: "Please refund order #12345"]
↓
[Support Agent — LangGraph-based]
↓ A2A Task delegation
[Payment Agent — CrewAI-based] ←─ MCP ─→ [Payment DB, External PG API]
↓ A2A response
[Support Agent] ←─ MCP ─→ [Customer DB, Mail delivery server]
↓
[Final response to user]Here is the flow for delegating an A2A task in Python:
import httpx
async def delegate_refund_task(order_id: str) -> dict:
# 결제 에이전트의 Agent Card 조회
async with httpx.AsyncClient() as client:
card_response = await client.get(
"https://payment-agent.internal/.well-known/agent.json"
)
agent_card = card_response.json()
# A2A 태스크 생성 및 전송
task_payload = {
"jsonrpc": "2.0",
"method": "tasks/send",
"params": {
"message": {
"role": "user",
"parts": [
{
"type": "text",
"text": f"주문 {order_id}에 대한 환불을 처리해주세요."
}
]
}
},
"id": "task-001"
}
async with httpx.AsyncClient() as client:
response = await client.post(
agent_card["url"],
json=task_payload,
# get_token()은 OAuth 2.1 클라이언트 자격증명 흐름(Client Credentials Flow)으로
# 액세스 토큰을 발급받아 반환하는 함수입니다 (실제 구현 필요)
headers={"Authorization": f"Bearer {get_token()}"}
)
return response.json()The key advantage of this structure is that the support agent doesn't need to know anything about the internal implementation of the payment agent. If the payment agent migrates from LangGraph to CrewAI, the support agent needs no changes as long as the Agent Card interface remains the same.
Example 3: Enterprise Research Workflow (Parallel Delegation)
Below is pseudocode illustrating the A2A parallel delegation pattern. delegate_task() and synthesize_results() are helper functions that need to be implemented to fit the actual environment:
[Orchestrator Agent]
↓ A2A (parallel delegation)
├── [Research Agent] ──MCP──> [Web Search Server, News API]
├── [Code Agent] ──MCP──> [GitHub, Code Execution Environment]
└── [Analysis Agent] ──MCP──> [DB, Spreadsheet]
↓ A2A (result aggregation)
[Orchestrator] → Final report generationimport asyncio
async def run_research_workflow(topic: str) -> str:
# 세 에이전트에 병렬로 A2A 태스크 위임
# delegate_task(endpoint, message) — A2A tasks/send를 래핑한 헬퍼 (구현 필요)
tasks = await asyncio.gather(
delegate_task("https://research-agent.internal/a2a", f"{topic} 관련 최신 정보 수집"),
delegate_task("https://code-agent.internal/a2a", f"{topic} 관련 오픈소스 코드 분석"),
delegate_task("https://analysis-agent.internal/a2a", f"{topic} 관련 데이터 통계 분석"),
)
research_result, code_result, analysis_result = tasks
# synthesize_results() — LLM으로 세 결과를 통합 보고서로 작성하는 헬퍼 (구현 필요)
return await synthesize_results(topic, research_result, code_result, analysis_result)Each sub-agent accesses its own tools internally via MCP, while communicating with the orchestrator via A2A. By using asyncio.gather for parallel delegation, all three agents start working simultaneously, which significantly reduces the total response time compared to sequential execution.
Pros and Cons Analysis
Advantages
| Item | MCP | A2A |
|---|---|---|
| Ecosystem maturity | 5,800+ public servers, support across all major platforms | 150+ organizations adopted, rapidly growing |
| Implementation simplicity | Server can be built in ~50 lines | Automatic support in LangGraph, CrewAI, etc. |
| Tool connectivity | Wrap existing REST/GraphQL APIs for immediate use | — |
| Agent collaboration | — | Cross-agent communication regardless of vendor or framework |
| Internal implementation hiding | — | Capabilities advertised only via Agent Card; internal logic need not be exposed |
| Long-running tasks | — | Real-time progress relay via SSE streaming |
| Governance | Linux Foundation AAIF | Linux Foundation AAIF |
MCP Drawbacks and Caveats
| Item | Details | Mitigation |
|---|---|---|
| Multi-agent limitations | Cannot support delegation or collaboration between agents | Use alongside A2A, or use framework-native orchestration |
| Dependency on Tool Description quality | Vague tool descriptions cause the LLM to call the wrong tool | Invest sufficient time in writing clear, specific descriptions |
| Local stdio is unsuitable for production | Only works on the same machine | Use OAuth 2.1 + Streamable HTTP for remote deployments |
A2A Drawbacks and Caveats
| Item | Details | Mitigation |
|---|---|---|
| Ecosystem immaturity | Released April 2025; shorter track record than MCP | Start with stable SDKs (LangGraph, CrewAI integrations) |
| Agent Card trustworthiness | Early risk of card forgery or tampering | Use Signed Agent Cards (introduced in v1.0) |
| Limitation when used alone | Using only A2A leaves agents unable to access tools | Always pair with MCP for internal tool access |
The issue I've run into most often in practice is the second item on the MCP side — Tool Description quality. Writing a lazy one-liner description caused the LLM to call the weather tool in the wrong context, or repeatedly pick the wrong one between two similarly named tools. Time spent on this is never wasted.
The Most Common Mistakes in Practice
-
Treating "MCP vs. A2A" as a binary choice: Honestly, I fell into this trap at first too. The two protocols are not in competition. In a multi-agent system, using only A2A leaves agents unable to access tools, and using only MCP gives you no way to standardize collaboration between agents.
-
Deploying local stdio MCP directly to production: It's convenient to use stdio during development, and some people just leave it as-is when going to production. For remote deployments, Streamable HTTP and OAuth 2.1 authentication must be configured.
-
Writing Tool Descriptions carelessly: In MCP, how well the LLM uses a tool depends directly on the quality of the
descriptionfield. Writing something vague like "Get weather" makes it hard for the LLM to judge when and how to use it. Writing something specific like "Retrieves real-time weather (temperature, humidity, precipitation probability) for a given city. Call this when the user asks about weather or whether they need an umbrella." is far more effective.
Closing Thoughts
MCP is an agent's hands and eyes; A2A is the language agents speak to each other. Depending on the scale of your system and the composition of your team, MCP alone may be sufficient, or you may need both. If you've read this far, the analogy from the opening should feel considerably clearer now than it did at the start.
Here's a summary of where to begin:
-
Start by getting hands-on experience with MCP. Install the official SDK with
pip install mcpornpm install @modelcontextprotocol/sdk, then wrap one of your existing REST APIs as an MCP server. Using MCP Inspector alongside it makes local debugging immediately possible. -
Identify the moment multi-agent becomes necessary. "A single agent with more than 10 tools, or a situation where different teams need to operate their own agents independently" is the signal to introduce A2A. If you're using LangGraph, an A2A endpoint is generated automatically just by configuring
langgraph.json. The A2A official documentation has well-organized integration examples for various frameworks. -
Explore hybrid architecture references. The LangGraph ↔ CrewAI cross-framework invocation example in the A2A GitHub repo is a great resource for building a mental model of how the two protocols work together.
References
- Introducing the Model Context Protocol | Anthropic
- Announcing the Agent2Agent Protocol (A2A) | Google Developers Blog
- A2A Protocol Official Specification | a2a-protocol.org
- A2A GitHub Repository | a2aproject/A2A
- Model Context Protocol Specification (2025-11-25) | modelcontextprotocol.io
- ACP Joins Forces with A2A | LFAI & Data
- A2A Protocol Surpasses 150 Organizations | Linux Foundation
- MCP vs A2A: Architecture, Security, and When to Use Each | StackOne
- MCP vs A2A: The Complete Guide to AI Agent Protocols in 2026 | DEV Community
- MCP TypeScript SDK | npm
- What Is Model Context Protocol (MCP)? | IBM
- What Is Agent2Agent (A2A) Protocol? | IBM