spring-projects / spring-projects/spring-ai

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

Open
#6,535 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage
Dominant language
Java
Stars
9.5k
Forks
2.9k
Avg merge
1d 7h
Merged PRs (30d)
6

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading AbstractAnnotatedMethodBeanPostProcessor and tracing how AsyncMcpAnnotationProviders receives its toolObjects during ASYNC startup. Reproduce the package-ordering scenario with a bean injecting McpAsyncServer and the listed @McpTool beans, then verify that all annotated methods register regardless of initialization order.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring, spring-boot
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.