spring-projects/spring-ai · warning

Multiple sampling methods found: <count>

Error message

Multiple sampling methods found: <count>

What it means

AsyncMcpSamplingProvider.getSamplingSpecifictions logs 'Multiple sampling methods found: N' when more than one @McpSampling-annotated method is discovered across the configured objects. Some MCP server wiring expects a single sampling handler, so multiple handlers may be ambiguous or only the first may take effect depending on downstream usage.

Source

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

					Function<CreateMessageRequest, Mono<CreateMessageResult>> methodCallback = AsyncMcpSamplingMethodCallback
						.builder()
						.method(mcpSamplingMethod)
						.bean(samplingObject)
						.sampling(samplingAnnotation)
						.build();

					return new AsyncSamplingSpecification(samplingAnnotation.clients(), methodCallback);
				})
				.toList())
			.flatMap(List::stream)
			.toList();

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

		return samplingHandlers;
	}

	/**
	 * 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 @McpSampling-annotated method across the registered sampling objects, consolidating logic into it.
  2. Remove stale/duplicate annotated methods or drop their @McpSampling annotation.
  3. If multiple handlers are intentional, confirm downstream registration supports all of them; otherwise split into separate providers.

Example fix

// before
class Sampler { @McpSampling CompletableFuture<String> a(...) {...} @McpSampling CompletableFuture<String> b(...) {...} }
// after
class Sampler { @McpSampling CompletableFuture<String> handle(...) { /* merged logic */ } }
Defensive patterns

Strategy: validation

Validate before calling

// Enforce a single sampling handler before registration:
long count = Arrays.stream(samplingObjects)
    .flatMapToLong(o -> Arrays.stream(o.getClass().getDeclaredMethods())
        .filter(m -> m.isAnnotationPresent(McpSampling.class)))
    .count();
if (count > 1) throw new IllegalStateException("Only one @McpSampling method allowed, found " + count);

Prevention

When it happens

Trigger: Two or more public methods annotated with @McpSampling exist across the sampling objects passed to AsyncMcpSamplingProvider; samplingHandlers.size() > 1 triggers the warn at AsyncMcpSamplingProvider.java:116.

Common situations: Accidental duplicate handler methods added during refactoring; multiple sampling classes registered where one combined handler was intended; copy-paste leaving an old sampling method in place alongside the new one.

Related errors


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