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

Method cannot have more than one @McpProgressToken parameter

Error message

Method cannot have more than one @McpProgressToken parameter: {method.getName()} in {method.getDeclaringClass().getName()}

What it means

validateParameters() walks the @McpPrompt method's parameters and allows at most one parameter annotated with @McpProgressToken; the framework maps the incoming progress token to it. Declaring two or more such parameters is ambiguous and rejected with IllegalArgumentException naming the method and declaring class.

Source

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

		java.lang.reflect.Parameter[] parameters = method.getParameters();

		// Check for duplicate parameter types
		boolean hasExchangeParam = false;
		boolean hasRequestParam = false;
		boolean hasMapParam = false;
		boolean hasProgressTokenParam = false;
		boolean hasMetaParam = false;
		boolean hasRequestContextParam = false;

		for (java.lang.reflect.Parameter param : parameters) {
			Class<?> paramType = param.getType();

			this.validateParamType(paramType);

			// Skip @McpProgressToken annotated parameters from validation
			if (param.isAnnotationPresent(McpProgressToken.class)) {
				if (hasProgressTokenParam) {
					throw new IllegalArgumentException("Method cannot have more than one @McpProgressToken parameter: "
							+ method.getName() + " in " + method.getDeclaringClass().getName());
				}
				hasProgressTokenParam = true;
				continue;
			}

			// Skip McpMeta parameters from validation
			if (McpMeta.class.isAssignableFrom(paramType)) {
				if (hasMetaParam) {
					throw new IllegalArgumentException("Method cannot have more than one McpMeta parameter: "
							+ method.getName() + " in " + method.getDeclaringClass().getName());
				}
				hasMetaParam = true;
				continue;
			}

			if (McpSyncRequestContext.class.isAssignableFrom(paramType)) {
				if (hasRequestContextParam) {

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Remove the extra @McpProgressToken annotation so exactly one parameter carries it.
  2. If both values are needed, capture the token once and pass it to a shared helper instead of injecting it twice.
  3. Review the method signature and keep only supported parameter kinds (single prompt arg, McpMeta, single context, single @McpProgressToken).

Example fix

// before
@McpPrompt(name = "p")
public String complete(String q, @McpProgressToken String t1, @McpProgressToken String t2) { ... }
// after
@McpPrompt(name = "p")
public String complete(String q, @McpProgressToken String token) { ... }
Defensive patterns

Strategy: validation

Validate before calling

long tokenParams = Arrays.stream(method.getParameters())
    .filter(p -> p.isAnnotationPresent(McpProgressToken.class)).count();
if (tokenParams > 1) throw new IllegalStateException("Only one @McpProgressToken parameter allowed");

Try / catch

try { registry.register(bean); } catch (IllegalArgumentException e) { log.error("Invalid @McpPrompt signature: {}", e.getMessage()); }

Prevention

When it happens

Trigger: An @McpPrompt method declaring two parameters annotated @McpProgressToken, e.g. complete(String value, @McpProgressToken String t1, @McpProgressToken String t2).

Common situations: Copy-pasting a parameter block and forgetting to remove the duplicate @McpProgressToken annotation; refactoring that added a second progress-aware parameter; misunderstanding that only one token can be injected per callback.

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/6dc06f79e3917a5d. Report an issue: GitHub.