MCP 기반 시스템에서 실행 흐름(Control Flow) 과 대화 상태(Conversation State) 가 어디에서 관리되는지를 client 서비스를 구현하고, 구조적으로 정리한다.
MCP 기반 구조에서 실행 흐름과 대화 상태는 어느 계층의 책임인가?
MCP 기반 시스템은 단순 Client–Server 모델이라기보다 다음과 같은 계층 구조로 이해하는 편이 자연스럽다.
LLM (Inference)
↑↓
Orchestration Layer (Claude Desktop)
↑↓ JSON-RPC (MCP)
MCP Server (Tool Execution)
↑↓
External API
각 계층의 책임은 다음과 같이 구분된다.
LLM
Claude Desktop (Client)
MCP Server
External API
따라서 Claude Desktop은 단순 UI가 아니라
실행 흐름을 조정하는 Orchestration Layer로 보는 것이 타당하다.
await mcpClient.connect(transport);
이 호출은 내부적으로 JSON-RPC 기반 초기화 절차를 수행한다.
Client MCP Server
│ initialize (req) │
├───────────────────────▶│
│ initialize (res) │
│◀───────────────────────┤
│ initialized (notify) │
├───────────────────────▶│
이 단계에서:
가 이루어진다.
즉, MCP 연결은 단순 소켓 연결이 아니라
명시적 초기화 단계를 포함하는 상태 기반 프로토콜 과정이다.

MCP는 JSON-RPC 기반 요청/응답 프로토콜이다.
중요한 점은 다음이다.
MCP는 대화 맥락을 정의하지 않는다.
초기화 상태는 존재하지만,
사용자 대화 이력이나 컨텍스트 전략은 프로토콜의 책임 범위를 벗어난다.
따라서 MCP는 다음에 가깝다.

구현 과정에서 확인한 핵심은
“세션(Session)”이 단일 개념이 아니라는 점이다.
initialize 이후 유지되는 상태messages 배열의 수명/reset으로 초기화되는 영역
여기서 중요한 기술적 배경이 있다.
Claude API 호출은 요청 단위로 상태를 유지하지 않는 구조에 가깝다.
매 호출 시 전체 대화 이력이 함께 전달된다.
messages = [
user,
assistant(tool_use),
tool(result),
assistant,
...
]
LLM은 내부적으로 대화 상태를 저장하지 않으며,
현재 턴에 필요한 모든 맥락은 messages 배열로 제공된다.
따라서 다음은 클라이언트의 책임이 된다.
정리하면:
Transport는 연결의 수명이고,
Conversation은 맥락의 수명이다.
이 둘을 구분하면 구조가 명확해진다.
Claude의 Tool 사용 흐름은 단일 요청-응답 모델이 아니라,
클라이언트가 구성하는 반복 제어 구조 위에서 동작한다.
이를 추상화하면 다음과 같다.
User Input
↓
LLM 호출
↓
stop_reason 확인
├─ tool_use → Tool 실행 → 결과를 messages에 추가
└─ end_turn → 종료
↓
반복
각 계층의 책임은 다음과 같이 분리된다.
LLM
Client
MCP Server

중요한 점은,
반복 로직은 LLM 내부가 아니라 Orchestration Layer에서 구성된다는 것이다.
1편에서는 Execution Layer(MCP Server)를 분석했다.
이번 글에서는 Orchestration Layer의 구조적 책임을 살펴봤다.
핵심은 다음 세 가지다.