diff --git a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/controller/McpRouterController.java b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/controller/McpRouterController.java index 61805e6..b765aa3 100644 --- a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/controller/McpRouterController.java +++ b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/controller/McpRouterController.java @@ -84,7 +84,10 @@ public class McpRouterController { @GetMapping("/tools/list") public ResponseEntity listTools() { - List activeTools = redisRegistryService.getAllTools(); + List activeTools = redisRegistryService.getAllTools() + .stream() + .filter(ToolMetadata::isVisible) + .collect(java.util.stream.Collectors.toList()); JsonRpcResponse response = new JsonRpcResponse(); response.setId(UUID.randomUUID().toString()); @@ -95,7 +98,10 @@ public class McpRouterController { @GetMapping(value = "/tools/docs/markdown", produces = "text/markdown;charset=UTF-8") public ResponseEntity generateToolsMarkdown() { - List tools = redisRegistryService.getAllTools(); + List tools = redisRegistryService.getAllTools() + .stream() + .filter(ToolMetadata::isVisible) + .collect(java.util.stream.Collectors.toList()); StringBuilder md = new StringBuilder(); md.append("# \uD83E\uDD16 Shinhan AI Tool Catalog\n\n"); diff --git a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java index 29eb91c..17a81b9 100644 --- a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java +++ b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/dto/ToolMetadata.java @@ -40,6 +40,9 @@ public class ToolMetadata { // 2-3. Pod 실행 URL (독립적인 Microservice 라우팅용, 예: http://localhost:8082) private String podUrl; + // 2-4. 가시성 여부 + private boolean visible; + // 3. 연동 아키텍처 구분 (DIRECT / MCI_EAI) private String integrationType; // 연동 타입: "DIRECT" 또는 "MCI_EAI" diff --git a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/service/ToolPlanner.java b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/service/ToolPlanner.java index 1e7d3a3..6d12e6b 100644 --- a/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/service/ToolPlanner.java +++ b/axhub-gateway/src/main/java/io/shinhanlife/axhub/biz/mcp/gateway/service/ToolPlanner.java @@ -37,17 +37,8 @@ public class ToolPlanner { var toolMetadata = redisRegistryService.getTool(toolName); if (toolMetadata == null) { - log.warn(" [Planner] 등록되지 않은 툴 요청: {}. 레지스트리를 참조하지 않고 강제 연동 모드로 전환합니다.", toolName); - // 히든 툴(register=false)에 대한 강제 라우팅 폴백 - String fallbackPodUrl = "http://tool-other:8084"; // 기본값 (get_template_file_url 등) - if (toolName.contains("email")) fallbackPodUrl = "http://tool-email:8083"; - else if (toolName.contains("sms")) fallbackPodUrl = "http://tool-sms:8082"; - - toolMetadata = ToolMetadata.builder() - .toolName(toolName) - .integrationType("DIRECT") - .podUrl(fallbackPodUrl) - .build(); + log.warn(" [Planner] 등록되지 않은 툴 요청: {}", toolName); + throw new RuntimeException("해당 툴(" + toolName + ")이 레지스트리에 존재하지 않습니다."); } // 2-1. [신규] 도메인 그룹핑 기반 권한 검증 diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/annotation/McpFunction.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/annotation/McpFunction.java index c9d20de..8ee4db3 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/annotation/McpFunction.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/annotation/McpFunction.java @@ -16,4 +16,7 @@ public @interface McpFunction { // 추가: Redis 자동 등록 및 Heartbeat 대상 여부 제어 boolean register() default true; + + // 추가: 툴 목록 노출 여부 제어 (false 시 라우팅은 되나 목록에서 숨김) + boolean visible() default true; } diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/config/McpProperties.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/config/McpProperties.java index 72b5387..2b8accf 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/config/McpProperties.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/config/McpProperties.java @@ -19,5 +19,6 @@ public class McpProperties { private String prompt; private String mappingId; private Boolean register; + private Boolean visible; } } diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/ToolMetadata.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/ToolMetadata.java index 79dc3bc..438d777 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/ToolMetadata.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/dto/ToolMetadata.java @@ -49,4 +49,9 @@ public class ToolMetadata { public String getMciServiceId() { return mciServiceId; } public void setMciServiceId(String mciServiceId) { this.mciServiceId = mciServiceId; } + + private boolean visible = true; + + public boolean isVisible() { return visible; } + public void setVisible(boolean visible) { this.visible = visible; } } diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/ToolRegistryHeartbeatSender.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/ToolRegistryHeartbeatSender.java index a9da007..ad19567 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/ToolRegistryHeartbeatSender.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/ToolRegistryHeartbeatSender.java @@ -77,6 +77,9 @@ public class ToolRegistryHeartbeatSender { meta.setMciServiceId(prop != null && prop.getMappingId() != null ? prop.getMappingId() : functionAnnotation.mappingId()); meta.setPodUrl(podUrl); + boolean isVisible = prop != null && prop.getVisible() != null ? prop.getVisible() : functionAnnotation.visible(); + meta.setVisible(isVisible); + Map prompts = new HashMap<>(); String promptText = prop != null && prop.getPrompt() != null ? prop.getPrompt() : functionAnnotation.prompt(); prompts.put(functionAnnotation.name(), promptText); diff --git a/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/TemplateUtilityService.java b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/TemplateUtilityService.java index 3491878..08bdb62 100644 --- a/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/TemplateUtilityService.java +++ b/axhub-tool-other/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/service/TemplateUtilityService.java @@ -14,11 +14,10 @@ import java.util.Map; public class TemplateUtilityService extends AbstractMcpToolService { @McpFunction( - name = "get_template_file_url", - description = "각종 양식(엑셀, PDF 등) 샘플 파일의 다운로드 URL을 제공합니다.", - prompt = "고객 등록 엑셀 샘플 파일 다운로드 링크 줘.", - mappingId = "COM_TMPL_01", - register = false + name = "get_template_file_url", + description = "특정 템플릿의 양식 파일(엑셀, 워드 등)을 다운로드 받을 수 있는 시스템 URL을 반환합니다. AI는 이 URL을 사용자에게 마크다운 링크 형태로 제공해야 합니다.", + prompt = "요청하신 템플릿 양식 파일 다운로드 URL은 다음과 같습니다. 클릭하여 다운로드하세요:", + visible = false ) public Map getTemplateFileUrl(TemplateDownloadReq data) { try {