Skip to content

@McpTool beans silently fail to register when another bean injects McpAsyncServer before BeanPostProcessor is ready (ASYNC mode) #6535

Description

@longlong354

Bug description

When spring.ai.mcp.server.type=ASYNC, all @mcptool annotated beans silently fail to register if any other Spring bean (injected earlier due to package scan ordering) depends on McpAsyncServer. The root cause is that AbstractAnnotatedMethodBeanPostProcessor implements only BeanPostProcessor (not PriorityOrdered), so when McpAsyncServer is eagerly initialized to satisfy another bean's dependency, the scanner's BeanPostProcessor has not yet been registered, and all @mcptool beans bypass scanning entirely. The result is AsyncMcpAnnotationProviders receiving an empty toolObjects list.

Environment

Spring AI: 2.0.0
Spring Boot: 4.1.0
Java: 21
MCP Server transport: SSE (WebFlux)
spring.ai.mcp.server.type=ASYNC
Steps to reproduce

Create a project with spring-ai-starter-mcp-server-webflux and set spring.ai.mcp.server.type=ASYNC.
Define @mcptool beans in package com.demo.tools (e.g., McpDemoTools, AsyncPushTools).
Create a bean in a package that is scanned alphabetically before com.demo.tools (e.g., com.demo.schedule.BroadCastDemo) that injects McpAsyncServer:
@component
public class BroadCastDemo {
@Autowired(required = false)
private McpAsyncServer mcpAsyncServer;
// ...
}
Start the application. Observe: no @mcptool methods are registered, and the log shows No tool methods found in the provided tool objects: [].
Expected behavior

All @mcptool annotated methods should be discovered and registered regardless of other beans' dependency on McpAsyncServer. Bean initialization ordering should not affect annotation scanning.

Minimal Complete Reproducible example

Package structure:

com.demo.config // BroadCastDemoConfig (workaround, see below)
com.demo.schedule // BroadCastDemo — injects McpAsyncServer, scanned early
com.demo.tools.demo // McpDemoTools — @mcptool beans, scanned later
com.demo.tools.push // AsyncPushTools — @mcptool beans, scanned later
BroadCastDemo.java (in com.demo.schedule):

@component
public class BroadCastDemo {
@Autowired(required = false)
private McpAsyncServer mcpAsyncServer;
}
McpDemoTools.java (in com.demo.tools.demo):

@service
public class McpDemoTools {
@mcptool(description = "Add two numbers")
public int add(@McpToolParam(description = "first") int a,
@McpToolParam(description = "second") int b) {
return a + b;
}
}
With @component on BroadCastDemo: all @mcptool methods fail to register. Remove @component from BroadCastDemo: all @mcptool methods register correctly.

Workaround: Move the McpAsyncServer-dependent bean registration to a @configuration class in a package scanned alphabetically after the @mcptool packages, or remove @component and register it manually via @bean.

Suggested fix: Make AbstractAnnotatedMethodBeanPostProcessor implement PriorityOrdered with HIGHEST_PRECEDENCE, ensuring the scanner's BeanPostProcessor is registered before any regular bean initialization, regardless of dependency-driven eager initialization.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions