{"record":{"id":"7667289d54637598","repo":"spring-projects/spring-ai","slug":"no-tool-methods-found-in-the-provided-tool-objects-766728","errorCode":null,"errorMessage":"No tool methods found in the provided tool objects: <toolObjects>","messagePattern":"No tool methods found in the provided tool objects: <toolObjects>","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/provider/tool/AsyncStatelessMcpToolProvider.java","lineNumber":166,"sourceCode":"\t\t\t\t\t\t\t\t\t: ReturnMode.TEXT;\n\n\t\t\t\t\tBiFunction<McpTransportContext, CallToolRequest, Mono<CallToolResult>> methodCallback = new AsyncStatelessMcpToolMethodCallback(\n\t\t\t\t\t\t\treturnMode, mcpToolMethod, toolObject);\n\n\t\t\t\t\tAsyncToolSpecification toolSpec = AsyncToolSpecification.builder()\n\t\t\t\t\t\t.tool(tool)\n\t\t\t\t\t\t.callHandler(methodCallback)\n\t\t\t\t\t\t.build();\n\n\t\t\t\t\treturn toolSpec;\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 (toolSpecs.isEmpty()) {\n\t\t\tif (logger.isWarnEnabled()) {\n\t\t\t\tlogger.warn(\"No tool methods found in the provided tool objects: \" + this.toolObjects);\n\t\t\t}\n\t\t}\n\n\t\treturn toolSpecs;\n\t}\n\n}\n","sourceCodeStart":148,"sourceCodeEnd":174,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/provider/tool/AsyncStatelessMcpToolProvider.java#L148-L174","documentation":"AsyncStatelessMcpToolProvider.getToolSpecifications logs this warning when annotation scanning of the configured tool objects produces zero tool specifications. The stateless async server will register no tools; the warning exists to catch providers wired with objects that contain no @McpTool methods.","triggerScenarios":"Objects supplied to AsyncStatelessMcpToolProvider lack public @McpTool methods, the annotated methods are invisible/incompatible to the scanner, or toolObjects is empty — empty toolSpecs triggers the warn at AsyncStatelessMcpToolProvider.java:166.","commonSituations":"Forgetting to annotate tool methods; passing the wrong service bean to the provider; methods private after a refactor; duplicate tool providers where one ends up empty.","solutions":["Add/repair @McpTool annotations on public methods within the registered tool objects.","Verify the tool object list given to AsyncStatelessMcpToolProvider is correct and non-empty.","Check method visibility and parameter annotations (@McpToolParam) expected by the scanner.","Drop the provider registration if it intentionally exposes no tools."],"exampleFix":"// before\nnew AsyncStatelessMcpToolProvider(List.of(new ServiceWithNoTools()));\n// after\nnew AsyncStatelessMcpToolProvider(List.of(new RealTools())); // class with @McpTool-annotated public methods","handlingStrategy":"validation","validationCode":"// Guard against empty stateless tool providers:\nList<Object> validTools = toolObjects.stream()\n    .filter(o -> Arrays.stream(o.getClass().getDeclaredMethods())\n        .anyMatch(m -> m.isAnnotationPresent(McpTool.class)))\n    .toList();\nif (validTools.isEmpty()) throw new IllegalArgumentException(\"No tool objects with @McpTool methods supplied\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Verify @McpTool annotations after any package or version upgrade.","Pass concrete tool-bearing beans to AsyncStatelessMcpToolProvider, never empty or placeholder lists.","Keep annotated tool methods public with scanner-compatible signatures.","Monitor server startup logs and treat this warning as a build failure in CI."],"tags":["mcp","annotation-scanning","tools","empty-specifications"],"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"}