SSE와 Streamable HTTP 3부 — MCP는 왜 Streamable HTTP를 사용하는가

SSE와 Streamable HTTP 3부 — MCP는 왜 Streamable HTTP를 사용하는가

1부에서는 SSE가 하나의 HTTP Response를 유지하면서 데이터를 조금씩 전달하는 원리를 살펴봤습니다.

2부에서는 한 단계 더 나아가 이런 질문을 던졌습니다.

SSE만으로 복잡한 AI 시스템의 통신을 처리할 수 있을까?

SSE는 Server → Client 방향의 스트리밍에는 매우 유용합니다.

WebSocket을 사용하면 양방향 통신도 가능합니다.

하지만 MCP 같은 RPC 기반 시스템에서 중요한 것은 단순히 단방향인가, 양방향인가의 문제가 아니었습니다.

MCP에서는 다양한 형태의 메시지를 처리해야 합니다.

Request
Response
Notification
Streaming
Session

그리고 2부 마지막에 이런 질문을 남겼습니다.

HTTP의 단순한 Request/Response 구조를 유지하면서, 필요한 순간에만 스트리밍할 수는 없을까?

이번 글에서 살펴볼 Streamable HTTP가 바로 이 질문과 연결됩니다.


1. 먼저 이름부터 살펴보자

Streamable HTTP라는 이름을 처음 보면 흔히 이렇게 생각할 수 있습니다.

SSE
 ↓
새로운 스트리밍 기술
 ↓
Streamable HTTP

하지만 이렇게 이해하면 조금 어색합니다.

Streamable HTTP는 SSE를 대체하는 새로운 스트리밍 포맷이라고 보기보다는,

HTTP를 기본 전송 방식으로 사용하면서 필요할 때 스트리밍까지 사용할 수 있도록 구성한 MCP의 Transport 방식이라고 이해하는 편이 좋습니다.

이름도 자세히 보면

Streaming HTTP

가 아니라

Streamable HTTP

입니다.

항상 Streaming하는 HTTP가 아니라,

필요하면 Stream할 수 있는 HTTP

라는 관점입니다.


2. 가장 단순한 경우부터 생각해보자

MCP Client가 MCP Server에게 Tool 목록을 요청한다고 해보겠습니다.

MCP Client                     MCP Server
    │                              │
    │──── tools/list ─────────────>│
    │                              │
    │<──── tool list ──────────────│
    │                              │

이 요청은 일반적인 Request/Response로 충분합니다.

굳이 장시간 연결을 유지하거나 지속적인 이벤트 스트림을 만들 필요가 없습니다.

개념적으로는 평범한 HTTP 요청처럼 처리할 수 있습니다.

POST /mcp
Content-Type: application/json

{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list"
}

서버가 처리한 뒤 결과를 반환합니다.

HTTP/1.1 200 OK
Content-Type: application/json

{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        ...
    }
}

구조만 보면 우리가 오래전부터 사용해온 HTTP API와 크게 다르지 않습니다.

Client
   │
   │ HTTP POST
   ▼
Server
   │
   │ 처리
   ▼
JSON Response

여기까지만 보면 스트리밍은 필요하지 않습니다.


3. 그런데 모든 Tool이 빨리 끝나는 것은 아니다

이번에는 다른 Tool을 호출해보겠습니다.

tools/call
    │
    ▼
analyze_invoice()

인보이스 분석 Tool 내부에서 다음과 같은 작업이 발생한다고 해봅시다.

PDF
 │
 ▼
Rendering
 │
 ▼
OCR / VLM
 │
 ▼
Field Extraction
 │
 ▼
Validation
 │
 ▼
Result

이 작업이 20초 걸린다고 생각해봅시다.

가장 단순한 방법은 20초를 기다린 뒤 결과를 반환하는 것입니다.

Client                         Server
   │                              │
   │──── tools/call ─────────────>│
   │                              │
   │                              │
   │         20 seconds           │
   │                              │
   │                              │
   │<──── result ─────────────────│

기술적으로 아무 문제 없습니다.

하지만 경우에 따라 서버가 처리 과정에서 여러 메시지를 전달해야 할 수도 있습니다.

processing...

OCR completed

extracting...

validating...

completed

이제 단순 JSON Response 하나만으로는 표현하기 불편해집니다.

이때 스트리밍이 필요해집니다.


4. Streamable HTTP의 핵심 구조

Streamable HTTP의 핵심 아이디어를 단순화하면 다음과 같습니다.

                  POST /mcp

MCP Client ───────────────────────> MCP Server

Client는 MCP 메시지를 HTTP POST로 보냅니다.

그런데 서버의 Response는 상황에 따라 달라질 수 있습니다.

단순한 요청이라면:

MCP Client                     MCP Server
    │                              │
    │──── POST /mcp ──────────────>│
    │                              │
    │<──── JSON Response ──────────│

스트리밍이 필요하다면:

MCP Client                     MCP Server
    │                              │
    │──── POST /mcp ──────────────>│
    │                              │
    │<════ SSE Stream ═════════════│
    │<──── message ────────────────│
    │<──── message ────────────────│
    │<──── message ────────────────│
    │<──── result ─────────────────│

즉 같은 HTTP 기반 Transport 안에서 상황에 따라 다른 Response 형태를 사용할 수 있습니다.

                 POST /mcp
                     │
                     ▼
                MCP Server
                     │
            ┌────────┴────────┐
            │                 │
            ▼                 ▼
     JSON Response       SSE Stream

이 구조가 Streamable HTTP를 이해하는 가장 중요한 그림입니다.


5. 여기서 SSE가 사라진 것이 아니다

이 부분에서 많이 헷갈립니다.

MCP가 기존 SSE Transport에서 Streamable HTTP로 이동했다고 하면,

“이제 MCP에서는 SSE를 사용하지 않는구나.”

라고 생각할 수 있습니다.

그렇지 않습니다.

Streamable HTTP에서도 SSE가 사용될 수 있습니다.

차이는 SSE가 Transport 전체를 지배하는 구조가 아니라는 것입니다.

개념적으로 보면 다음과 같습니다.

Streamable HTTP
      │
      ├── HTTP POST
      │
      ├── JSON Response
      │
      └── SSE Response

즉 SSE는 사라진 것이 아니라 필요한 경우 사용할 수 있는 스트리밍 메커니즘으로 들어가 있습니다.

그래서 이름이 꽤 정확합니다.

HTTP
 +
optional streaming
 =
Streamable HTTP

6. 기존 SSE Transport는 어떻게 동작했을까?

이 차이를 이해하려면 기존 MCP의 HTTP+SSE Transport를 살펴보는 것이 좋습니다.

단순화하면 Client는 먼저 SSE 연결을 만들었습니다.

MCP Client                     MCP Server
    │                              │
    │──── GET /sse ───────────────>│
    │                              │
    │<════ SSE Connection ═════════│
    │                              │

그리고 서버는 이 SSE 연결을 통해 Client가 메시지를 보낼 HTTP endpoint를 알려줄 수 있었습니다.

개념적으로 다음과 같은 구조입니다.

                  SSE
MCP Client <════════════════ MCP Server
    │
    │
    │ POST message
    └──────────────────────> MCP Server

즉 메시지 흐름을 단순화하면:

Client → Server
    HTTP POST

Server → Client
    SSE

였습니다.

그래서 두 개의 통신 경로를 관리하게 됩니다.

          POST
Client ─────────────> Server

          SSE
Client <═════════════ Server

동작은 가능하지만 구조가 조금 복잡합니다.


7. Streamable HTTP에서는 구조가 단순해진다

Streamable HTTP에서는 MCP 통신을 하나의 MCP HTTP endpoint 중심으로 구성할 수 있습니다.

예를 들어:

POST /mcp

입니다.

Client가 메시지를 보냅니다.

Client
   │
   │ POST /mcp
   ▼
MCP Server

서버는 요청 특성에 따라 적절한 Response를 반환합니다.

                  POST /mcp
                      │
                      ▼
                 MCP Server
                      │
          ┌───────────┴───────────┐
          │                       │
          ▼                       ▼
  application/json        text/event-stream
          │                       │
          ▼                       ▼
     JSON Response            SSE Stream

이렇게 보면 Streamable HTTP라는 이름이 훨씬 이해하기 쉬워집니다.


8. 그런데 GET은 왜 필요할까?

여기서 조금 더 깊이 들어가보겠습니다.

Streamable HTTP에서 핵심은 POST이지만, 경우에 따라 Client가 서버에서 발생하는 메시지를 받기 위한 SSE Stream을 열 수 있습니다.

개념적으로는 다음과 같습니다.

MCP Client                     MCP Server
    │                              │
    │──── GET /mcp ───────────────>│
    │                              │
    │<════ SSE Stream ═════════════│
    │                              │

이 연결을 통해 서버가 Client에게 메시지를 전달할 수 있습니다.

즉 전체적으로 보면 이런 형태가 가능합니다.

                POST /mcp
Client ─────────────────────────> Server


                 GET /mcp
Client ─────────────────────────> Server
Client <════════ SSE ════════════ Server

여기서 중요한 것은 모든 요청마다 반드시 SSE 연결이 필요한 것은 아니라는 점입니다.

필요한 통신 패턴에 따라 사용할 수 있습니다.


9. 하나의 Endpoint가 중요한 이유

기존 구조를 다시 보겠습니다.

/sse

/messages

처럼 통신 역할이 나뉘어 있을 수 있었습니다.

Streamable HTTP에서는 개념적으로 다음처럼 단순화됩니다.

/mcp

그리고 HTTP Method가 역할을 구분합니다.

POST /mcp
    │
    └── Client → Server message


GET /mcp
    │
    └── Server → Client SSE stream

이 구조는 일반적인 HTTP 인프라와도 잘 맞습니다.

예를 들어:

Client
   │
   ▼
Load Balancer
   │
   ▼
API Gateway / Reverse Proxy
   │
   ▼
MCP Server

기존 HTTP 운영 환경에서 다루기 훨씬 자연스러운 구조가 됩니다.


10. HTTP 인프라를 그대로 활용할 수 있다

WebSocket은 매우 강력하지만 일반 HTTP와 연결 생명주기가 다릅니다.

HTTP

Request
   ↓
Response
   ↓
End

WebSocket은 연결을 Upgrade한 뒤 장시간 유지합니다.

HTTP
 │
 │ Upgrade
 ▼
WebSocket
 │
 │
 │ persistent connection
 │
 │
 ▼

반면 Streamable HTTP는 기본적으로 HTTP의 세계에 남아 있습니다.

HTTP POST

HTTP GET

HTTP Status

HTTP Header

Authentication

Proxy

Load Balancer

따라서 기존 웹 인프라와 자연스럽게 통합할 수 있다는 장점이 있습니다.

특히 MCP Server를 실제 운영 환경에 배포한다고 생각하면 이 차이가 중요해집니다.


11. Stateless하게 사용할 수도 있다

Streamable HTTP의 또 다른 중요한 특징은 반드시 모든 Client 연결에 대해 무거운 장기 세션 상태를 유지해야 하는 것은 아니라는 점입니다.

예를 들어 아주 단순한 MCP Server라면:

Client
   │
   │ POST tools/call
   ▼
Server
   │
   │ Tool 실행
   ▼
Response

요청 하나가 끝나면 서버가 별도의 연결 상태를 유지하지 않아도 됩니다.

이런 구조는 서버 확장에도 유리합니다.

                 Load Balancer
                       │
          ┌────────────┼────────────┐
          ▼            ▼            ▼
      MCP #1        MCP #2        MCP #3

특정 Client가 반드시 같은 서버 프로세스에 계속 붙어 있어야 하는 구조보다 운영이 단순해질 수 있습니다.

물론 실제 MCP 시스템에서는 세션이 필요한 경우도 있습니다.

중요한 것은 Transport 자체가 모든 통신을 하나의 영구 연결에 강하게 묶지 않는다는 것입니다.


12. Session이 필요한 경우도 있다

반대로 Client와 Server 사이에 상태를 유지해야 하는 경우도 있습니다.

예를 들어 Server가 Client에게 Session ID를 제공한다고 생각해봅시다.

Client                         Server
   │                              │
   │──── initialize ─────────────>│
   │                              │
   │<──── Session ID: abc123 ─────│

이후 Client는 해당 Session을 식별해서 요청할 수 있습니다.

POST /mcp

Mcp-Session-Id: abc123

개념적으로 보면:

Client
   │
   │ Session abc123
   │
   ├──── tools/list
   │
   ├──── tools/call
   │
   └──── resources/read
   │
   ▼
MCP Server

따라서 Streamable HTTP는 단순한 Stateless HTTP만을 의미하는 것도 아닙니다.

필요한 경우 Session을 유지할 수도 있습니다.


13. 그래서 Streamable HTTP는 양방향인가?

여기서 재미있는 질문이 생깁니다.

Streamable HTTP는 양방향 통신인가?

WebSocket과 같은 의미의 Full-Duplex 양방향 연결이라고 생각하면 조금 다릅니다.

WebSocket은 하나의 연결에서 양쪽이 자유롭게 메시지를 보냅니다.

Client <════════════════════> Server

Streamable HTTP는 기본적으로 HTTP Request와 Response 모델을 사용합니다.

Client ───── Request ───────> Server
Client <──── Response ─────── Server

필요한 경우 서버 방향의 스트림을 추가할 수 있습니다.

Client ───── GET ───────────> Server
Client <════ SSE ════════════ Server

따라서 통신 결과만 보면 양쪽 방향의 메시지를 처리할 수 있지만,

WebSocket처럼 하나의 Full-Duplex 연결을 만드는 방식과는 구조적으로 다릅니다.


14. 세 가지를 다시 비교해보자

이제 SSE, WebSocket, Streamable HTTP를 한 번에 비교해보겠습니다.

SSE

Server ───────────────────> Client

특징:

  • Server → Client 스트리밍
  • HTTP 기반
  • 단순한 이벤트 스트림
  • LLM 응답이나 진행 상태 전달에 적합

WebSocket

Server <══════════════════> Client

특징:

  • Full-Duplex
  • 지속적인 연결
  • 양쪽에서 자유롭게 메시지 전송
  • 실시간 상호작용에 적합

Streamable HTTP

Client ───── POST ─────────> Server
Client <──── JSON ────────── Server

필요한 경우

Client <════ SSE ═══════════ Server

특징:

  • HTTP Request/Response 중심
  • 필요할 때 Streaming
  • SSE 사용 가능
  • RPC 형태의 통신에 적합
  • 기존 HTTP 인프라와 잘 맞음

즉 셋은 누가 더 좋은 기술인가를 비교하는 관계가 아닙니다.

해결하려는 문제가 다릅니다.


15. 실제 AI 서비스에서는 어떻게 사용할까?

이제 실제 시스템에 적용해봅시다.

사용자가 웹에서 인보이스를 업로드하고 AI Agent가 이를 분석한다고 가정하겠습니다.

전체 구조는 다음과 같습니다.

Browser
   │
   │ POST /analyze
   ▼
FastAPI
   │
   ▼
Agent
   │
   │ MCP
   ▼
MCP Client
   │
   │ Streamable HTTP
   ▼
MCP Server
   │
   ├── OCR Tool
   ├── Invoice Parser
   └── Validation Tool

여기서 두 종류의 스트리밍이 존재할 수 있습니다.

첫 번째는 사용자 경험을 위한 스트리밍입니다.

FastAPI
   │
   ├── "분석 시작"
   ├── "OCR 진행 중"
   ├── "필드 추출 중"
   └── "완료"
        │
        ▼
      Browser

이 구간에서는 SSE가 좋은 선택이 될 수 있습니다.

FastAPI ═════ SSE ═════> Browser

반면 Agent와 MCP Server 사이에서는 Tool 호출이라는 RPC적인 통신이 발생합니다.

Agent
  │
  │ tools/call
  ▼
MCP Server
  │
  │ Tool 실행
  ▼
Result

여기에서는 Streamable HTTP가 자연스럽습니다.

Agent ══ Streamable HTTP ══> MCP Server

즉 같은 시스템 안에서도 서로 다른 통신 방식이 사용될 수 있습니다.


16. SSE와 Streamable HTTP는 경쟁 관계가 아니다

이 시리즈에서 가장 강조하고 싶은 부분입니다.

처음에는 이렇게 생각하기 쉽습니다.

SSE vs Streamable HTTP

마치 Streamable HTTP가 SSE를 대체하기 위해 등장한 새로운 스트리밍 기술처럼 느껴집니다.

하지만 실제 시스템에서는 이렇게 보는 편이 더 정확합니다.

Web Application

Browser
   │
   │ SSE
   ▼
FastAPI


Agent System

Agent
   │
   │ Streamable HTTP
   ▼
MCP Server

두 기술은 서로 다른 구간에서 서로 다른 문제를 해결할 수 있습니다.

Browser와 FastAPI 사이에서는 사용자가 작업 진행 상황이나 LLM의 생성 결과를 실시간으로 받아야 할 수 있습니다.

Browser <════ SSE ════ FastAPI

이때 SSE는 매우 단순하고 효과적인 방법입니다.

반면 Agent와 MCP Server 사이에서는 단순한 이벤트 전달보다 Tool 호출, Request/Response, Notification, Session 같은 RPC적인 통신이 중요합니다.

Agent ──── tools/call ──────> MCP Server
Agent <──── result ────────── MCP Server

이런 구간에서는 Streamable HTTP가 더 자연스럽습니다.

따라서 둘의 관계를

SSE
 ↓
구식 기술

Streamable HTTP
 ↓
새로운 기술

처럼 이해해서는 안 됩니다.

오히려 다음과 같이 보는 편이 좋습니다.

SSE
│
└── Server → Client Streaming


Streamable HTTP
│
├── HTTP Request / Response
│
└── 필요할 경우 SSE Streaming

그리고 중요한 사실이 하나 있습니다.

Streamable HTTP 자체도 필요할 때 SSE를 사용합니다.

즉 SSE는 Streamable HTTP의 경쟁자가 아니라, Streamable HTTP가 스트리밍을 구현할 때 활용할 수 있는 메커니즘이기도 합니다.


17. 왜 MCP는 이런 구조가 필요했을까?

이제 다시 MCP의 목적을 생각해봅시다.

MCP Server는 단순한 스트리밍 서버가 아닙니다.

AI Agent에게 외부 기능을 제공하는 서버입니다.

예를 들어 다음과 같은 Tool이 있다고 해보겠습니다.

search_documents()

analyze_invoice()

send_email()

query_database()

generate_report()

Agent는 필요한 순간에 특정 Tool을 호출합니다.

Agent
  │
  │ tools/call
  ▼
MCP Server
  │
  ▼
Tool

대부분의 Tool 호출은 매우 자연스러운 Request/Response 구조를 가집니다.

Request

"이 Tool을 실행해줘"

        ↓

Tool 실행

        ↓

Response

"결과는 이것이야"

그런데 Tool의 특성은 모두 다릅니다.

어떤 Tool은 100ms 안에 끝날 수 있습니다.

get_current_time()

      ↓

   100ms

      ↓

   Result

어떤 Tool은 수십 초가 걸릴 수도 있습니다.

analyze_invoice()

      ↓

PDF Rendering

      ↓

VLM Analysis

      ↓

Field Extraction

      ↓

Validation

      ↓

Result

따라서 MCP Transport는 두 가지 상황을 모두 다룰 수 있어야 합니다.

짧은 작업
   │
   ▼
Request / Response


긴 작업
   │
   ▼
Request / Streaming / Response

Streamable HTTP는 바로 이런 특성에 잘 맞습니다.


18. WebSocket을 기본 Transport로 사용하지 않는 이유도 보인다

여기까지 이해하면 처음에 했던 질문으로 다시 돌아갈 수 있습니다.

그냥 WebSocket을 사용하면 더 간단하지 않을까?

WebSocket을 사용하면 물론 양방향 메시징을 구현할 수 있습니다.

MCP Client <══════════════> MCP Server

하지만 MCP의 대부분의 동작은 본질적으로 RPC에 가깝습니다.

tools/list

tools/call

resources/read

prompts/get

즉 기본 패턴은 다음과 같습니다.

Request
   │
   ▼
Server Processing
   │
   ▼
Response

모든 요청을 처리하기 위해 반드시 영구적인 Full-Duplex 연결을 유지해야 하는 것은 아닙니다.

HTTP가 이미 잘 처리하고 있는 문제를 굳이 다른 통신 모델로 바꿀 필요가 없는 것입니다.

또 실제 운영 환경을 생각하면 HTTP가 가진 장점도 큽니다.

Reverse Proxy

Load Balancer

Authentication

HTTP Header

HTTP Status

Observability

Rate Limiting

Existing Infrastructure

많은 인프라가 이미 HTTP를 중심으로 만들어져 있습니다.

Streamable HTTP는 이런 생태계를 그대로 활용할 수 있습니다.


19. 이름에 답이 있다

이제 다시 이름을 보겠습니다.

Streamable HTTP

처음에는 조금 애매하게 느껴졌던 이름이 이제는 꽤 정확하게 보입니다.

핵심은 이것입니다.

HTTP를 사용한다. 그리고 필요한 경우 Stream할 수 있다.

즉,

HTTP
 │
 ├── 일반 Response 가능
 │
 └── Streaming Response 가능

입니다.

항상 연결을 유지하는 것도 아니고,

항상 SSE를 사용하는 것도 아니며,

항상 Streaming하는 것도 아닙니다.

필요한 통신 방식에 따라 HTTP의 Response 형태를 선택할 수 있습니다.

그래서 Streaming HTTP가 아니라 Streamable HTTP입니다.


20. 세 기술을 한 문장으로 정리하면

이제 SSE, WebSocket, Streamable HTTP를 아주 단순하게 정리해보겠습니다.

SSE

서버가 클라이언트에게 지속적으로 데이터를 보내고 싶다.

Server ─────────────────> Client

LLM 답변, 작업 진행 상황, 알림 등에 잘 맞습니다.


WebSocket

클라이언트와 서버가 지속적으로 서로 메시지를 주고받고 싶다.

Server <════════════════> Client

채팅, 게임, 협업 시스템처럼 지속적인 Full-Duplex 통신에 잘 맞습니다.


Streamable HTTP

HTTP Request/Response를 기본으로 사용하면서 필요한 경우 스트리밍도 하고 싶다.

Client ───── Request ─────> Server
Client <──── Response ───── Server

          또는

Client ───── Request ─────> Server
Client <════ SSE Stream ═══ Server

RPC 기반의 MCP 통신에 잘 맞습니다.


21. 실제 시스템에서는 함께 사용한다

중요한 것은 하나의 기술을 선택해서 시스템 전체에 적용해야 하는 것이 아니라는 점입니다.

예를 들어 AI 기반 인보이스 분석 서비스를 만든다고 생각해보겠습니다.

┌──────────────┐
│   Browser    │
└──────┬───────┘
       │
       │ HTTP
       ▼
┌──────────────┐
│   FastAPI    │
└──────┬───────┘
       │
       │
       ▼
┌──────────────┐
│    Agent     │
└──────┬───────┘
       │
       │ MCP
       ▼
┌──────────────┐
│  MCP Server  │
└──────┬───────┘
       │
       ├── OCR Tool
       ├── Parser Tool
       └── Validation Tool

여기서 Browser와 FastAPI 사이에서는 사용자에게 진행 상황을 보여주고 싶을 수 있습니다.

Browser <════ SSE ════ FastAPI

"파일 업로드 완료"

"OCR 진행 중"

"데이터 추출 중"

"검증 중"

"완료"

반면 Agent와 MCP Server 사이에서는 Tool 호출이 이루어집니다.

Agent
  │
  │ tools/call
  ▼
MCP Server
  │
  ▼
OCR Tool

이 구간에서는 Streamable HTTP를 사용할 수 있습니다.

Browser
   │
   │ SSE
   ▼
FastAPI
   │
   ▼
Agent
   │
   │ Streamable HTTP
   ▼
MCP Server

이 그림을 보면 SSE와 Streamable HTTP를 왜 단순 비교해서는 안 되는지 명확해집니다.

사용되는 계층과 해결하는 문제가 다르기 때문입니다.


22. 결국 중요한 것은 Transport가 아니라 요구사항이다

개발하다 보면 새로운 기술이 등장할 때마다 이런 질문을 하게 됩니다.

SSE가 좋은가?

WebSocket이 좋은가?

Streamable HTTP가 좋은가?

하지만 사실 이 질문에는 정답이 없습니다.

먼저 물어야 하는 것은 이것입니다.

데이터는 어느 방향으로 흐르는가?

연결을 계속 유지해야 하는가?

Request / Response 관계가 중요한가?

서버가 임의의 시점에 메시지를 보내야 하는가?

스트리밍이 항상 필요한가?

세션 상태를 유지해야 하는가?

기존 HTTP 인프라를 활용해야 하는가?

이 요구사항이 정해진 뒤 Transport를 선택해야 합니다.

예를 들어 단순한 LLM 스트리밍이라면:

SSE

만으로 충분할 수 있습니다.

실시간 협업 시스템이라면:

WebSocket

이 자연스러울 수 있습니다.

Agent와 Tool Server 사이의 RPC 통신이라면:

Streamable HTTP

가 좋은 선택이 될 수 있습니다.

기술을 먼저 선택하고 시스템을 거기에 맞추는 것이 아니라,

통신의 특성을 먼저 이해하고 그에 맞는 기술을 선택하는 것이 중요합니다.


마치며

이번 시리즈는 아주 단순한 질문에서 시작했습니다.

HTTP는 Response를 한 번 보내는데 어떻게 데이터를 계속 전달할 수 있을까?

1부에서는 그 답으로 SSE를 살펴봤습니다.

HTTP Response
   │
   ├── data
   ├── data
   ├── data
   └── end

그리고 2부에서는 SSE만으로 모든 통신 문제를 해결할 수 없다는 것을 살펴봤습니다.

복잡한 AI 시스템에서는 단순한 스트리밍뿐 아니라 다음과 같은 메시지의 관계가 중요했습니다.

Request

Response

Notification

Streaming

Session

그리고 이번 3부에서는 MCP가 왜 Streamable HTTP라는 방식을 사용하는지 살펴봤습니다.

Streamable HTTP의 핵심은 의외로 단순합니다.

HTTP Request/Response를 기본으로 사용하고, 필요한 경우 스트리밍할 수 있도록 한다.

그래서 일반적인 요청은 평범한 HTTP Response로 끝날 수 있습니다.

Request
   │
   ▼
JSON Response

하지만 스트리밍이 필요하다면 SSE를 사용할 수도 있습니다.

Request
   │
   ▼
SSE Stream
   │
   ├── message
   ├── message
   ├── message
   └── end

즉 Streamable HTTP는 SSE를 버린 것이 아닙니다.

오히려 HTTP와 SSE를 필요한 상황에 맞게 활용할 수 있도록 Transport 구조를 정리한 것에 가깝습니다.

그리고 이 구조는 MCP처럼 다양한 Tool을 호출하는 AI Agent 시스템과 잘 맞습니다.

Browser
   │
   │ SSE
   ▼
FastAPI
   │
   ▼
Agent
   │
   │ Streamable HTTP
   ▼
MCP Server
   │
   ├── Tool
   ├── Tool
   └── Tool

결국 중요한 것은 어떤 기술이 더 최신인가가 아닙니다.

어떤 구간에서 어떤 종류의 통신이 필요한가를 이해하는 것입니다.

SSE, WebSocket, Streamable HTTP는 서로를 대체하기 위해 존재하는 기술이라기보다 각자 다른 통신 문제를 해결하기 위한 도구입니다.

이 차이를 이해하면 AI Agent와 MCP 기반 시스템을 설계할 때 Transport를 훨씬 명확하게 선택할 수 있습니다.


시리즈 정리

1부

HTTP 연결 하나로 데이터를 계속 보내는 SSE

HTTP Response와 Streaming의 기본 원리를 살펴봤습니다.

2부

SSE만으로는 부족한가? 양방향 통신과 RPC의 문제

SSE와 WebSocket의 차이, 그리고 MCP에서 Request/Response와 Notification이 왜 중요한지 살펴봤습니다.

3부

MCP는 왜 Streamable HTTP를 사용하는가

HTTP Request/Response와 SSE Streaming을 함께 활용하는 Streamable HTTP의 구조와 MCP에서 이 방식이 필요한 이유를 살펴봤습니다.