spring-projects/spring-ai · warning

No tool methods found in the provided tool objects: <toolObj

Error message

No tool methods found in the provided tool objects: <toolObjects>

What it means

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.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/provider/tool/AsyncStatelessMcpToolProvider.java:166

									: ReturnMode.TEXT;

					BiFunction<McpTransportContext, CallToolRequest, Mono<CallToolResult>> methodCallback = new AsyncStatelessMcpToolMethodCallback(
							returnMode, mcpToolMethod, toolObject);

					AsyncToolSpecification toolSpec = AsyncToolSpecification.builder()
						.tool(tool)
						.callHandler(methodCallback)
						.build();

					return toolSpec;
				})
				.toList())
			.flatMap(List::stream)
			.toList();

		if (toolSpecs.isEmpty()) {
			if (logger.isWarnEnabled()) {
				logger.warn("No tool methods found in the provided tool objects: " + this.toolObjects);
			}
		}

		return toolSpecs;
	}

}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Add/repair @McpTool annotations on public methods within the registered tool objects.
  2. Verify the tool object list given to AsyncStatelessMcpToolProvider is correct and non-empty.
  3. Check method visibility and parameter annotations (@McpToolParam) expected by the scanner.
  4. Drop the provider registration if it intentionally exposes no tools.

Example fix

// before
new AsyncStatelessMcpToolProvider(List.of(new ServiceWithNoTools()));
// after
new AsyncStatelessMcpToolProvider(List.of(new RealTools())); // class with @McpTool-annotated public methods
Defensive patterns

Strategy: validation

Validate before calling

// Guard against empty stateless tool providers:
List<Object> validTools = toolObjects.stream()
    .filter(o -> Arrays.stream(o.getClass().getDeclaredMethods())
        .anyMatch(m -> m.isAnnotationPresent(McpTool.class)))
    .toList();
if (validTools.isEmpty()) throw new IllegalArgumentException("No tool objects with @McpTool methods supplied");

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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


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