cd ../
AI·2026-03-30·8 min read·# entry/030

MCP Transport 파헤치기 — Life Cycle, stdio, Streamable HTTP

Model Context Protocol의 연결 생명주기와 두 가지 표준 Transport(stdio, Streamable HTTP)의 동작 방식을 공식 문서 기준으로 분석합니다.

이 글은 MCP 공식 문서에 근거하며, MCP 서버를 AI 애플리케이션의 하나의 모듈로 바라보는 관점에서 설명합니다. Client는 AI 애플리케이션(또는 그 안의 MCP Client 모듈), Server는 MCP Server를 의미합니다.

공식 문서 전제

Life Cycle

일반적인 웹 애플리케이션이 TCP 커넥션 이후 곧바로 통신에 진입하는 것과 달리, MCP는 연결 전에 서로의 기능을 파악하고 협상하는 구조화된 생명주기를 가집니다.

1

초기화 (Initialization)

클라이언트와 서버의 첫 상호작용이자 필수 단계입니다. 이 단계에서 다음 세 가지가 이루어집니다.

  • 프로토콜 버전 호환성 확인
  • 기능(Capability) 교환 및 협상
  • 구현 세부 정보 공유

클라이언트가 initialize 요청을 전송하며 시작합니다.

initialize request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-11-25",
    "capabilities": {
      "roots": { "listChanged": true },
      "sampling": {},
      "elicitation": { "form": {}, "url": {} },
      "tasks": {
        "requests": {
          "elicitation": { "create": {} },
          "sampling": { "createMessage": {} }
        }
      }
    },
    "clientInfo": {
      "name": "ExampleClient",
      "title": "예시 클라이언트 표시 이름",
      "version": "1.0.0",
      "description": "예시 MCP 클라이언트 애플리케이션",
      "websiteUrl": "https://example.com"
    }
  }
}

초기화가 완료되면 클라이언트는 initialized 알림을 전송해 운영 준비가 되었음을 알립니다.

initialized notification
{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}
초기화 순서 규칙
  • 클라이언트: Server가 initialize 요청에 응답하기 전에 ping 외의 요청을 보내선 안 됩니다.
  • 서버: initialized 알림을 수신하기 전에 ping과 로깅 외의 요청을 보내선 안 됩니다.
2

버전 협상 (Version Negotiation)

클라이언트는 자신이 지원하는 최신 프로토콜 버전initialize 요청에 담아 보냅니다.

상황Server 응답
동일 버전 지원같은 버전으로 응답
미지원 버전자신이 지원하는 버전으로 응답
Client가 Server 버전 미지원Client가 연결 종료
3

Capability 협상

Client와 Server가 서로 어떤 기능을 지원하는지 선언합니다. 이후 Operation 단계에서는 협상된 Capability 범위 안에서만 통신해야 합니다.

선언 주체Capability의미
ServertoolsTool 호출 기능 제공
ServerresourcesResource 읽기 기능 제공
Serverprompts프롬프트 템플릿 제공
Serverlogging로그 스트리밍 지원
ClientsamplingLLM 샘플링 요청 지원
Clientroots파일시스템 루트 제공
4

Operation — 실제 통신

초기화와 협상이 완료되면 협상된 Capability 범위 안에서 자유롭게 통신합니다. tools/call, resources/read 같은 요청들이 이 구간에서 발생합니다.

협상되지 않은 기능은 사용 불가

초기화 단계에서 선언되지 않은 Capability는 Operation 중에 요청할 수 없습니다.

5

Shutdown — 연결 종료

별도의 종료 메시지 없이, 전송 레이어를 닫는 것으로 종료를 신호합니다. 전송 방식에 따라 처리 방법이 다릅니다.

Transport종료 방식
stdio (로컬 프로세스)입력 스트림 닫기 → SIGTERMSIGKILL 순서
HTTPHTTP 커넥션 닫기

Transport: 통신 방식

REST API에서 HTTP / WebSocket / gRPC 중 선택하듯, MCP는 현재 두 가지 표준 Transport를 정의합니다.

MCP Server가 로컬 머신에서 실행되는 경우 사용합니다. AI 애플리케이션이 MCP 서버 프로세스를 직접 실행시키고, 표준 입출력(stdin / stdout)으로 JSON-RPC 메시지를 주고받습니다.

AI Application
┌───────────────────────────────────┐
│                                   │
│  ┌─────────────┐  stdin/stdout  ┌─────────────┐
│  │  MCP Client │ ◄────────────► │  MCP Server │
│  └─────────────┘                └─────────────┘
│         (동일 프로세스 또는 서브프로세스)          │
└───────────────────────────────────┘
stdio의 특징
  • 네트워크 불필요 — 로컬 CLI 도구처럼 사용
  • 별도 인증 불필요 — 프로세스 격리로 보안 처리
  • Claude Desktop, Cursor 등 로컬 MCP 연동 방식이 이 Transport를 사용

Session 관리

Streamable HTTP에서 Server가 상태를 유지하고 싶을 경우 Session을 사용할 수 있습니다.

1

Session ID 발급

Server가 initialize 응답 헤더에 MCP-Session-Id를 포함해 반환합니다.

2

이후 요청에 ID 포함

Client는 이후 모든 요청 헤더에 MCP-Session-Id를 포함합니다.

3

Session 만료 처리

Session이 만료되면 Server는 404를 반환합니다. Client가 404를 받으면 initialize부터 다시 시작합니다.

4

명시적 종료

Client가 Session을 끝내고 싶으면 DELETE /mcp 요청을 전송합니다.


SSE 연결 끊김 처리

네트워크 불안정으로 SSE 연결이 끊어질 수 있습니다.

DB의 커서 기반 페이지네이션과 동일한 원리입니다. 어디까지 전송했는지 기억한 뒤 이어서 전송합니다.

1

이벤트 ID 부여

Server는 SSE 이벤트마다 고유 id를 부여합니다.

2

재연결 요청

연결이 끊어지면 Client는 Last-Event-ID 헤더와 함께 GET /mcp으로 재연결합니다.

3

이어서 전송

Server는 해당 ID 이후 이벤트부터 재전송합니다.

연결 끊김 ≠ 요청 취소

SSE 연결이 끊어졌다고 해서 진행 중인 요청이 취소된 것으로 취급하지 않습니다. 명시적으로 취소하려면 취소 알림(cancellation notification) 을 별도로 전송해야 합니다.


보안 주의사항

Origin 헤더 검증 필수

Streamable HTTP 사용 시 Origin 헤더 검증을 반드시 수행해야 합니다.

검증하지 않으면 DNS rebinding 공격에 취약해집니다. 외부 사이트가 브라우저를 통해 로컬의 MCP Server를 호출할 수 있기 때문입니다. Origin이 유효하지 않으면 403 Forbidden으로 차단해야 합니다.


Protocol Version 헤더

HTTP 사용 시 모든 요청 헤더에 다음을 포함해야 합니다.

MCP-Protocol-Version: 2025-11-25

핸드셰이크에서 협상된 버전을 사용하면 됩니다.

헤더 누락 시 동작
  • 헤더가 없으면: Server는 2025-03-26 버전으로 간주합니다.
  • 헤더의 버전이 유효하지 않으면: Server는 400 Bad Request를 반환합니다.