Streamable HTTP란 무엇인가?
목차
- Streamable HTTP란 무엇인가?
- SSE(Server-Sent Events)와 무엇이 다른가?
- Streamable HTTP의 장점
- Streamable HTTP의 단점 및 주의사항
- 언제 Streamable HTTP를 쓰면 좋나?
- Python-FastMCP
- Java-Spring AI
Streamable HTTP란 무엇인가?
Streamable HTTP는 Model Context Protocol(MCP)의 표준 전송 방식 중 하나로
MCP 서버를 HTTP 기반의 독립 프로세스로 띄우고 여러 클라이언트가 동시에 접속해 양방향 통신을 할 수 있게 하는 프로토콜이다.
요청→서버: 각 JSON-RPC 메시지를 개별 HTTP POST로 보낸다.
서버→클라이언트: 서버는 응답을 단일 JSON으로 돌려줄 수도 있고 SSE(text/event-stream)로 스트림을 열어 다중 메시지를 연속 전송할 수도 있다.
또한 클라이언트가 별도의 HTTP GET으로 서버의 알림 스트림을 구독할 수도 있다.
MCP 사양은 기존 HTTP+SSE
운용 방식을 대체하는 것으로 Streamable HTTP를 명시하고 보안 권고 및 세션/재전송 등 운용 세부를 규정한다.
SSE(Server-Sent Events)와 무엇이 다른가?
전통적인 SSE는 서버→클라이언트 단방향 스트리밍이다.
클라이언트의 상호작용은 보통 별도 HTTP 요청/폴링이나 다른 채널이 필요해 완전한 양방향 흐름을 만들기 번거롭다.
반면 Streamable HTTP는 POST(클라이언트→서버) 와 SSE/JSON(서버→클라이언트) 를 하나의 MCP 엔드포인트에서 통합 운용한다.
요청-응답과 실시간 스트림을 한 프로토콜로 다루므로 도구 실행 중간 진행 이벤트, 리소스/프롬프트 변경 알림, 추가 쿼리 요청 같은 서버발 메시지를 자연스럽게 끼워 넣을 수 있다.
Streamable HTTP의 장점
- 진짜 양방향 흐름
- 클라이언트 요청은 POST로, 서버 응답은 JSON 또는 SSE 스트림으로 다중 메시지 전달이 가능해서 중간 진행 상황(progress)·로그·부분 결과 등을 실시간으로 보낼 수 있다.
- 별도 웹소켓 없이도 실시간 상호작용 UX를 만들기 쉽다.
- 멀티 클라이언트·네트워크 배포에 적합
- 하나의 서버가 동시에 여러 클라이언트를 처리하고, 표준 HTTP 인프라(리버스 프록시, 인증 게이트웨이, 로깅, 모니터링)와 잘 맞는다.
- 세션·재전송·프로토콜 버전 협상
- 사양이 세션 ID, Last-Event-ID 기반 스트림 재개, MCP-Protocol-Version 헤더를 정의해 연결 끊김 회복·하위 호환 시나리오를 표준화한다.
- 레거시 SSE 대비 이관이 쉬움
- 사양이 백워드 컴패티빌리티 가이드를 제공해 구형 HTTP+SSE 서버/클라이언트와의 공존 전략을 제시한다.
Streamable HTTP의 단점 및 주의사항
- 구현 복잡도 증가
- 단순 SSE보다 요청 경로(POST)·스트림 경로(GET/SSE)·세션·재전송 등 고려할 지점이 많아진다.
- 잘못 구현하면 중복 전송/유실/순서 보장 문제가 생길 수 있으니 사양의 제약(응답을 스트림에서 반드시 완료 후 종료 등)을 지켜야 한다.
- SSE의 인프라 제약은 여전히 존재
- 서버→클라이언트 스트림은 SSE를 활용하므로, 프록시/로드밸런서의 타임아웃, HTTP/2 전환, 헤더 버퍼 같은 이슈를 점검해야 한다.
- 보안 고려 필수
- 사양은 Origin 헤더 검증, 로컬 바인딩(127.0.0.1), 인증 적용을 강하게 권고한다.
- 특히 DNS Rebinding 공격에 취약할 수 있으므로 방어가 필요하다.
- 레거시 클라이언트 호환성
- 구형 SSE 전용 클라이언트와는 바로 호환되지 않을 수 있다.
- 사양이 제시한 폴백 절차(405/404 시 구형 프로토콜로 전환)를 구현해야 무중단 전환이 가능하다.
언제 Streamable HTTP를 쓰면 좋나?
툴 실행 과정의 중간 단계, 로그, 토큰 스트리밍 등 부분 결과를 즉시 보여줘야 하는 UX
멀티 사용자·멀티 세션 환경, 중앙 서버로 MCP를 네트워크에 공개해야 하는 경우
리소스/도구/프롬프트 변경 알림 같이 서버발 이벤트가 중요한 시스템
이미 HTTP 인프라(인증 프록시, API 게이트웨이, 관측·모니터링)를 보유한 조직
반대로 단일 사용자/로컬에서 간단히 붙이는 용도라면 STDIO가 더 간단하고 정말 단순한 서버→클라이언트 알림만 필요하다면 구형 SSE도(레거시지만) 충분할 수 있다.
Python-FastMCP
Python의 FastMCP가 Streamable HTTP 전송으로 제공하고 SSE 전송은 레거시로 분류해 신규 프로젝트에선 HTTP 사용을 권장한다.
Streamable HTTP MCP 서버
1
2
3
4
5
6
7
8
9
10
from fastmcp import FastMCP
mcp = FastMCP("MyServer")
@mcp.tool
def hello(name: str) -> str:
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run(transport="http", host="127.0.0.1", port=8000)
Streamable HTTP MCP 클라이언트
1
2
3
4
5
6
7
8
9
10
11
12
13
from fastmcp.client.transports import StreamableHttpTransport
transport = StreamableHttpTransport(url="https://api.example.com/mcp")
client = Client(transport)
transport = StreamableHttpTransport(
url="https://api.example.com/mcp",
headers={
"Authorization": "Bearer your-token-here",
"X-Custom-Header": "value"
}
)
client = Client(transport)
Java-Spring AI
Spring AI가 STREAMABLE 프로토콜을 제공하며 WebMVC/WebFlux 스타터로 스트리머블 서버를 간단히 구성하고 도구/리소스/프롬프트 변경 알림, keep-alive(ping) 등의 운용 옵션을 지원한다.
Streamable HTTP MCP 서버
- 의존성 추가 (maven 방식)
1 2 3 4 5 6 7 8 9
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-client</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-client-webflux</artifactId> </dependency>
- 의존성 추가 (gradle 방식)
1 2 3 4
dependencies { implementation 'org.springframework.ai:spring-ai-starter-mcp-server-webmvc:1.1-SNAPSHOT' implementation 'org.springframework.ai:spring-ai-starter-mcp-client-webflux:1.1-SNAPSHOT' }
- 서버 설정
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
spring: ai: mcp: server: protocol: STREAMABLE name: streamable-mcp-server version: 1.0.0 type: SYNC instructions: "This streamable server provides real-time notifications" resource-change-notification: true tool-change-notification: true prompt-change-notification: true streamable-http: mcp-endpoint: /api/mcp keep-alive-interval: 30s
- sever 구현 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Service
public class WeatherService {
@Tool(description = "Get weather information by city name")
public String getWeather(String cityName) {
// Implementation
}
}
@SpringBootApplication
public class McpServerApplication {
private static final Logger logger = LoggerFactory.getLogger(McpServerApplication.class);
public static void main(String[] args) {
SpringApplication.run(McpServerApplication.class, args);
}
@Bean
public ToolCallbackProvider weatherTools(WeatherService weatherService) {
return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
}
}
Streamable HTTP MCP 클라이언트
- 의존성 추가 (maven 방식)
1 2 3 4
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-client</artifactId> </dependency>
- 의존성 추가 (gradle 방식)
1 2 3
dependencies { implementation 'org.springframework.ai:spring-ai-starter-mcp-client' }
- 클라이언트 설정
1 2 3 4 5 6 7 8 9 10 11
spring: ai: mcp: client: streamable-http: connections: server1: url: http://localhost:8080 server2: url: http://otherserver:8081 endpoint: /custom-sse
- 클라이언트 구현 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Value("${ai.user.input}") private String userInput; @Bean public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, ToolCallbackProvider tools, ConfigurableApplicationContext context) { return args -> { var chatClient = chatClientBuilder .defaultToolCallbacks(tools) .build(); System.out.println("\n>>> QUESTION: " + userInput); System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(userInput).call().content()); context.close(); }; } }
참고 문서
- FastMCP
- https://gofastmcp.com/deployment/running-server
- https://gofastmcp.com/clients/transports
- Spring AI
- https://docs.spring.io/spring-ai/reference/1.1-SNAPSHOT/api/mcp/mcp-streamable-http-server-boot-starter-docs.html
- https://docs.spring.io/spring-ai/reference/1.1-SNAPSHOT/api/mcp/mcp-client-boot-starter-docs.html
- MCP
- https://modelcontextprotocol.io/specification/2025-06-18/basic/transports