Streamable-HTTP MCP 서버
Streamable-HTTP MCP 서버 (Streamable-HTTP MCP Servers)
Streamable HTTP 전송은 MCP 서버가 HTTP POST와 GET 요청으로 여러 클라이언트 연결을 처리할 수 있는 독립 프로세스로 동작하게 하고, 여러 서버 메시지에 대해 선택적 Server-Sent Events (SSE) 스트리밍을 지원해요. 기존 SSE 전송을 대체하며, 도구·리소스·프롬프트의 동적 변경을 클라이언트에 알려야 하는 애플리케이션에 적합해요.
출처: 문서
본문
Streamable-HTTP MCP 서버 (Streamable-HTTP MCP Servers)
Streamable HTTP 전송은 MCP 서버가 HTTP POST와 GET 요청을 사용해 여러 클라이언트 연결을 처리할 수 있는 독립 프로세스로 동작하게 해 주고, 여러 서버 메시지에 대해 선택적 Server-Sent Events (SSE) 스트리밍을 지원해요. 그것은 SSE 전송을 대체해요.
스펙 버전 2025-03-26에 도입된 이 서버들은 도구, 리소스, 프롬프트의 동적 변경을 클라이언트에 알려야 하는 애플리케이션에 이상적이에요.
참고:
spring.ai.mcp.server.protocol=STREAMABLE프로퍼티를 설정하세요.
참고: Streamable-HTTP 서버에 연결하려면 Streamable-HTTP 클라이언트를 사용하세요.
Streamable-HTTP WebMVC 서버
spring-ai-starter-mcp-server-webmvc 의존성을 사용하세요:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
그리고 spring.ai.mcp.server.protocol 프로퍼티를 STREAMABLE로 설정하세요.
- Spring MVC Streamable 전송과 함께 완전한 MCP 서버 기능
- 도구, 리소스, 프롬프트, 완성, 로깅, 진행, ping, root-changes 기능 지원
- 영구 연결 관리
Streamable-HTTP WebFlux 서버
spring-ai-starter-mcp-server-webflux 의존성을 사용하세요:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
그리고 spring.ai.mcp.server.protocol 프로퍼티를 STREAMABLE로 설정하세요.
- WebFlux Streamable 전송과 함께 반응형 MCP 서버
- 도구, 리소스, 프롬프트, 완성, 로깅, 진행, ping, root-changes 기능 지원
- 블로킹되지 않는 영구 연결 관리
구성 프로퍼티 (Configuration Properties)
공통 프로퍼티 (Common Properties)
모든 공통 프로퍼티는 spring.ai.mcp.server 프리픽스가 붙어요:
| Property | Description | Default |
|---|---|---|
enabled |
streamable MCP 서버 활성화/비활성화 | true |
protocol |
MCP 서버 프로토콜 | streamable 서버를 활성화하려면 STREAMABLE로 설정해야 함 |
tool-callback-converter |
Spring AI ToolCallback을 MCP Tool 스펙으로 변환 활성화/비활성화 | true |
name |
식별을 위한 서버 이름 | mcp-server |
version |
서버 버전 | 1.0.0 |
instructions |
클라이언트 상호작용을 위한 선택적 지침 | null |
type |
서버 타입 (SYNC/ASYNC) | SYNC |
capabilities.resource |
리소스 기능 활성화/비활성화 | true |
capabilities.tool |
도구 기능 활성화/비활성화 | true |
capabilities.prompt |
프롬프트 기능 활성화/비활성화 | true |
capabilities.completion |
완성 기능 활성화/비활성화 | true |
resource-change-notification |
리소스 변경 알림 활성화 | true |
prompt-change-notification |
프롬프트 변경 알림 활성화 | true |
tool-change-notification |
도구 변경 알림 활성화 | true |
expose-mcp-client-tools |
다운스트림 MCP 도구(MCP 클라이언트가 제공)를 이 MCP 서버의 도구로 다시 노출할지 여부 | false |
tool-response-mime-type |
도구 이름별 응답 MIME 타입 | - |
request-timeout |
요청 타임아웃 기간 | 20 seconds |
MCP 어노테이션 프로퍼티 (MCP Annotations Properties)
MCP 서버 어노테이션은 Java 어노테이션을 사용해 MCP 서버 핸들러를 선언적으로 구현하는 방법을 제공해요. 서버 mcp-annotations 프로퍼티는 spring.ai.mcp.server.annotation-scanner 프리픽스가 붙어요:
| Property | Description | Default Value |
|---|---|---|
enabled |
MCP 서버 어노테이션 자동 스캔 활성화/비활성화 | true |
Streamable-HTTP 프로퍼티 (Streamable-HTTP Properties)
모든 streamable-HTTP 프로퍼티는 spring.ai.mcp.server.streamable-http 프리픽스가 붙어요:
| Property | Description | Default |
|---|---|---|
mcp-endpoint |
커스텀 MCP 엔드포인트 경로 | /mcp |
keep-alive-interval |
연결 keep-alive 간격 | null (비활성) |
disallow-delete |
delete 작업 금지 | false |
기능과 역량 (Features and Capabilities)
MCP 서버는 개별적으로 활성화하거나 비활성화할 수 있는 네 가지 주요 기능 타입을 지원해요:
- 도구 (Tools) -
spring.ai.mcp.server.capabilities.tool=true|false로 도구 기능 활성화/비활성화 - 리소스 (Resources) -
spring.ai.mcp.server.capabilities.resource=true|false로 리소스 기능 활성화/비활성화 - 프롬프트 (Prompts) -
spring.ai.mcp.server.capabilities.prompt=true|false로 프롬프트 기능 활성화/비활성화 - 완성 (Completions) -
spring.ai.mcp.server.capabilities.completion=true|false로 완성 기능 활성화/비활성화
모든 기능은 기본적으로 활성화돼 있어요. 기능을 비활성화하면 서버가 해당 기능을 등록하고 클라이언트에 노출하는 것을 막게 돼요.
MCP Server Boot Starter는 서버가 도구, 리소스, 프롬프트를 클라이언트에 노출할 수 있게 해 줘요. Spring 빈으로 등록된 커스텀 기능 핸들러를 서버 타입에 따라 자동으로 동기/비동기 명세로 변환해요:
도구 (Tools)
언어 모델이 호출할 수 있는 도구를 서버가 노출할 수 있게 해 줘요. MCP Server Boot Starter는 다음을 제공해요:
- 변경 알림 지원
- Spring AI 도구를 서버 타입에 따라 자동으로 동기/비동기 명세로 변환
- Spring 빈을 통한 자동 도구 명세:
@Bean
public ToolCallbackProvider myTools(...) {
List<ToolCallback> tools = ...
return ToolCallbackProvider.from(tools);
}
또는 저수준 API 사용:
@Bean
public List<McpServerFeatures.SyncToolSpecification> myTools(...) {
List<McpServerFeatures.SyncToolSpecification> tools = ...
return tools;
}
자동 설정은 다음에서 모든 도구 콜백을 자동으로 감지하고 등록해요:
- 개별
ToolCallback빈 ToolCallback빈 목록ToolCallbackProvider빈
도구는 이름으로 중복 제거되며, 각 도구 이름의 첫 번째 등장이 사용돼요.
참고:
tool-callback-converter를false로 설정하면 모든 도구 콜백의 자동 감지·등록을 비활성화할 수 있어요.
도구 컨텍스트 지원 (Tool Context Support)
ToolContext가 지원되어 도구 호출에 컨텍스트 정보를 전달할 수 있어요. exchange 키 아래에 McpSyncServerExchange 인스턴스를 담고 있으며, McpToolUtils.getMcpExchange(toolContext)로 접근할 수 있어요. exchange.loggingNotification(…)과 exchange.createMessage(…)을 보여 주는 예제를 참고하세요.
리소스 (Resources)
서버가 클라이언트에 리소스를 노출하는 표준화된 방법을 제공해요.
- 정적·동적 리소스 명세
- 선택적 변경 알림
- 리소스 템플릿 지원
- 동기/비동기 리소스 명세 간 자동 변환
- Spring 빈을 통한 자동 리소스 명세:
@Bean
public List<McpServerFeatures.SyncResourceSpecification> myResources(...) {
var systemInfoResource = McpSchema.Resource.builder(...);
var resourceSpecification = new McpServerFeatures.SyncResourceSpecification(systemInfoResource, (exchange, request) -> {
try {
var systemInfo = Map.of(...);
String jsonContent = new JsonMapper().writeValueAsString(systemInfo);
return McpSchema.ReadResourceResult.builder(
List.of(McpSchema.TextResourceContents.builder(request.uri(), jsonContent).mimeType("application/json").build())).build();
}
catch (Exception e) {
throw new RuntimeException("Failed to generate system info", e);
}
});
return List.of(resourceSpecification);
}
프롬프트 (Prompts)
서버가 클라이언트에 프롬프트 템플릿을 노출하는 표준화된 방법을 제공해요.
- 변경 알림 지원
- 템플릿 버전 관리
- 동기/비동기 프롬프트 명세 간 자동 변환
- Spring 빈을 통한 자동 프롬프트 명세:
@Bean
public List<McpServerFeatures.SyncPromptSpecification> myPrompts() {
var prompt = McpSchema.Prompt.builder("greeting").description("A friendly greeting prompt")
.arguments(List.of(McpSchema.PromptArgument.builder("name").title("The name to greet").required(true).build())).build();
var promptSpecification = new McpServerFeatures.SyncPromptSpecification(prompt, (exchange, getPromptRequest) -> {
String nameArgument = (String) getPromptRequest.arguments().get("name");
if (nameArgument == null) { nameArgument = "friend"; }
var userMessage = PromptMessage.builder(Role.USER, TextContent.builder("Hello " + nameArgument + "! How can I assist you today?").build()).build();
return GetPromptResult.builder(List.of(userMessage)).description("A personalized greeting message").build();
});
return List.of(promptSpecification);
}
완성 (Completions)
서버가 클라이언트에 완성 기능을 노출하는 표준화된 방법을 제공해요.
- 동기·비동기 완성 명세 모두 지원
- Spring 빈을 통한 자동 등록:
@Bean
public List<McpServerFeatures.SyncCompletionSpecification> myCompletions() {
var completion = new McpServerFeatures.SyncCompletionSpecification(
McpSchema.PromptReference.builder( "code-completion").title("Provides code completion suggestions").build(),
(exchange, request) -> {
// Implementation that returns completion suggestions
return new McpSchema.CompleteResult(List.of("python", "pytorch", "pyside"), 10, true);
}
);
return List.of(completion);
}
로깅 (Logging)
서버가 구조화된 로그 메시지를 클라이언트에 보내는 표준화된 방법을 제공해요. 도구, 리소스, 프롬프트 또는 완성 호출 핸들러 안에서 제공된 McpSyncServerExchange/McpAsyncServerExchange exchange 객체를 사용해 로깅 메시지를 보내요:
(exchange, request) -> {
exchange.loggingNotification(LoggingMessageNotification.builder(LoggingLevel.INFO, "This is a test log message")
.logger("test-logger")
.build());
}
MCP 클라이언트에서 로깅 consumer를 등록해 이 메시지를 처리할 수 있어요:
mcpClientSpec.loggingConsumer((McpSchema.LoggingMessageNotification log) -> {
// Handle log messages
});
진행 (Progress)
서버가 클라이언트에 진행 업데이트를 보내는 표준화된 방법을 제공해요. 도구, 리소스, 프롬프트 또는 완성 호출 핸들러 안에서 제공된 McpSyncServerExchange/McpAsyncServerExchange exchange 객체를 사용해 진행 알림을 보내요:
(exchange, request) -> {
exchange.progressNotification(ProgressNotification.builder("test-progress-token", 0.25)
.total(1.0)
.message("tool call in progress")
.build());
}
MCP 클라이언트는 진행 알림을 받아 그에 맞게 UI를 업데이트할 수 있어요. 이를 위해 진행 consumer를 등록해야 해요.
mcpClientSpec.progressConsumer((McpSchema.ProgressNotification progress) -> {
// Handle progress notifications
});
루트 목록 변경 (Root List Changes)
roots가 변경되면 listChanged를 지원하는 클라이언트가 루트 변경 알림을 보내요.
- 루트 변경 모니터링 지원
- 반응형 애플리케이션을 위한 비동기 consumer 자동 변환
- Spring 빈을 통한 선택적 등록
@Bean
public BiConsumer<McpSyncServerExchange, List<McpSchema.Root>> rootsChangeHandler() {
return (exchange, roots) -> {
logger.info("Registering root resources: {}", roots);
};
}
핑 (Ping)
서버가 클라이언트가 아직 살아 있는지 확인하는 핑 메커니즘. 도구, 리소스, 프롬프트 또는 완성 호출 핸들러 안에서 제공된 McpSyncServerExchange/McpAsyncServerExchange exchange 객체를 사용해 핑 메시지를 보내요:
(exchange, request) -> {
exchange.ping();
}
Keep Alive
서버는 선택적으로 연결된 클라이언트에 주기적으로 핑을 보내 연결 상태를 확인할 수 있어요. 기본적으로 keep-alive는 비활성화돼 있어요. keep-alive를 활성화하려면 구성에서 keep-alive-interval 프로퍼티를 설정하세요:
spring:
ai:
mcp:
server:
streamable-http:
keep-alive-interval: 30s
참고: 현재 streamable-http 서버에서는 keep-alive 메커니즘을 서버로부터의 메시지 수신 (SSE) 연결에서만 사용할 수 있어요.
사용 예시 (Usage Examples)
Streamable HTTP 서버 구성 (Streamable HTTP Server Configuration)
# Using spring-ai-starter-mcp-server-streamable-webmvc
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
MCP 서버로 Spring Boot 애플리케이션 만들기
@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();
}
}
자동 설정은 도구 콜백을 MCP 도구로 자동으로 등록해요. ToolCallback을 생성하는 빈이 여러 개 있어도 되며, 자동 설정이 그것들을 병합해요.