STDIO 및 SSE MCP 서버
STDIO 및 SSE MCP 서버 (STDIO and SSE MCP Servers)
STDIO와 SSE MCP 서버는 각각 전용 starter가 있는 여러 전송 메커니즘을 지원해요. STDIO는 명령줄·데스크톱 도구에 적합하고, SSE는 Spring MVC 또는 WebFlux 기반의 HTTP 실시간 스트리밍을 제공해요. 이 글에서 구성 프로퍼티와 기능을 차근차근 살펴볼게요.
출처: 문서
본문
STDIO 및 SSE MCP 서버 (STDIO and SSE MCP Servers)
STDIO와 SSE MCP 서버는 각각 전용 starter가 있는 여러 전송 메커니즘을 지원해요.
참고: STDIO 및 SSE 서버에 연결하려면 STDIO 클라이언트 또는 SSE 클라이언트를 사용하세요.
STDIO MCP 서버
STDIO 서버 전송과 함께 완전한 MCP 서버 기능 지원.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server</artifactId>
</dependency>
- 명령줄과 데스크톱 도구에 적합
- 추가 웹 의존성 불필요
- 기본 서버 컴포넌트 구성
- 도구, 리소스, 프롬프트 명세 처리
- 서버 기능과 변경 알림 관리
- 동기·비동기 서버 구현 모두 지원
SSE WebMVC 서버
Spring MVC 기반의 SSE(Server-Sent Events) 서버 전송과 선택적 STDIO 전송과 함께 완전한 MCP 서버 기능 지원.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
- Spring MVC를 사용한 HTTP 기반 전송 (
WebMvcSseServerTransportProvider) - 자동 구성된 SSE 엔드포인트
- 선택적
STDIO전송 (spring.ai.mcp.server.stdio=true로 활성화) spring-boot-starter-web과org.springframework.ai:mcp-spring-webmvc의존성 포함
SSE WebFlux 서버
Spring WebFlux 기반의 SSE(Server-Sent Events) 서버 전송과 선택적 STDIO 전송과 함께 완전한 MCP 서버 기능 지원.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
이 starter는 McpWebFluxServerAutoConfiguration와 McpServerAutoConfiguration 자동 구성을 활성화해 다음을 제공해요:
- Spring WebFlux를 사용한 반응형 전송 (
WebFluxSseServerTransportProvider) - 자동 구성된 반응형 SSE 엔드포인트
- 선택적
STDIO전송 (spring.ai.mcp.server.stdio=true로 활성화) spring-boot-starter-webflux와org.springframework.ai:mcp-spring-webflux의존성 포함
참고: Spring Boot의 기본 동작 때문에
org.springframework.web.servlet.DispatcherServlet과org.springframework.web.reactive.DispatcherHandler가 모두 클래스패스에 있으면 Spring Boot는DispatcherServlet을 우선시해요. 따라서 프로젝트가spring-boot-starter-web을 사용한다면spring-ai-starter-mcp-server-webflux대신spring-ai-starter-mcp-server-webmvc를 사용하는 것이 권장돼요.
구성 프로퍼티 (Configuration Properties)
공통 프로퍼티 (Common Properties)
모든 공통 프로퍼티는 spring.ai.mcp.server 프리픽스가 붙어요:
| Property | Description | Default |
|---|---|---|
enabled |
MCP 서버 활성화/비활성화 | true |
tool-callback-converter |
Spring AI ToolCallback을 MCP Tool 스펙으로 변환 활성화/비활성화 | true |
stdio |
STDIO 전송 활성화/비활성화 | false |
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 타입. 예를 들어 spring.ai.mcp.server.tool-response-mime-type.generateImage=image/png는 generateImage() 도구 이름에 image/png 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 |
SSE 프로퍼티 (SSE Properties)
모든 SSE 프로퍼티는 spring.ai.mcp.server 프리픽스가 붙어요:
| Property | Description | Default |
|---|---|---|
sse-message-endpoint |
클라이언트가 메시지를 보내기 위해 사용하는 웹 전송용 커스텀 SSE 메시지 엔드포인트 경로 | /mcp/message |
sse-endpoint |
웹 전송용 커스텀 SSE 엔드포인트 경로 | /sse |
base-url |
선택적 URL 프리픽스. 예를 들어 base-url=/api/v1이면 클라이언트는 /api/v1 + sse-endpoint에서 SSE 엔드포인트에, 메시지 엔드포인트는 /api/v1 + sse-message-endpoint에서 접근해야 해요 |
- |
keep-alive-interval |
연결 keep-alive 간격 | null (비활성) |
참고: 하위 호환성 때문에 SSE 프로퍼티에는 추가 접미사(예:
.sse)가 없어요.
기능과 역량 (Features and Capabilities)
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").description("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:
keep-alive-interval: 30s
사용 예시 (Usage Examples)
표준 STDIO 서버 구성 (Standard STDIO Server Configuration)
# Using spring-ai-starter-mcp-server
spring:
ai:
mcp:
server:
name: stdio-mcp-server
version: 1.0.0
type: SYNC
WebMVC 서버 구성 (WebMVC Server Configuration)
# Using spring-ai-starter-mcp-server-webmvc
spring:
ai:
mcp:
server:
name: webmvc-mcp-server
version: 1.0.0
type: SYNC
instructions: "This server provides weather information tools and resources"
capabilities:
tool: true
resource: true
prompt: true
completion: true
# sse properties
sse-message-endpoint: /mcp/messages
keep-alive-interval: 30s
WebFlux 서버 구성 (WebFlux Server Configuration)
# Using spring-ai-starter-mcp-server-webflux
spring:
ai:
mcp:
server:
name: webflux-mcp-server
version: 1.0.0
type: ASYNC # Recommended for reactive applications
instructions: "This reactive server provides weather information tools and resources"
capabilities:
tool: true
resource: true
prompt: true
completion: true
# sse properties
sse-message-endpoint: /mcp/messages
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을 생성하는 빈이 여러 개 있어도 되며, 자동 설정이 그것들을 병합해요.
예제 애플리케이션 (Example Applications)
- Weather Server (WebFlux) - WebFlux 전송과 함께하는 Spring AI MCP Server Boot Starter
- Weather Server (STDIO) - STDIO 전송과 함께하는 Spring AI MCP Server Boot Starter
- Weather Server Manual Configuration - 자동 설정을 사용하지 않고 Java SDK로 서버를 수동 구성하는 Spring AI MCP Server Boot Starter