forked from kimhyungsik/ax_hub_mcp_tool
refactor: apply new Naming standard (uid, categoryKey, subToolName) across modules
This commit is contained in:
@@ -36,7 +36,10 @@ import java.util.Map;
|
||||
public class ToolMetadata {
|
||||
|
||||
// 1. Tool 기본 정보
|
||||
private String toolName; // 툴 고유 명칭 (예: CustomerSearchTool)
|
||||
private String uid; // UUID 형식의 고유 식별자
|
||||
private String semver; // 버전 (예: 1.0.0)
|
||||
private String name; // 사람이 읽는 라벨 (1-128자)
|
||||
private String subToolName; // MCP 서브툴 명칭 (64자 이하, 예: CustomerSearchTool)
|
||||
private String description; // 툴의 목적 및 설명 (LLM 프롬프트에 활용 가능)
|
||||
|
||||
// 2. 파라미터 스키마 (JSON Schema 형태의 Map)
|
||||
@@ -45,8 +48,8 @@ public class ToolMetadata {
|
||||
// 2-0. 프론트엔드 UI용 함수별 프롬프트 매핑 (추가됨)
|
||||
private Map<String, String> actionPrompts;
|
||||
|
||||
// 2-1. 도메인 부서 그룹명 (권한 관리에 사용)
|
||||
private String domainGroup;
|
||||
// 2-1. 도메인 부서 그룹명 (category_key, 슬러그 형식)
|
||||
private String categoryKey;
|
||||
|
||||
// 2-2. 툴 처리 엔드포인트 URI 경로 (예: /api/tool/customer-info)
|
||||
private String endpoint;
|
||||
|
||||
@@ -109,11 +109,11 @@ public class McpRouterController {
|
||||
public ResponseEntity<JsonRpcResponse> listTools() {
|
||||
List<ToolMetadata> activeTools = redisRegistryService.getAllTools()
|
||||
.stream()
|
||||
.filter(ToolMetadata::isVisible)
|
||||
.filter(ToolMetadata::getVisible)
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
|
||||
java.util.Set<String> knownTools = activeTools.stream()
|
||||
.map(ToolMetadata::getToolName)
|
||||
.map(ToolMetadata::getUid)
|
||||
.collect(java.util.stream.Collectors.toSet());
|
||||
|
||||
java.util.Set<String> fallbackUrls = new java.util.HashSet<>(gatewayFallbackProperties.getRoutes().values());
|
||||
@@ -130,9 +130,9 @@ public class McpRouterController {
|
||||
|
||||
if (localTools != null) {
|
||||
for (ToolMetadata t : localTools) {
|
||||
if (!Boolean.TRUE.equals(t.getIsRegistered()) && Boolean.TRUE.equals(t.getVisible()) && !knownTools.contains(t.getToolName())) {
|
||||
if (!Boolean.TRUE.equals(t.getIsRegistered()) && Boolean.TRUE.equals(t.getVisible()) && !knownTools.contains(t.getUid())) {
|
||||
activeTools.add(t);
|
||||
knownTools.add(t.getToolName());
|
||||
knownTools.add(t.getUid());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,7 +152,7 @@ public class McpRouterController {
|
||||
public ResponseEntity<String> generateToolsMarkdown() {
|
||||
List<ToolMetadata> tools = redisRegistryService.getAllTools()
|
||||
.stream()
|
||||
.filter(ToolMetadata::isVisible)
|
||||
.filter(ToolMetadata::getVisible)
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
|
||||
StringBuilder md = new StringBuilder();
|
||||
@@ -165,7 +165,7 @@ public class McpRouterController {
|
||||
// Group by Domain Group
|
||||
Map<String, List<ToolMetadata>> groupedTools = new java.util.HashMap<>();
|
||||
for (ToolMetadata tool : tools) {
|
||||
String group = tool.getDomainGroup() != null ? tool.getDomainGroup() : "기타 (Others)";
|
||||
String group = tool.getCategoryKey() != null ? tool.getCategoryKey() : "기타 (Others)";
|
||||
groupedTools.computeIfAbsent(group, k -> new java.util.ArrayList<>()).add(tool);
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ public class McpRouterController {
|
||||
|
||||
int index = 1;
|
||||
for (ToolMetadata tool : entry.getValue()) {
|
||||
md.append("### ").append(index++).append(". ").append(tool.getToolName()).append("\n");
|
||||
md.append("### ").append(index++).append(". ").append(tool.getUid()).append("\n");
|
||||
if (tool.getDescription() != null) {
|
||||
md.append("- **설명**: ").append(tool.getDescription()).append("\n");
|
||||
}
|
||||
@@ -223,14 +223,14 @@ public class McpRouterController {
|
||||
}
|
||||
|
||||
@PostMapping("/registry/deregister")
|
||||
public ResponseEntity<String> deregisterTool(@RequestBody String toolName) {
|
||||
redisRegistryService.removeTool(toolName);
|
||||
public ResponseEntity<String> deregisterTool(@RequestBody String uid) {
|
||||
redisRegistryService.removeTool(uid);
|
||||
return ResponseEntity.ok("Deregistered");
|
||||
}
|
||||
|
||||
@PostMapping("/registry/heartbeat")
|
||||
public ResponseEntity<String> heartbeat(@RequestBody String toolName) {
|
||||
boolean success = redisRegistryService.refreshHeartbeat(toolName);
|
||||
public ResponseEntity<String> heartbeat(@RequestBody String uid) {
|
||||
boolean success = redisRegistryService.refreshHeartbeat(uid);
|
||||
if (success) {
|
||||
return ResponseEntity.ok("Heartbeat updated");
|
||||
} else {
|
||||
|
||||
@@ -39,28 +39,28 @@ public class RedisRegistryService {
|
||||
* 툴 등록 및 갱신 (TTL 기반으로 60초 뒤 자동 만료)
|
||||
*/
|
||||
public void saveTool(ToolMetadata meta) {
|
||||
String key = KEY_PREFIX + meta.getToolName();
|
||||
String key = KEY_PREFIX + meta.getUid();
|
||||
meta.setLastHeartbeat(System.currentTimeMillis());
|
||||
redisTemplate.opsForValue().set(key, meta, DEFAULT_TTL);
|
||||
log.info(" [RedisRegistry] 툴 등록 완료: {}", meta.getToolName());
|
||||
log.info(" [RedisRegistry] 툴 등록 완료: {}", meta.getUid());
|
||||
}
|
||||
|
||||
/**
|
||||
* 하트비트 갱신 (TTL 초기화)
|
||||
*/
|
||||
public boolean refreshHeartbeat(String toolName) {
|
||||
String key = KEY_PREFIX + toolName;
|
||||
public boolean refreshHeartbeat(String uid) {
|
||||
String key = KEY_PREFIX + uid;
|
||||
Boolean exists = redisTemplate.expire(key, DEFAULT_TTL);
|
||||
if (Boolean.TRUE.equals(exists)) {
|
||||
log.debug(" [RedisRegistry] 하트비트 갱신: {}", toolName);
|
||||
log.debug(" [RedisRegistry] 하트비트 갱신: {}", uid);
|
||||
return true;
|
||||
} else {
|
||||
log.warn(" [RedisRegistry] 존재하지 않는 툴에 대한 하트비트 요청: {}", toolName);
|
||||
log.warn(" [RedisRegistry] 존재하지 않는 툴에 대한 하트비트 요청: {}", uid);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public List<String> getAvailablePods(String toolName) {
|
||||
ToolMetadata tool = getTool(toolName);
|
||||
public List<String> getAvailablePods(String uid) {
|
||||
ToolMetadata tool = getTool(uid);
|
||||
|
||||
if (tool != null && tool.getPodUrl() != null) {
|
||||
return List.of(tool.getPodUrl());
|
||||
@@ -71,8 +71,8 @@ public class RedisRegistryService {
|
||||
/**
|
||||
* 실행 시 툴 정보 조회 (Tool Execution 시 참조)
|
||||
*/
|
||||
public ToolMetadata getTool(String toolName) {
|
||||
return redisTemplate.opsForValue().get(KEY_PREFIX + toolName);
|
||||
public ToolMetadata getTool(String uid) {
|
||||
return redisTemplate.opsForValue().get(KEY_PREFIX + uid);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,8 +90,8 @@ public class RedisRegistryService {
|
||||
/**
|
||||
* 툴 명시적 제거 (Deregister)
|
||||
*/
|
||||
public void removeTool(String toolName) {
|
||||
redisTemplate.delete(KEY_PREFIX + toolName);
|
||||
log.info(" [RedisRegistry] 툴 삭제 완료: {}", toolName);
|
||||
public void removeTool(String uid) {
|
||||
redisTemplate.delete(KEY_PREFIX + uid);
|
||||
log.info(" [RedisRegistry] 툴 삭제 완료: {}", uid);
|
||||
}
|
||||
}
|
||||
@@ -73,19 +73,19 @@ public class ToolPlanner {
|
||||
log.info(" [Planner] Fallback 라우팅 매칭됨: {} -> {}", toolName, fallbackPodUrl);
|
||||
|
||||
toolMetadata = ToolMetadata.builder()
|
||||
.toolName(toolName)
|
||||
.uid(toolName)
|
||||
.integrationType("DIRECT")
|
||||
.podUrl(fallbackPodUrl)
|
||||
.build();
|
||||
}
|
||||
|
||||
// 2-1. [신규] 도메인 그룹핑 기반 권한 검증
|
||||
if (tenantId != null && toolMetadata.getDomainGroup() != null) {
|
||||
if (tenantId != null && toolMetadata.getCategoryKey() != null) {
|
||||
List<String> allowedDomains = securityProperties.getTenantDomains().get(tenantId);
|
||||
if (allowedDomains == null ||
|
||||
(!allowedDomains.contains("ALL") && !allowedDomains.contains(toolMetadata.getDomainGroup()))) {
|
||||
log.warn(" [Planner] 권한 거부 - Tenant: {}, Request Domain: {}", tenantId, toolMetadata.getDomainGroup());
|
||||
throw new SecurityException("해당 도메인(" + toolMetadata.getDomainGroup() + ")의 툴을 실행할 권한이 없습니다.");
|
||||
(!allowedDomains.contains("ALL") && !allowedDomains.contains(toolMetadata.getCategoryKey()))) {
|
||||
log.warn(" [Planner] 권한 거부 - Tenant: {}, Request Domain: {}", tenantId, toolMetadata.getCategoryKey());
|
||||
throw new SecurityException("해당 도메인(" + toolMetadata.getCategoryKey() + ")의 툴을 실행할 권한이 없습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user