# MCP Java SDK 선택적 도입 설계 - 상태: 적용 완료 - 적용 버전: `io.modelcontextprotocol.sdk:mcp-json-jackson3:2.0.0` - 대상 런타임: Java 21, Spring Boot 4.0.7 - 적용 원칙: 외부 계약과 AX HUB 고유 실행 경계는 유지하고, 표준 프로토콜 모델과 JSON Schema 검증만 SDK에 위임한다. ## 1. 도입 결론 이 프로젝트는 MCP Java SDK의 서버 Starter나 HTTP transport를 사용하지 않는다. 현재 `/mcp` endpoint는 Agent Builder와 합의한 동기 JSON, `Mcp-Session-Id`, protocol version HTTP 400, trace 계약을 이미 구현하고 있으므로 SDK transport를 함께 활성화하면 같은 endpoint에 두 프로토콜 처리 경로가 생길 수 있기 때문이다. 대신 실제 사용 모듈인 `mcp-json-jackson3`에 직접 의존한다. 이 모듈이 `mcp-core`를 전이 제공하므로 aggregate artifact를 별도로 선언하지 않는다. 적용 범위는 다음과 같다. | 적용 영역 | SDK 타입/기능 | 기존 코드에서의 사용 위치 | |---|---|---| | MCP method 이름 | `McpSchema.METHOD_*` | handler와 protocol validator | | JSON-RPC 버전과 표준 오류 번호 | `McpSchema.JSONRPC_VERSION`, `McpSchema.ErrorCodes` | request parser, response, error enum | | initialize 결과 | `McpSchema.InitializeResult`, `Implementation`, `ServerCapabilities` | `InitializeHandler` | | tools/list 결과 | `McpSchema.ListToolsResult`, `Tool` | `ToolsListHandler` | | tools/call 결과 | `McpSchema.CallToolResult`, `TextContent` | `ToolsCallHandler` | | Tool arguments schema 검증 | `DefaultJsonSchemaValidator` | `ToolArgumentValidator` | 이 서버는 Spring AI API를 사용하지 않으므로 Spring AI BOM을 두지 않는다. MCP SDK 버전은 `2.0.0`으로 직접 고정한다. Starter를 추가하지 않았기 때문에 Spring AI MCP auto-configuration, 별도 `/mcp` mapping, SSE/Streamable transport bean은 생성되지 않는다. ## 2. 전체 요청 경계 ```text Agent Builder -> 기존 McpExchangeFilter - 호출자 header 추출 (guid, request-id, session, 사원 식별자) - guid, x-request-id, MCP Session correlation - protocol version HTTP header 검증 - HTTP/Tool 경계 trace log -> 기존 McpController -> 기존 JsonRpcRequestParser / McpMethodHandlerRegistry -> Handler - initialize: SDK InitializeResult 생성 - tools/list: 기존 Registry metadata -> SDK Tool/ListToolsResult - tools/call: 기존 실행 결과 -> SDK CallToolResult/TextContent -> 기존 JsonRpcResponse envelope -> application/json 응답 ``` Tool 실행 경로는 다음과 같다. ```text tools/call -> 기존 ToolsCallHandler params 검증 -> 기존 ToolRegistryService -> 기존 basic contract + SDK JSON Schema 검증 -> SDK JSON Schema 2020-12 검증 -> 기존 ToolRoutingService / ToolClient -> 기존 timeout·correlation 처리 (MCP는 인증·인가하지 않음) ``` SDK 모델은 handler의 표준 MCP payload를 만드는 데만 사용한다. SDK server가 요청을 dispatch하거나 Tool Service를 호출하지 않는다. ## 3. SDK와 기존 소스의 책임 경계 ### SDK에 위임한 책임 - 표준 MCP method 문자열과 JSON-RPC 상수 - initialize, Tool definition, list result, call result의 표준 필드 구조 - text content의 `type: "text"` 표현 - JSON Schema 2020-12 기반 arguments 검증과 schema 컴파일 재사용 - `minLength`, `pattern`, `enum`, `additionalProperties`, 중첩 객체 등 기존 기본 validator보다 넓은 schema keyword ### 기존 구현이 계속 소유하는 책임 - `/mcp` HTTP mapping과 항상 `application/json`을 반환하는 transport 정책 - `Accept: application/json, text/event-stream` 수용 - `Mcp-Session-Id` 생성과 stateless correlation - `MCP-Protocol-Version` 누락·미지원 시 HTTP 400 처리 - JSON-RPC parse/invalid request/invalid params의 현재 오류 envelope와 메시지 - Tool Service 매니페스트 pull, Redis/memory fallback, local fixture - Tool endpoint/timeout/version 진단 정보와 dynamic metadata - 호출자 header 추출·검증과 Tool Service bypass 정책 (인증·인가는 하지 않음, ADR-0006) - `guid`·`x-request-id` 전파, 요청 context 정리, HTTP/Tool 경계 로그 - Tool 선택 금지, exactly-one Tool 실행, outbound routing과 업무 오류 변환 ## 4. 기존 계약 보존 방법 | 위험 | 회피 방식 | |---|---| | SDK Starter가 기존 `/mcp`와 충돌 | Starter를 사용하지 않고 core 모델과 Jackson 3 validator만 의존 | | SDK가 Tool 검증 실패를 `isError=true`로 바꿈 | SDK server handler를 사용하지 않고 검증 실패를 기존 `-32602 Invalid params`로 변환 | | 기존 required/type 오류 문구 변경 | 공개된 기본 검증을 SDK보다 먼저 실행해 기존 메시지를 그대로 유지 | | `Mcp-Session-Id`/protocol header 동작 변경 | 기존 filter, controller, validator를 유지 | | `tools/call` 결과 필드 위치 변경 | 직렬화 계약 테스트로 `content[0]._meta.searchTime`과 `isError`를 고정 | | local tools/list 공개 필드 누락 | SDK `Tool` 변환 전 `_meta`만 제거하고 title/outputSchema/annotations를 직렬화 비교 | | Registry의 기존 Tool에 inputSchema 누락 | SDK 필수 조건을 만족하는 빈 object schema로 정규화 | | dynamic Registry를 annotation Tool로 고정 | `@McpTool`을 사용하지 않고 요청마다 기존 Registry service를 조회 | | correlation·Trace 기능이 SDK 내부로 사라짐 | transport와 실행 orchestration을 기존 코드에 유지 | | SDK 업그레이드로 wire payload 변경 | SDK 버전을 명시하고 initialize/list/call golden serialization 테스트를 통과한 경우에만 변경 | ## 5. JSON Schema 검증 정책 SDK 검증은 `ToolExecutionService`가 Registry 기반 argument validation을 수행하는 위치에 연결했다. 검증 순서는 다음과 같다. 1. 기존 object/required/basic type 검증으로 공개된 오류 문구를 보존한다. 2. SDK JSON Schema validator로 나머지 2020-12 keyword를 검증한다. 3. 실패하면 Tool Service를 호출하지 않고 기존 `JsonRpcException(INVALID_PARAMS)`으로 종료한다. SDK 원문 오류는 입력값을 포함할 수 있으므로 외부에는 `arguments do not match inputSchema`만 반환한다. SDK validator는 Spring singleton으로 한 번 생성되며 동일 schema의 컴파일 결과를 재사용한다. Registry가 제공하는 schema 자체의 허용 dialect와 `$ref` 원격 해석 정책은 운영 Registry 계약으로 별도 통제해야 한다. ## 6. 의도적으로 도입하지 않은 SDK 기능 - `spring-ai-starter-mcp-server-webmvc` - SDK sync/async/stateless server와 transport provider - SSE 또는 Streamable HTTP 응답 - SDK authorization/security 구현 - annotation 기반 정적 `@McpTool` 등록 - SDK가 소유하는 Tool lifecycle, list-changed notification - Resources, Prompts, Sampling, Elicitation 이 기능들은 현재 요구사항을 해결하지 않거나 기존 계약과 중복된다. 실제 필요가 생기면 별도 ADR과 Agent Builder contract test를 먼저 추가한다. ## 7. 변경 및 검증 기준 SDK 버전을 올릴 때는 다음을 모두 확인한다. 1. Spring Boot/Java/MCP Java SDK 조합의 dependency resolution 2. SDK `McpSchema` 필드와 Jackson 3 직렬화 변경 여부 3. initialize, tools/list, tools/call 성공·실패 JSON의 기존 예제 일치 4. JSON-RPC 오류 code/message/data 및 HTTP status 5. `Accept`에 `text/event-stream`이 있어도 JSON 응답을 유지하는지 6. `Mcp-Session-Id`, protocol version, `guid`, `x-request-id` 전파 7. local profile, Registry 장애 fallback, Redis 비필수 동작 8. `.\gradlew.bat clean test` 참고: - [MCP Java SDK](https://github.com/modelcontextprotocol/java-sdk) - [Spring AI 2.0 Upgrade Notes](https://docs.spring.io/spring-ai/reference/upgrade-notes.html) - [Spring AI MCP Server](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html)