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
	 */
	@Override

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Remove the McpAsyncRequestContext parameter from the tool method signature.
  2. If exchange/context data is needed, use McpTransportContext as the parameter type instead, which stateless callbacks support.
  3. 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

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


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