{"record":{"id":"2ac24593c165bc55","repo":"spring-projects/spring-ai","slug":"no-tool-methods-found-in-the-provided-tool-objects-2ac245","errorCode":null,"errorMessage":"No tool methods found in the provided tool objects: + this.toolObjects","messagePattern":"No tool methods found in the provided tool objects: \\+ this\\.toolObjects","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/provider/tool/SyncMcpToolProvider.java","lineNumber":154,"sourceCode":"\n\t\t\t\t\tReturnMode returnMode = useStructuredOtput ? ReturnMode.STRUCTURED\n\t\t\t\t\t\t\t: (methodReturnType == Void.TYPE || methodReturnType == void.class ? ReturnMode.VOID\n\t\t\t\t\t\t\t\t\t: ReturnMode.TEXT);\n\n\t\t\t\t\tBiFunction<McpSyncServerExchange, CallToolRequest, CallToolResult> methodCallback = new SyncMcpToolMethodCallback(\n\t\t\t\t\t\t\treturnMode, mcpToolMethod, toolObject);\n\n\t\t\t\t\tvar toolSpec = SyncToolSpecification.builder().tool(tool).callHandler(methodCallback).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":136,"sourceCodeEnd":162,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/provider/tool/SyncMcpToolProvider.java#L136-L162","documentation":"This is a warning (not an exception) logged by SyncMcpToolProvider.getToolSpecifications when reflection over the supplied @McpTool-annotated tool objects yields zero tool specifications. The provider still returns an empty list, so downstream MCP clients will see a server/tool provider with no tools. It indicates the tool objects were provided but none of their methods matched the tool annotation scan.","triggerScenarios":"Calling SyncMcpToolProvider with tool objects whose classes have no @McpTool-annotated methods; annotation metadata not on the classpath so scanning finds nothing; passing the wrong (unrelated) objects as toolObjects; methods annotated with a custom/incorrect annotation name instead of @McpTool.","commonSituations":"Renaming or removing @McpTool annotations during refactoring; building tools with a non-public method visibility the scanner skips; wiring an empty or wrong bean list into the provider constructor; mixing mcp-annotations versions where the annotation package changed.","solutions":["Verify each object passed to the provider has at least one method annotated with @McpTool","Check that methods are public (or otherwise visible to the annotation scanner) and the mcp-annotations dependency is on the classpath","Log/inspect this.toolObjects at construction time to confirm the right beans are wired","Upgrade/align the spring-ai mcp-annotations version so the annotation the scanner looks for matches the one used in your code"],"exampleFix":"// before\nSyncMcpToolProvider provider = SyncMcpToolProvider.builder()\n    .toolObjects(new MyService()) // MyService has no @McpTool methods\n    .build();\n// after\npublic class MyService {\n    @McpTool(name = \"getWeather\", description = \"Get weather\")\n    public String getWeather(String city) { ... }\n}\nSyncMcpToolProvider provider = SyncMcpToolProvider.builder()\n    .toolObjects(new MyService())\n    .build();","handlingStrategy":"validation","validationCode":"// before building the provider\nlong toolCount = java.util.Arrays.stream(toolObjects)\n    .flatMap(o -> Arrays.stream(o.getClass().getDeclaredMethods()))\n    .filter(m -> m.isAnnotationPresent(org.springframework.ai.mcp.annotation.McpTool.class))\n    .count();\nif (toolCount == 0) throw new IllegalStateException(\"No @McpTool methods found in tool objects\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always annotate at least one public method with @McpTool in each tool object","Write a startup assertion/test that the provider's getToolSpecifications() returns a non-empty list","Import @McpTool from the correct package","Check logs for this warning in integration tests before deploying"],"tags":["mcp","tools","annotation","configuration"],"backgroundTag":"empty-required-field","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"}