{"record":{"id":"696639a28e053ede","repo":"koala73/worldmonitor","slug":"provide-exactly-one-of-country-code-preset-or-me","errorCode":null,"errorMessage":"provide exactly one of country_code, preset, or members.","messagePattern":"provide exactly one of country_code, preset, or members\\.","errorType":"validation","errorClass":"RpcValidationError","httpStatus":400,"severity":"error","filePath":"api/mcp/registry/rpc-tools.ts","lineNumber":2153,"sourceCode":"        },\n      },\n      required: [],\n      oneOf: [\n        { required: ['country_code'] },\n        { required: ['preset'] },\n        { required: ['members'] },\n      ],\n    },\n    outputSchema: FIVE_FACTOR_SCORECARD_OUTPUT_SCHEMA,\n    annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },\n    _coverageKeys: ['scorecard:five-factor:v1', 'seed-meta:scorecard:five-factor'],\n    _execute: async (params, base, context) => {\n      const countryCode = argStr(params.country_code).trim().toUpperCase();\n      const preset = argStr(params.preset).trim().toUpperCase();\n      const members = Array.isArray(params.members) ? params.members : [];\n      const selectors = Number(countryCode.length > 0) + Number(preset.length > 0) + Number(members.length > 0);\n      if (selectors !== 1) {\n        throw new RpcValidationError('get-five-factor-scorecard', [{\n          field: 'selection',\n          description: 'provide exactly one of country_code, preset, or members.',\n        }]);\n      }\n\n      const q = new URLSearchParams();\n      let path: string;\n      if (countryCode) {\n        if (!/^[A-Z]{2}$/.test(countryCode)) {\n          throw new RpcValidationError('get-five-factor-scorecard', [{\n            field: 'country_code',\n            description: 'must be an ISO 3166-1 alpha-2 country code.',\n          }]);\n        }\n        path = '/api/scorecard/v1/get-five-factor-scorecard';\n        q.set('countryCode', countryCode);\n      } else {\n        path = '/api/scorecard/v1/get-bloc-scorecard';","sourceCodeStart":2135,"sourceCodeEnd":2171,"githubUrl":"https://github.com/koala73/worldmonitor/blob/9361220cc013571781071f0206e4d80fd14b2f7f/api/mcp/registry/rpc-tools.ts#L2135-L2171","documentation":"The get-five-factor-scorecard tool requires exactly one of three mutually exclusive selectors: country_code, preset, or members. The handler counts how many are present (non-empty) and throws RpcValidationError when the count is not exactly 1 — i.e. zero selectors or more than one selector was supplied.","triggerScenarios":"Calling get-five-factor-scorecard with: none of the three fields set; two or three set at once (e.g. both country_code and preset); members provided as an array alongside country_code; or all fields present but empty strings/empty array (count 0).","commonSituations":"An agent template that fills multiple selector fields by default; a UI passing through stale params from a previous query type; confusion between the single-country and group (preset/members) variants of the scorecard API.","solutions":["Send exactly one selector: either country_code, or preset, or members — delete the others from the request.","For a single country use country_code: 'DE'; for a predefined basket use preset; for an ad-hoc group use members only.","If building params programmatically, construct the params object conditionally so only one key is ever set.","Empty strings count as absent — ensure the chosen selector is actually non-empty (argStr(...).trim() and members.length > 0)."],"exampleFix":"// before\ncallTool('get-five-factor-scorecard', { country_code: 'DE', preset: 'G10' })\n// after\ncallTool('get-five-factor-scorecard', { country_code: 'DE' })","handlingStrategy":"validation","validationCode":"const selectors = ['country_code', 'preset', 'members'].filter((k) => {\n  const v = params[k];\n  return Array.isArray(v) ? v.length > 0 : typeof v === 'string' && v.trim().length > 0;\n});\nif (selectors.length !== 1) throw new Error(`exactly one of country_code, preset, members required; got [${selectors}]`);","typeGuard":"function hasExactlyOneSelector(p: { country_code?: string; preset?: string; members?: unknown[] }): boolean {\n  const n = Number(!!p.country_code?.trim()) + Number(!!p.preset?.trim()) + Number((p.members?.length ?? 0) > 0);\n  return n === 1;\n}","tryCatchPattern":"try {\n  return await callTool('get-five-factor-scorecard', params);\n} catch (err) {\n  if (err instanceof RpcValidationError && err.fields?.[0]?.field === 'selection') {\n    // rebuild params with a single selector and retry once\n  } else throw err;\n}","preventionTips":["Build scorecard params conditionally so only one selector key is ever present.","Never spread a previous query's params into a new scorecard call.","Remember empty strings and empty arrays count as absent.","Document selector exclusivity in tool-calling agent prompts."],"tags":["validation","mcp","rpc","parameters","input"],"backgroundTag":"rpc-validation-error","analyzedSha":"9361220cc013571781071f0206e4d80fd14b2f7f","analyzedAt":"2026-09-01T10:32:37.851Z","contentChangedAt":"2026-09-01T10:32:37.851Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}