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")
public class McpProperties {
private String namespace;
private Map<String, FunctionProp> functions;
@Data

View File

@@ -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;
}
}
}
}

View File

@@ -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<String, String> 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);
}
}