spring-projects/spring-ai · error · IllegalArgumentException

Method can have at most 2 input parameters (excluding @McpPr

Error message

Method can have at most 2 input parameters (excluding @McpProgressToken and McpMeta) when no URI variables are present: ${method} in ${declaringClass} has ${count} non-special parameters

What it means

A @McpResource method without URI variables may declare at most 2 non-special input parameters (special = @McpProgressToken-annotated and McpMeta parameters). validateParametersWithoutUriVariables counts ordinary parameters and throws IllegalArgumentException when more than 2 remain, since with no URI template there are at most a request + request-context slot.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/resource/AbstractMcpResourceMethodCallback.java:189

	 */
	protected void validateParametersWithoutUriVariables(Method method) {
		Parameter[] parameters = method.getParameters();

		// Count parameters excluding @McpProgressToken and McpMeta annotated ones
		int nonSpecialParamCount = 0;

		for (Parameter param : parameters) {
			if (!param.isAnnotationPresent(McpProgressToken.class) && !McpMeta.class.isAssignableFrom(param.getType())
					&& !McpSyncRequestContext.class.isAssignableFrom(param.getType())
					&& !McpAsyncRequestContext.class.isAssignableFrom(param.getType())
					&& !isExchangeOrContextType(param.getType())) {
				nonSpecialParamCount++;
			}
		}

		// Check parameter count - must have at most 2 non-special parameters
		if (nonSpecialParamCount > 2) {
			throw new IllegalArgumentException(
					"Method can have at most 2 input parameters (excluding @McpProgressToken and McpMeta) when no URI variables are present: "
							+ method.getName() + " in " + method.getDeclaringClass().getName() + " has "
							+ nonSpecialParamCount + " non-special parameters");
		}

		// Check parameter types
		boolean hasValidParams = false;
		boolean hasExchangeParam = false;
		boolean hasRequestOrUriParam = false;
		boolean hasMetaParam = false;
		boolean hasRequestContextParam = false;

		for (Parameter param : parameters) {
			// Skip @McpProgressToken annotated parameters
			if (param.isAnnotationPresent(McpProgressToken.class)) {
				continue;
			}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Reduce the method to at most 2 non-special parameters (e.g. one request object plus one context).
  2. Group extra inputs into a single request/record parameter.
  3. Annotate auxiliary parameters with @McpProgressToken or use McpMeta so they are excluded from the count only if semantically correct.
  4. If the resource URI actually has URI variables, declare them; the URI-variable validation path allows different signatures.

Example fix

// before
@McpResource(uri = "file:///docs")
public String read(String path, String encoding, int maxLines) { ... }

// after
@McpResource(uri = "file:///docs")
public String read(ReadOptions options) { ... } // group params into one request object
Defensive patterns

Strategy: validation

Validate before calling

static boolean resourceParamCountValid(Method m, int uriVarCount) {
    if (uriVarCount > 0) return true; // different rules apply
    long nonSpecial = java.util.Arrays.stream(m.getParameters())
        .filter(p -> p.getAnnotation(McpProgressToken.class) == null
            && p.getType() != McpMeta.class)
        .count();
    return nonSpecial <= 2;
}

Try / catch

try {
    resourceManager.register(callback);
} catch (IllegalArgumentException e) {
    throw new IllegalStateException("@McpResource signature has too many parameters", e);
}

Prevention

When it happens

Trigger: Declaring a @McpResource method with 3+ ordinary parameters (e.g. multiple request objects or plain values) while the resource URI has no URI variables; each parameter not annotated with @McpProgressToken and not of type McpMeta increments the count.

Common situations: Copy-pasting tool method signatures into resource methods; trying to pass extra options by adding parameters; misunderstanding that URI variables count as regular parameters when present (different validator applies).

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/04ee32626a5bbed8. Report an issue: GitHub.