본문 바로가기
  • 데이터에 가치를 더하다, 서영석입니다.
카테고리 없음

MCP -A2A 연동 테스트

by 꿀먹은데이터 2026. 4. 12.

지난 글에서 MCP 서버를 Railway에 올렸다.

 

"파일 정리 에이전트"가 작업을 끝내고, 그 결과를 "슬랙 알림 에이전트"한테 넘기고 싶다.
근데 방법이 없다. 에이전트끼리 대화하는 표준이 없다.

MCP는 AI ↔ 도구 사이의 프로토콜이다.
그럼 AI ↔ AI 사이는를 A2A라고 부른다.

A2A란

A2A(Agent-to-Agent)는 Google이 2025년 4월에 공개한 오픈 프로토콜이다.
AI 에이전트끼리 서로를 발견하고, 작업을 위임하고, 결과를 주고받기 위한 표준이다.

쉽게 말하면:

MCP = AI가 도구(DB, API, 파일)를 쓰는 방법
A2A = AI가 다른 AI에게 일을 시키는 방법
구분 MCP A2A
통신 대상 도구 (DB, API, 파일시스템) 다른 에이전트
방향 클라이언트 → 서버 에이전트 ↔ 에이전트
주체 Anthropic Google (오픈소스)
역할 AI의 손 AI의 동료
현재 상태 표준화됨 초안 공개, 빠르게 확산 중

둘은 경쟁이 아니다. 같이 쓰는 거다.


핵심 개념 3가지

1. Agent Card

에이전트가 자기 자신을 소개하는 명함이다.
/.well-known/agent.json 경로에 노출된다.

# agent.json
{
  "name": "FileOrganizerAgent",
  "description": "파일을 분석하고 폴더 구조를 제안하는 에이전트",
  "url": "https://file-agent.up.railway.app",
  "version": "1.0.0",
  "capabilities": {
    "streaming": true,
    "pushNotifications": false
  },
  "skills": [
    {
      "id": "scan_folder",
      "name": "폴더 스캔",
      "description": "지정된 경로의 파일 목록을 반환합니다",
      "inputModes": ["text"],
      "outputModes": ["text", "data"]
    },
    {
      "id": "organize_files",
      "name": "파일 정리",
      "description": "AI가 폴더 구조를 제안하고 적용합니다",
      "inputModes": ["text"],
      "outputModes": ["text"]
    }
  ]
}

다른 에이전트가 이 카드를 읽고 "이 에이전트한테 뭘 시킬 수 있겠구나"를 파악한다.

2. Task

에이전트 간 작업 단위다. 상태가 있다.

submitted → working → completed
                    → failed
                    → input-required  ← 사람 개입 필요

작업 하나가 오래 걸릴 수 있기 때문에 비동기로 처리된다.

3. Message & Part

에이전트끼리 주고받는 메시지 형식이다.

{
  "role": "user",
  "parts": [
    { "type": "text", "text": "다운로드 폴더 정리해줘" },
    { "type": "data", "data": { "path": "/Users/me/Downloads" } }
  ]
}

텍스트, 데이터, 파일을 섞어서 보낼 수 있다.


A2A 서버 만들기 (Python)

from a2a.server import A2AServer, AgentCard, AgentSkill
from a2a.types import Task, Message
 
# Agent Card 정의
card = AgentCard(
    name="FileOrganizerAgent",
    description="파일 정리 에이전트",
    url="https://file-agent.up.railway.app",
    skills=[
        AgentSkill(
            id="organize_files",
            name="파일 정리",
            description="폴더를 스캔하고 AI로 분류합니다"
        )
    ]
)
 
server = A2AServer(agent_card=card)
 
@server.on_task("organize_files")
async def handle_organize(task: Task) -> Task:
    path = task.message.data.get("path", "")
 
    # 실제 파일 정리 로직 (MCP 서버 호출 또는 직접 처리)
    result = await organize_directory(path)
 
    task.status = "completed"
    task.artifacts = [{"type": "data", "data": result}]
    return task
 
server.run(host="0.0.0.0", port=8001)

다른 에이전트에서 호출하기

from a2a.client import A2AClient
 
# 에이전트 발견
client = A2AClient("https://file-agent.up.railway.app")
card = await client.get_agent_card()
 
print(card.skills)  # 이 에이전트가 뭘 할 수 있는지 확인
 
# 작업 위임
task = await client.send_task(
    skill_id="organize_files",
    message={
        "role": "user",
        "parts": [
            {"type": "text", "text": "다운로드 폴더 정리해줘"},
            {"type": "data", "data": {"path": "/Users/me/Downloads"}}
        ]
    }
)
 
# 결과 대기
result = await client.wait_for_completion(task.id)
print(result.artifacts)

코드가 MCP랑 비슷해 보이지만 방향이 다르다.
MCP는 Claude가 도구를 쓰는 것이고, A2A는 에이전트가 에이전트를 쓰는 것이다.


MCP + A2A 같이 쓰면

지금까지 만든 것들을 연결하면 이런 그림이 나온다.

사용자
  │
  ▼
오케스트레이터 에이전트 (Claude)
  ├── MCP → sales-db 서버 (DB 조회)
  ├── MCP → file-organizer 서버 (파일 정리)
  │
  └── A2A → 슬랙 알림 에이전트 ──── MCP → Slack API
           → 리포트 생성 에이전트 ── MCP → PDF 서버

Claude는 MCP로 도구를 쓰고, A2A로 전문화된 에이전트들에게 작업을 위임한다.
각 에이전트는 자기 영역에서 또 MCP 서버를 쓴다.

이게 "멀티에이전트 시스템"이다.


A2A는 아직 완성된 표준이 아니다.

  • 인증 방식이 명확하지 않다
  • 라이브러리가 아직 불안정하다
  • 실제 프로덕션에서 쓰는 사례가 많지 않다

그러나 방향은 맞다. 에이전트가 늘어날수록 에이전트 간 통신 표준은 반드시 필요하다.
MCP가 처음 나왔을 때도 비슷한 상황이었다. 지금은 Claude, Cursor, Windsurf 다 쓴다.

A2A도 그렇게 될 거라고 본다.


마치며

MCP 시리즈를 쭉 따라왔다면 이제 그림이 보일 것이다.

MCP는 AI가 세상과 연결되는 방법이고 A2A는 AI가 AI와 협력하는 방법이다

앞으로는 여러 에이전트가 역할을 나눠 가지고, 서로 대화하면서 복잡한 작업을 처리한다.

그 표준의 한쪽이 MCP고, 다른 쪽이 A2A다. 둘 다 알아두면 앞으로 나올 에이전트 아키텍처를 읽는 데 훨씬 수월해진다.

반응형