fix(mcp): Implement tool de-duplication by name in MCP server
Add de-duplication logic for tools in the MCP server configuration, ensuring that tools with the same name are not registered multiple times. The implementation keeps the first occurrence of each tool name and discards duplicates. - Modified toSyncToolSpecifications and toAsyncToolSpecification methods to de-duplicate tools - Updated tests to verify that duplicate tools are properly filtered out Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
@@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.modelcontextprotocol.server.McpAsyncServer;
|
||||
import io.modelcontextprotocol.server.McpAsyncServerExchange;
|
||||
@@ -145,12 +146,25 @@ public class McpServerAutoConfiguration {
|
||||
|
||||
private List<McpServerFeatures.SyncToolSpecification> toSyncToolSpecifications(List<ToolCallback> tools,
|
||||
McpServerProperties serverProperties) {
|
||||
return tools.stream().map(tool -> {
|
||||
String toolName = tool.getToolDefinition().name();
|
||||
MimeType mimeType = (serverProperties.getToolResponseMimeType().containsKey(toolName))
|
||||
? MimeType.valueOf(serverProperties.getToolResponseMimeType().get(toolName)) : null;
|
||||
return McpToolUtils.toSyncToolSpecification(tool, mimeType);
|
||||
}).toList();
|
||||
|
||||
// De-duplicate tools by their name, keeping the first occurrence of each tool
|
||||
// name
|
||||
return tools.stream()
|
||||
.collect(Collectors.toMap(tool -> tool.getToolDefinition().name(), // Key:
|
||||
// tool
|
||||
// name
|
||||
tool -> tool, // Value: the tool itself
|
||||
(existing, replacement) -> existing)) // On duplicate key, keep the
|
||||
// existing tool
|
||||
.values()
|
||||
.stream()
|
||||
.map(tool -> {
|
||||
String toolName = tool.getToolDefinition().name();
|
||||
MimeType mimeType = (serverProperties.getToolResponseMimeType().containsKey(toolName))
|
||||
? MimeType.valueOf(serverProperties.getToolResponseMimeType().get(toolName)) : null;
|
||||
return McpToolUtils.toSyncToolSpecification(tool, mimeType);
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -231,12 +245,24 @@ public class McpServerAutoConfiguration {
|
||||
|
||||
private List<McpServerFeatures.AsyncToolSpecification> toAsyncToolSpecification(List<ToolCallback> tools,
|
||||
McpServerProperties serverProperties) {
|
||||
return tools.stream().map(tool -> {
|
||||
String toolName = tool.getToolDefinition().name();
|
||||
MimeType mimeType = (serverProperties.getToolResponseMimeType().containsKey(toolName))
|
||||
? MimeType.valueOf(serverProperties.getToolResponseMimeType().get(toolName)) : null;
|
||||
return McpToolUtils.toAsyncToolSpecification(tool, mimeType);
|
||||
}).toList();
|
||||
// De-duplicate tools by their name, keeping the first occurrence of each tool
|
||||
// name
|
||||
return tools.stream()
|
||||
.collect(Collectors.toMap(tool -> tool.getToolDefinition().name(), // Key:
|
||||
// tool
|
||||
// name
|
||||
tool -> tool, // Value: the tool itself
|
||||
(existing, replacement) -> existing)) // On duplicate key, keep the
|
||||
// existing tool
|
||||
.values()
|
||||
.stream()
|
||||
.map(tool -> {
|
||||
String toolName = tool.getToolDefinition().name();
|
||||
MimeType mimeType = (serverProperties.getToolResponseMimeType().containsKey(toolName))
|
||||
? MimeType.valueOf(serverProperties.getToolResponseMimeType().get(toolName)) : null;
|
||||
return McpToolUtils.toAsyncToolSpecification(tool, mimeType);
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -161,7 +161,7 @@ public class McpServerAutoConfigurationIT {
|
||||
void toolRegistrationConfiguration() {
|
||||
this.contextRunner.withUserConfiguration(TestToolConfiguration.class).run(context -> {
|
||||
List<SyncToolSpecification> tools = context.getBean("syncTools", List.class);
|
||||
assertThat(tools).hasSize(2);
|
||||
assertThat(tools).hasSize(1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ public class McpServerAutoConfigurationIT {
|
||||
.withUserConfiguration(TestToolConfiguration.class)
|
||||
.run(context -> {
|
||||
List<AsyncToolSpecification> tools = context.getBean("asyncTools", List.class);
|
||||
assertThat(tools).hasSize(2);
|
||||
assertThat(tools).hasSize(1);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user