2026-08-18 10:54:47 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:23:31 +09:00
2026-08-14 18:16:14 +09:00
2026-08-14 18:16:14 +09:00

DAP WAS MCP Tool Pods

신한라이프 업무 기능을 MCP(Model Context Protocol) Tool로 제공하는 Java 멀티 모듈 프로젝트입니다. 각 업무 모듈은 독립 실행 가능한 Spring Boot 애플리케이션이며, MCP Streamable HTTP와 REST 실행 API를 함께 제공합니다.

이 저장소에는 Gateway 애플리케이션이 포함되어 있지 않습니다. Tool Pod는 설정된 외부 Gateway에 Tool 등록을 시도하지만, Tool 조회와 직접 실행은 각 Pod가 자체적으로 처리합니다.

기술 기준

  • Java 21
  • Gradle Wrapper 8.14.3
  • Spring Boot 3.5.11
  • MCP Java SDK 2.0.0
  • Spring AI Community MCP Annotations 0.9.0
  • Jackson 2.20.1
  • MapStruct, MyBatis, Redis, Kafka, Resilience4j
  • JUnit 5

모듈 구성

모듈 역할 기본 포트 Tool 수
dap-was-lib MCP 서버, Tool 스캔·실행, Schema, Manifest, 보안, MCI/EAI/HTTP 연동 공통 기능 - -
dap-was-cus 고객·CRM·VOC·웹 콘텐츠 관리 Tool 8084 51
dap-was-sal 영업·청구·인수·동의·현장지원 Tool 8082 52
dap-was-pro 상품·계약·고객·GA 설계사 Tool 8085 50
dap-was-sys IAM·시스템 상태·공지·점검·배포 Tool 8086 50

총 203개의 @McpTool 선언과 203개의 V17 Tool YAML 정의가 있습니다.

현재 업무 구현은 개발·연동 검증 단계입니다. dap-was-salcmm_claim_searchcmm_memo_retriever는 각각 MCI와 HTTP Client 흐름을 사용하며, 나머지 Tool은 외부 시스템을 변경하지 않는 모의 응답을 중심으로 구현되어 있습니다.

처리 구조

MCP Client 또는 REST Client
  ├─ MCP Streamable HTTP: /mcp
  └─ REST: POST /mcp/{toolName}
          │
          ▼
Tool Pod
  ├─ McpToolMethodRegistry
  │    └─ Spring Bean의 @McpTool 메서드 탐색 및 실행 메서드 캐시
  ├─ ToolRegistryHeartbeatSender
  │    ├─ Tool 메타데이터 생성
  │    ├─ tool-definitions YAML 병합
  │    └─ 외부 Gateway 등록 시도
  ├─ McpToolExecutionService
  │    ├─ 입력 Schema 검증
  │    ├─ 요청 DTO 변환 및 Tool 호출
  │    └─ 출력 Schema 검증
  └─ UseCase → Converter → MCI/EAI/HTTP Client 또는 Mock 응답

애플리케이션 시작 시 다음 순서로 Tool이 준비됩니다.

  1. ToolDefinitionRepositoryclasspath*:tool-definitions/**/*.yml을 읽고 V17 필수 항목을 검증합니다.
  2. ToolRegistryHeartbeatSender@McpTool 메서드를 스캔하고 YAML 정의를 병합해 ToolMetadata를 생성합니다.
  3. McpToolMethodRegistry가 실제 호출 가능한 Bean과 메서드를 Tool 이름으로 캐시합니다.
  4. ToolPodMcpToolSynchronizer가 Tool을 MCP SDK 서버에 등록합니다.
  5. REST와 MCP 요청은 공통 McpToolExecutionService를 통해 실행됩니다.

제공 API

각 업무 Pod가 동일한 API 구조를 제공합니다.

목적 메서드 경로
MCP Streamable HTTP MCP 프로토콜 /mcp
MCP 메시지 전송 MCP 프로토콜 /mcp/message
로컬 Tool 메타데이터 조회 GET /mcp/api/v1/tools/local
Tool 직접 실행 POST /mcp/{toolName}
Tool Manifest 조회 GET /tool-manifest

GET /tool-manifestIf-None-Match 요청 헤더를 지원합니다. Manifest가 변경되지 않았으면 304 Not Modified를 반환합니다.

REST 실행 예시

다음은 SYS Pod의 시스템 상태 Tool 호출 예시입니다.

$headers = @{
  'trace-id' = 'trace-local-001'
  'request-id' = 'request-local-001'
}

Invoke-RestMethod `
  -Method Post `
  -Uri 'http://localhost:8086/mcp/iam_system_status' `
  -Headers $headers `
  -ContentType 'application/json' `
  -Body '{"environment":"개발"}'

주요 실행 응답은 다음과 같습니다.

HTTP 상태 코드 의미
200 - Tool 실행 성공
404 TOOL_NOT_FOUND 요청한 Tool 이름이 없음
422 INVALID_PARAM 요청이 입력 Schema와 일치하지 않음
500 INVALID_TOOL_RESPONSE 결과가 출력 Schema와 일치하지 않음
502 TOOL_ERROR Tool 실행 중 예외 발생

Tool 구현 방식

호출 가능한 메서드는 Spring AI Community의 @McpTool로 선언합니다. 프로젝트 고유 실행·표시 정보는 @GrowToolHint로 보완합니다.

@McpTool(
    name = "iam_system_status",
    title = "시스템 상태 조회",
    description = "모의 시스템 상태 정보를 조회합니다.",
    annotations = @McpTool.McpAnnotations(openWorldHint = false)
)
@GrowToolHint(
    categoryKey = "iam",
    mappingId = "DIRECT_IAM_STATUS",
    requiresApproval = false
)
SystemStatusResponse getSystemStatus(SystemStatusRequest request);

@McpTool.name은 다음 형식을 사용합니다.

^[a-z][a-z0-9_]{2,63}$

예: cmm_claim_search, crm_customer_detail, iam_system_status

이름 중복과 형식은 validateMcpToolNames, V17 정의는 validateToolSchemaV17 Gradle 작업으로 검사합니다. 모든 bootJar 작업은 두 검증 작업에 의존합니다.

Tool YAML 정의

각 Tool은 업무 모듈의 다음 경로에 YAML 정의를 가집니다.

dap-was-*/src/main/resources/tool-definitions/{category}/{tool-name}.yml

V17 정의의 주요 필수 항목은 다음과 같습니다.

  • name, display_name, version, category_key
  • description.function, when_to_use, when_not_to_use, io_limits
  • 3~10개의 example_queries
  • read_only, destructive, idempotent
  • parameters_schema.type: object
  • parameters_schema.additionalProperties: false
  • 각 입력 property의 description

입력·출력 Schema는 ToolSchemaResolver가 어노테이션의 Schema 리소스와 인라인 Schema, DTO에서 생성한 Schema를 해석합니다. ToolRegistryHeartbeatSender는 여기에 YAML의 parameters_schemaoutput_schema를 병합하여 최종 메타데이터를 만듭니다.

로컬 실행

사전 조건

  • JDK 21
  • 프로젝트에 포함된 Gradle Wrapper
  • Redis 또는 외부 연동이 필요한 경우 Docker

기본 활성 프로필은 local입니다. 로컬 프로필은 H2 메모리 DB와 P6Spy를 사용합니다.

$env:SPRING_PROFILES_ACTIVE = 'local'

각 Pod는 별도 터미널에서 실행합니다.

# 영업 Tool Pod
$env:AXHUB_TOOL_URL = 'http://localhost:8082'
.\gradlew.bat :dap-was-sal:bootRun

# 고객 Tool Pod
$env:AXHUB_TOOL_URL = 'http://localhost:8084'
.\gradlew.bat :dap-was-cus:bootRun

# 상품 Tool Pod
$env:AXHUB_TOOL_URL = 'http://localhost:8085'
.\gradlew.bat :dap-was-pro:bootRun

# 시스템 Tool Pod
$env:AXHUB_TOOL_URL = 'http://localhost:8086'
.\gradlew.bat :dap-was-sys:bootRun

실행 후 SYS Pod 기준 확인 URL은 다음과 같습니다.

http://localhost:8086/mcp/api/v1/tools/local
http://localhost:8086/tool-manifest
http://localhost:8086/swagger-ui/index.html

주요 환경 변수

환경 변수 설명 기본값
SPRING_PROFILES_ACTIVE Spring 활성 프로필 local
PORT Pod 수신 포트 모듈별 기본 포트
AXHUB_TOOL_URL Manifest와 Gateway 등록에 사용할 Pod 외부 URL http://localhost:${server.port}
AXHUB_GATEWAY_URL 외부 Gateway URL http://localhost:8081
SPRING_DATA_REDIS_HOST Redis 호스트 localhost
SPRING_DATA_REDIS_PORT Redis 포트 6379
GLOW_COMMUNICATION_MCI_HOST MCI 대상 호스트 프로필별 설정
GLOW_COMMUNICATION_MCI_PORT MCI 대상 포트 프로필별 설정

테스트와 검증

# 운영 소스 전체 컴파일
.\gradlew.bat classes

# 전체 테스트
.\gradlew.bat test

# 모듈별 테스트
.\gradlew.bat :dap-was-lib:test
.\gradlew.bat :dap-was-cus:test
.\gradlew.bat :dap-was-sal:test
.\gradlew.bat :dap-was-pro:test
.\gradlew.bat :dap-was-sys:test

# Tool 이름·중복 검사
.\gradlew.bat validateMcpToolNames

# 203개 Tool V17 정의 검사
.\gradlew.bat validateToolSchemaV17

# 검증, 테스트, 패키징
.\gradlew.bat clean build

현재 검증 상태

2026-08-18 기준 확인 결과입니다.

  • 전체 운영 소스 classes: 성공
  • validateMcpToolNames: 성공
  • validateToolSchemaV17: 203개 Tool 성공
  • SAL·PRO·SYS 테스트: 20개 성공
  • 전체 test: 테스트 소스 컴파일 오류로 실패
    • LIB의 ToolScaffolderTest가 변경 전 FieldDefinition 생성자를 사용
    • LIB의 ToolManifestServiceTest 패키지와 테스트용 생성자 접근 범위가 불일치

전체 빌드의 기준을 회복하려면 위 테스트 소스 회귀를 먼저 정리해야 합니다.

Docker Compose

Compose는 네 업무 Pod를 정의합니다.

서비스 컨테이너 포트 호스트 포트
was-sal 8082 8282
was-cus 8084 8284
was-pro 8085 8285
was-sys 8086 8286

모듈 Dockerfile은 사전에 생성된 Boot JAR를 이미지에 복사합니다. 먼저 JAR를 빌드한 뒤 Compose를 실행합니다.

.\gradlew.bat :dap-was-sal:bootJar :dap-was-cus:bootJar :dap-was-pro:bootJar :dap-was-sys:bootJar
docker compose up --build

주의: docker-compose.ymlhttp://gateway:8081을 Gateway 주소로 사용하지만 이 저장소의 Compose에는 gateway 서비스가 없습니다. 동일 Docker 네트워크에 Gateway를 제공하거나 AXHUB_GATEWAY_URL을 실제 접근 가능한 주소로 변경해야 합니다.

보안 및 운영 주의사항

현재 구현을 운영 환경에 노출하기 전에 아래 항목을 반드시 점검해야 합니다.

  • API Key 인터셉터는 /rpc/**, /mcp/api/v1/**에만 적용됩니다. 실제 Tool 실행 경로인 /mcp/{toolName}과 MCP 전송 경로 /mcp는 현재 검사 대상이 아닙니다.
  • mcp.security.api-keys가 비어 있으면 인터셉터가 익명 요청을 허용합니다. 현재 기본 설정에는 API Key가 정의되어 있지 않습니다.
  • mcp.security.tenant-domains는 설정 객체에 바인딩되지만 Tool별 인가에 사용되지 않습니다.
  • requiresApproval은 메타데이터에만 기록되며 실행 차단이나 승인 확인 로직은 없습니다.
  • 입력·출력 Schema 처리 자체에서 예외가 발생하면 현재 실행 서비스는 로그를 남기고 검증을 건너뜁니다.
  • CORS는 모든 Origin을 허용하면서 credential도 허용하도록 설정되어 있습니다. 운영 Origin을 명시적으로 제한해야 합니다.
  • Gateway 등록은 별도 비관리 스레드에서 Tool별로 최대 12회 재시도합니다. Gateway 장애 시 장시간 실행될 수 있으므로 타임아웃과 종료 정책을 점검해야 합니다.
  • Tool 요청과 연동 오류 로그에 개인정보나 인증정보가 포함되지 않도록 DTO와 로그 마스킹 정책을 검토해야 합니다.

주요 소스 위치

주제 위치
공통 빌드 및 검증 작업 build.gradle
REST Tool 실행 API dap-was-lib/src/main/java/io/shinhanlife/dap/mcc/presentation/BusinessToolController.java
Tool 실행 서비스 dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/McpToolExecutionService.java
실행 메서드 Registry dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/McpToolMethodRegistry.java
MCP SDK 서버 dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolMcpServerConfiguration.java
MCP Tool 동기화 dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolPodMcpToolSynchronizer.java
Tool 스캔 및 Gateway 등록 dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/ToolRegistryHeartbeatSender.java
YAML Tool 정의 로딩 dap-was-lib/src/main/java/io/shinhanlife/dap/lib/metadata/ToolDefinitionRepository.java
V17 정의 검증 dap-was-lib/src/main/java/io/shinhanlife/dap/lib/metadata/ToolDefinitionValidator.java
Manifest 생성 dap-was-lib/src/main/java/io/shinhanlife/dap/lib/manifest/ToolManifestService.java
API Key 인터셉터 dap-was-lib/src/main/java/io/shinhanlife/dap/lib/mcp/security/ApiKeyInterceptor.java
Tool·Pod 스캐폴딩 dap-was-lib/src/main/java/io/shinhanlife/dap/lib/util/ToolScaffolder.java, PodScaffolder.java

개발 시 권장 확인 순서

  1. Tool 메서드와 요청·응답 DTO를 구현합니다.
  2. 동일 이름의 V17 YAML 정의를 tool-definitions 아래에 추가합니다.
  3. validateMcpToolNamesvalidateToolSchemaV17을 실행합니다.
  4. 모듈 테스트와 전체 테스트를 실행합니다.
  5. 로컬 Pod에서 /mcp/api/v1/tools/local/tool-manifest를 확인합니다.
  6. REST와 MCP 양쪽에서 동일한 Tool 결과와 오류 계약을 확인합니다.
Description
AX HUB MCP Tool
Readme 253 MiB
Languages
Java 77.1%
Dockerfile 14.2%
Shell 8.7%