spring-projects/spring-ai · warning

ASYNC Providers don't support imperative (non-reactive) retu

Error message

ASYNC Providers don't support imperative (non-reactive) return types. Skipping method <method> with non-reactive return type <returnType>

What it means

When building an MCP server with ASYNC (reactive) providers, Spring AI inspects each annotated tool/resource/prompt method's return type. Methods with imperative (non-reactive) return types such as String or a plain object cannot be adapted to the async provider model, so they are skipped and a warning is logged instead of failing. The method is silently excluded from the resulting MCP server specification.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/common/McpPredicates.java:61

	public static boolean isUriTemplate(String uri) {
		return URI_VARIABLE_PATTERN.matcher(uri).find();
	}

	public final static Predicate<Method> isReactiveReturnType = method -> Mono.class
		.isAssignableFrom(method.getReturnType()) || Flux.class.isAssignableFrom(method.getReturnType())
			|| Publisher.class.isAssignableFrom(method.getReturnType());

	public final static Predicate<Method> isNotReactiveReturnType = method -> !Mono.class
		.isAssignableFrom(method.getReturnType()) && !Flux.class.isAssignableFrom(method.getReturnType())
			&& !Publisher.class.isAssignableFrom(method.getReturnType());

	public static Predicate<Method> filterNonReactiveReturnTypeMethod() {
		return method -> {
			if (isReactiveReturnType.test(method)) {
				return true;
			}
			if (logger.isWarnEnabled()) {
				logger.warn("ASYNC Providers don't support imperative (non-reactive) return types. Skipping method "
						+ method + " with non-reactive return type " + method.getReturnType());
			}
			return false;
		};
	}

	public static Predicate<Method> filterReactiveReturnTypeMethod() {
		return method -> {
			if (isNotReactiveReturnType.test(method)) {
				return true;
			}
			if (logger.isWarnEnabled()) {
				logger.warn("SYNC Providers don't support reactive return types. Skipping method " + method
						+ " with reactive return type " + method.getReturnType());
			}
			return false;
		};
	}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Change the annotated method's return type to a reactive type (Mono<T> or Flux<T>) and wrap the existing logic, e.g. Mono.just(...)
  2. Register the bean with a SYNC server/provider instead of ASYNC if reactive signatures are not desired
  3. Split the annotated service so reactive-only methods live in the class registered with the async provider

Example fix

// before
@McpTool(description = "Greeting")
public String greet(String name) { return "Hello " + name; }

// after
@McpTool(description = "Greeting")
public Mono<String> greet(String name) { return Mono.just("Hello " + name); }
Defensive patterns

Strategy: validation

Validate before calling

for (Method m : toolService.getClass().getDeclaredMethods()) {
  if (m.isAnnotationPresent(McpTool.class) && !reactiveType.test(m.getReturnType())) {
    throw new IllegalStateException(m + " must return Mono/Flux for ASYNC providers");
  }
}
// reactiveType: Class<?> r -> r == Mono.class || r == Flux.class

Type guard

static boolean isReactiveReturn(Method m) {
  Class<?> r = m.getReturnType();
  return Mono.class.isAssignableFrom(r) || Flux.class.isAssignableFrom(r);
}

Prevention

When it happens

Trigger: Registering a @McpTool/@McpResource annotated bean with an ASYNC MCP server (McpServer.async(...) or async provider builder) where one or more annotated methods return plain types (String, POJOs) instead of Mono/Flux.

Common situations: Sharing the same annotated service class between a sync and an async server; migrating code from the sync starter to the async starter without changing method signatures; developers forgetting that async providers require reactive return types.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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