MCP(Model Context Protocol)는 도구를 연결하고, A2A(Agent-to-Agent Protocol)는 에이전트를 연결한다: 멀티에이전트 아키텍처에서의 역할 분담과 도입 기준
AI 에이전트를 처음 설계할 때 저도 이 질문 앞에서 한참 멈췄습니다. "MCP를 써야 하나, A2A를 써야 하나?" 그런데 막상 두 프로토콜의 스펙을 파고들다 보면, 이게 사실 잘못된 질문이라는 걸 깨닫게 됩니다. Model Context Protocol과 Agent-to-Agent Protocol은 같은 문제를 해결하는 경쟁 규격이 아니라, 서로 다른 계층을 담당하는 상호 보완적인 표준이기 때문입니다.
쉽게 비유하자면 이렇습니다. MCP는 에이전트에게 "손과 눈"을 줍니다. 파일 시스템을 읽고, API를 호출하고, 데이터베이스에 접근하는 능력이죠. 반면 A2A는 에이전트들이 서로 "대화"하게 만들어줍니다. 결제를 담당하는 에이전트와 상담을 담당하는 에이전트가 벤더나 프레임워크가 달라도 협업할 수 있도록요. 이 글을 다 읽고 나면, 어떤 상황에서 MCP만으로 충분한지, 언제 A2A를 함께 도입하면 좋을지에 대한 구체적인 판단 기준을 가져갈 수 있을 겁니다. 두 프로토콜이 각각 어떤 문제를 해결하는지, 실제 아키텍처에서 어떻게 함께 동작하는지, 그리고 실무에서 흔히 빠지는 함정까지 같이 살펴보겠습니다.
참고로 두 프로토콜 모두 이미 업계가 수렴하고 있는 표준입니다. 어느 쪽이 "살아남을지" 걱정할 필요 없이, 각자의 역할에 맞게 쓰는 방법을 고민하는 단계에 와 있습니다.
핵심 개념
MCP: 에이전트와 도구 사이의 표준 인터페이스
MCP(Model Context Protocol)는 Anthropic이 2024년 11월 공개한 오픈 표준입니다. 핵심 아이디어는 단순합니다. LLM이 외부 세계에 접근하는 방식을 하나의 표준으로 통일하자는 거죠. 그 전까지는 각 에이전트마다 자체 방식으로 API를 호출하거나 파일을 읽었는데, 이걸 "MCP 서버"라는 공통 인터페이스 뒤로 숨겨버립니다.
MCP 서버가 노출하는 원시(primitive)는 세 가지입니다.
| Primitive | 역할 | 예시 |
|---|---|---|
| Resources | 정보 조회 (읽기 전용) | 파일 내용, DB 레코드, API 응답 |
| Tools | 부수 효과를 동반한 실행 | 파일 쓰기, API 호출, 코드 실행 |
| Prompts | 재사용 가능한 프롬프트 템플릿 | 코드 리뷰 요청, 요약 요청 양식 |
간단한 Python MCP 서버를 보면 구조가 바로 눈에 들어옵니다.
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())주의 로컬 개발 단계에서는
stdio방식으로 간단히 테스트할 수 있지만, 프로덕션 배포에서는 OAuth 2.1과 Streamable HTTP를 사용하는 원격 방식이 필수입니다. stdio는 같은 머신에서만 동작하기 때문입니다. OAuth 2.1은 기존 OAuth 2.0의 보안 취약점을 보완하고 PKCE를 필수화한 개정 표준으로, 특히 원격 서버 간 API 호출 인증에 권장됩니다.
A2A: 에이전트와 에이전트 사이의 표준 통신
A2A(Agent-to-Agent Protocol)는 Google이 2025년 4월 공개한 오픈 표준입니다. HTTP + SSE + JSON-RPC 2.0 기반으로, 서로 다른 벤더·프레임워크로 만들어진 에이전트들이 서로를 발견하고 작업을 위임·조율할 수 있도록 합니다.
참고 JSON-RPC 2.0은 JSON으로 요청과 응답을 주고받는 경량 원격 프로시저 호출 규약입니다. REST처럼 URL 경로로 리소스를 구분하는 대신, 메시지 본문의
"method"필드로 호출할 동작을 지정합니다. A2A에서 에이전트 간 태스크 전달에 이 방식을 채택한 이유는 단일 엔드포인트에서 다양한 작업 유형을 유연하게 표현할 수 있기 때문입니다.
핵심 개념은 두 가지입니다.
Agent Card: 에이전트가 자신의 역량을 광고하는 JSON 문서입니다. 내부 구현은 감추고 "나는 이런 일을 할 수 있다"는 인터페이스만 외부에 노출합니다. 보통 /.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: 에이전트 간 작업 위임의 단위입니다. Task는 명확한 생명주기를 가집니다.
submitted → working → completed
↘ failed
↘ canceled오케스트레이터가 서브에이전트에게 태스크를 보내면(submitted), 서브에이전트가 처리를 시작하고(working), SSE를 통해 진행 상태를 실시간으로 중계받다가 최종 결과를 수신합니다(completed 또는 failed). 이 상태 관리가 실제 구현에서 꽤 중요한 포인트인데, 특히 웹 리서치나 코드 실행처럼 수십 초가 걸리는 장기 태스크를 다룰 때 상태 전환을 제대로 처리하지 않으면 타임아웃이나 중복 실행 같은 문제가 생기기 쉽습니다.
SSE(Server-Sent Events) HTTP 연결을 유지하면서 서버가 클라이언트로 실시간 데이터를 단방향 스트리밍하는 기술입니다. WebSocket처럼 양방향이 아니라 서버→클라이언트 단방향이지만, HTTP 위에서 동작해 프록시·방화벽 호환성이 높습니다. A2A에서 태스크 진행 상태를 실시간으로 전달할 때 활용됩니다.
두 계층이 만드는 아키텍처
현재 AI 에이전트 생태계에서 컨센서스로 자리잡은 계층 구조는 이렇습니다.
에이전트 조율 : A2A ← 에이전트 간 위임·협업
도구 접근 : MCP ← 에이전트와 도구/데이터 연결각 에이전트는 A2A로 다른 에이전트와 작업을 주고받으면서, 내부적으로는 MCP로 필요한 도구에 접근합니다. 이 두 계층이 맞물리면 에이전트 하나가 직접 모든 걸 처리하는 구조에서 벗어나, 각자 역할에 특화된 에이전트들이 협업하는 구조—이것을 멀티에이전트 오케스트레이션이라고 부릅니다—로 확장할 수 있습니다.
보안 참고 MCP 원격 배포 시에는 Tool 호출 요청이 인증된 클라이언트에서만 오는지 검증이 필요하고, A2A에서는 Agent Card를 신뢰하기 전에 그 카드가 실제로 해당 에이전트가 발행한 것인지 확인해야 합니다. A2A v1.0에서 도입된 Signed Agent Cards는 이 문제를 부분적으로 해소합니다. 엔터프라이즈 환경에서는 두 프로토콜 모두 내부 API 게이트웨이나 서비스 메시를 통해 추가 보안 레이어를 얹는 것을 권장합니다.
실전 적용
예시 1: 싱글 에이전트 + 다중 도구 (MCP만 사용)
가장 흔하게 접하는 패턴입니다. 코딩 어시스턴트나 사내 AI 봇처럼 하나의 에이전트가 여러 도구에 동시에 접근해야 할 때입니다. 저도 처음 MCP를 써본 게 Claude Code와 GitHub를 연동할 때였는데, 설정이 생각보다 훨씬 간단해서 놀랐습니다. 에이전트 하나에 도구가 다섯 개쯤 붙어 있고 팀 내에서만 쓰는 구조라면, A2A 없이 이 패턴만으로도 충분히 강력합니다.
TypeScript로 간단한 MCP 클라이언트를 연결하는 예시입니다.
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);| 코드 포인트 | 설명 |
|---|---|
StdioClientTransport |
로컬 개발용 stdio 전송 방식 (프로덕션에서는 HTTP 방식으로 교체) |
client.listTools() |
MCP 서버가 노출하는 도구 목록 동적 조회 |
client.callTool() |
도구 호출 및 결과 수신 |
예시 2: 멀티에이전트 오케스트레이션 (MCP + A2A 하이브리드)
규모가 커지다 보면 "이 에이전트 하나로는 너무 복잡하다"는 순간이 옵니다. 저는 단일 에이전트에 도구가 열두 개를 넘어가고 결제, 고객 상담, 재고 조회 로직이 뒤섞이기 시작할 때 그 순간이 왔습니다. 컨텍스트가 길어지고 도구 선택 오류가 잦아지면서, "이건 역할을 나눠야겠다"는 결론이 자연스럽게 나오더라고요. 고객 서비스 환불 처리 시나리오를 예시로 보겠습니다.
[사용자 요청: "주문 #12345 환불해주세요"]
↓
[상담 에이전트 — LangGraph 기반]
↓ A2A Task 위임
[결제 에이전트 — CrewAI 기반] ←─ MCP ─→ [결제 DB, 외부 PG사 API]
↓ A2A 응답
[상담 에이전트] ←─ MCP ─→ [고객 DB, 메일 발송 서버]
↓
[사용자에게 최종 답변]Python으로 A2A 태스크를 위임하는 흐름입니다.
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()이 구조의 핵심 장점은 상담 에이전트가 결제 에이전트의 내부 구현을 전혀 몰라도 된다는 점입니다. 결제 에이전트가 LangGraph에서 CrewAI로 마이그레이션해도 Agent Card 인터페이스만 동일하다면 상담 에이전트는 수정할 필요가 없습니다.
예시 3: 엔터프라이즈 리서치 워크플로우 (병렬 위임)
아래는 A2A 병렬 위임 패턴을 보여주는 의사코드입니다. delegate_task()와 synthesize_results()는 실제 환경에 맞게 구현이 필요한 헬퍼 함수입니다.
[오케스트레이터 에이전트]
↓ A2A (병렬 위임)
├── [리서치 에이전트] ──MCP──> [웹 검색 서버, 뉴스 API]
├── [코드 에이전트] ──MCP──> [GitHub, 코드 실행 환경]
└── [분석 에이전트] ──MCP──> [DB, 스프레드시트]
↓ A2A (결과 취합)
[오케스트레이터] → 최종 보고서 생성import 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)각 서브에이전트는 내부적으로 MCP를 써서 자신의 도구에 접근하고, 오케스트레이터와는 A2A로 통신합니다. asyncio.gather로 병렬 위임하면 세 에이전트가 동시에 작업을 시작하므로 순차 실행 대비 전체 응답 시간이 크게 줄어듭니다.
장단점 분석
장점
| 항목 | MCP | A2A |
|---|---|---|
| 생태계 성숙도 | 5,800+ 공개 서버, 모든 주요 플랫폼 지원 | 150+ 조직 채택, 빠른 성장세 |
| 구현 단순성 | 50줄 내외로 서버 구축 가능 | LangGraph, CrewAI 등 자동 지원 |
| 도구 연결 | 기존 REST/GraphQL API를 래핑해 즉시 활용 | — |
| 에이전트 협업 | — | 벤더·프레임워크 무관한 크로스 에이전트 통신 |
| 내부 구현 은닉 | — | Agent Card로만 역량 광고, 내부 로직 노출 불필요 |
| 장기 실행 태스크 | — | SSE 스트리밍으로 진행 상태 실시간 중계 |
| 거버넌스 | Linux Foundation AAIF | Linux Foundation AAIF |
MCP 단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| 멀티에이전트 한계 | 에이전트 간 위임·협업 지원 불가 | A2A와 함께 사용하거나 프레임워크 내장 오케스트레이션 활용 |
| Tool Description 품질 의존 | 도구 설명이 애매하면 LLM이 잘못 호출 | 명확하고 구체적인 description 작성에 충분한 시간 투자 |
| 로컬 stdio는 프로덕션 부적합 | 같은 머신에서만 동작 | 원격 배포 시 OAuth 2.1 + Streamable HTTP 방식 사용 |
A2A 단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| 생태계 미성숙 | 2025년 4월 출시, MCP 대비 역사 짧음 | 안정화된 SDK(LangGraph, CrewAI 통합)부터 시작 |
| Agent Card 신뢰성 | 초기에는 카드 위·변조 위험 존재 | Signed Agent Cards (v1.0 도입) 활용 |
| 단독 사용 한계 | A2A만 쓰면 에이전트가 도구에 접근 불가 | 내부 도구 접근에는 반드시 MCP 병행 |
실무에서 제가 가장 많이 경험한 건 MCP 쪽 두 번째 항목—Tool Description 품질 문제입니다. description 한 줄을 대충 쓴 탓에 LLM이 날씨 도구를 엉뚱한 맥락에서 호출하거나, 비슷한 이름의 두 도구 중 잘못된 걸 선택하는 일이 반복됐습니다. 이 부분에 시간을 쓰는 게 결코 아깝지 않더라고요.
실무에서 가장 흔한 실수
-
"MCP냐 A2A냐" 양자택일로 접근하기: 솔직히 저도 처음에 이 함정에 빠졌습니다. 두 프로토콜은 경쟁 관계가 아닙니다. 멀티에이전트 시스템에서 A2A만 쓰면 에이전트가 도구에 접근할 수 없고, MCP만 쓰면 에이전트 간 협업을 표준화할 수 없습니다.
-
로컬 stdio MCP를 그대로 프로덕션에 배포하기: 개발 편의상 stdio를 쓰다가 운영 환경에서도 그대로 올리는 경우가 있습니다. 원격 배포에서는 Streamable HTTP와 OAuth 2.1 인증을 반드시 설정해야 합니다.
-
Tool Description을 대충 작성하기: MCP에서 LLM이 도구를 얼마나 잘 활용하는지는
description필드 품질에 직접 의존합니다. "날씨 가져오기"처럼 모호하게 적으면 LLM이 언제 어떻게 써야 할지 판단하기 어렵습니다. "특정 도시의 실시간 날씨(기온, 습도, 강수 확률)를 조회합니다. 사용자가 날씨나 우산 필요 여부를 물을 때 호출합니다."처럼 구체적으로 적어두는 것이 훨씬 효과적입니다.
마치며
MCP는 에이전트의 손과 눈이고, A2A는 에이전트들의 언어입니다. 시스템 규모와 팀 구성에 따라 MCP만으로 충분할 수도, 둘 다 필요할 수도 있습니다. 여기까지 읽으셨다면, 처음 글머리에서 들었던 그 비유가 이제 처음보다 훨씬 선명하게 느껴지실 겁니다.
어디서 시작하면 좋을지 정리해보면 이렇습니다.
-
MCP부터 경험해보시면 좋습니다.
pip install mcp또는npm install @modelcontextprotocol/sdk로 공식 SDK를 설치한 뒤, 기존 REST API 하나를 MCP 서버로 래핑해보시면 됩니다. MCP Inspector를 함께 사용하면 로컬에서 바로 디버깅이 가능합니다. -
멀티에이전트가 필요해지는 시점을 파악해보시면 좋습니다. "단일 에이전트에 도구가 10개가 넘거나, 서로 다른 팀이 각자 에이전트를 독립적으로 운영해야 하는 상황"이 A2A를 도입할 신호입니다. LangGraph를 사용 중이라면
langgraph.json설정만으로 A2A 엔드포인트가 자동 생성됩니다. A2A 공식 문서에 프레임워크별 통합 예제가 잘 정리되어 있습니다. -
하이브리드 아키텍처 레퍼런스를 살펴보시면 좋습니다. A2A GitHub 레포에 있는 LangGraph ↔ CrewAI 크로스 프레임워크 호출 예제는 두 프로토콜이 함께 동작하는 그림을 이해하는 데 큰 도움이 됩니다.
참고 자료
- 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