spring-projects/spring-ai · error · UnsupportedOperationException
Stateless tool methods do not support McpAsyncRequestContext
Error message
Stateless tool methods do not support McpAsyncRequestContext parameter.
What it means
AsyncStatelessMcpToolMethodCallback serves @McpTool methods registered on a stateless async client. Stateless callbacks have no per-conversation exchange, so McpAsyncRequestContext (which needs an active exchange) cannot be created; createRequestContext unconditionally throws UnsupportedOperationException if the method declares such a parameter. Only McpTransportContext parameters are supported.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/tool/AsyncStatelessMcpToolMethodCallback.java:70
* The {@code toolCallExceptionClass} argument is ignored: exception handling now
* follows the {@code @Tool} contract based on the exception type. Will be removed in
* 2.1.0.
*/
@Deprecated
public AsyncStatelessMcpToolMethodCallback(ReturnMode returnMode, java.lang.reflect.Method toolMethod,
Object toolObject, Class<? extends Throwable> toolCallExceptionClass) {
super(returnMode, toolMethod, toolObject, toolCallExceptionClass);
}
@Override
protected boolean isExchangeOrContextType(Class<?> paramType) {
return McpTransportContext.class.isAssignableFrom(paramType)
|| McpAsyncRequestContext.class.isAssignableFrom(paramType);
}
@Override
protected McpAsyncRequestContext createRequestContext(McpTransportContext exchange, CallToolRequest request) {
throw new UnsupportedOperationException(
"Stateless tool methods do not support McpAsyncRequestContext parameter.");
}
@Override
protected McpTransportContext resolveTransportContext(McpTransportContext context) {
return context;
}
/**
* Apply the callback to the given request.
* <p>
* This method builds the arguments for the method call, invokes the method, and
* returns the result asynchronously.
* @param mcpTransportContext The transport context
* @param request The tool call request, must not be null
* @return A Mono containing the result of the method invocation
*/
@OverrideView on GitHub (pinned to 98a7beda4f)
Solutions
- Remove the McpAsyncRequestContext parameter from the tool method signature.
- If exchange/context data is needed, use McpTransportContext as the parameter type instead, which stateless callbacks support.
- If per-exchange context is genuinely required, register the tool with the stateful async callback (AsyncMcpToolMethodCallback) instead of the stateless one.
Example fix
// before
@McpTool(name = "weather")
String weather(String city, McpAsyncRequestContext ctx) { ... }
// after
@McpTool(name = "weather")
String weather(String city) { ... } Defensive patterns
Strategy: validation
Validate before calling
// Fail fast at startup if a stateless tool method declares an unsupported context parameter
for (Method m : bean.getClass().getDeclaredMethods()) {
if (m.isAnnotationPresent(McpTool.class)) {
for (Class<?> p : m.getParameterTypes()) {
if (McpAsyncRequestContext.class.isAssignableFrom(p)) {
throw new IllegalStateException("@McpTool " + m.getName() + " cannot take McpAsyncRequestContext in a stateless callback");
}
}
}
} Prevention
- Never declare McpAsyncRequestContext parameters in stateless tool methods.
- Use McpTransportContext when a context parameter is needed.
- Document stateless vs stateful callback constraints for your team.
When it happens
Trigger: Declaring a @McpTool method like: @McpTool(name="x") void tool(String arg, McpAsyncRequestContext ctx) on a stateless async tool callback, then invoking it — the framework reaches createRequestContext and throws.
Common situations: Developers copy an async tool method that used McpAsyncRequestContext from a stateful setup into a stateless one; migrating code between stateful and stateless MCP client configurations.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Stateless tool methods do not support McpSyncRequestContext
- Roots not supported by the client:
- Currently only methods with a single ElicitRequest parameter
- Method must return ElicitResult or StructuredElicitResult:
- Asynchronous progress methods must return void or Mono<Void>
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/30cfd9cb4b16ff9b.
Report an issue: GitHub.