{"record":{"id":"8f9941f0907bf728","repo":"ruvnet/ruflo","slug":"mcp-caller-auth-enabled-but-no-token","errorCode":"mcp-caller-auth-enabled-but-no-token","errorMessage":"mcp-caller-auth-enabled-but-no-token","messagePattern":"mcp-caller-auth-enabled-but-no-token","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/services/policy-runtime.ts","lineNumber":353,"sourceCode":" * `verifyInvocationToken` here, and the tool-mismatch check is not exercised\n * for this use case. What this retains: a process that never received the\n * signed token cannot forge one, so it cannot impersonate `agent:<workerId>`.\n * What it does NOT retain: a compromised worker process can still use its\n * own valid token for every MCP call for the rest of its lifetime — the\n * token does not limit blast radius to a single call.\n */\nfunction resolveMcpCallerIdentity(): { id: string; type: 'agent' | 'legacy' } {\n  if (!isMcpCallerAuthEnabled()) {\n    return {\n      id: process.env.CLAUDE_FLOW_PRINCIPAL_ID ?? 'legacy-cli',\n      type: process.env.CLAUDE_FLOW_PRINCIPAL_ID ? 'agent' : 'legacy',\n    };\n  }\n\n  const encodedToken = process.env.CLAUDE_FLOW_MCP_INVOCATION_TOKEN;\n  const publicKeyHex = process.env.CLAUDE_FLOW_MCP_CALLER_PUBKEY;\n  if (!encodedToken || !publicKeyHex) {\n    throw new Error('mcp-caller-auth-enabled-but-no-token');\n  }\n\n  const token = decodeTokenEnvelope(encodedToken);\n  if (!token) {\n    throw new Error('mcp-caller-auth-enabled-but-no-token');\n  }\n\n  let publicKey;\n  try {\n    publicKey = publicKeyFromHex(publicKeyHex);\n  } catch {\n    throw new Error('mcp-caller-auth-enabled-but-no-token');\n  }\n\n  const result = verifyInvocationToken(token, publicKey, {});\n  if (!result.valid) {\n    throw new Error(`mcp-caller-auth-verification-failed:${result.reason}`);\n  }","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/ruvnet/ruflo/blob/2602b642d92234c710ffbe96bfb33007d481ceab/v3/@claude-flow/cli/src/services/policy-runtime.ts#L335-L371","documentation":"When MCP caller authentication is enabled, resolveMcpCallerIdentity requires both CLAUDE_FLOW_MCP_INVOCATION_TOKEN and CLAUDE_FLOW_MCP_CALLER_PUBKEY to be set. It throws this coded error when either variable is missing or empty, refusing to authorize the tool call rather than falling back to unauthenticated access.","triggerScenarios":"authorizeMcpTool runs with auth enabled but process.env.CLAUDE_FLOW_MCP_INVOCATION_TOKEN or CLAUDE_FLOW_MCP_CALLER_PUBKEY is unset/empty.","commonSituations":"Enabling mcp caller auth in config without provisioning the corresponding env vars; running the server under a service manager that strips the operator's env; forgetting to pass the token to a child process.","solutions":["Set both CLAUDE_FLOW_MCP_INVOCATION_TOKEN and CLAUDE_FLOW_MCP_CALLER_PUBKEY in the server environment","Check the service/launch configuration actually exports the vars (systemd Environment=, docker -e, etc.)","If auth was enabled unintentionally, disable MCP caller auth in policy config"],"exampleFix":"// before\n# token not exported\n// after\nexport CLAUDE_FLOW_MCP_INVOCATION_TOKEN=<token-envelope>\nexport CLAUDE_FLOW_MCP_CALLER_PUBKEY=<64-hex-pubkey>","handlingStrategy":"validation","validationCode":"if (!process.env.CLAUDE_FLOW_MCP_INVOCATION_TOKEN || !process.env.CLAUDE_FLOW_MCP_CALLER_PUBKEY) { throw new Error('MCP caller auth enabled but token/pubkey env vars missing'); }","typeGuard":"const hasMcpAuthEnv = (): boolean => Boolean(process.env.CLAUDE_FLOW_MCP_INVOCATION_TOKEN && process.env.CLAUDE_FLOW_MCP_CALLER_PUBKEY);","tryCatchPattern":"try { await callMcpTool(tool, args); } catch (e) { if (e.message === 'mcp-caller-auth-enabled-but-no-token') { /* set env vars or disable caller auth */ } throw e; }","preventionTips":["Enable MCP caller auth only after provisioning both env vars","Verify env vars in startup health checks","Document the required env vars in deployment configs"],"tags":["env","authentication","mcp","policy"],"backgroundTag":"missing-env-var","analyzedSha":"2602b642d92234c710ffbe96bfb33007d481ceab","analyzedAt":"2026-09-15T22:58:14.805Z","contentChangedAt":"2026-09-15T22:58:14.805Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}