spring-projects/spring-ai · info

Multiple elicitation methods found: <count>

Error message

Multiple elicitation methods found: <count>

What it means

AsyncMcpElicitationProvider expects at most one elicitation handler among the supplied objects; MCP elicitation is a single server-level capability, not a list of providers. When it finds more than one @McpElicitation-annotated method it logs this warning reporting the count, but still proceeds (the handlers are returned). The warning flags ambiguous configuration that the library does not treat as fatal.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/provider/elicitation/AsyncMcpElicitationProvider.java:116

					Function<ElicitRequest, Mono<ElicitResult>> methodCallback = AsyncMcpElicitationMethodCallback
						.builder()
						.method(mcpElicitationMethod)
						.bean(elicitationObject)
						.elicitation(elicitationAnnotation)
						.build();

					return new AsyncElicitationSpecification(elicitationAnnotation.clients(), methodCallback);
				})
				.toList())
			.flatMap(List::stream)
			.toList();

		if (elicitationHandlers.isEmpty()) {
			logger.warn("No elicitation methods found");
		}
		if (elicitationHandlers.size() > 1) {
			if (logger.isWarnEnabled()) {
				logger.warn("Multiple elicitation methods found: " + elicitationHandlers.size());
			}
		}

		return elicitationHandlers;
	}

	/**
	 * Returns the methods of the given bean class.
	 * @param bean the bean instance
	 * @return the methods of the bean class
	 */
	protected Method[] doGetClassMethods(Object bean) {
		return bean.getClass().getDeclaredMethods();
	}

}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Keep exactly one @McpElicitation-annotated method across all objects passed to the provider and delete or un-annotate the rest
  2. If you genuinely need multiple behaviors, gate them inside the single handler method rather than registering several handlers
  3. Check which beans are auto-scanned into the provider list and exclude duplicates

Example fix

// before
class A { @McpElicitation Mono<ElicitResult> h1(ElicitRequest r) {...} }
class B { @McpElicitation Mono<ElicitResult> h2(ElicitRequest r) {...} }
new AsyncMcpElicitationProvider(List.of(new A(), new B()));

// after
class A { @McpElicitation Mono<ElicitResult> handle(ElicitRequest r) { /* route internally */ } }
new AsyncMcpElicitationProvider(List.of(new A()));
Defensive patterns

Strategy: validation

Validate before calling

long count = beans.stream()
    .flatMapToLong(b -> Arrays.stream(b.getClass().getDeclaredMethods())
        .filter(m -> m.isAnnotationPresent(McpElicitation.class)))
    .count();
if (count > 1) throw new IllegalStateException("Multiple @McpElicitation handlers: " + count);

Type guard

static boolean hasSingleElicitationHandler(List<Object> beans) {
    return beans.stream()
        .flatMap(b -> Arrays.stream(b.getClass().getDeclaredMethods()))
        .filter(m -> m.isAnnotationPresent(McpElicitation.class))
        .count() == 1;
}

Prevention

When it happens

Trigger: getElicitationSpecifications() collects more than one method annotated @McpElicitation across the provider objects (elicitationHandlers.size() > 1), e.g. two beans each with an elicitation handler or duplicate annotation on multiple methods in one class.

Common situations: Registering multiple elicitation service beans after a refactor; copying an example handler and leaving both in the classpath-scanned configuration; mixing legacy and new handler methods during migration.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/a8032c0a87461d19. Report an issue: GitHub.