{"record":{"id":"cf8720a94ad890d8","repo":"googleapis/mcp-toolbox","slug":"parameter-q-is-not-secure-and-must-not-be-passed","errorCode":null,"errorMessage":"parameter %q is not secure and must not be passed in secureArguments","messagePattern":"parameter %q is not secure and must not be passed in secureArguments","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/server/mcp/v20260728/method.go","lineNumber":898,"sourceCode":"\turlParams, _ := util.UrlParamsFromContext(ctx)\n\n\tfor _, p := range paramDefs {\n\t\tif p != nil && p.GetSecure() {\n\t\t\tsecureParamMap[p.GetName()] = true\n\t\t}\n\t}\n\n\t// Validate that secure parameters are not passed in standard arguments (Agent error)\n\tfor argName := range req.Params.Arguments {\n\t\tif secureParamMap[argName] {\n\t\t\treturn nil, fmt.Errorf(\"parameter %q is secure and must not be passed in standard arguments\", argName), nil\n\t\t}\n\t}\n\n\t// Validate that non-secure parameters are not passed in secureArguments (Protocol error)\n\tfor argName := range req.Params.SecureArguments {\n\t\tif !secureParamMap[argName] {\n\t\t\treturn nil, nil, fmt.Errorf(\"parameter %q is not secure and must not be passed in secureArguments\", argName)\n\t\t}\n\t}\n\n\t// Validate that required secure parameters are present in secureArguments (Protocol error)\n\tfor _, p := range paramDefs {\n\t\tif p != nil && p.GetSecure() {\n\t\t\tname := p.GetName()\n\t\t\tif p.GetValueFromParam() == \"\" {\n\t\t\t\tif _, bound := urlParams[name]; !bound {\n\t\t\t\t\tif parameters.CheckParamRequired(p.GetRequired(), p.GetDefault()) {\n\t\t\t\t\t\tif req.Params.SecureArguments == nil {\n\t\t\t\t\t\t\treturn nil, nil, fmt.Errorf(\"missing required secure parameter %q in secureArguments\", name)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif _, ok := req.Params.SecureArguments[name]; !ok {\n\t\t\t\t\t\t\treturn nil, nil, fmt.Errorf(\"missing required secure parameter %q in secureArguments\", name)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}","sourceCodeStart":880,"sourceCodeEnd":916,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/server/mcp/v20260728/method.go#L880-L916","documentation":"validateAndMergeSecureParams rejects secureArguments entries whose names do not correspond to a parameter marked secure. This is a protocol-level error (nil agent error, protocol error returned) — the client is misusing the secureArguments channel for a regular parameter.","triggerScenarios":"A tools/call request includes params.secureArguments containing a key that maps to a non-secure parameter (or an entirely unknown parameter) of the invoked tool.","commonSituations":"Client blanket-copies every argument into secureArguments after learning about the extension; parameter definitions changed in tools.yaml so a formerly-secure param is now plain; typo in a secure parameter name making it unresolvable in secureParamMap.","solutions":["Remove the non-secure parameter from params.secureArguments and pass it in params.arguments instead","Verify the tool's parameter definitions in tools.yaml match what the client sends (name and secure flag)","Update the client so only parameters with secure: true go into secureArguments"],"exampleFix":"// before\n{\"params\": {\"arguments\": {}, \"secureArguments\": {\"query\": \"SELECT 1\"}}}  // query is not secure\n// after\n{\"params\": {\"arguments\": {\"query\": \"SELECT 1\"}, \"secureArguments\": {}}}","handlingStrategy":"validation","validationCode":"const secureNames = new Set(toolParams.filter(p => p.secure).map(p => p.name));\nfor (const key of Object.keys(secureArgs)) {\n  if (!secureNames.has(key)) throw new Error(`\"${key}\" is not secure; move it to arguments`);\n}","typeGuard":"function secureArgsOnlyContainsSecure(secureArgs, secureNames) {\n  return Object.keys(secureArgs).every(k => secureNames.has(k));\n}","tryCatchPattern":"try {\n  await mcp.toolsCall({ name: tool, arguments: args, secureArguments: secureArgs });\n} catch (e) {\n  if (/is not secure and must not be passed in secureArguments/.test(e.message)) {\n    const key = e.message.match(/parameter \"([^\"]+)\"/)?.[1];\n    args[key] = secureArgs[key]; delete secureArgs[key]; // retry correctly split\n  } else { throw e; }\n}","preventionTips":["Only route params explicitly marked secure: true in the manifest into secureArguments","Diff client-side schemas against tools.yaml after any config change","Avoid bulk-mirroring arguments into secureArguments 'just in case'","Validate outgoing calls with a schema derived from the tool manifest"],"tags":["mcp","security","secure-parameters","protocol-error"],"backgroundTag":"secure-param-in-plain-arguments","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}