11 KiB
AX HUB Tool 설계 가이드
1. 설계 목표
Tool은 AI가 기능을 정확히 선택하고, 입력값을 안전하게 전달하며, 레거시 응답을 사람이 이해할 수 있는 형태로 반환하도록 설계한다.
핵심 원칙은 다음과 같다.
- Tool의 업무 목적과 호출 조건을 명확히 작성한다.
- AI용 DTO와 MCI·HTTP 전문 DTO를 분리한다.
- 입력과 출력의 JSON Schema를 구체적으로 정의한다.
- endpoint, timeout, 인증 값은 설정으로 분리한다.
- 동일한 Tool명은 빌드 단계에서 차단한다.
2. Tool명 규칙
현재 V17 검증 규칙은 다음과 같다.
^[a-z][a-z0-9_]{2,63}$
권장 형식은 {업무도메인}_{업무기능}_{행위}이다.
cmm_claim_search
cmm_comcode_lookup
smp_exchange_inquiry
ins_insurance_processor
설계 규칙:
- 소문자 영문, 숫자, 언더스코어만 사용한다.
- Pod명(
cus,sal,pro,sys)은 Tool명에 넣지 않는다. - 마침표와 공백을 사용하지 않는다.
- 구현 클래스명이나 인터페이스 ID만으로 이름을 만들지 않는다.
- 이름은 한 번 배포한 뒤 호환성을 위해 가급적 변경하지 않는다.
mcp.namespace를 설정하면 런타임 등록명 앞에 namespace가 붙을 수 있으므로, 기본값인 빈 문자열 사용 여부를 Pod 운영 기준과 함께 확정한다.
3. 업무 패키지 구조
io.shinhanlife.dat.mcc
├─ biz.{category}
│ ├─ dto
│ ├─ converter
│ └─ usecase
│ └─ impl
└─ infra.itrf
├─ mci.{clientSystemCode}
│ └─ io
└─ http.{httpApiName}
└─ io
각 계층의 책임은 다음과 같다.
| 계층 | 책임 |
|---|---|
biz.*.dto |
AI가 이해하는 Tool 요청·응답 모델 |
biz.*.converter |
Tool DTO와 연계 전문 DTO 변환 |
biz.*.usecase |
@McpTool로 노출할 업무 계약 |
biz.*.usecase.impl |
변환, Client 호출, 응답 해석 |
infra.itrf.mci.* |
MCI 인터페이스별 Client와 요청·응답 전문 |
infra.itrf.http.* |
HTTP API별 Client와 요청·응답 전문 |
한 UseCase 인터페이스에는 관련된 Tool 함수를 여러 개 선언할 수 있다. 이때 구현체에도 동일한 메서드를 추가하고, 각 메서드마다 독립된 @McpTool과 @GrowToolHint를 지정한다. 공통 추상 UseCase 상속은 필수가 아니다.
4. Tool 선언
@McpTool(
name = "cmm_claim_search",
title = "보험금 청구 상태 조회",
description = "청구번호 또는 계약번호로 보험금 청구 상태를 조회합니다."
)
@GrowToolHint(
register = true,
categoryKey = "cmm",
mappingId = "CLCNNB00001"
)
ClaimSearchResponse searchClaim(ClaimSearchRequest request);
| 항목 | 작성 기준 |
|---|---|
name |
시스템 식별용 영문 Tool명 |
title |
사용자 화면에 표시할 짧은 업무명 |
description |
Tool이 실제로 수행하는 기능 설명 |
categoryKey |
업무 분류 코드 |
mappingId |
MCI 인터페이스 ID 또는 업무 연계 식별자 |
register |
false이면 개발 중인 Tool을 외부 노출 대상에서 제외 |
title과 description은 같은 문장을 반복하지 않는다. title은 짧은 명칭, description은 대상·조건·결과를 포함한 한두 문장으로 작성한다.
5. Tool Schema V17 메타데이터
각 Tool에는 다음 경로의 정의 파일을 둔다.
src/main/resources/tool-definitions/{categoryKey}/{toolName}.yml
필수 구성 예시는 다음과 같다.
name: cmm_claim_search
display_name: 보험금 청구 상태 조회
version: 1.0.0
category_key: cmm
description:
function: 청구번호 또는 계약번호를 기준으로 청구 상태와 심사 결과를 조회한다.
when_to_use: 기존 청구 건의 진행 상태나 지급 결과를 확인할 때 사용한다.
when_not_to_use: 신규 보험금 청구 접수나 기존 청구 변경에는 사용하지 않는다.
io_limits: 청구번호 또는 계약번호 중 하나 이상이 필요하며 조회 기능만 제공한다.
display_description: 보험금 청구 상태와 심사 결과를 조회합니다.
example_queries:
- 내 보험금 청구가 어디까지 진행됐는지 알려줘
- 계약번호로 최근 청구 상태를 확인해줘
- 청구 심사 결과가 나왔는지 조회해줘
read_only: true
destructive: false
idempotent: true
parameters_schema:
type: object
properties:
claimNo:
type: string
description: 조회할 보험금 청구번호
additionalProperties: false
tags: [보험금, 청구조회]
legacy_interface_id: CLCNNB00001
required_env_keys: []
owner_org: MCP_TOOL
V17 검증 기준:
name은 Tool명 정규식을 만족해야 한다.- 표시명, 버전, 분류, 4종 설명은 비어 있으면 안 된다.
- 자연어 예시 질의는 3~10개이며 Tool명을 직접 포함하지 않는다.
read_only,destructive,idempotent를 명시한다.- Schema 최상위 타입은
object이다. - 모든 속성에
description이 있어야 한다. additionalProperties는false이다.
6. Input Schema 설계
6.1 단순한 요청
필드 수가 적고 조건이 단순하면 DTO의 @Schema, @McpToolParam과 타입 정보를 이용해 생성한다.
@Schema(
description = "보험금 청구번호",
example = "CLM202608100001",
requiredMode = Schema.RequiredMode.REQUIRED
)
private String claimNo;
6.2 복잡한 요청
중첩 객체, 조건부 필드, 정규식, 배열 제약처럼 복잡한 규칙은 JSON 리소스로 관리한다.
src/main/resources/tool-schemas/{categoryKey}/{schema-name}-input-schema.json
@GrowToolHint(
categoryKey = "cmm",
inputSchemaResource = "classpath:tool-schemas/cmm/claim-search-resource-input-schema.json"
)
명시한 inputSchemaResource가 있으면 리소스 Schema를 우선 사용한다. 리소스가 없을 때 DTO 기반 Schema를 사용한다.
7. Output Schema 설계
단순한 응답 DTO는 클래스에 @McpOutputSchema를 붙인다.
@McpOutputSchema
public class ClaimSearchResponse {
// fields
}
복잡한 응답은 다음 리소스를 사용한다.
src/main/resources/tool-schemas/{categoryKey}/{schema-name}-output-schema.json
@GrowToolHint(
categoryKey = "cmm",
outputSchemaResource = "classpath:tool-schemas/cmm/claim-search-resource-output-schema.json"
)
우선순위는 명시 JSON 리소스 → @McpOutputSchema DTO 생성 → 미사용 순서다. Output Schema를 명시한 Tool만 실행 결과를 해당 Schema로 검증한다.
8. 응답 DTO 작성 규칙
- 코드와 라벨을 함께 제공한다:
status,statusLabel. - null의 의미를 필드 설명에 명시한다: “심사 전이면 null이며 0원으로 해석하지 않는다.”
- 조건부 필드는 조건을 설명한다: “status가 REJECTED일 때만 값이 있다.”
- 배열에는 정렬 기준을 설명한다: “접수일 내림차순.”
- 결과가 잘릴 수 있으면
hasMore같은 필드를 제공한다. - 민감정보는 가능한 한 응답에 포함하지 않는다. 마스킹은 생략이 불가능할 때의 보조 수단이다.
- 레거시 원문 응답을 그대로 반환하지 않고 Tool 응답 DTO에 필요한 값만 매핑한다.
배열 요소가 복합 객체이면 응답 DTO 안에 의미 있는 inner class를 정의할 수 있다.
public class ActivityStatusResponse {
private List<ActivityItem> items;
public static class ActivityItem {
private String status;
private String statusLabel;
}
}
9. MCI 연동 설계
권장 호출 흐름은 다음과 같다.
Tool Request
→ UseCaseImpl
→ Converter.toMciRequest()
→ Mci{System}Client
→ AxhubMciComponent
→ GlowMciComponent
→ Converter.toResponse()
→ Tool Response
파일 구성 예:
Onnba3011Request.java
Onnba3011Response.java
Onnba3011Converter.java
Onnba3011UseCase.java
Onnba3011UseCaseImpl.java
MciCfpaClient.java
CLCNNB00001_I.java
CLCNNB00001_O.java
UseCaseImpl에서 직접 MCI 전문 필드를 하나씩 조립하지 않는다. 변환은 Converter에 두고, MCI Client는 변환이 끝난 전문을 받는다.
10. Glow HTTP 연동 설계
권장 호출 흐름은 다음과 같다.
Tool Request
→ UseCaseImpl
→ Converter.toHttpRequest()
→ {HttpApiName}Client
→ AxhubHttpComponent
→ GlowHttpComponent
→ Converter.toResponse()
→ Tool Response
Client는 설정의 API 이름만 참조한다.
@Component
@RequiredArgsConstructor
public class InsuranceClient {
private static final String API_NAME = "insurance";
private final AxhubHttpComponent http;
public <I, O> O call(I request, Class<O> responseType) {
return http.call(API_NAME, request, responseType);
}
}
URL과 HTTP 메서드는 glow.communication.http.api-list에 정의한다.
glow:
communication:
http:
api-list:
- name: insurance
domain: ${AXHUB_INSURANCE_HTTP_DOMAIN:http://localhost:${server.port}}
url: ${AXHUB_INSURANCE_HTTP_URL:/api/mock/http/ins_insurance_processor}
method: POST
content-type: application/json;charset=UTF-8
biz-pod: false
name은 Client의 API_NAME과 같아야 한다. 업무 Java 코드에는 실제 host, port, path를 하드코딩하지 않는다.
11. 공통 헤더와 추적성
Tool 호출 시 다음 헤더는 선택적으로 받을 수 있다.
| 헤더 | 의미 |
|---|---|
trace-id |
전체 업무 흐름 추적 ID. 연속 호출 동안 유지 |
request-id |
개별 요청 ID. HTTP 호출 단위로 새 값 사용 가능 |
employee-id |
암호화된 사번. 현재 필수 아님 |
X-Request-Id |
호환용 요청 ID |
AxhubHttpComponent는 현재 요청 Context의 trace-id, request-id, 암호화 사번을 Glow HTTP 요청 헤더로 전달한다. 민감 헤더와 DTO 원문은 일반 로그에 그대로 남기지 않는다.
12. 빌드 시 자동 검증
.\gradlew.bat validateMcpToolNames
.\gradlew.bat validateToolSchemaV17
validateMcpToolNames: 모든 Tool 모듈의@McpTool(name)중복 검사validateToolSchemaV17:@McpTool과 V17 정의 파일의 필수 규칙 검사- 각 Tool Pod의
bootJar는 두 검증 Task에 의존하므로 오류가 있으면 배포 JAR이 생성되지 않는다.
13. Tool 설계 완료 조건
- Tool명이 규칙에 맞고 중복되지 않는다.
- title, description, 사용/비사용 조건이 구체적이다.
- V17 Tool 정의 파일이 존재한다.
- AI DTO와 MCI·HTTP 전문 DTO가 분리되어 있다.
- Converter가 요청과 응답을 담당한다.
- endpoint와 timeout이 설정으로 분리되어 있다.
- Input/Output Schema의 단순·복잡 기준을 적용했다.
- 응답의 코드·라벨, null 의미, 조건, 배열 정렬, 잘림 여부를 설명했다.
- 불필요한 개인정보를 입출력에서 제거했다.