Spring AI MCP 서버의 STDIO 및 SSE 구현

Spring AI MCP 서버는 다양한 데이터 전송 메커니즘을 지원하며, 각각의 전송 방식은 고유한 스타터를 통해 활성화됩니다. 이 문서에서는 STDIO와 SSE(SERVER-SENT EVENTS)에 초점을 맞춰 설명합니다.

STDIO

STDIO 서버는 MCP(Machine Communication Protocol) 서버의 모든 기능을 지원합니다. 이를 사용하면 다음과 같은 장점이 있습니다:
  • 명령줄 도구 및 데스크탑 애플리케이션과의 통합이 용이합니다.
  • 웹 관련 종속성이 필요 없습니다.
  • 기본적인 서버 구성 요소를 처리할 수 있습니다.
  • 도구, 자원 및 프롬프트 규격을 관리합니다.
  • 서버 상태 변경 알림을 제공합니다.
  • 동기 및 비동기 서버 구현을 지원합니다.
다음 의존성을 추가하세요:
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server</artifactId>
</dependency>

SSE WebMVC

SSE 서버는 Spring MVC 기반으로 동작하며, HTTP를 통해 데이터를 전송합니다. 다음은 주요 특징입니다:
  • WebMvcSseServerTransportProvider를 활용하여 SSE를 제공합니다.
  • SSE 엔드포인트를 자동으로 설정합니다.
  • 필요 시 STDIO 전송을 선택적으로 활성화할 수 있습니다 (spring.ai.mcp.server.stdio=true).
관련 의존성은 다음과 같습니다:
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>

SSE WebFlux

Spring WebFlux를 기반으로 하는 반응형 SSE 서버입니다. 주요 기능은 다음과 같습니다:
  • WebFluxSseServerTransportProvider를 사용하여 반응형 데이터 전송을 제공합니다.
  • 자동으로 설정된 반응형 SSE 엔드포인트를 제공합니다.
  • 필요 시 STDIO 전송을 선택적으로 활성화할 수 있습니다 (spring.ai.mcp.server.stdio=true).
다음 의존성을 추가하세요:
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>

설정

공통 설정

모든 설정 속성은 spring.ai.mcp.server로 시작합니다. 아래 표는 주요 설정 항목을 보여줍니다:
속성 설명 기본값
enabled MCP 서버 활성화 여부 true
tool-callback-converter Spring AI ToolCallbacks를 MCP 도구 규격으로 변환 true
stdio STDIO 전송 활성화 여부 false
name 서버 식별자 이름 mcp-server
version 서버 버전 정보 1.0.0

주석(Annotation)

MCP 서버 주석은 MCP 서버 핸들러를 Java 주석을 통해 선언적으로 구현할 수 있게 해줍니다. 주요 설정 항목은 다음과 같습니다:
속성 설명 기본값
enabled MCP 서버 주석 자동 스캐닝 활성화 여부 true

SSE 설정

SSE 관련 설정은 아래와 같습니다:
속성 설명 기본값
sse-message-endpoint SSE 메시지 엔드포인트 경로 /cp/message
keep-alive-interval 연결 유지 간격 (초 단위) null

특징 및 능력

도구(Tools)

서버는 클라이언트에게 노출될 도구들을 등록할 수 있습니다. 다음은 도구 등록 예제입니다:
@Bean
public ToolCallbackProvider registerTools(...) {
    List<ToolCallback> tools = ...;
    return ToolCallbackProvider.from(tools);
}
또는 저수준 API를 사용할 수도 있습니다:
@Bean
public List registerSyncTools(...) {
    List tools = ...;
    return tools;
}

자원(Resources)

서버는 클라이언트에게 자원을 제공할 수 있습니다. 다음은 자원 등록 예제입니다:
@Bean
public List defineResources(...) {
    var systemInfoResource = new McpSchema.Resource(...);
    var resourceSpecification = new McpServerFeatures.SyncResourceSpecification(systemInfoResource, (context, request) -> {
        try {
            var systemInfo = Map.of(...);
            String jsonContent = new ObjectMapper().writeValueAsString(systemInfo);
            return new McpSchema.ReadResourceResult(
                    List.of(new McpSchema.TextResourceContents(request.uri(), "application/json", jsonContent)));
        } catch (Exception e) {
            throw new RuntimeException("System info 생성 실패", e);
        }
    });

    return List.of(resourceSpecification);
}

프롬프트(Prompts)

서버는 클라이언트에게 프롬프트 템플릿을 제공할 수 있습니다. 다음은 예제입니다:
@Bean
public List definePrompts() {
    var prompt = new McpSchema.Prompt("greeting", "Friendly greeting",
        List.of(new McpSchema.PromptArgument("name", "Name to greet", true)));

    var promptSpecification = new McpServerFeatures.SyncPromptSpecification(prompt, (context, request) -> {
        String nameArgument = (String) request.arguments().get("name");
        if (nameArgument == null) { nameArgument = "friend"; }
        var userMessage = new PromptMessage(Role.USER, new TextContent("Hello " + nameArgument + "!"));
        return new GetPromptResult("Personalized greeting", List.of(userMessage));
    });

    return List.of(promptSpecification);
}

완료(Completions)

서버는 클라이언트에게 코드 완성 제안을 제공할 수 있습니다. 다음은 예제입니다:
@Bean
public List defineCompletions() {
    var completion = new McpServerFeatures.SyncCompletionSpecification(
        new McpSchema.PromptReference(
            "ref/prompt", "code-completion", "코드 완성 제안 제공"),
        (context, request) -> {
            return new McpSchema.CompleteResult(List.of("python", "pytorch"), 10, true);
        }
    );

    return List.of(completion);
}

로그(Logging)

서버는 클라이언트에게 구조화된 로그 메시지를 보낼 수 있습니다. 다음은 예제입니다:
(context, request) -> {
    context.loggingNotification(LoggingMessageNotification.builder()
        .level(LoggingLevel.INFO)
        .logger("test-logger")
        .data("Test log message")
        .build());
}

진행 상황(Progress)

서버는 클라이언트에게 진행 상황 업데이트를 보낼 수 있습니다. 다음은 예제입니다:
(context, request) -> {
    context.progressNotification(ProgressNotification.builder()
        .progressToken("progress-token")
        .progress(0.5)
        .total(1.0)
        .message("작업 중...")
        .build());
}

샘플 구성

STDIO

spring:
  ai:
    mcp:
      server:
        name: stdio-mcp-server
        version: 1.0.0
        type: SYNC

WebMVC

spring:
  ai:
    mcp:
      server:
        name: webmvc-mcp-server
        version: 1.0.0
        type: SYNC
        sse-message-endpoint: /mcp/messages
        keep-alive-interval: 30s

WebFlux

spring:
  ai:
    mcp:
      server:
        name: webflux-mcp-server
        version: 1.0.0
        type: ASYNC
        sse-message-endpoint: /mcp/messages
        keep-alive-interval: 30s

태그: spring-boot spring-mvc spring-webflux

6월 8일 23:05에 게시됨