spring-projects/spring-ai · error · IllegalStateException
Multiple tools with the same name (%s)
Error message
Multiple tools with the same name (%s)
What it means
SyncMcpToolCallbackProvider.getToolCallbacks() validates that the aggregated list of ToolCallbacks across all configured MCP clients has no duplicate tool names and throws IllegalStateException otherwise. Because tool invocation is by name, duplicates would be ambiguous, so the provider fails fast during discovery.
Source
Thrown at mcp/common/src/main/java/org/springframework/ai/mcp/SyncMcpToolCallbackProvider.java:185
}
private static McpConnectionInfo connectionInfo(McpSyncClient mcpClient) {
return McpConnectionInfo.builder()
.clientCapabilities(mcpClient.getClientCapabilities())
.clientInfo(mcpClient.getClientInfo())
.initializeResult(mcpClient.getCurrentInitializationResult())
.build();
}
/**
* Validates tool callbacks for duplicate names.
* @param toolCallbacks callbacks to validate
* @throws IllegalStateException if duplicate names exist
*/
private void validateToolCallbacks(List<ToolCallback> toolCallbacks) {
List<String> duplicateToolNames = ToolUtils.getDuplicateToolNames(toolCallbacks);
if (!duplicateToolNames.isEmpty()) {
throw new IllegalStateException(
"Multiple tools with the same name (%s)".formatted(String.join(", ", duplicateToolNames)));
}
}
/**
* Creates tool callbacks from multiple MCP clients.
* <p>
* Discovers and consolidates tools from all provided clients into a single list,
* ensuring no naming conflicts.
* @param mcpClients MCP clients to discover tools from
* @return consolidated list of tool callbacks
*/
public static List<ToolCallback> syncToolCallbacks(List<McpSyncClient> mcpClients) {
if (CollectionUtils.isEmpty(mcpClients)) {
return List.of();
}
return List.of((new SyncMcpToolCallbackProvider(mcpClients).getToolCallbacks()));View on GitHub (pinned to 98a7beda4f)
Solutions
- Configure a unique connectionNamePrefix per MCP client so tool names become <prefix>_<toolName>
- Rename or deduplicate the colliding tool on one of the MCP servers
- Use the duplicated names listed in the message to locate the offending clients/servers
- Remove the redundant MCP client connection if both expose the same toolset
Example fix
// before (application.yml) — no prefixes, both servers expose "search"
spring:
ai:
mcp:
client:
connections:
server1:
url: http://host1/sse
server2:
url: http://host2/sse
// after — prefixes ensure unique tool names (server1_search, server2_search)
spring:
ai:
mcp:
client:
toolcallback:
connection-name-prefix: mcp
connections:
server1:
url: http://host1/sse
server2:
url: http://host2/sse Defensive patterns
Strategy: validation
Validate before calling
SyncMcpToolCallbackProvider p = new SyncMcpToolCallbackProvider(clients);
List<ToolCallback> cbs = p.getToolCallbacks(); // wraps validation
List<String> dups = ToolUtils.getDuplicateToolNames(cbs);
if (!dups.isEmpty()) throw new IllegalStateException("Duplicate MCP tool names at startup: " + dups); Type guard
long distinct = callbacks.stream().map(c -> c.getToolDefinition().name()).distinct().count(); boolean hasDuplicates = distinct != callbacks.size();
Prevention
- Assign a unique connection-name-prefix per MCP server connection in configuration
- Call getToolCallbacks() early at startup so duplicates surface before serving traffic
- Don't register the same MCP server twice in the connections map
- Watch for spring-ai upgrades that change default tool naming and re-run duplicate checks
When it happens
Trigger: Calling getToolCallbacks() on a SyncMcpToolCallbackProvider aggregating multiple McpSyncClients where tools from different clients resolve to identical names — typically because no connectionNamePrefix is set or the same prefix is reused.
Common situations: spring.ai.mcp.client connections for two servers that both expose e.g. 'fetch_docs' without connection-name-prefix configured; duplicating a server entry in the connections map; upgrading to a spring-ai version where default naming no longer includes a unique prefix.
Related errors
- Multiple tools with the same name (%s)
- Failed to read stdio connection resource
- SSE connection '<connectionName>' requires a 'url' property.
- Failed to create SSE transport for connection '<connectionNa
- At least one client Id must be specified
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/a4d8b97de1717798.
Report an issue: GitHub.