spring-projects/spring-ai · info

No elicitation methods found

Error message

No elicitation methods found

What it means

SyncMcpElicitationProvider scans provider objects for @McpElicitation methods with synchronous signatures and builds handler specifications. An empty result logs this warning; no exception is thrown and the server runs without an elicitation handler. The library emits it because passing objects to an elicitation provider while yielding zero handlers usually indicates a wiring or annotation mistake.

Source

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

						&& ElicitRequest.class.isAssignableFrom(method.getParameterTypes()[0]))
				.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
				.map(mcpElicitationMethod -> {
					var elicitationAnnotation = mcpElicitationMethod.getAnnotation(McpElicitation.class);

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

					return new SyncElicitationSpecification(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. Add @McpElicitation to a method in the supplied bean with a synchronous signature matching what the sync provider's predicates accept
  2. Move the annotated method into the class itself if it currently lives in a superclass or interface
  3. Switch to AsyncMcpElicitationProvider if the handler returns Mono/Flux
  4. Remove the provider registration if elicitation is intentionally unused

Example fix

// before
class Handlers { } // empty bean registered as elicitation source

// after
class Handlers {
    @McpElicitation
    public ElicitResult handle(ElicitRequest request) { ... }
}
new SyncMcpElicitationProvider(List.of(new Handlers()));
Defensive patterns

Strategy: validation

Validate before calling

if (Arrays.stream(bean.getClass().getDeclaredMethods())
        .noneMatch(m -> m.isAnnotationPresent(McpElicitation.class))) {
    throw new IllegalStateException("No @McpElicitation handler in " + bean.getClass());
}

Type guard

static boolean hasSyncElicitationHandler(Object bean) {
    return Arrays.stream(bean.getClass().getDeclaredMethods())
        .anyMatch(m -> m.isAnnotationPresent(McpElicitation.class));
}

Prevention

When it happens

Trigger: getElicitationSpecifications() finds no method annotated @McpElicitation (or none matching the sync predicate filters) in the supplied objects, or the objects list is empty.

Common situations: Missing @McpElicitation annotation; async (Mono/Flux) handler given to the sync provider; handler declared in a superclass; elicitation bean not actually injected into the provider constructor.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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