spring-projects/spring-ai · error
Parameter must be of type List<McpSchema.Tool>: " + method.g
Error message
Parameter must be of type List<McpSchema.Tool>: " + method.getName() + " in " + method.getDeclaringClass().getName() + " has parameter of type " + paramType.getName()
What it means
After confirming exactly one parameter, validateParameters checks that the parameter type is assignable from java.util.List. The tool-list-changed dispatch passes a List<McpSchema.Tool>, so a non-List parameter (e.g. Tool[] or List<Tool> of the wrong raw type declared differently) cannot receive it; the exception message includes the method name, declaring class, and offending parameter type.
Source
Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/changed/tool/AbstractMcpToolListChangedMethodCallback.java:102
/**
* 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 for
* @param exchange The server exchange
* @param updatedTools The updated list of tools
* @return An array of arguments for the method invocation
*/
protected Object[] buildArgs(Method method, Object exchange, List<McpSchema.Tool> updatedTools) {
Parameter[] parameters = method.getParameters();
Object[] args = new Object[parameters.length];
View on GitHub (pinned to 98a7beda4f)
Solutions
- Change the handler's single parameter type to List<McpSchema.Tool> (or a raw List/assignable subtype)
- Convert the data source: if you have an array-based producer, wrap it in Arrays.asList before it reaches the callback registration
- Check the raw parameter type via reflection if generics are involved — the library only checks the raw type, so List must appear in the declared signature
Example fix
// before
public void onToolListChanged(McpSchema.Tool[] tools) { ... }
// after
public void onToolListChanged(java.util.List<io.modelcontextprotocol.spec.McpSchema.Tool> tools) { ... } Defensive patterns
Strategy: validation
Validate before calling
if (handlerMethod.getParameterCount() == 1 && !java.util.List.class.isAssignableFrom(handlerMethod.getParameterTypes()[0])) throw new IllegalArgumentException("Parameter must be List<McpSchema.Tool>"); Type guard
static boolean takesToolList(java.lang.reflect.Method m) { return m.getParameterCount() == 1 && java.util.List.class.isAssignableFrom(m.getParameterTypes()[0]); } Try / catch
try { buildCallback(handlerMethod); } catch (IllegalArgumentException e) { log.error("Parameter type error: {}", e.getMessage()); } Prevention
- Use List<McpSchema.Tool> (not arrays, sets, or other collections) for the single handler parameter
- Copy the canonical signature from the library's javadoc/tests
- Check raw parameter types when relying on generics
When it happens
Trigger: Registering a handler like void onToolListChanged(Tool[] tools) or void onToolListChanged(Set<McpSchema.Tool> tools) — the single parameter's raw type is not a List, so List.class.isAssignableFrom(paramType) fails.
Common situations: Porting handlers from callback APIs that deliver arrays instead of lists, or hand-writing a consumer where the developer misremembered the expected signature of AbstractMcpToolListChangedMethodCallback.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Parameter must be of type List<McpSchema.Prompt>:
- Method must have exactly 1 parameter (List<McpSchema.Tool>):
- Single parameter must be of type ProgressNotification: {meth
- Method must have exactly 1 parameter (List<McpSchema.Prompt>
- Method must have exactly 1 parameter (List<McpSchema.Resourc
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/c871c2985f915f8b.
Report an issue: GitHub.