spring-projects/spring-ai · error · IllegalArgumentException
Found 2 elicitation handlers for client [%s], found in bean
Error message
Found 2 elicitation handlers for client [%s], found in bean with names %s. Only one @McpElicitation handler is allowed per client
What it means
During bean-factory post-processing, AbstractClientMcpHandlerRegistry collects beans annotated with @McpElicitation per target client. MCP allows at most one elicitation handler per client, so if two or more annotated beans map to the same client name it throws IllegalArgumentException listing the conflicting bean names. This fails fast at application startup rather than at first elicitation request.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/spring/AbstractClientMcpHandlerRegistry.java:104
this.allAnnotatedBeans.add(beanName);
}
for (var foundAnnotation : foundAnnotations) {
if (foundAnnotation instanceof McpSampling sampling) {
for (var client : sampling.clients()) {
samplingClientToAnnotatedBeans.computeIfAbsent(client, c -> new ArrayList<>()).add(beanName);
}
}
else if (foundAnnotation instanceof McpElicitation elicitation) {
for (var client : elicitation.clients()) {
elicitationClientToAnnotatedBeans.computeIfAbsent(client, c -> new ArrayList<>()).add(beanName);
}
}
}
}
for (var elicitationEntry : elicitationClientToAnnotatedBeans.entrySet()) {
if (elicitationEntry.getValue().size() > 1) {
throw new IllegalArgumentException(
"Found 2 elicitation handlers for client [%s], found in bean with names %s. Only one @McpElicitation handler is allowed per client"
.formatted(elicitationEntry.getKey(), new LinkedHashSet<>(elicitationEntry.getValue())));
}
}
for (var samplingEntry : samplingClientToAnnotatedBeans.entrySet()) {
if (samplingEntry.getValue().size() > 1) {
throw new IllegalArgumentException(
"Found 2 sampling handlers for client [%s], found in bean with names %s. Only one @McpSampling handler is allowed per client"
.formatted(samplingEntry.getKey(), new LinkedHashSet<>(samplingEntry.getValue())));
}
}
Map<String, McpSchema.ClientCapabilities.Builder> capsPerClient = new HashMap<>();
for (var samplingClient : samplingClientToAnnotatedBeans.keySet()) {
capsPerClient.computeIfAbsent(samplingClient, ignored -> McpSchema.ClientCapabilities.builder()).sampling();
}
for (var elicitationClient : elicitationClientToAnnotatedBeans.keySet()) {
capsPerClient.computeIfAbsent(elicitationClient, ignored -> McpSchema.ClientCapabilities.builder())View on GitHub (pinned to 98a7beda4f)
Solutions
- Remove or disable one of the conflicting @McpElicitation beans so only one handler exists per client (the message lists the offending bean names).
- If both handlers are needed, consolidate their logic into a single @McpElicitation method that dispatches internally.
- Change one bean's client target so each client has at most one elicitation handler.
Example fix
// before: two beans both annotate @McpElicitation for client "myClient"
@Bean MyElicitationHandlerA handlerA() { ... }
@Bean MyElicitationHandlerB handlerB() { ... }
// after: single consolidated handler
@Bean MyElicitationHandler handler() { ... } // merges A and B logic Defensive patterns
Strategy: validation
Validate before calling
// At startup, verify exactly one @McpElicitation handler per client before context refresh completes
Map<String, Long> counts = beansWithMcpElicitation.stream()
.collect(Collectors.groupingBy(b -> b.clientName(), Collectors.counting()));
counts.forEach((client, n) -> {
if (n > 1) throw new IllegalStateException("Multiple @McpElicitation handlers for client " + client);
}); Prevention
- Keep at most one @McpElicitation bean per client name.
- Search the codebase for @McpElicitation after adding a new handler.
- Centralize handler definitions in a single configuration class to avoid accidental duplicates.
When it happens
Trigger: Declaring two (or more) beans whose methods carry @McpElicitation targeting the same MCP client name; application startup with both registered triggers postProcessBeanFactory to throw.
Common situations: Two configuration classes each defining an elicitation handler for the same client; a copied/renamed bean left in place alongside the new handler; component scanning picking up duplicate @McpElicitation beans.
Related errors
- Found 2 sampling handlers for client [%s], found in bean wit
- SSE connection '<connectionName>' requires a 'url' property.
- Failed to read stdio connection resource
- Failed to create SSE transport for connection '<connectionNa
- Multiple tools with the same name (%s)
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/c39d3644693d3c4c.
Report an issue: GitHub.