feat: Separate tool routing (register) from UI visibility (visible)
This commit is contained in:
@@ -84,7 +84,10 @@ public class McpRouterController {
|
|||||||
|
|
||||||
@GetMapping("/tools/list")
|
@GetMapping("/tools/list")
|
||||||
public ResponseEntity<JsonRpcResponse> listTools() {
|
public ResponseEntity<JsonRpcResponse> listTools() {
|
||||||
List<ToolMetadata> activeTools = redisRegistryService.getAllTools();
|
List<ToolMetadata> activeTools = redisRegistryService.getAllTools()
|
||||||
|
.stream()
|
||||||
|
.filter(ToolMetadata::isVisible)
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
|
||||||
JsonRpcResponse response = new JsonRpcResponse();
|
JsonRpcResponse response = new JsonRpcResponse();
|
||||||
response.setId(UUID.randomUUID().toString());
|
response.setId(UUID.randomUUID().toString());
|
||||||
@@ -95,7 +98,10 @@ public class McpRouterController {
|
|||||||
|
|
||||||
@GetMapping(value = "/tools/docs/markdown", produces = "text/markdown;charset=UTF-8")
|
@GetMapping(value = "/tools/docs/markdown", produces = "text/markdown;charset=UTF-8")
|
||||||
public ResponseEntity<String> generateToolsMarkdown() {
|
public ResponseEntity<String> generateToolsMarkdown() {
|
||||||
List<ToolMetadata> tools = redisRegistryService.getAllTools();
|
List<ToolMetadata> tools = redisRegistryService.getAllTools()
|
||||||
|
.stream()
|
||||||
|
.filter(ToolMetadata::isVisible)
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
|
||||||
StringBuilder md = new StringBuilder();
|
StringBuilder md = new StringBuilder();
|
||||||
md.append("# \uD83E\uDD16 Shinhan AI Tool Catalog\n\n");
|
md.append("# \uD83E\uDD16 Shinhan AI Tool Catalog\n\n");
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ public class ToolMetadata {
|
|||||||
// 2-3. Pod 실행 URL (독립적인 Microservice 라우팅용, 예: http://localhost:8082)
|
// 2-3. Pod 실행 URL (독립적인 Microservice 라우팅용, 예: http://localhost:8082)
|
||||||
private String podUrl;
|
private String podUrl;
|
||||||
|
|
||||||
|
// 2-4. 가시성 여부
|
||||||
|
private boolean visible;
|
||||||
|
|
||||||
// 3. 연동 아키텍처 구분 (DIRECT / MCI_EAI)
|
// 3. 연동 아키텍처 구분 (DIRECT / MCI_EAI)
|
||||||
private String integrationType; // 연동 타입: "DIRECT" 또는 "MCI_EAI"
|
private String integrationType; // 연동 타입: "DIRECT" 또는 "MCI_EAI"
|
||||||
|
|
||||||
|
|||||||
@@ -37,17 +37,8 @@ public class ToolPlanner {
|
|||||||
var toolMetadata = redisRegistryService.getTool(toolName);
|
var toolMetadata = redisRegistryService.getTool(toolName);
|
||||||
|
|
||||||
if (toolMetadata == null) {
|
if (toolMetadata == null) {
|
||||||
log.warn(" [Planner] 등록되지 않은 툴 요청: {}. 레지스트리를 참조하지 않고 강제 연동 모드로 전환합니다.", toolName);
|
log.warn(" [Planner] 등록되지 않은 툴 요청: {}", toolName);
|
||||||
// 히든 툴(register=false)에 대한 강제 라우팅 폴백
|
throw new RuntimeException("해당 툴(" + toolName + ")이 레지스트리에 존재하지 않습니다.");
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2-1. [신규] 도메인 그룹핑 기반 권한 검증
|
// 2-1. [신규] 도메인 그룹핑 기반 권한 검증
|
||||||
|
|||||||
@@ -16,4 +16,7 @@ public @interface McpFunction {
|
|||||||
|
|
||||||
// 추가: Redis 자동 등록 및 Heartbeat 대상 여부 제어
|
// 추가: Redis 자동 등록 및 Heartbeat 대상 여부 제어
|
||||||
boolean register() default true;
|
boolean register() default true;
|
||||||
|
|
||||||
|
// 추가: 툴 목록 노출 여부 제어 (false 시 라우팅은 되나 목록에서 숨김)
|
||||||
|
boolean visible() default true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,5 +19,6 @@ public class McpProperties {
|
|||||||
private String prompt;
|
private String prompt;
|
||||||
private String mappingId;
|
private String mappingId;
|
||||||
private Boolean register;
|
private Boolean register;
|
||||||
|
private Boolean visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,4 +49,9 @@ public class ToolMetadata {
|
|||||||
|
|
||||||
public String getMciServiceId() { return mciServiceId; }
|
public String getMciServiceId() { return mciServiceId; }
|
||||||
public void setMciServiceId(String mciServiceId) { this.mciServiceId = 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; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ public class ToolRegistryHeartbeatSender {
|
|||||||
meta.setMciServiceId(prop != null && prop.getMappingId() != null ? prop.getMappingId() : functionAnnotation.mappingId());
|
meta.setMciServiceId(prop != null && prop.getMappingId() != null ? prop.getMappingId() : functionAnnotation.mappingId());
|
||||||
meta.setPodUrl(podUrl);
|
meta.setPodUrl(podUrl);
|
||||||
|
|
||||||
|
boolean isVisible = prop != null && prop.getVisible() != null ? prop.getVisible() : functionAnnotation.visible();
|
||||||
|
meta.setVisible(isVisible);
|
||||||
|
|
||||||
Map<String, String> prompts = new HashMap<>();
|
Map<String, String> prompts = new HashMap<>();
|
||||||
String promptText = prop != null && prop.getPrompt() != null ? prop.getPrompt() : functionAnnotation.prompt();
|
String promptText = prop != null && prop.getPrompt() != null ? prop.getPrompt() : functionAnnotation.prompt();
|
||||||
prompts.put(functionAnnotation.name(), promptText);
|
prompts.put(functionAnnotation.name(), promptText);
|
||||||
|
|||||||
@@ -15,10 +15,9 @@ public class TemplateUtilityService extends AbstractMcpToolService {
|
|||||||
|
|
||||||
@McpFunction(
|
@McpFunction(
|
||||||
name = "get_template_file_url",
|
name = "get_template_file_url",
|
||||||
description = "각종 양식(엑셀, PDF 등) 샘플 파일의 다운로드 URL을 제공합니다.",
|
description = "특정 템플릿의 양식 파일(엑셀, 워드 등)을 다운로드 받을 수 있는 시스템 URL을 반환합니다. AI는 이 URL을 사용자에게 마크다운 링크 형태로 제공해야 합니다.",
|
||||||
prompt = "고객 등록 엑셀 샘플 파일 다운로드 링크 줘.",
|
prompt = "요청하신 템플릿 양식 파일 다운로드 URL은 다음과 같습니다. 클릭하여 다운로드하세요:",
|
||||||
mappingId = "COM_TMPL_01",
|
visible = false
|
||||||
register = false
|
|
||||||
)
|
)
|
||||||
public Map<String, Object> getTemplateFileUrl(TemplateDownloadReq data) {
|
public Map<String, Object> getTemplateFileUrl(TemplateDownloadReq data) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user