fix: restore tool category metadata

This commit is contained in:
jade
2026-08-06 01:01:05 +09:00
parent a88122bd09
commit e92a0b7699
22 changed files with 30 additions and 30 deletions

View File

@@ -25,7 +25,7 @@ import java.lang.annotation.Target;
public @interface ToolHint { public @interface ToolHint {
boolean register() default false; boolean register() default false;
boolean requiresApproval() default false; boolean requiresApproval() default false;
String group() default ""; String categoryKey() default "com";
String mappingId() default ""; String mappingId() default "";
String inputSchemaResource() default ""; String inputSchemaResource() default "";
String outputSchemaResource() default ""; String outputSchemaResource() default "";

View File

@@ -107,8 +107,8 @@ public class ToolRegistryHeartbeatSender {
meta.setTimeoutMillis(5000L); meta.setTimeoutMillis(5000L);
meta.setEnabled(true); meta.setEnabled(true);
meta.setDescription(functionAnnotation.description()); meta.setDescription(functionAnnotation.description());
meta.setCategoryKey(hintAnnotation == null || hintAnnotation.group().isBlank() meta.setCategoryKey(hintAnnotation == null || hintAnnotation.categoryKey().isBlank()
? "default" : hintAnnotation.group()); ? "common" : hintAnnotation.categoryKey());
meta.setIntegrationType("REST"); meta.setIntegrationType("REST");
meta.setMciServiceId(hintAnnotation != null ? hintAnnotation.mappingId() : ""); meta.setMciServiceId(hintAnnotation != null ? hintAnnotation.mappingId() : "");
meta.setPodUrl(podUrl); meta.setPodUrl(podUrl);

View File

@@ -12,15 +12,15 @@ public final class ToolSourceUpdater {
private ToolSourceUpdater() { private ToolSourceUpdater() {
} }
public static void updateToolSource(String toolName, String domainGroup, String description, public static void updateToolSource(String toolName, String categoryKey, String description,
boolean register, Boolean requiresApproval) throws IOException { boolean register, Boolean requiresApproval) throws IOException {
String configuredSourceDirectory = System.getenv("AXHUB_SOURCE_DIR"); String configuredSourceDirectory = System.getenv("AXHUB_SOURCE_DIR");
Path rootDirectory = configuredSourceDirectory == null || configuredSourceDirectory.isBlank() Path rootDirectory = configuredSourceDirectory == null || configuredSourceDirectory.isBlank()
? Paths.get(".") : Paths.get(configuredSourceDirectory); ? Paths.get(".") : Paths.get(configuredSourceDirectory);
updateToolSource(rootDirectory, toolName, domainGroup, description, register, requiresApproval); updateToolSource(rootDirectory, toolName, categoryKey, description, register, requiresApproval);
} }
static void updateToolSource(Path rootDirectory, String toolName, String domainGroup, String description, static void updateToolSource(Path rootDirectory, String toolName, String categoryKey, String description,
boolean register, Boolean requiresApproval) throws IOException { boolean register, Boolean requiresApproval) throws IOException {
Path targetFile = findToolSource(rootDirectory, toolName); Path targetFile = findToolSource(rootDirectory, toolName);
if (targetFile == null) { if (targetFile == null) {
@@ -29,7 +29,7 @@ public final class ToolSourceUpdater {
String content = Files.readString(targetFile); String content = Files.readString(targetFile);
content = updateMcpTool(content, toolName, description); content = updateMcpTool(content, toolName, description);
content = updateToolHint(content, domainGroup, register, requiresApproval); content = updateToolHint(content, categoryKey, register, requiresApproval);
Files.writeString(targetFile, content); Files.writeString(targetFile, content);
} }
@@ -61,7 +61,7 @@ public final class ToolSourceUpdater {
return description == null ? content : replaceAttribute(content, range, "description", quote(description)); return description == null ? content : replaceAttribute(content, range, "description", quote(description));
} }
private static String updateToolHint(String content, String domainGroup, boolean register, Boolean requiresApproval) { private static String updateToolHint(String content, String categoryKey, boolean register, Boolean requiresApproval) {
AnnotationRange range = annotationArguments(content, "ToolHint", null); AnnotationRange range = annotationArguments(content, "ToolHint", null);
if (range == null) { if (range == null) {
throw new IllegalArgumentException("ToolHint declaration not found next to McpTool"); throw new IllegalArgumentException("ToolHint declaration not found next to McpTool");
@@ -72,8 +72,8 @@ public final class ToolSourceUpdater {
updated = replaceAttribute(updated, range, "requiresApproval", Boolean.toString(requiresApproval)); updated = replaceAttribute(updated, range, "requiresApproval", Boolean.toString(requiresApproval));
range = annotationArguments(updated, "ToolHint", null); range = annotationArguments(updated, "ToolHint", null);
} }
if (domainGroup != null && !domainGroup.isBlank()) { if (categoryKey != null && !categoryKey.isBlank()) {
updated = replaceAttribute(updated, range, "group", quote(domainGroup)); updated = replaceAttribute(updated, range, "categoryKey", quote(categoryKey));
} }
return updated; return updated;
} }

View File

@@ -32,6 +32,6 @@ class ToolSourceUpdaterTest {
String updated = Files.readString(source); String updated = Files.readString(source);
assertTrue(updated.contains("@McpTool(name = \"oth.cmm.sample.search\", description = \"new\")")); assertTrue(updated.contains("@McpTool(name = \"oth.cmm.sample.search\", description = \"new\")"));
assertTrue(updated.contains("@ToolHint(register = true, requiresApproval = true")); assertTrue(updated.contains("@ToolHint(register = true, requiresApproval = true"));
assertTrue(updated.contains("group = \"customer\""), updated); assertTrue(updated.contains("categoryKey = \"customer\""), updated);
} }
} }

View File

@@ -7,6 +7,6 @@ import io.shinhanlife.dap.mcc.biz.cmm.dto.*;
public interface BalanceUseCase { public interface BalanceUseCase {
@McpTool(name = "oth.cmm.balance.inquiry", title = "잔고 조회 툴", description = "고객의 계좌 잔액을 조회합니다.") @McpTool(name = "oth.cmm.balance.inquiry", title = "잔고 조회 툴", description = "고객의 계좌 잔액을 조회합니다.")
@ToolHint(register = false, mappingId = "ACC_001") @ToolHint(register = false, categoryKey = "cmm", mappingId = "ACC_001")
Object execute(BalanceRequest req); Object execute(BalanceRequest req);
} }

View File

@@ -8,6 +8,6 @@ public interface BillingProcessUseCase {
Object getStatus(BillingStatusRequest req); Object getStatus(BillingStatusRequest req);
@McpTool(name = "oth.cmm.billing.process", title = "청구 프로세스 툴", description = "청구 처리") @McpTool(name = "oth.cmm.billing.process", title = "청구 프로세스 툴", description = "청구 처리")
@ToolHint(register = false, mappingId = "BILL_002") @ToolHint(register = false, categoryKey = "cmm", mappingId = "BILL_002")
Object processBilling(BillingProcessRequest data); Object processBilling(BillingProcessRequest data);
} }

View File

@@ -9,6 +9,6 @@ public interface BondIssueUseCase {
Object check(BondCheckRequest req); Object check(BondCheckRequest req);
@McpTool(name = "oth.cmm.bond.issue", title = "채권 발행 툴", description = "증권 발행 테스트1") @McpTool(name = "oth.cmm.bond.issue", title = "채권 발행 툴", description = "증권 발행 테스트1")
@ToolHint(register = false, mappingId = "BOND_002") @ToolHint(register = false, categoryKey = "cmm", mappingId = "BOND_002")
Object issue(BondIssueRequest data); Object issue(BondIssueRequest data);
} }

View File

@@ -9,7 +9,7 @@ import io.shinhanlife.dap.mcc.biz.cmm.dto.ClaimSearchResponse;
public interface ClaimSearchSchemaSampleUseCase { public interface ClaimSearchSchemaSampleUseCase {
@McpTool(name = "oth.cmm.claim.search", title = "청구 조회 스키마 샘플", description = "Claim search Tool sample using input and output JSON Schema resources.", annotations = @McpTool.McpAnnotations(readOnlyHint = true, idempotentHint = true)) @McpTool(name = "oth.cmm.claim.search", title = "청구 조회 스키마 샘플", description = "Claim search Tool sample using input and output JSON Schema resources.", annotations = @McpTool.McpAnnotations(readOnlyHint = true, idempotentHint = true))
@ToolHint(register = false, @ToolHint(register = false, categoryKey = "cmm",
inputSchemaResource = "classpath:mcp/schema/claim-search-resource-input-schema.json", inputSchemaResource = "classpath:mcp/schema/claim-search-resource-input-schema.json",
outputSchemaResource = "classpath:mcp/schema/claim-search-resource-output-schema.json") outputSchemaResource = "classpath:mcp/schema/claim-search-resource-output-schema.json")
ClaimSearchResponse search(ClaimSearchRequest request); ClaimSearchResponse search(ClaimSearchRequest request);

View File

@@ -9,10 +9,10 @@ public interface CommonUtilityUseCase {
Object registerVacation(VacationRegisterRequest req); Object registerVacation(VacationRegisterRequest req);
@McpTool(name = "oth.cmm.leave.count", title = "공통 유틸리티 툴", description = "연차 갯수 조회") @McpTool(name = "oth.cmm.leave.count", title = "공통 유틸리티 툴", description = "연차 갯수 조회")
@ToolHint(register = false, mappingId = "HR_VAC_02") @ToolHint(register = false, categoryKey = "cmm", mappingId = "HR_VAC_02")
Object getLeaveCount(LeaveCountRequest data); Object getLeaveCount(LeaveCountRequest data);
@McpTool(name = "oth.cmm.secret.execute", title = "공통 유틸리티 툴", description = "비공개 툴 테스트") @McpTool(name = "oth.cmm.secret.execute", title = "공통 유틸리티 툴", description = "비공개 툴 테스트")
@ToolHint(register = false, mappingId = "SECRET_001") @ToolHint(register = false, categoryKey = "cmm", mappingId = "SECRET_001")
Object secretTool(LeaveCountRequest data); Object secretTool(LeaveCountRequest data);
} }

View File

@@ -9,6 +9,6 @@ public interface ContractInquiryUseCase {
Object getStatus(ContractStatusRequest req); Object getStatus(ContractStatusRequest req);
@McpTool(name = "oth.cmm.contract.detail", title = "계약 상세조회 툴", description = "계약상세 조회") @McpTool(name = "oth.cmm.contract.detail", title = "계약 상세조회 툴", description = "계약상세 조회")
@ToolHint(register = false, mappingId = "CNTR_002") @ToolHint(register = false, categoryKey = "cmm", mappingId = "CNTR_002")
Object getDetail(ContractDetailRequest data); Object getDetail(ContractDetailRequest data);
} }

View File

@@ -9,6 +9,6 @@ public interface CustomerInfoUseCase {
Object getGrade(CustomerGradeRequest req); Object getGrade(CustomerGradeRequest req);
@McpTool(name = "oth.cmm.customer.detail", title = "고객 상세조회 툴", description = "고객상세 정보 조회") @McpTool(name = "oth.cmm.customer.detail", title = "고객 상세조회 툴", description = "고객상세 정보 조회")
@ToolHint(register = false, mappingId = "CRM_002") @ToolHint(register = false, categoryKey = "cmm", mappingId = "CRM_002")
Object getDetail(CustomerDetailRequest data); Object getDetail(CustomerDetailRequest data);
} }

View File

@@ -21,6 +21,6 @@ import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaCommonCodeRequest;
*/ */
public interface MetaCommonCodeUseCase { public interface MetaCommonCodeUseCase {
@McpTool(name = "oth.cmm.common-code.lookup", title = "메타 공통코드 조회 툴", description = "메타 통합코드 목록을 조회해줘", annotations = @McpTool.McpAnnotations(openWorldHint = true)) @McpTool(name = "oth.cmm.common-code.lookup", title = "메타 공통코드 조회 툴", description = "메타 통합코드 목록을 조회해줘", annotations = @McpTool.McpAnnotations(openWorldHint = true))
@ToolHint(register = false, requiresApproval = false, mappingId = "CLCNNB00001") @ToolHint(register = false, requiresApproval = false, categoryKey = "cmm", mappingId = "CLCNNB00001")
Object execute(MetaCommonCodeRequest req); Object execute(MetaCommonCodeRequest req);
} }

View File

@@ -21,6 +21,6 @@ import io.shinhanlife.dap.mcc.biz.cmm.dto.MetaTableRequest;
*/ */
public interface MetaTableUseCase { public interface MetaTableUseCase {
@McpTool(name = "oth.cmm.meta.table", title = "메타 테이블 조회 툴", description = "메타 테이블 정보 목록을 조회해줘", annotations = @McpTool.McpAnnotations(openWorldHint = true)) @McpTool(name = "oth.cmm.meta.table", title = "메타 테이블 조회 툴", description = "메타 테이블 정보 목록을 조회해줘", annotations = @McpTool.McpAnnotations(openWorldHint = true))
@ToolHint(register = false, requiresApproval = false, mappingId = "CLCNNB00001") @ToolHint(register = false, requiresApproval = false, categoryKey = "cmm", mappingId = "CLCNNB00001")
Object execute(MetaTableRequest req); Object execute(MetaTableRequest req);
} }

View File

@@ -9,6 +9,6 @@ import java.util.Map;
public interface TemplateUtilityUseCase { public interface TemplateUtilityUseCase {
@McpTool(name = "oth.cmm.template.url", title = "템플릿 유틸리티 툴", description = "요청한 템플릿(엑셀, 워드 등) 파일(양식)을 다운로드 받을 수 있는 시스템 URL을 반환합니다. AI는 이 URL을 사용자에게 마크다운 링크 형태로 제공해야 합니다.") @McpTool(name = "oth.cmm.template.url", title = "템플릿 유틸리티 툴", description = "요청한 템플릿(엑셀, 워드 등) 파일(양식)을 다운로드 받을 수 있는 시스템 URL을 반환합니다. AI는 이 URL을 사용자에게 마크다운 링크 형태로 제공해야 합니다.")
@ToolHint @ToolHint(categoryKey = "cmm")
Map<String, Object> getTemplateFileUrl(TemplateDownloadRequest req); Map<String, Object> getTemplateFileUrl(TemplateDownloadRequest req);
} }

View File

@@ -6,6 +6,6 @@ import io.shinhanlife.dap.mcc.biz.oth.dto.*;
public interface Onnba3011UseCase { public interface Onnba3011UseCase {
@McpTool(name = "oth.sol.request.detail", title = "보종By가입설계한도계산조회 툴") @McpTool(name = "oth.sol.request.detail", title = "보종By가입설계한도계산조회 툴")
@ToolHint(register = false) @ToolHint(register = false, categoryKey = "oth")
Object callOnnba3011(Onnba3011Request req); Object callOnnba3011(Onnba3011Request req);
} }

View File

@@ -8,6 +8,6 @@ import io.shinhanlife.dap.mcc.biz.smp.dto.DailyQuoteResponse;
public interface DailyQuoteToolUseCase { public interface DailyQuoteToolUseCase {
@McpTool(name = "oth.smp.quote.daily", title = "오늘의 명언 툴", description = "무작위로 영감을 주는 명언을 하나 가져옵니다.") @McpTool(name = "oth.smp.quote.daily", title = "오늘의 명언 툴", description = "무작위로 영감을 주는 명언을 하나 가져옵니다.")
@ToolHint(register = false, mappingId = "QUOTE_001") @ToolHint(register = false, categoryKey = "smp", mappingId = "QUOTE_001")
DailyQuoteResponse execute(DailyQuoteRequest req); DailyQuoteResponse execute(DailyQuoteRequest req);
} }

View File

@@ -10,6 +10,6 @@ import io.shinhanlife.dap.mcc.biz.smp.dto.ExchangeRateResponse;
public interface ExchangeRateToolUseCase { public interface ExchangeRateToolUseCase {
@McpTool(name = "oth.smp.exchange-rate.inquiry", title = "실시간 환율 조회 툴", description = "원하는 통화의 실시간 환율을 조회합니다. (예: USD, EUR, JPY)") @McpTool(name = "oth.smp.exchange-rate.inquiry", title = "실시간 환율 조회 툴", description = "원하는 통화의 실시간 환율을 조회합니다. (예: USD, EUR, JPY)")
@ToolHint(register = false, mappingId = "EXCHANGE_001") @ToolHint(register = false, categoryKey = "smp", mappingId = "EXCHANGE_001")
ExchangeRateResponse execute(ExchangeRateRequest req); ExchangeRateResponse execute(ExchangeRateRequest req);
} }

View File

@@ -7,6 +7,6 @@ import io.shinhanlife.dap.mcc.biz.smp.dto.TeamMemberRequest;
public interface TeamMemberUseCase { public interface TeamMemberUseCase {
@McpTool(name = "oth.smp.team.list", title = "신한라이프 MCP, TOOL 파트 구성원 조회", description = "신한라이프 MCP, TOOL 파트 구성원을 조회합니다.", annotations = @McpTool.McpAnnotations(openWorldHint = true)) @McpTool(name = "oth.smp.team.list", title = "신한라이프 MCP, TOOL 파트 구성원 조회", description = "신한라이프 MCP, TOOL 파트 구성원을 조회합니다.", annotations = @McpTool.McpAnnotations(openWorldHint = true))
@ToolHint(register = false, requiresApproval = false, mappingId = "DIRECT0001") @ToolHint(register = false, requiresApproval = false, categoryKey = "smp", mappingId = "DIRECT0001")
Object execute(TeamMemberRequest req); Object execute(TeamMemberRequest req);
} }

View File

@@ -7,6 +7,6 @@ import io.shinhanlife.dap.mcc.biz.smp.dto.*;
public interface WeatherToolUseCase { public interface WeatherToolUseCase {
@McpTool(name = "oth.smp.weather.inquiry", title = "날씨 조회 툴", description = "특정 도시의 현재 날씨, 온도, 풍속 정보를 조회합니다.") @McpTool(name = "oth.smp.weather.inquiry", title = "날씨 조회 툴", description = "특정 도시의 현재 날씨, 온도, 풍속 정보를 조회합니다.")
@ToolHint(register = false, mappingId = "WEATHER_001") @ToolHint(register = false, categoryKey = "smp", mappingId = "WEATHER_001")
WeatherResponse execute(WeatherRequest req); WeatherResponse execute(WeatherRequest req);
} }

View File

@@ -22,6 +22,6 @@ import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqDetailRequest;
public interface SolReqDetailUseCase { public interface SolReqDetailUseCase {
@McpTool(name = "oth.sol.request.detail", title = "SolReqDetail 툴", description = "SOL 의뢰서 상세 조회", annotations = @McpTool.McpAnnotations(openWorldHint = true, readOnlyHint = true)) @McpTool(name = "oth.sol.request.detail", title = "SolReqDetail 툴", description = "SOL 의뢰서 상세 조회", annotations = @McpTool.McpAnnotations(openWorldHint = true, readOnlyHint = true))
@ToolHint(register = false, requiresApproval = false, mappingId = "SOLG00000002") @ToolHint(register = false, requiresApproval = false, categoryKey = "sol", mappingId = "SOLG00000002")
Object execute(SolReqDetailRequest req); Object execute(SolReqDetailRequest req);
} }

View File

@@ -7,6 +7,6 @@ import io.shinhanlife.dap.mcc.biz.sol.dto.SolReqListRequest;
public interface SolReqListUseCase { public interface SolReqListUseCase {
@McpTool(name = "oth.sol.request.list", title = "SolReqList 툴", description = "SOL 의뢰서 목록 조회해줘", annotations = @McpTool.McpAnnotations(openWorldHint = true)) @McpTool(name = "oth.sol.request.list", title = "SolReqList 툴", description = "SOL 의뢰서 목록 조회해줘", annotations = @McpTool.McpAnnotations(openWorldHint = true))
@ToolHint(register = false, requiresApproval = false, mappingId = "SOLG00000001") @ToolHint(register = false, requiresApproval = false, categoryKey = "sol", mappingId = "SOLG00000001")
Object execute(SolReqListRequest req); Object execute(SolReqListRequest req);
} }

View File

@@ -6,6 +6,6 @@ import io.shinhanlife.dap.mcc.biz.sms.dto.*;
public interface SmsToolUseCase { public interface SmsToolUseCase {
@McpTool(name = "sms.send", title = "SMS 발송 툴", description = "SMS 발송 기능을 제공합니다.") @McpTool(name = "sms.send", title = "SMS 발송 툴", description = "SMS 발송 기능을 제공합니다.")
@ToolHint(register = false, mappingId = "SMS_SEND") @ToolHint(register = false, categoryKey = "notification", mappingId = "SMS_SEND")
Object sendSms(SmsSendRequest req); Object sendSms(SmsSendRequest req);
} }