n8n AI Agent + MCP로 멀티에이전트 오케스트레이션 설계하기 — 계층화 아키텍처와 실무 함정
"오늘 받은 이메일 요약하고, 관련 일정 잡고, Linear에 이슈도 만들어줘" — 이런 복합 요청을 단일 에이전트에 욱여넣으면 어떻게 되는지 직접 겪어봤습니다. 프롬프트는 점점 비대해지고, 20개 넘는 도구 중에 뭘 써야 할지 모델이 헷갈려하고, 결과는 실행마다 제각각이 됩니다. 저도 처음엔 "그냥 시스템 프롬프트를 더 잘 쓰면 되겠지" 싶었는데, 실무에서 그 생각이 얼마나 순진했는지 금세 깨달았습니다.
n8n의 AI Agent Tool 노드와 MCP(Model Context Protocol)를 조합하면 이 문제를 구조적으로 풀 수 있습니다. 오케스트레이터 에이전트가 의도를 분류하고, 각 전문 서브에이전트에게 도메인 책임을 나눠주며, 각 에이전트는 자신에게 필요한 MCP 도구만 바인딩하는 방식입니다. 이 글을 읽고 나면, n8n 캔버스에서 오케스트레이터 + 서브에이전트 2개 이상의 계층 구조를 직접 구성하고, 운영 환경에서 자주 마주치는 함정들을 피해가는 방법을 갖추게 됩니다.
n8n을 써봤거나, LangGraph·CrewAI 같은 코드 기반 프레임워크에 피로감을 느낀 백엔드 개발자라면 특히 유용한 내용입니다.
핵심 개념
n8n AI Agent 노드 — ReAct 루프를 품은 LLM 래퍼
ReAct(Reasoning + Acting) 루프: LLM이 "어떤 도구를 쓸까" 추론하고 → 도구를 선택·실행하고 → 결과를 관찰하고 → 다음 행동을 결정하는 사이클을 반복하는 자율 실행 패턴입니다.
AI Agent 노드는 이 ReAct 루프를 캡슐화한 노드입니다. 시스템 프롬프트, 모델 선택, 메모리 백엔드, 출력 스키마를 노드 단위로 독립 설정할 수 있어서 — 에이전트마다 다른 모델을 붙이거나, 서로 다른 메모리 전략을 쓰는 것이 가능합니다.
AI Agent 노드 구성 요소
├── System Prompt : 이 에이전트의 역할·제약 정의
├── Model : GPT-4o / Claude Sonnet / Gemini 등
├── Memory : Window / Redis / pgvector 선택
├── Output Schema : 구조화 출력 강제 (JSON Schema)
└── Tools : MCP Client, Code, HTTP Request 등메모리 백엔드 선택이 헷갈릴 수 있는데, 저는 이렇게 구분하고 있습니다. 단기 세션 상태는 Redis, 장기 RAG 컨텍스트는 pgvector, 단일 대화 내 히스토리는 Window Memory입니다. 에이전트의 역할에 따라 하나씩만 붙이면 충분합니다.
AI Agent Tool 노드는 여기서 한 단계 더 나아가 다른 AI Agent를 도구(Tool)로 등록할 수 있게 해줍니다. 2025년 상반기 정식 출시된 이 노드 덕분에 서브워크플로를 별도 캔버스로 분리하지 않고도 단일 캔버스에서 계층적 에이전트 구조를 시각적으로 구성할 수 있게 됐습니다.
AI Agent Tool 노드: 에이전트를 다른 에이전트의
tools배열에 등록하는 노드. 오케스트레이터가tool_call을 내리면 해당 서브에이전트가 실행되고 결과를 반환합니다. 별도 워크플로 호출 없이 단일 캔버스에서 중첩(nested) 에이전트 체계를 완성합니다.
MCP — 도구 탐색과 실행의 표준 계약
MCP(Model Context Protocol)는 Anthropic이 설계한 개방형 프로토콜로, AI 에이전트가 외부 도구와 데이터 소스를 일관된 인터페이스로 탐색(discover)하고 실행(invoke)할 수 있게 합니다. 각 SaaS마다 다른 API 스펙을 직접 구현하는 대신, MCP 서버 하나를 통해 도구 목록을 받아 쓰는 구조입니다.
n8n은 MCP를 두 방향으로 지원합니다.
| 노드 | 방향 | 역할 |
|---|---|---|
MCP Client Tool |
소비(Consume) | 외부 MCP 서버의 도구를 에이전트 내부에서 호출 |
MCP Server Trigger |
노출(Expose) | n8n 워크플로 자체를 MCP 서버로 공개 — Claude Desktop·Cursor 등이 호출 가능 |
이 두 노드의 조합이 흥미로운 이유는, n8n이 단순히 MCP 도구를 소비하는 클라이언트일 뿐 아니라 1,650개 이상의 외부 서비스 통합 능력을 MCP 서버로 제공할 수도 있기 때문입니다. Claude Desktop이 n8n을 통해 Slack 메시지를 보내거나 Salesforce를 조회하는 그림이 가능해집니다.
오케스트레이션 아키텍처 — 전체 흐름
멀티에이전트 파이프라인의 핵심 흐름은 다음과 같습니다.
사용자 요청 (자연어)
↓
┌─────────────────────────────────┐
│ 오케스트레이터 에이전트 │
│ (의도 분류 · 태스크 분해) │
└──────┬──────────┬───────────┬───┘
↓ ↓ ↓
이메일 에이전트 캘린더 에이전트 데이터 에이전트
(MCP: Gmail) (MCP: GCal) (MCP: DB/Vector)
↓ ↓ ↓
└──────────┴───────────┘
↓
Fan-In 노드 (Merge)
↓
최종 응답 생성오케스트레이터는 비교적 "무거운" 모델(GPT-4o, Claude Sonnet)을 쓰고, 실행 단계의 서브에이전트는 경량 모델(GPT-4o-mini, Haiku)을 쓰는 계층화 전략이 토큰 비용을 크게 줄여주는 핵심입니다. 의도 분류는 정확도가 파이프라인 전체 성공률을 좌우하므로 좋은 모델을 쓰는 게 맞고, 도메인이 고정된 실행 단계는 경량 모델로도 충분합니다.
구조화 출력(Structured Output): 에이전트가 자연어 대신 JSON Schema에 맞는 고정된 형식으로 응답하도록 강제하는 방식. 에이전트 간 데이터 전달 시 LLM 환각(hallucination) 위험을 크게 낮춥니다.
실전 적용
예시 1: 비즈니스 어시스턴트 — 이메일·일정·태스크 통합
"오늘 미팅 관련 이메일 정리하고, 내일 팀 회의 잡고, Linear에 액션 아이템 만들어줘" 같은 복합 요청을 처리하는 시나리오입니다. 실무에서 자주 맞닥뜨리는 상황인데, 단일 에이전트로 처리하면 도구 선택 실패가 잦습니다.
오케스트레이터 시스템 프롬프트
You are a business assistant orchestrator.
Analyze the user's request and route tasks to the appropriate sub-agents.
Available agents:
- email_agent: read/write Gmail messages
- calendar_agent: check/create Google Calendar events
- task_agent: create/update Linear issues and Notion pages
Always respond in the following JSON format:
{
"intent": "string",
"agents_to_invoke": ["email_agent", "calendar_agent"],
"routing_reason": "string"
}오케스트레이터가 agents_to_invoke 배열을 반환하면, 이후 Switch 노드가 해당 배열을 파싱해 각 서브에이전트로 분기합니다. Switch 노드에서 {{ $json.agents_to_invoke.includes('email_agent') }} 조건으로 이메일 에이전트 분기를 만들고, 나머지 에이전트도 같은 방식으로 연결하면 됩니다. 여러 에이전트를 동시에 실행해야 한다면 n8n의 Split Out 노드로 배열을 분해한 뒤 각 에이전트를 병렬로 트리거할 수 있습니다.
서브에이전트 구성
이메일 에이전트
├── System Prompt : Gmail 전용. 다른 도구 호출 금지.
├── Model : claude-haiku-4-5 (비용 절감)
├── Tools : MCP Client Tool → Gmail MCP Server
└── Output Schema : { "source": "email", "emails": [...], "summary": "..." }
캘린더 에이전트
├── System Prompt : Google Calendar 전용.
├── Model : gpt-4o-mini
├── Tools : MCP Client Tool → GCal MCP Server
└── Output Schema : { "source": "calendar", "events": [...], "conflicts": [...] }
태스크 에이전트
├── System Prompt : Linear / Notion 전용.
├── Model : gpt-4o-mini
├── Tools : MCP Client Tool → Linear MCP + Notion MCP
└── Output Schema : { "source": "task", "created_issues": [...], "pages": [...] }Output Schema에 source 필드를 꼭 포함시켜 두시면 좋습니다. 뒤에서 Fan-In 노드가 에이전트별 결과를 구분할 때 이 필드를 기준으로 병합하기 때문입니다.
| 구성 요소 | 선택 이유 |
|---|---|
| 오케스트레이터에 고급 모델 | 의도 분류 오류가 전체 파이프라인 실패로 이어지므로 정확도 우선 |
| 서브에이전트에 경량 모델 | 도메인이 고정되어 있어 복잡한 추론 불필요 |
| 구조화 출력 강제 | 에이전트 결과를 Fan-In 노드에서 병합할 때 파싱 오류 방지 |
| MCP Client Tool | 각 에이전트에 필요한 도구만 바인딩 → 불필요한 도구 노출 차단 |
예시 2: MCP Context Reducer 패턴
예시 1의 태스크 에이전트에 MCP 서버를 연결했을 때 도구가 50개 이상이라면 어떻게 될까요? 솔직히 저도 처음엔 "그냥 다 줘버리지 뭐" 했다가, GPT-4o가 엉뚱한 도구를 반복적으로 골라서 파이프라인 전체가 엉망이 되는 상황을 겪었습니다. 도구가 많을수록 모델의 선택 정확도가 낮아지고, 그만큼 불필요한 토큰도 낭비됩니다.
n8n 공식 템플릿(#4475)이 제안하는 해법이 바로 Context Reducer 패턴입니다.
사용자 요청
↓
전처리 에이전트 (Context Reducer)
- 전체 도구 목록에서 이 요청에 필요한 도구 3~5개만 선별
- 선별된 도구 목록을 JSON으로 반환
↓
실행 에이전트
- 전처리 에이전트가 건넨 최소 도구 집합만 사용
- 컨텍스트 크기 대폭 감소 → 비용 절감 + 정확도 향상tool_manifest 주입 방식
{{ $json.tool_manifest }}는 MCP Client Tool이 연결된 MCP 서버에서 도구 목록을 조회한 결과입니다. 구체적으로는, HTTP Request 노드나 MCP 초기화 단계에서 서버의 /tools/list 엔드포인트를 호출해 도구 이름·설명 목록을 JSON으로 직렬화한 뒤, Code 노드에서 $json.tool_manifest로 세팅하고 Context Reducer의 프롬프트에 주입합니다.
Context Reducer 에이전트 프롬프트
You are a tool selector. Given the user's request and the full tool manifest,
select ONLY the tools needed to fulfill this request.
Full tool manifest:
{{ $json.tool_manifest }}
User request:
{{ $json.user_request }}
Respond with:
{
"selected_tools": ["tool_a", "tool_b"],
"reason": "short explanation"
}이 패턴을 MCP Server Trigger와 결합하면 n8n 워크플로 자체가 "지능형 MCP 게이트웨이" 역할을 하게 됩니다. 외부 AI 클라이언트(Claude Desktop 등)가 호출하면, n8n이 먼저 컨텍스트를 줄이고 최적화된 도구 집합으로 응답하는 구조입니다.
예시 3: 웹 리서치 멀티에이전트 — 병렬 Fan-Out/Fan-In
리서치 업무는 여러 소스를 동시에 탐색해야 하므로 직렬 에이전트 체인보다 병렬 처리가 훨씬 효과적입니다. 처음에 이걸 직렬로 구성했다가 응답 시간이 너무 길어져서 구조를 전면 재설계했던 기억이 납니다.
리서치 오케스트레이터
│ (주제 분석 → 검색 쿼리 3개 생성 → 병렬 분기)
│
├── 검색 에이전트 (MCP: Brave Search)
│ └── Output: { "source": "brave", "items": [...] }
│
├── 스크레이핑 에이전트 (MCP: Firecrawl)
│ └── Output: { "source": "firecrawl", "content": [...] }
│
└── 벡터 검색 에이전트 (MCP: Supabase pgvector)
└── Output: { "source": "supabase", "documents": [...] }
│
└──────────────────────┐
↓
Fan-In 노드 (Merge)
↓
요약·인용 에이전트
(결과 통합 → 출처 포함 리포트 생성)Fan-In 노드에서 결과 병합
// n8n Code 노드 (JavaScript)
const results = $input.all();
const merged = {
search_results: results.find(r => r.json.source === 'brave')?.json.items ?? [],
scraped_content: results.find(r => r.json.source === 'firecrawl')?.json.content ?? [],
internal_docs: results.find(r => r.json.source === 'supabase')?.json.documents ?? [],
collected_at: new Date().toISOString()
};
return [{ json: merged }];이 코드가 제대로 동작하려면 각 에이전트의 Output Schema에 source 필드가 반드시 포함되어야 합니다. 'brave', 'firecrawl', 'supabase'로 각각 고정값을 지정해두면 Fan-In 단계에서 헷갈릴 일이 없습니다.
핵심은 오케스트레이터가 검색 쿼리를 생성하는 역할만 담당하고, 실제 검색·스크레이핑·벡터 조회는 각 에이전트가 완전히 독립적으로 처리한다는 점입니다. 각 에이전트가 실패해도 다른 에이전트의 결과는 보존됩니다.
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| 로우코드 접근성 | 복잡한 멀티에이전트 아키텍처를 코드 없이 시각적으로 구성 가능 |
| 단일 캔버스 | AI Agent Tool 노드로 서브워크플로 분리 없이 에이전트 중첩 가능 |
| 표준 프로토콜 | MCP 준수로 Claude, GPT, Gemini 등 다양한 AI 클라이언트와 호환 |
| 비용 최적화 | 모델 계층화(고급/경량 혼합)로 토큰 비용 크게 절감 가능 |
| 풍부한 연동 | 820개 코어 + 830개 커뮤니티 노드로 거의 모든 외부 서비스 연결 |
| 메모리 유연성 | Redis(단기), pgvector(장기 RAG), Window Memory(대화 컨텍스트) 자유 선택 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| SSE 연결 안정성 | MCP Server Trigger는 SSE 기반 — 다중 웹훅 레플리카 환경에서 연결 단절 가능 | Queue Mode에서 /mcp* 경로를 단일 웹훅 레플리카로 라우팅 설정 |
| 역방향 프록시 설정 | nginx 등에서 SSE 프록시 버퍼링이 기본 활성화되어 스트림 차단 발생 | proxy_buffering off 및 X-Accel-Buffering: no 설정 필수 |
| 디버깅 복잡도 | 에이전트 호출 깊이가 깊어질수록 실행 추적이 어려워짐 | 각 에이전트 출력에 trace_id 필드를 포함시키고, Code 노드에서 Postgres 등 외부 DB에 실행 메타데이터를 기록하는 관찰 레이어 추가 |
| 컨텍스트 오염 | 에이전트 간 비정형 데이터 전달 시 LLM 환각 증가 위험 | 구조화 출력(JSON Schema) 강제로 타입 고정 |
| 레이턴시 누적 | 직렬 에이전트 체인은 각 LLM 호출 시간이 합산됨 | 가능한 경우 Fan-Out 병렬 처리로 전환 |
SSE(Server-Sent Events): 서버에서 클라이언트로 단방향 스트리밍을 유지하는 HTTP 기반 프로토콜. MCP Server Trigger가 이를 사용하기 때문에 프록시 레이어에서 버퍼링을 비활성화하지 않으면 스트림이 중단됩니다.
실무에서 가장 흔한 실수
- 오케스트레이터에 도구를 직접 바인딩하는 것 — 오케스트레이터는 "라우팅"만 담당해야 합니다. 이메일 도구가 오케스트레이터에 붙어 있으면 분기 결정 없이 직접 호출해버리는 상황이 생깁니다.
- 에이전트 간 통신을 자연어로 하는 것 — "이메일 확인해줘" 같은 자연어를 서브에이전트에 그대로 전달하면 에이전트마다 해석이 달라집니다. JSON Schema로 타입을 고정하는 것이 훨씬 안정적입니다.
- 모든 에이전트에 같은 모델을 쓰는 것 — 실행 단계의 단순 도구 호출에 GPT-4o를 쓰는 건 비용 낭비입니다. 의도 분류는 고급 모델, 실행은 경량 모델로 계층화하는 것을 권장합니다.
마치며
n8n의 AI Agent Tool 노드와 MCP를 조합하면, 로우코드 방식으로 프로덕션급 멀티에이전트 오케스트레이션을 구성할 수 있습니다.
지금 바로 시작해볼 수 있는 3단계:
- n8n 클라우드 또는 로컬 인스턴스에서 템플릿 #4475를 열어보시면 좋습니다 —
MCP Server with AI Agent as Context Reducer템플릿이 MCP Client Tool과 구조화 출력의 조합을 실제로 어떻게 구성했는지 가장 빠르게 파악할 수 있는 출발점입니다. - 오케스트레이터 + 서브에이전트 2개 구조로 최소 파이프라인을 만들어볼 수 있습니다 — Gmail MCP와 Google Calendar MCP를 각각 담당하는 에이전트를
AI Agent Tool로 등록하고, 오케스트레이터 시스템 프롬프트에 라우팅 지시를 작성하는 것으로 충분합니다. - 각 에이전트의 출력 스키마를 JSON Schema로 고정해보시면 좋습니다 — 처음엔 귀찮아 보이지만, 에이전트 간 데이터 흐름이 안정되는 순간 디버깅 시간이 눈에 띄게 줄어드는 걸 체감할 수 있습니다.