{"record":{"id":"6dc06f79e3917a5d","repo":"spring-projects/spring-ai","slug":"method-cannot-have-more-than-one-mcpprogresstoken-6dc06f","errorCode":null,"errorMessage":"Method cannot have more than one @McpProgressToken parameter: {method.getName()} in {method.getDeclaringClass().getName()}","messagePattern":"Method cannot have more than one @McpProgressToken parameter: (.+?) in (.+?)","errorType":"validation","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/AbstractMcpPromptMethodCallback.java","lineNumber":130,"sourceCode":"\t\tjava.lang.reflect.Parameter[] parameters = method.getParameters();\n\n\t\t// Check for duplicate parameter types\n\t\tboolean hasExchangeParam = false;\n\t\tboolean hasRequestParam = false;\n\t\tboolean hasMapParam = false;\n\t\tboolean hasProgressTokenParam = false;\n\t\tboolean hasMetaParam = false;\n\t\tboolean hasRequestContextParam = false;\n\n\t\tfor (java.lang.reflect.Parameter param : parameters) {\n\t\t\tClass<?> paramType = param.getType();\n\n\t\t\tthis.validateParamType(paramType);\n\n\t\t\t// Skip @McpProgressToken annotated parameters from validation\n\t\t\tif (param.isAnnotationPresent(McpProgressToken.class)) {\n\t\t\t\tif (hasProgressTokenParam) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"Method cannot have more than one @McpProgressToken parameter: \"\n\t\t\t\t\t\t\t+ method.getName() + \" in \" + method.getDeclaringClass().getName());\n\t\t\t\t}\n\t\t\t\thasProgressTokenParam = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Skip McpMeta parameters from validation\n\t\t\tif (McpMeta.class.isAssignableFrom(paramType)) {\n\t\t\t\tif (hasMetaParam) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"Method cannot have more than one McpMeta parameter: \"\n\t\t\t\t\t\t\t+ method.getName() + \" in \" + method.getDeclaringClass().getName());\n\t\t\t\t}\n\t\t\t\thasMetaParam = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (McpSyncRequestContext.class.isAssignableFrom(paramType)) {\n\t\t\t\tif (hasRequestContextParam) {","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/prompt/AbstractMcpPromptMethodCallback.java#L112-L148","documentation":"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.","triggerScenarios":"An @McpPrompt method declaring two parameters annotated @McpProgressToken, e.g. complete(String value, @McpProgressToken String t1, @McpProgressToken String t2).","commonSituations":"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.","solutions":["Remove the extra @McpProgressToken annotation so exactly one parameter carries it.","If both values are needed, capture the token once and pass it to a shared helper instead of injecting it twice.","Review the method signature and keep only supported parameter kinds (single prompt arg, McpMeta, single context, single @McpProgressToken)."],"exampleFix":"// before\n@McpPrompt(name = \"p\")\npublic String complete(String q, @McpProgressToken String t1, @McpProgressToken String t2) { ... }\n// after\n@McpPrompt(name = \"p\")\npublic String complete(String q, @McpProgressToken String token) { ... }","handlingStrategy":"validation","validationCode":"long tokenParams = Arrays.stream(method.getParameters())\n    .filter(p -> p.isAnnotationPresent(McpProgressToken.class)).count();\nif (tokenParams > 1) throw new IllegalStateException(\"Only one @McpProgressToken parameter allowed\");","typeGuard":null,"tryCatchPattern":"try { registry.register(bean); } catch (IllegalArgumentException e) { log.error(\"Invalid @McpPrompt signature: {}\", e.getMessage()); }","preventionTips":["Count @McpProgressToken annotations when writing prompt methods","After copy-pasting parameters, re-read the full signature","Keep a project convention: one progress token parameter max, injected once and reused"],"tags":["java","mcp","annotation","method-signature"],"backgroundTag":"invalid-argument-value","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}