MCP와 에이전트 간 프로토콜
MCP 서버 설계, A2A 프로토콜, AG-UI 프로토콜, Agent Card, 3-프로토콜 스택, 구현 예시
오케스트레이션이 커질수록 "모델이 도구를 쓰는 문제"와 "에이전트가 다른 에이전트와 협력하는 문제"를 분리해야 합니다. 이 장에서는 MCP는 capability exposure, A2A는 agent delegation이라는 관점으로 구분합니다.
기준일과 해석 범위
이 장의 프로토콜 설명은 2026년 3월 27일 기준 공식 문서를 바탕으로 정리했습니다. A2A v1.0.0 정식 출시, MCP 2026 로드맵 발표를 반영합니다. 구현체별 SDK나 프레임워크 적응 방식은 바뀔 수 있으므로, 실제 도입 전에는 해당 프로토콜의 최신 스펙과 SDK 문서를 다시 확인하는 편이 안전합니다.
어떤 문제를 푸는가
| 항목 | MCP | A2A 계열 프로토콜 | 커스텀 HTTP/API |
|---|---|---|---|
| 핵심 목적 | 모델/호스트에 도구, 리소스, 프롬프트를 노출 | 다른 agent에 작업을 위임하고 상태를 주고받음 | 특정 시스템 동작을 직접 구현 |
| 적합한 상황 | 문서 조회, DB read, 내부 시스템 tool 연결 | 전문 agent 호출, 장기 작업 위임, capability discovery | 규격이 단순하고 모델 노출이 필요 없음 |
| 장점 | 표준화된 tool/resource surface | 네트워크 경계의 agent 협업을 모델링하기 쉬움 | 단순하고 통제 강함 |
| 주의점 | tool 수가 늘면 설명과 권한 관리가 어려움 | 상태, 인증, streaming을 함께 설계해야 함 | 에이전트 친화적 메타데이터가 부족 |
권장 아키텍처
- MCP는 보통 host runtime 안에서 모델이 사용할 capability를 표준 형태로 노출합니다.
- A2A는 orchestrator가 외부 또는 별도 런타임의 전문 agent에 일을 맡길 때 유용합니다.
- 두 패턴은 경쟁 관계가 아니라, 하나의 시스템 안에서 함께 쓰이는 경우가 많습니다.
MCP 2026 로드맵
2026년 3월 MCP 로드맵이 공개되었습니다. 월간 SDK 다운로드 97M을 기록한 MCP가 다음 단계로 설정한 방향은 아래와 같습니다.
| 영역 | 핵심 내용 |
|---|---|
| Transport Scalability | Streamable HTTP 기반 수평 확장 — stateless 배포와 로드밸런싱 지원 |
| MCP Server Cards | .well-known/mcp.json에 서버 메타데이터 게시, 자동 검색(auto-discovery) 표준화 |
| Agent Communication | 멀티에이전트 환경에서 MCP 서버를 매개로 하는 통신 패턴 공식화 |
| Enterprise Readiness | 감사 추적(audit trail), SSO 통합, API 게이트웨이 패턴 |
MCP Server Cards
MCP Server Cards는 A2A의 Agent Card에 대응하는 개념으로, MCP 서버의 기능을 machine-readable 형태로 노출합니다.
// .well-known/mcp.json — 실전 예시
{
"name": "billing-mcp",
"version": "2.1.0",
"description": "고객 청구, 결제, 환불 관리 도구 모음",
"homepage": "https://internal.example.com/billing-mcp",
"tools": [
{
"name": "get_invoice",
"description": "고객 ID와 기간으로 청구서를 조회합니다",
"inputSchema": {
"type": "object",
"properties": {
"customerId": { "type": "string" },
"month": { "type": "string", "pattern": "^\\d{4}-\\d{2}$" }
},
"required": ["customerId"]
}
},
{
"name": "create_refund",
"description": "청구서에 대한 환불을 생성합니다",
"inputSchema": {
"type": "object",
"properties": {
"invoiceId": { "type": "string" },
"amount": { "type": "number" },
"reason": { "type": "string" }
},
"required": ["invoiceId", "amount"]
}
}
],
"resources": [
{ "name": "billing-policy", "uri": "billing://policy", "mimeType": "text/markdown" },
{ "name": "pricing-table", "uri": "billing://pricing/2026", "mimeType": "application/json" }
],
"auth": {
"type": "oauth2",
"authorizationUrl": "https://auth.example.com/authorize",
"tokenUrl": "https://auth.example.com/token",
"scopes": {
"billing:read": "청구서 조회",
"billing:write": "환불 생성, 청구서 수정"
}
},
"transport": ["streamable-http"],
"endpoint": "https://billing-mcp.example.com/mcp",
"rateLimit": { "requestsPerMinute": 120 },
"contacts": [{ "name": "billing-team", "email": "billing@example.com" }]
}이로써 MCP 서버 간 자동 검색, 호스트의 서버 선택, 게이트웨이의 라우팅 정책 적용이 표준화됩니다.
MCP를 쓸 때의 설계 기준
1. tool, resource, prompt를 구분한다
- Tool: 시스템 동작 또는 조회
- Resource: 문서, 스키마, 정적 컨텍스트
- Prompt: 반복 사용하는 지시문 템플릿
이 셋을 구분하지 않으면 모델이 불필요하게 tool 호출을 남발하거나, 문서 조회를 실행성 tool로 오해합니다.
2. host 권한과 server 권한을 분리한다
MCP server가 많은 시스템 접근권을 가진다고 해서, 모든 host가 그 권한을 그대로 가져야 하는 것은 아닙니다. host별 allowlist, read/write 분리, audit log가 필요합니다.
3. 응답은 "모델이 읽기 쉬운 형태"보다 "근거가 보존되는 형태"가 우선이다
예를 들어 검색 결과라면 본문 요약만 주는 것보다 title, url, snippet, updatedAt을 함께 반환하는 편이 좋습니다.
A2A v1.0.0 정식 출시
Google이 주도하고 150개 이상 조직이 참여한 A2A(Agent-to-Agent) 프로토콜이 v1.0.0으로 정식 출시되었습니다. Linux Foundation이 관리하며, Google ADK가 네이티브 A2A를 지원합니다.
3가지 전송 방식
| 전송 | 용도 | 비고 |
|---|---|---|
| HTTP/REST | 범용, 가장 간단한 통합 | 기존 방식 |
| gRPC | 고성능, 저지연 내부 통신 | v1.0.0 신규 |
| JSON-RPC 2.0 | 양방향 메시지, 기존 MCP와 유사한 패턴 | 기존 방식 |
스트리밍
SendStreamingMessage: 실시간 중간 결과 전송SubscribeToTask: 장기 실행 작업의 상태 변경 구독
Agent Card (공식 스펙)
Agent Card는 JSON 형태의 메타데이터로, agent의 아이덴티티, 역량, 스킬, 인증 방식을 선언합니다.
| 필드 | 의미 |
|---|---|
| name / description | agent 식별과 역할 |
| skills | 해결 가능한 문제 목록 (입출력 스키마 포함) |
| auth | 인증 방식 (OAuth2, API Key, mTLS 등) |
| capabilities | 스트리밍, push notification 지원 여부 |
| endpoint | 접근 URL과 프로토콜 |
// .well-known/agent.json — 실전 예시
{
"name": "billing-agent",
"description": "고객 청구, 결제 분석, 환불 처리를 담당하는 전문 에이전트",
"url": "https://billing-agent.example.com/a2a",
"version": "1.2.0",
"protocolVersion": "1.0.0",
"skills": [
{
"id": "invoice-lookup",
"name": "청구서 조회 및 분석",
"description": "고객의 청구서를 조회하고 이상 항목을 분석합니다",
"tags": ["billing", "invoice", "analysis"],
"examples": [
"고객 C-5678의 3월 청구서를 확인해 주세요",
"지난 분기 청구 이상 항목을 분석해 주세요"
]
},
{
"id": "refund-processing",
"name": "환불 처리",
"description": "환불 요청을 검증하고 처리합니다. 사용자 승인이 필요할 수 있습니다",
"tags": ["billing", "refund"],
"examples": [
"청구서 INV-1234에 대해 부분 환불을 진행해 주세요"
]
}
],
"capabilities": {
"streaming": true,
"pushNotifications": true,
"stateTransitions": ["input_required", "auth_required"]
},
"auth": [
{
"type": "oauth2",
"authorizationUrl": "https://auth.example.com/authorize",
"tokenUrl": "https://auth.example.com/token",
"scopes": ["billing:read", "billing:write"]
},
{
"type": "apiKey",
"headerName": "X-API-Key",
"description": "내부 서비스 간 통신용 API 키"
}
]
}Task 라이프사이클
A2A v1.0.0의 공식 Task 상태 전이는 다음과 같습니다.
input-required와 auth-required 상태가 공식 스펙에 포함됨으로써, human-in-the-loop와 동적 인증 흐름을 프로토콜 수준에서 표현할 수 있게 되었습니다.
task 단위를 기준으로 설계한다
agent 대 agent 통신은 단일 RPC보다 작업 생성 -> 상태 조회 -> 결과 수신 구조가 운영에 유리합니다. 장기 실행, 부분 실패, resume를 다루기 쉬워지기 때문입니다.
응답보다 상태 전이가 중요하다
working, input-required, auth-required, completed, failed 같은 상태를 먼저 정의하면 UI, 승인, 재시도 정책을 붙이기 쉬워집니다.
AG-UI (Agent-User Interaction) 프로토콜
A2A가 에이전트 간 통신을 표준화했다면, AG-UI는 에이전트와 사용자 간 상호작용을 표준화하는 프로토콜입니다. 멀티에이전트 시스템에서 에이전트가 사용자에게 결과를 보여주고, 입력을 요청하는 방식을 통일합니다.
3가지 Primitive
| Primitive | 역할 | 사용 예시 |
|---|---|---|
show_text | 에이전트가 사용자에게 텍스트, 마크다운, 구조화된 결과를 표시 | 분석 결과 요약, 작업 진행 상황 알림 |
show_tool_use | 에이전트가 어떤 도구를 어떤 인자로 호출했는지 UI에 투명하게 노출 | "billing DB 조회 중...", 도구 호출 로그 표시 |
request_user_input | 에이전트가 사용자에게 추가 정보나 승인을 요청 | "결제를 진행할까요?", 파라미터 보완 요청 |
멀티에이전트 환경에서의 UI 상태 동기화
에이전트 간 handoff가 발생하면 UI 상태도 함께 전환되어야 합니다. AG-UI는 이 전환을 프로토콜 수준에서 처리합니다.
Agent A에서 Agent B로 handoff가 일어나도, 사용자 입장에서는 하나의 연속된 대화로 보입니다. AG-UI가 이 전환을 매끄럽게 이어주는 역할을 합니다.
3-프로토콜 스택
MCP, A2A, AG-UI는 각각 다른 층위의 문제를 해결하며, 함께 쓸 때 완전한 에이전트 시스템을 구성합니다.
| 층 | 프로토콜 | 해결하는 문제 |
|---|---|---|
| 도구 접근 | MCP | 모델/에이전트가 외부 도구, 리소스, 프롬프트에 접근 |
| 에이전트 간 통신 | A2A | 에이전트가 다른 에이전트에 작업 위임, 상태 추적 |
| 사용자 상호작용 | AG-UI | 에이전트가 사용자에게 결과 표시, 입력 요청, 도구 사용 투명성 |
Microsoft Agent Framework의 통합 지원
Microsoft Agent Framework(Azure AI Agent Service 기반)는 2026년 기준 A2A, AG-UI, MCP 세 프로토콜을 모두 네이티브로 지원하는 대표적인 프레임워크입니다.
- MCP: Azure 내부 서비스를 MCP 서버로 노출하여 에이전트가 도구로 사용
- A2A: 외부 조직의 에이전트와 표준화된 방식으로 작업 위임
- AG-UI: Teams, Copilot 등 Microsoft UI 계층과 에이전트의 상호작용 표준화
이러한 통합 지원은 단일 프레임워크 안에서 도구 접근, 에이전트 협업, 사용자 상호작용을 일관되게 설계할 수 있다는 점에서 의미가 있습니다.
실제 구현 예시
MCP 서버 구현 (TypeScript)
간단한 도구 제공 MCP 서버의 기본 구조입니다.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { z } from "zod";
const server = new McpServer({
name: "billing-mcp",
version: "1.0.0",
});
// Tool 정의: 청구서 조회
server.tool(
"get_invoice",
"고객의 청구서를 조회합니다",
{ customerId: z.string(), month: z.string().optional() },
async ({ customerId, month }) => {
const invoice = await db.invoices.find({ customerId, month });
return {
content: [
{
type: "text",
text: JSON.stringify({
id: invoice.id,
amount: invoice.amount,
status: invoice.status,
dueDate: invoice.dueDate,
}),
},
],
};
}
);
// Resource 정의: 결제 정책 문서
server.resource("billing-policy", "billing://policy", async (uri) => ({
contents: [
{
uri: uri.href,
mimeType: "text/markdown",
text: "## 환불 정책\n- 결제 후 7일 이내 전액 환불 가능\n...",
},
],
}));
// Streamable HTTP transport로 서버 시작
const transport = new StreamableHTTPServerTransport({ endpoint: "/mcp" });
await server.connect(transport);A2A 태스크 생성/상태 조회 (HTTP REST)
A2A 프로토콜로 원격 에이전트에 작업을 위임하는 호출 순서입니다.
# 1. Agent Card 조회 — 에이전트의 역량과 인증 방식 확인
GET https://billing-agent.example.com/.well-known/agent.json
# 2. 태스크 생성 — 작업 위임
POST https://billing-agent.example.com/a2a
Content-Type: application/json
{
"jsonrpc": "2.0",
"method": "tasks/send",
"id": "req-001",
"params": {
"id": "task-abc-123",
"message": {
"role": "user",
"parts": [
{
"type": "text",
"text": "고객 C-5678의 3월 청구서를 확인하고 이상이 있으면 보고해 주세요"
}
]
}
}
}
# 3. 태스크 상태 조회 — 진행 상황 확인
POST https://billing-agent.example.com/a2a
Content-Type: application/json
{
"jsonrpc": "2.0",
"method": "tasks/get",
"id": "req-002",
"params": {
"id": "task-abc-123"
}
}
# 응답 예시 (working 상태)
{
"jsonrpc": "2.0",
"id": "req-002",
"result": {
"id": "task-abc-123",
"status": { "state": "working" },
"artifacts": []
}
}
# 4. 완료 후 결과 수신
{
"jsonrpc": "2.0",
"id": "req-003",
"result": {
"id": "task-abc-123",
"status": { "state": "completed" },
"artifacts": [
{
"name": "billing-report",
"parts": [
{ "type": "text", "text": "C-5678 고객 3월 청구서: 정상. 총액 ₩1,250,000" }
]
}
]
}
}에러 처리 시나리오
프로토콜 간 통신에서 자주 발생하는 에러 상황과 권장 대응 방식입니다.
| 시나리오 | 증상 | 권장 대응 |
|---|---|---|
| 네트워크 실패 | MCP/A2A 요청 timeout 또는 connection refused | exponential backoff 재시도 (최대 3회), circuit breaker 패턴 적용 |
| 타임아웃 | 장기 실행 태스크가 응답 없이 지연 | A2A의 tasks/get으로 폴링, SubscribeToTask로 push 구독 전환 |
| 인증 만료 | OAuth2 토큰 만료로 401 응답 | refresh token으로 자동 갱신, 실패 시 auth_required 상태 전이 |
| 부분 실패 | 멀티스텝 작업 중 일부만 완료 | 완료된 artifact 보존, 실패 지점부터 재시도 (idempotent 설계 필수) |
| Agent Card 조회 실패 | .well-known/agent.json 404 | 캐시된 Agent Card 사용, fallback endpoint 시도, 최종 실패 시 사용자 알림 |
// 에러 처리 패턴 예시: A2A 태스크 호출 with retry
async function sendA2ATask(
endpoint: string,
task: A2ATaskRequest,
maxRetries = 3
): Promise<A2ATaskResponse> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${await getValidToken()}`,
},
body: JSON.stringify(task),
signal: AbortSignal.timeout(30_000),
});
if (response.status === 401) {
await refreshAuthToken();
continue; // 토큰 갱신 후 재시도
}
if (!response.ok) {
throw new Error(`A2A error: ${response.status}`);
}
return await response.json();
} catch (error) {
if (attempt === maxRetries) throw error;
await delay(Math.pow(2, attempt) * 1000); // exponential backoff
}
}
throw new Error("Max retries exceeded");
}함께 쓰는 패턴
MCP와 A2A는 보통 아래처럼 함께 배치됩니다.
| 층 | 역할 | 예시 |
|---|---|---|
| AG-UI | 사용자와 에이전트 간 상호작용 | 결과 표시, 승인 요청, 도구 사용 투명성 |
| Orchestrator | 어떤 agent나 capability를 호출할지 결정 | triage, approval, workflow control |
| MCP | 문서, DB, SaaS, 내부 함수 접근 | search, retrieve, create ticket |
| A2A | 원격 전문 agent와 task lifecycle 관리 | billing agent, compliance agent |
핵심은 "MCP로 도구를 표준화하고, A2A로 원격 협업을 표준화하고, AG-UI로 사용자 상호작용을 표준화한다"는 3단 분업입니다. 셋을 같은 층위로 다루지 않으면 권한·상태·감사 로그 설계가 훨씬 선명해집니다.
2026년 3월 기준으로 MCP Server Cards(.well-known/mcp.json)와 A2A Agent Card가 각각 표준화되면서, 도구 검색과 에이전트 검색을 같은 게이트웨이에서 통합 관리하는 패턴이 등장하고 있습니다.
통합 게이트웨이 패턴
MCP Server Card와 A2A Agent Card는 형태와 용도가 다르지만, 게이트웨이에서 통합 레지스트리로 관리하면 오케스트레이터가 "도구를 쓸지, 에이전트에 위임할지"를 동적으로 결정할 수 있습니다.
게이트웨이의 라우팅 판단 기준:
| 판단 기준 | MCP 서버로 라우팅 | A2A 에이전트로 라우팅 |
|---|---|---|
| 작업 복잡도 | 단일 도구 호출로 해결 | 멀티스텝 추론이 필요 |
| 상태 관리 | stateless (조회, 생성) | 상태 전이가 있는 장기 작업 |
| 자율성 | 오케스트레이터가 결과를 직접 해석 | 에이전트가 자율적으로 판단 |
| 인증 범위 | 도구 단위 scope | 에이전트 단위 위임 권한 |
선택 기준
| 질문 | 권장 선택 |
|---|---|
| 모델이 직접 문서/도구를 써야 하는가 | MCP |
| 다른 팀의 전문 agent를 네트워크 경계 너머 호출하는가 | A2A |
| 실행 계약이 완전히 결정적이고 agent 메타데이터가 필요 없는가 | 커스텀 HTTP/API |
| 같은 capability를 여러 host에서 재사용해야 하는가 | MCP |
| 장기 작업과 상태 조회가 중요한가 | A2A 또는 workflow task API |
보안과 거버넌스
| 통제 | MCP에서 중요 | A2A에서 중요 |
|---|---|---|
| 인증/인가 | host별 tool 허용 범위 | agent별 task 권한 |
| 감사 로그 | 어떤 tool을 누가 호출했는가 | 누가 어떤 작업을 위임했는가 |
| 데이터 최소화 | resource 범위 제한 | handoff payload 최소화 |
| replay 대응 | idempotent tool 설계 | task id, dedupe key |
안티패턴
| 안티패턴 | 문제 | 대안 |
|---|---|---|
| MCP로 agent delegation까지 해결하려고 함 | task lifecycle이 불분명 | delegation은 A2A/workflow로 분리 |
| A2A에 너무 큰 자유형 payload 전달 | 입력 검증과 복구가 어려움 | structured contract 사용 |
| Agent Card 없이 호출 규칙을 문서로만 관리 | discoverability 부족 | machine-readable metadata 유지 |
| 장기 작업을 동기 응답으로 강제 | timeout와 운영 복잡도 증가 | async task pattern 사용 |
ADR 스타일 결론
Decision
MCP는 모델이 capability를 읽고 쓰게 만드는 표준 surface로, A2A는 agent가 다른 agent에 작업을 위임하는 협업 프로토콜로 분리합니다. capability exposure와 task delegation을 같은 층위로 섞지 않고, 각각의 인증, 상태, 감사 로그를 별도로 설계합니다.