feat: Auto-prefix container namespaces to tool names to prevent conflicts

This commit is contained in:
jade
2026-07-08 17:23:27 +09:00
parent 3129a57727
commit 62f9060f25
6 changed files with 32 additions and 10 deletions

View File

@@ -11,6 +11,7 @@ import java.util.Map;
@ConfigurationProperties(prefix = "mcp") @ConfigurationProperties(prefix = "mcp")
public class McpProperties { public class McpProperties {
private String namespace;
private Map<String, FunctionProp> functions; private Map<String, FunctionProp> functions;
@Data @Data

View File

@@ -64,11 +64,18 @@ public class BusinessToolController {
for (Object bean : toolBeans.values()) { for (Object bean : toolBeans.values()) {
for (Method method : bean.getClass().getDeclaredMethods()) { for (Method method : bean.getClass().getDeclaredMethods()) {
McpFunction mcpFunc = method.getAnnotation(McpFunction.class); McpFunction mcpFunc = method.getAnnotation(McpFunction.class);
if (mcpFunc != null && mcpFunc.name().equals(functionName)) { if (mcpFunc != null) {
targetBean = bean; String baseName = mcpFunc.name();
targetMethod = method; String expectedName = mcpProperties.getNamespace() != null && !mcpProperties.getNamespace().isEmpty()
targetFunctionAnnotation = mcpFunc; ? mcpProperties.getNamespace() + "_" + baseName
break outerLoop; : baseName;
if (expectedName.equals(functionName)) {
targetBean = bean;
targetMethod = method;
targetFunctionAnnotation = mcpFunc;
break outerLoop;
}
} }
} }
} }

View File

@@ -58,19 +58,24 @@ public class ToolRegistryHeartbeatSender {
for (Method method : bean.getClass().getDeclaredMethods()) { for (Method method : bean.getClass().getDeclaredMethods()) {
McpFunction functionAnnotation = method.getAnnotation(McpFunction.class); McpFunction functionAnnotation = method.getAnnotation(McpFunction.class);
if (functionAnnotation != null) { if (functionAnnotation != null) {
String baseName = functionAnnotation.name();
String finalName = mcpProperties.getNamespace() != null && !mcpProperties.getNamespace().isEmpty()
? mcpProperties.getNamespace() + "_" + baseName
: baseName;
McpProperties.FunctionProp prop = null; McpProperties.FunctionProp prop = null;
if (mcpProperties.getFunctions() != 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(); boolean isRegister = prop != null && prop.getRegister() != null ? prop.getRegister() : functionAnnotation.register();
if (!isRegister) { if (!isRegister) {
log.info(" [HeartbeatSender] '{}' 툴은 설정에 의해 외부 등록(Redis) 대상에서 제외되었습니다.", functionAnnotation.name()); log.info(" [HeartbeatSender] '{}' 툴은 설정에 의해 외부 등록(Redis) 대상에서 제외되었습니다. (최종 이름: {})", baseName, finalName);
continue; continue;
} }
ToolMetadata meta = new ToolMetadata(); ToolMetadata meta = new ToolMetadata();
meta.setToolName(functionAnnotation.name()); meta.setToolName(finalName);
meta.setDescription(prop != null && prop.getDescription() != null ? prop.getDescription() : functionAnnotation.description()); meta.setDescription(prop != null && prop.getDescription() != null ? prop.getDescription() : functionAnnotation.description());
meta.setDomainGroup(toolAnnotation.group()); meta.setDomainGroup(toolAnnotation.group());
meta.setIntegrationType(toolAnnotation.routingType()); meta.setIntegrationType(toolAnnotation.routingType());
@@ -82,7 +87,7 @@ public class ToolRegistryHeartbeatSender {
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(finalName, promptText);
meta.setActionPrompts(prompts); meta.setActionPrompts(prompts);
if (method.getParameterCount() > 0) { if (method.getParameterCount() > 0) {
@@ -94,7 +99,7 @@ public class ToolRegistryHeartbeatSender {
finalSchema.put("properties", schema); finalSchema.put("properties", schema);
meta.setParametersSchema(finalSchema); meta.setParametersSchema(finalSchema);
} catch (Exception e) { } catch (Exception e) {
log.error("Failed to generate schema for {}", functionAnnotation.name(), e); log.error("Failed to generate schema for {}", finalName, e);
} }
} }

View File

@@ -5,3 +5,6 @@ spring.profiles.active=local
# Suppress Kafka Connection Logs # Suppress Kafka Connection Logs
logging.level.org.apache.kafka=ERROR logging.level.org.apache.kafka=ERROR
# Auto Prefix Namespace
mcp.namespace=email

View File

@@ -5,3 +5,6 @@ spring.profiles.active=local
# Suppress Kafka Connection Logs # Suppress Kafka Connection Logs
logging.level.org.apache.kafka=ERROR logging.level.org.apache.kafka=ERROR
# Auto Prefix Namespace
mcp.namespace=other

View File

@@ -5,3 +5,6 @@ spring.profiles.active=local
# Suppress Kafka Connection Logs # Suppress Kafka Connection Logs
logging.level.org.apache.kafka=ERROR logging.level.org.apache.kafka=ERROR
# Auto Prefix Namespace
mcp.namespace=sms