{"record":{"id":"28d50ee8702beb6b","repo":"apache/shardingsphere","slug":"completion-argument-s-is-not-declared-for-s","errorCode":null,"errorMessage":"Completion argument `%s` is not declared for %s `%s`.","messagePattern":"Completion argument `(.+?)` is not declared for (.+?) `(.+?)`\\.","errorType":"validation","errorClass":"MCPInvalidRequestException","httpStatus":null,"severity":"error","filePath":"mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/completion/MCPCompletionService.java","lineNumber":124,"sourceCode":"        Collection<MCPCompletionCandidate> candidates = handlerResult.getCandidates();\n        int maxValues = Math.min(MAX_VALUES_LIMIT, 0 == descriptor.getMaxValues() ? DEFAULT_MAX_VALUES : descriptor.getMaxValues());\n        List<MCPCompletionCandidate> filteredCandidates = candidates.stream().filter(each -> matchesPrefix(each.getValue(), prefix)).sorted(createCandidateComparator(prefix)).toList();\n        String matchStrategy = \"prefix\";\n        if (filteredCandidates.isEmpty() && !prefix.isEmpty()) {\n            filteredCandidates = candidates.stream().filter(each -> matchesContains(each.getValue(), prefix)).sorted(createCandidateComparator(prefix)).toList();\n            matchStrategy = \"contains_fallback\";\n        }\n        List<MCPCompletionCandidate> returnedCandidates = filteredCandidates.stream().limit(maxValues).toList();\n        CompletionMetadataContext metadataContext = new CompletionMetadataContext(descriptor, argumentName, prefix, matchStrategy, actualContextArguments, handlerResult,\n                filteredCandidates, returnedCandidates);\n        Map<String, Object> meta = createMeta(metadataContext);\n        return new MCPCompletionResult(returnedCandidates.stream().map(MCPCompletionCandidate::getValue).toList(), filteredCandidates.size(), filteredCandidates.size() > returnedCandidates.size(),\n                meta);\n    }\n    \n    private void validateDeclaredArgument(final MCPCompletionTargetDescriptor descriptor, final String argumentName) {\n        if (!descriptor.getArguments().contains(argumentName)) {\n            throw new MCPInvalidRequestException(String.format(\"Completion argument `%s` is not declared for %s `%s`.\",\n                    Objects.toString(argumentName, \"\"), descriptor.getReferenceType(), descriptor.getReference()));\n        }\n    }\n    \n    private void mergeInferredContextArguments(final Map<String, String> contextArguments, final Map<String, Object> inferredContextArguments) {\n        for (Entry<String, Object> entry : inferredContextArguments.entrySet()) {\n            if (Objects.toString(contextArguments.get(entry.getKey()), \"\").isEmpty()) {\n                contextArguments.put(entry.getKey(), Objects.toString(entry.getValue(), \"\"));\n            }\n        }\n    }\n    \n    private Comparator<MCPCompletionCandidate> createCandidateComparator(final String prefix) {\n        String normalizedPrefix = prefix.toLowerCase(Locale.ENGLISH);\n        return Comparator.comparingInt((MCPCompletionCandidate each) -> getExactMatchRank(each, normalizedPrefix))\n                .thenComparing(this::compareUpdateTime)\n                .thenComparing(each -> each.getValue().toLowerCase(Locale.ENGLISH))\n                .thenComparing(MCPCompletionCandidate::getValue);","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/completion/MCPCompletionService.java#L106-L142","documentation":"MCPCompletionService validates that the argument being completed is actually declared by the target completion descriptor (a tool's or prompt's declared argument list). If argumentName is not in descriptor.getArguments(), it throws MCPInvalidRequestException formatted with the argument name, reference type ('tool'/'prompt') and reference name. This guards against completion requests for arguments the referenced tool/prompt never declares.","triggerScenarios":"Calling the completion/complete endpoint with ref.name='some_tool' and argument.name='foo' when some_tool's input schema does not declare an argument named 'foo' — usually a typo, a stale client hardcoding an argument that was renamed, or completing against the wrong reference.","commonSituations":"Argument renamed between MCP server versions while the client caches the old schema; misspelled argument names; copying a completion request example that targets a different tool; drifting tool schemas between environments.","solutions":["List the tool/prompt (tools/list, prompts/list) and use an argument name from its current declared arguments.","Fix typos in argument.name so it matches the tool input schema exactly (case-sensitive).","If the client caches schemas, refresh it after upgrading the MCP server.","Server-side, add the missing argument to the tool descriptor if it was intended to be completable."],"exampleFix":"// before\n{ \"method\": \"completion/complete\",\n  \"params\": { \"ref\": { \"type\": \"ref/tool\", \"name\": \"database_gateway_execute_query\" },\n              \"argument\": { \"name\": \"maxRow\", \"prefix\": \"1\" } } } // typo -> error\n\n// after\n{ \"method\": \"completion/complete\",\n  \"params\": { \"ref\": { \"type\": \"ref/tool\", \"name\": \"database_gateway_execute_query\" },\n              \"argument\": { \"name\": \"max_rows\", \"prefix\": \"1\" } } }","handlingStrategy":"validation","validationCode":"// Validate against the live tool/prompt schema before completing\nconst tools = (await mcp.request('tools/list')).tools;\nconst tool = tools.find(t => t.name === params.ref.name);\nconst declared = tool ? Object.keys(tool.inputSchema?.properties ?? {}) : [];\nif (!declared.includes(params.argument.name)) {\n  throw new Error(`argument '${params.argument.name}' not declared; choose from: ${declared.join(', ')}`);\n}\nreturn mcp.request('completion/complete', params);","typeGuard":"function isDeclaredCompletionArgument(toolsList, refName, argName) {\n  const tool = toolsList.find(t => t.name === refName);\n  return Boolean(tool) && Object.keys(tool.inputSchema?.properties ?? {}).includes(argName);\n}","tryCatchPattern":"try {\n  return await mcp.request('completion/complete', params);\n} catch (e) {\n  if (/is not declared for/.test(e.message)) { /* fix argument name from tools/list and retry once */ }\n  throw e;\n}","preventionTips":["Always read argument names from tools/list/prompts/list instead of hardcoding.","Refresh cached schemas after MCP server upgrades.","Match argument names case-sensitively.","Validate argument names against the tool input schema before calling completion."],"tags":["mcp","completion","validation","tool-arguments"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}