feat: Show unregistered tools and add UI filtering

This commit is contained in:
jade
2026-07-09 23:28:22 +09:00
parent 1f38392600
commit 49585082b3
7 changed files with 111 additions and 13 deletions

View File

@@ -39,7 +39,10 @@ public class ToolMetadata {
private String mciServiceId;
@Builder.Default
private boolean visible = true;
@Builder.Default
private boolean isRegistered = true;
}

View File

@@ -1,6 +1,7 @@
package io.shinhanlife.axhub.biz.mcp.tool.presentation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -23,6 +24,8 @@ import org.springframework.context.ApplicationContext;
import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpTool;
import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpFunction;
import io.shinhanlife.axhub.biz.mcp.tool.config.McpProperties;
import io.shinhanlife.axhub.biz.mcp.tool.dto.ToolMetadata;
import io.shinhanlife.axhub.biz.mcp.tool.service.ToolRegistryHeartbeatSender;
import java.lang.reflect.Method;
import io.shinhanlife.axhub.biz.mcp.tool.util.JsonSchemaGenerator;
import org.springframework.util.ClassUtils;
@@ -54,6 +57,13 @@ public class BusinessToolController {
private final ApplicationContext applicationContext;
private final ObjectMapper objectMapper;
private final McpProperties mcpProperties;
private final ToolRegistryHeartbeatSender toolRegistryHeartbeatSender;
// 내부 조회용 로컬 Tool 목록 엔드포인트
@GetMapping("/mcp/api/v1/tools/local")
public List<ToolMetadata> getLocalTools() {
return toolRegistryHeartbeatSender.getAllScannedTools();
}
// JSON RPC 기반 단일 라우팅 엔드포인트
@PostMapping("/mcp/api/v1/tools/call")

View File

@@ -5,6 +5,7 @@ import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpTool;
import io.shinhanlife.axhub.biz.mcp.tool.dto.ToolMetadata;
import io.shinhanlife.axhub.biz.mcp.tool.util.JsonSchemaGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
@@ -60,6 +61,9 @@ public class ToolRegistryHeartbeatSender {
private String podUrl;
private List<ToolMetadata> registeredTools = new ArrayList<>();
@Getter
private List<ToolMetadata> allScannedTools = new ArrayList<>();
@PostConstruct
public void init() {
@@ -89,7 +93,6 @@ public class ToolRegistryHeartbeatSender {
boolean isRegister = prop != null && prop.getRegister() != null ? prop.getRegister() : functionAnnotation.register();
if (!isRegister) {
log.info(" [HeartbeatSender] '{}' 툴은 설정에 의해 외부 등록(Redis) 대상에서 제외되었습니다. (최종 이름: {})", baseName, finalName);
continue;
}
ToolMetadata meta = new ToolMetadata();
@@ -102,6 +105,7 @@ public class ToolRegistryHeartbeatSender {
boolean isVisible = prop != null && prop.getVisible() != null ? prop.getVisible() : functionAnnotation.visible();
meta.setVisible(isVisible);
meta.setRegistered(isRegister);
Map<String, String> prompts = new HashMap<>();
String promptText = prop != null && prop.getPrompt() != null ? prop.getPrompt() : functionAnnotation.prompt();
@@ -121,8 +125,11 @@ public class ToolRegistryHeartbeatSender {
}
}
registeredTools.add(meta);
log.info(" [HeartbeatSender] 도구 메타데이터 생성: {}", meta.getToolName());
if (isRegister) {
registeredTools.add(meta);
}
allScannedTools.add(meta);
log.info(" [HeartbeatSender] 도구 메타데이터 생성: {} (isRegistered: {})", meta.getToolName(), isRegister);
}
}
}