spring-projects/spring-ai · warning
No async complete methods found in the provided complete…
Error message
No async complete methods found in the provided complete objects: <completeObjects>
What it means
AsyncMcpCompleteProvider.getCompleteSpecifications() scans the supplied completion provider objects for methods annotated as completion handlers (e.g. @McpComplete). If none of the objects expose a matching async complete method, an empty specification list results and this warning is logged. The provider is built with zero completions, so completion requests will find nothing.
Solutions
- Annotate at least one method in each complete object with @McpComplete and verify the import is org.springframework.ai.mcp.annotation.*
- Verify the method signature matches what the provider scans for (prompt-name argument plus completion String argument) and uses reactive return types for the async provider
- Check the log/scan setup so the annotated object is actually passed to the provider (not a different instance/class)
Example fix
// before
public class MyCompletes { public List<String> complete(String prefix) { return List.of(prefix + "!"); } }
// after
public class MyCompletes {
@McpComplete(prompt = "my-prompt")
public Mono<List<String>> complete(String prefix) { return Mono.just(List.of(prefix + "!")); }
} Defensive patterns
Strategy: validation
Validate before calling
boolean hasComplete = java.util.Arrays.stream(completeObject.getClass().getDeclaredMethods())
.anyMatch(m -> m.isAnnotationPresent(McpComplete.class));
if (!hasComplete) {
throw new IllegalStateException("Complete object " + completeObject + " has no @McpComplete methods");
} Type guard
static boolean hasAnnotatedCompleteMethods(Object o) {
return java.util.Arrays.stream(o.getClass().getDeclaredMethods())
.anyMatch(m -> m.isAnnotationPresent(McpComplete.class));
} Prevention
- Annotate completion methods with @McpComplete and verify imports
- Use reactive signatures for async providers (Mono/Flux)
- Review startup warnings for 'No async complete methods found'
When it happens
Trigger: Registering complete objects with the async completion provider where no method carries the completion annotation, the annotation is misplaced (wrong package/import), or the method signature does not match the expected complete shape.
Common situations: Typos or wrong @McpComplete import (e.g. from another library); methods returning reactive types scanned by a sync scanner or vice versa; forgetting the annotation entirely while passing a plain object as a complete provider.
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
- No complete methods found in the provided complete objects
- ASYNC Providers don't support imperative (non-reactive)…
- No complete methods found in the provided complete objects
- Async complete methods should use McpAsyncRequestContext…
- Either prompt or uri must be provided!
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/d90ecd8d396f8090.
Report an issue: GitHub.
Appendix: source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/provider/complete/AsyncMcpCompleteProvider.java:90
var completeRef = CompleteAdapter.asCompleteReference(completeAnnotation, mcpCompleteMethod);
var methodCallback = AsyncMcpCompleteMethodCallback.builder()
.method(mcpCompleteMethod)
.bean(completeObject)
.prompt(completeAnnotation.prompt().isEmpty() ? null : completeAnnotation.prompt())
.uri(completeAnnotation.uri().isEmpty() ? null : completeAnnotation.uri())
.build();
return new AsyncCompletionSpecification(completeRef, methodCallback);
})
.toList())
.flatMap(List::stream)
.toList();
if (asyncCompleteSpecification.isEmpty()) {
if (logger.isWarnEnabled()) {
logger
.warn("No async complete methods found in the provided complete objects: " + this.completeObjects);
}
}
return asyncCompleteSpecification;
}
/**
* 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)