spring-projects/spring-ai · error · java.lang.IllegalArgumentException

Stateless Streamable-Http prompt method must not declare par

Error message

Stateless Streamable-Http prompt method must not declare parameter of type: {paramType.getName()}. Use McpTransportContext instead. Method: {this.method.getName()} in {this.method.getDeclaringClass().getName()}

What it means

In stateless Streamable-HTTP mode there is no per-session server exchange, so an async stateless prompt method must not take McpSyncServerExchange or McpAsyncServerExchange parameters. The callback rejects such parameters at validation time and directs you to use the session-less McpTransportContext instead.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/AsyncStatelessMcpPromptMethodCallback.java:59

 * callback functions that can be used to handle prompt requests asynchronously in
 * stateless environments. It supports various method signatures and return types.
 *
 * @author Christian Tzolov
 */
public final class AsyncStatelessMcpPromptMethodCallback extends AbstractMcpPromptMethodCallback
		implements BiFunction<McpTransportContext, GetPromptRequest, Mono<GetPromptResult>> {

	private AsyncStatelessMcpPromptMethodCallback(Builder builder) {
		super(builder.method, builder.bean, builder.prompt);
	}

	@Override
	protected void validateParamType(Class<?> paramType) {

		if (McpSyncServerExchange.class.isAssignableFrom(paramType)
				|| McpAsyncServerExchange.class.isAssignableFrom(paramType)) {

			throw new IllegalArgumentException(
					"Stateless Streamable-Http prompt method must not declare parameter of type: " + paramType.getName()
							+ ". Use McpTransportContext instead." + " Method: " + this.method.getName() + " in "
							+ this.method.getDeclaringClass().getName());
		}
	}

	@Override
	protected Object assignExchangeType(Class<?> paramType, Object exchange) {

		if (McpTransportContext.class.isAssignableFrom(paramType)) {
			if (exchange instanceof McpTransportContext transportContext) {
				return transportContext;
			}
			else if (exchange instanceof McpSyncServerExchange syncServerExchange) {
				throw new IllegalArgumentException("Unsupported Sync exchange type: "
						+ syncServerExchange.getClass().getName() + " for Sync method: " + method.getName() + " in "
						+ method.getDeclaringClass().getName());

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Replace the McpSyncServerExchange/McpAsyncServerExchange parameter with McpTransportContext
  2. Remove the exchange parameter entirely if no transport context is needed
  3. Keep the stateful server mode if the method genuinely needs the exchange

Example fix

// before
public Mono<GetPromptResult> prompt(McpAsyncServerExchange exchange, Request req) {...}
// after
public Mono<GetPromptResult> prompt(McpTransportContext context, Request req) {...}
Defensive patterns

Strategy: validation

Validate before calling

boolean statelessSafe(Method m) { return Arrays.stream(m.getParameterTypes()).noneMatch(t -> McpSyncServerExchange.class.isAssignableFrom(t) || McpAsyncServerExchange.class.isAssignableFrom(t)); }

Try / catch

try { registerPrompts(bean); } catch (IllegalArgumentException e) { log.error("Stateless method misconfigured: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Declaring an @McpPrompt method with a McpSyncServerExchange or McpAsyncServerExchange parameter while the server runs in stateless Streamable-Http mode and is wired via AsyncStatelessMcpPromptMethodCallback.

Common situations: Switching a stateful MCP server to stateless Streamable-Http without updating method signatures; copying stateful examples into a stateless configuration.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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