{"record":{"id":"1453883c367c3772","repo":"nexu-io/open-design","slug":"raw-api-keys-are-not-accepted-by-open-design-mcp","errorCode":null,"errorMessage":"raw API keys are not accepted by Open Design MCP. Configure Local BYOK in the Open Design UI and start that run from the local product instead.","messagePattern":"raw API keys are not accepted by Open Design MCP\\. Configure Local BYOK in the Open Design UI and start that run from the local product instead\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/mcp.ts","lineNumber":2476,"sourceCode":"}\n\n// Commission a generation run. The caller never runs the skill/plugin\n// itself; we POST to /api/runs and the daemon spawns its own agent.\n// Returns the runId immediately so the caller can poll get_run —\n// start+poll because MCP is request/response and generation is\n// minutes-long.\nasync function startRun(\n  baseUrl: string,\n  args: McpArgs,\n  options: HandleMcpToolCallOptions = {},\n  headers?: Record<string, string>,\n) {\n  if (\n    Object.prototype.hasOwnProperty.call(args, 'apiKey')\n    || Object.prototype.hasOwnProperty.call(args, 'byokProvider')\n    || containsMcpCredentialField(args.inputs)\n  ) {\n    throw new Error(\n      'raw API keys are not accepted by Open Design MCP. Configure Local BYOK in the Open Design UI and start that run from the local product instead.',\n    );\n  }\n  const { id, resolved, active } = await resolveProjectArg(baseUrl, args.project, headers);\n  if (args.requestId !== undefined) requireString(args.requestId, 'requestId');\n  if (\n    options.pluginAttribution\n    && (typeof args.requestId !== 'string' || args.requestId.length === 0)\n  ) {\n    throw pluginContractError(\n      'requestId is required for attributed start_run calls so a lost response can be retried without starting a second logical run',\n    );\n  }\n  const requestId =\n    typeof args.requestId === 'string' && args.requestId.length > 0\n      ? args.requestId\n      : randomUUID();\n  const body: JsonObject = { projectId: id, clientRequestId: requestId };","sourceCodeStart":2458,"sourceCodeEnd":2494,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/mcp.ts#L2458-L2494","documentation":"startRun refuses to launch a run if args contains apiKey or byokProvider, or if args.inputs contains a field whose name matches a credential pattern (api_key, authorization, access_token, refresh_token, secret, password, checked recursively up to depth 20). Open Design MCP deliberately does not accept raw provider credentials; keys must live in Local BYOK configured through the UI.","triggerScenarios":"Passing apiKey in the MCP call; setting byokProvider; embedding a token in inputs.headers.authorization or inputs.api_key; nested credential fields deeper in the inputs object.","commonSituations":"An agent porting a direct-provider script into MCP and passing its key; a user pasting a bearer token into inputs.","solutions":["Remove apiKey, byokProvider, and any credential-shaped fields from the MCP args.","Configure the provider key via Local BYOK in the Open Design UI, then start the run from the local product.","Move secrets into headers managed by the daemon, not into MCP inputs."],"exampleFix":"// before\nstart_run({ apiKey: 'sk-...', inputs: { authorization: 'Bearer ...', prompt: 'hi' } })\n\n// after\n// set the key in Open Design UI -> Local BYOK, then:\nstart_run({ project: 'my-project', inputs: { prompt: 'hi' } })","handlingStrategy":"validation","validationCode":"const CRED = /^(?:api[_-]?key|authorization|access[_-]?token|refresh[_-]?token|secret|password)$/iu;\nfunction leaks(v: unknown, d = 0): boolean {\n  if (d > 20) return true;\n  if (!v || typeof v !== 'object') return false;\n  if (Array.isArray(v)) return v.some((x) => leaks(x, d + 1));\n  return Object.keys(v).some((k) => CRED.test(k)) || Object.values(v).some((x) => leaks(x, d + 1));\n}\nif ('apiKey' in args || 'byokProvider' in args || leaks(args.inputs)) {\n  throw new Error('strip credential fields; configure Local BYOK in the Open Design UI instead');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never pass provider keys through MCP args.","Route all credentials through Local BYOK configured in the UI.","Scan inputs for credential-shaped keys before submit."],"tags":["mcp","security","byok","credentials"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}