{"record":{"id":"6bbc662d920c2f3a","repo":"spring-projects/spring-ai","slug":"no-complete-methods-found-in-the-provided-complete-6bbc66","errorCode":null,"errorMessage":"No complete methods found in the provided complete objects: <completeObjects>","messagePattern":"No complete methods found in the provided complete objects: <completeObjects>","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/provider/complete/SyncStatelessMcpCompleteProvider.java","lineNumber":93,"sourceCode":"\t\t\t\t\tvar completeAnnotation = mcpCompleteMethod.getAnnotation(McpComplete.class);\n\t\t\t\t\tvar completeRef = CompleteAdapter.asCompleteReference(completeAnnotation, mcpCompleteMethod);\n\n\t\t\t\t\tBiFunction<McpTransportContext, CompleteRequest, CompleteResult> methodCallback = SyncStatelessMcpCompleteMethodCallback\n\t\t\t\t\t\t.builder()\n\t\t\t\t\t\t.method(mcpCompleteMethod)\n\t\t\t\t\t\t.bean(completeObject)\n\t\t\t\t\t\t.complete(completeAnnotation)\n\t\t\t\t\t\t.build();\n\n\t\t\t\t\treturn new SyncCompletionSpecification(completeRef, methodCallback);\n\t\t\t\t})\n\t\t\t\t.toList())\n\t\t\t.flatMap(List::stream)\n\t\t\t.toList();\n\n\t\tif (completeSpecs.isEmpty()) {\n\t\t\tif (logger.isWarnEnabled()) {\n\t\t\t\tlogger.warn(\"No complete methods found in the provided complete objects: \" + this.completeObjects);\n\t\t\t}\n\t\t}\n\n\t\treturn completeSpecs;\n\t}\n\n\t/**\n\t * Returns the methods of the given bean class.\n\t * @param bean the bean instance\n\t * @return the methods of the bean class\n\t */\n\tprotected Method[] doGetClassMethods(Object bean) {\n\t\treturn bean.getClass().getDeclaredMethods();\n\t}\n\n}\n","sourceCodeStart":75,"sourceCodeEnd":110,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/provider/complete/SyncStatelessMcpCompleteProvider.java#L75-L110","documentation":"SyncStatelessMcpCompleteProvider scans the supplied completeObjects for methods annotated with @McpComplete (sync/stateless signature, non-reactive return type, bidirectional parameters) and builds SyncCompletionSpecification entries. When the resulting list is empty it logs this warning; nothing is thrown, and the server simply registers zero completion providers. It exists to surface a likely wiring mistake: you handed the provider objects that contain no usable completion methods.","triggerScenarios":"Calling getCompleteSpecifications() when none of the completeObjects have a method passing all filters: annotated with @McpComplete, non-reactive return type (McpPredicates.filterReactiveReturnTypeMethod), and no bidirectional parameters (filterMethodWithBidirectionalParameters). Also triggered by methods declared on a superclass/interface (only getDeclaredMethods is scanned) or reactive methods accidentally given to the sync provider.","commonSituations":"Registering a plain Spring bean that forgot @McpComplete annotations; annotating methods on a parent class; passing reactive completion methods to the synchronous stateless provider; using annotation auto-configuration where no completion beans exist at all; bean proxies hiding annotated methods when annotations lack @Inherited-compatible placement.","solutions":["Verify each object passed to the provider has at least one public method annotated with @McpComplete with a sync (non-reactive) return type and no bidirectional parameters","Move @McpComplete methods into the class itself rather than a superclass or interface (only getDeclaredMethods is scanned)","If you use reactive (Mono/Flux) completion methods, use the Async stateless complete provider instead of the sync one","Check annotation scanning/import configuration so the beans actually reach the provider (e.g. @McpTool-compatible registration), and confirm the warn is not just an informational log from an optional feature","If completions are intentionally unused, remove the completeObjects registration instead of registering empty holders"],"exampleFix":"// before\nnew SyncStatelessMcpCompleteProvider(List.of(new CompletionService())); // no @McpComplete methods inside\n\n// after\nclass CompletionService {\n    @McpComplete(prompt = \"code-completion\")\n    public CompleteResult complete(CompleteRequest request) { ... }\n}\nnew SyncStatelessMcpCompleteProvider(List.of(new CompletionService()));","handlingStrategy":"validation","validationCode":"long found = Arrays.stream(completeObject.getClass().getDeclaredMethods())\n    .filter(m -> m.isAnnotationPresent(McpComplete.class))\n    .count();\nif (found == 0) throw new IllegalStateException(\n    completeObject.getClass().getName() + \" has no @McpComplete methods\");","typeGuard":"static boolean hasCompleteMethods(Object bean) {\n    return Arrays.stream(bean.getClass().getDeclaredMethods())\n        .anyMatch(m -> m.isAnnotationPresent(McpComplete.class));\n}","tryCatchPattern":null,"preventionTips":["Always pair each provider registration with at least one matching annotated method in the supplied bean","Keep MCP annotated methods on the concrete class, not superclasses or interfaces","Match provider variant (sync/async, stateful/stateless) to your method signatures","Run an integration test that starts the server and asserts feature counts before deploying"],"tags":["mcp","spring-ai","annotation-scanning","completion"],"backgroundTag":"empty-result-set","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}