spring-projects/spring-ai · error · IllegalArgumentException

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

Error message

Method can have at most 3 input parameters (excluding @McpProgressToken and McpMeta): 

What it means

validateParameters() in AbstractMcpCompleteMethodCallback counts non-special parameters (excluding @McpProgressToken-annotated and McpMeta parameters) and rejects methods with more than 3, since the completion input can supply at most the completion value, related argument context, and a request. Extra parameters make the signature unbindable.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/complete/AbstractMcpCompleteMethodCallback.java:162

	 * delegates exchange type checking to subclasses.
	 * @param method The method to validate
	 * @throws IllegalArgumentException if the parameters are not compatible
	 */
	protected void validateParameters(Method method) {
		Parameter[] parameters = method.getParameters();

		// Count non-special parameters (excluding @McpProgressToken and McpMeta)
		int nonSpecialParamCount = 0;
		for (Parameter param : parameters) {
			if (!param.isAnnotationPresent(McpProgressToken.class)
					&& !McpMeta.class.isAssignableFrom(param.getType())) {
				nonSpecialParamCount++;
			}
		}

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

		// Check parameter types
		boolean hasExchangeParam = false;
		boolean hasTransportContext = false;
		boolean hasRequestParam = false;
		boolean hasArgumentParam = false;
		boolean hasProgressTokenParam = false;
		boolean hasMetaParam = false;
		boolean hasRequestContextParam = false;

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

			// Skip @McpProgressToken annotated parameters from validation

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Reduce the method to at most 3 non-special parameters matching the supported completion argument types.
  2. Move auxiliary data into McpMeta or access it via the request context parameter instead of extra parameters.
  3. Split the logic into a thin completion handler that delegates to a richer internal method.

Example fix

// before
@McpComplete(prompt = "p")
public void complete(String value, String arg, Client c, Config cfg) { } // 4 params
// after
@McpComplete(prompt = "p")
public void complete(String value, McpMeta meta) {
    Config cfg = (Config) meta.get("config");
}
Defensive patterns

Strategy: validation

Validate before calling

long ordinary = Arrays.stream(method.getParameters())
    .filter(p -> !p.isAnnotationPresent(McpProgressToken.class))
    .filter(p -> !McpMeta.class.isAssignableFrom(p.getType()))
    .count();
if (ordinary > 3) throw new IllegalStateException("too many completion parameters: " + method.getName());

Prevention

When it happens

Trigger: Annotating a completion method whose signature has 4+ ordinary parameters (beyond progress-token and McpMeta) and registering it with the annotation callback.

Common situations: Reusing a generic service method with many arguments as a completion handler; adding client/context parameters beyond what the framework supports; merging multiple handler concerns into one method.

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