spring-projects/spring-ai · error
Method must have exactly 1 parameter (List<McpSchema.Tool>):
Error message
Method must have exactly 1 parameter (List<McpSchema.Tool>): " + method.getName() + " in " + method.getDeclaringClass().getName() + " has " + parameters.length + " parameters
What it means
validateParameters enforces that the tool-list-changed callback method takes exactly one parameter of type List<McpSchema.Tool>. The library invokes the method with a single argument (the updated tools list), so any other arity would fail at invocation time; it rejects the signature eagerly with the method name, declaring class, and actual parameter count in the message.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/changed/tool/AbstractMcpToolListChangedMethodCallback.java:94
* Validates that the method return type is compatible with the tool list changed
* consumer callback. This method should be implemented by subclasses to handle
* specific return type validation.
* @param method The method to validate
* @throws IllegalArgumentException if the return type is not compatible
*/
protected abstract void validateReturnType(Method method);
/**
* Validates method parameters. This method provides common validation logic.
* @param method The method to validate
* @throws IllegalArgumentException if the parameters are not compatible
*/
protected void validateParameters(Method method) {
Parameter[] parameters = method.getParameters();
// Check parameter count - must have exactly 1 parameter
if (parameters.length != 1) {
throw new IllegalArgumentException(
"Method must have exactly 1 parameter (List<McpSchema.Tool>): " + method.getName() + " in "
+ method.getDeclaringClass().getName() + " has " + parameters.length + " parameters");
}
// Check parameter type - must be List<McpSchema.Tool>
Class<?> paramType = parameters[0].getType();
if (!List.class.isAssignableFrom(paramType)) {
throw new IllegalArgumentException("Parameter must be of type List<McpSchema.Tool>: " + method.getName()
+ " in " + method.getDeclaringClass().getName() + " has parameter of type " + paramType.getName());
}
}
/**
* Builds the arguments array for invoking the method.
* <p>
* This method constructs an array of arguments based on the method's parameter types
* and the available values.
* @param method The method to build arguments forView on GitHub (pinned to 98a7beda4f)
Solutions
- Change the handler method signature to accept exactly one parameter: void myHandler(List<McpSchema.Tool> tools)
- Move extra context (client, session) into bean fields or constructor injection instead of method parameters
- Verify with reflection before building: beanClass.getMethod("name", List.class) — this also enforces the correct arity
Example fix
// before
public void onToolListChanged(List<McpSchema.Tool> tools, McpSyncClient client) { ... }
// after
public void onToolListChanged(List<McpSchema.Tool> tools) { ... } // inject client via field if needed Defensive patterns
Strategy: validation
Validate before calling
if (handlerMethod.getParameterCount() != 1 || !java.util.List.class.isAssignableFrom(handlerMethod.getParameterTypes()[0])) throw new IllegalArgumentException(handlerMethod + " must take exactly one List<McpSchema.Tool> parameter");
Type guard
static boolean validToolListChangedSignature(java.lang.reflect.Method m) { return m != null && m.getParameterCount() == 1 && java.util.List.class.isAssignableFrom(m.getParameterTypes()[0]); } Try / catch
try { validateHandler(bean.getClass().getMethod("onToolListChanged", java.util.List.class)); } catch (IllegalArgumentException e) { fail("Invalid handler signature: " + e.getMessage()); } Prevention
- Write handlers with the exact signature void name(List<McpSchema.Tool> tools)
- Inject context (clients, services) via fields/constructor, not handler parameters
- Add a startup self-check that reflects over registered handlers
When it happens
Trigger: Registering a handler method annotated/registered as a tool-list-changed consumer whose signature has 0 parameters, 2+ parameters (e.g. (List<McpSchema.Tool> tools, McpSyncClient client)), or varargs — validateParameters throws IllegalArgumentException when method.getParameters().length != 1.
Common situations: Developers writing callback handlers modeled on other MCP listener APIs that pass extra context parameters, or adding a second parameter (like a session or client) to an existing one-argument handler during refactoring.
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
- Method must have exactly 1 parameter (List<McpSchema.Prompt>
- Method must have exactly 1 parameter (List<McpSchema.Resourc
- Method must not be null
- Parameter must be of type List<McpSchema.Tool>: " + method.g
- Method must have void or Mono<Void> return type: " + method.
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/373f505171b4da73.
Report an issue: GitHub.