From 62f9060f254ad33d29d5f1a178423144903483cb Mon Sep 17 00:00:00 2001 From: jade Date: Wed, 8 Jul 2026 17:23:27 +0900 Subject: [PATCH] feat: Auto-prefix container namespaces to tool names to prevent conflicts --- .../biz/mcp/tool/config/McpProperties.java | 1 + .../tool/controller/BusinessToolController.java | 17 ++++++++++++----- .../service/ToolRegistryHeartbeatSender.java | 15 ++++++++++----- .../src/main/resources/application.properties | 3 +++ .../src/main/resources/application.properties | 3 +++ .../src/main/resources/application.properties | 3 +++ 6 files changed, 32 insertions(+), 10 deletions(-) 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 2b8accf..a4309df 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 @@ -11,6 +11,7 @@ import java.util.Map; @ConfigurationProperties(prefix = "mcp") public class McpProperties { + private String namespace; private Map functions; @Data diff --git a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/controller/BusinessToolController.java b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/controller/BusinessToolController.java index 87d9de6..1be9172 100644 --- a/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/controller/BusinessToolController.java +++ b/axhub-tool-core/src/main/java/io/shinhanlife/axhub/biz/mcp/tool/controller/BusinessToolController.java @@ -64,11 +64,18 @@ public class BusinessToolController { for (Object bean : toolBeans.values()) { for (Method method : bean.getClass().getDeclaredMethods()) { McpFunction mcpFunc = method.getAnnotation(McpFunction.class); - if (mcpFunc != null && mcpFunc.name().equals(functionName)) { - targetBean = bean; - targetMethod = method; - targetFunctionAnnotation = mcpFunc; - break outerLoop; + if (mcpFunc != null) { + String baseName = mcpFunc.name(); + String expectedName = mcpProperties.getNamespace() != null && !mcpProperties.getNamespace().isEmpty() + ? mcpProperties.getNamespace() + "_" + baseName + : baseName; + + if (expectedName.equals(functionName)) { + targetBean = bean; + targetMethod = method; + targetFunctionAnnotation = mcpFunc; + break outerLoop; + } } } } 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 ad19567..1d87785 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 @@ -58,19 +58,24 @@ public class ToolRegistryHeartbeatSender { for (Method method : bean.getClass().getDeclaredMethods()) { McpFunction functionAnnotation = method.getAnnotation(McpFunction.class); if (functionAnnotation != null) { + String baseName = functionAnnotation.name(); + String finalName = mcpProperties.getNamespace() != null && !mcpProperties.getNamespace().isEmpty() + ? mcpProperties.getNamespace() + "_" + baseName + : baseName; + McpProperties.FunctionProp prop = null; if (mcpProperties.getFunctions() != null) { - prop = mcpProperties.getFunctions().get(functionAnnotation.name()); + prop = mcpProperties.getFunctions().get(baseName); } boolean isRegister = prop != null && prop.getRegister() != null ? prop.getRegister() : functionAnnotation.register(); if (!isRegister) { - log.info(" [HeartbeatSender] '{}' 툴은 설정에 의해 외부 등록(Redis) 대상에서 제외되었습니다.", functionAnnotation.name()); + log.info(" [HeartbeatSender] '{}' 툴은 설정에 의해 외부 등록(Redis) 대상에서 제외되었습니다. (최종 이름: {})", baseName, finalName); continue; } ToolMetadata meta = new ToolMetadata(); - meta.setToolName(functionAnnotation.name()); + meta.setToolName(finalName); meta.setDescription(prop != null && prop.getDescription() != null ? prop.getDescription() : functionAnnotation.description()); meta.setDomainGroup(toolAnnotation.group()); meta.setIntegrationType(toolAnnotation.routingType()); @@ -82,7 +87,7 @@ public class ToolRegistryHeartbeatSender { Map prompts = new HashMap<>(); String promptText = prop != null && prop.getPrompt() != null ? prop.getPrompt() : functionAnnotation.prompt(); - prompts.put(functionAnnotation.name(), promptText); + prompts.put(finalName, promptText); meta.setActionPrompts(prompts); if (method.getParameterCount() > 0) { @@ -94,7 +99,7 @@ public class ToolRegistryHeartbeatSender { finalSchema.put("properties", schema); meta.setParametersSchema(finalSchema); } catch (Exception e) { - log.error("Failed to generate schema for {}", functionAnnotation.name(), e); + log.error("Failed to generate schema for {}", finalName, e); } } diff --git a/axhub-tool-email/src/main/resources/application.properties b/axhub-tool-email/src/main/resources/application.properties index a575430..29f31d8 100644 --- a/axhub-tool-email/src/main/resources/application.properties +++ b/axhub-tool-email/src/main/resources/application.properties @@ -5,3 +5,6 @@ spring.profiles.active=local # Suppress Kafka Connection Logs logging.level.org.apache.kafka=ERROR + +# Auto Prefix Namespace +mcp.namespace=email diff --git a/axhub-tool-other/src/main/resources/application.properties b/axhub-tool-other/src/main/resources/application.properties index dca90a4..0430deb 100644 --- a/axhub-tool-other/src/main/resources/application.properties +++ b/axhub-tool-other/src/main/resources/application.properties @@ -5,3 +5,6 @@ spring.profiles.active=local # Suppress Kafka Connection Logs logging.level.org.apache.kafka=ERROR + +# Auto Prefix Namespace +mcp.namespace=other diff --git a/axhub-tool-sms/src/main/resources/application.properties b/axhub-tool-sms/src/main/resources/application.properties index a068533..0397a08 100644 --- a/axhub-tool-sms/src/main/resources/application.properties +++ b/axhub-tool-sms/src/main/resources/application.properties @@ -5,3 +5,6 @@ spring.profiles.active=local # Suppress Kafka Connection Logs logging.level.org.apache.kafka=ERROR + +# Auto Prefix Namespace +mcp.namespace=sms