{"record":{"id":"e1b1631d9247c7a6","repo":"danny-avila/LibreChat","slug":"forbidden-insufficient-mcp-server-permissions","errorCode":null,"errorMessage":"Forbidden: Insufficient MCP server permissions","messagePattern":"Forbidden: Insufficient MCP server permissions","errorType":"exception","errorClass":"Error","httpStatus":403,"severity":"error","filePath":"api/server/services/MCP.js","lineNumber":1058,"sourceCode":"      },\n      required: [],\n    };\n  }\n\n  const normalizedToolKey = `${toolName}${Constants.mcp_delimiter}${normalizeServerName(serverName)}`;\n\n  /** @type {(toolArguments: Object | string, config?: GraphRunnableConfig) => Promise<unknown>} */\n  const _call = async (toolArguments, config) => {\n    const effectiveUser = config?.configurable?.user ?? capturedUser;\n    const permissionUser = effectiveUser;\n    const userId = effectiveUser?.id || config?.configurable?.user_id || capturedUser?.id;\n    try {\n      const provider = (config?.metadata?.provider || capturedProvider)?.toLowerCase();\n      const canUseMCP = mcpPermissionContext\n        ? await mcpPermissionContext.canUseServers(permissionUser)\n        : await userCanUseMCPServers(permissionUser);\n      if (!canUseMCP) {\n        throw new Error('Forbidden: Insufficient MCP server permissions');\n      }\n      const flowsCache = getLogStores(CacheKeys.FLOWS);\n      const flowManager = getFlowStateManager(flowsCache);\n      const derivedSignal = config?.signal ? AbortSignal.any([config.signal]) : undefined;\n      const mcpManager = getMCPManager(userId);\n\n      const { args: _args, stepId, ...toolCall } = config.toolCall ?? {};\n      const flowId = `${serverName}:oauth_login:${config.metadata.thread_id}:${config.metadata.run_id}`;\n      const runStepDeltaEmitter = createRunStepDeltaEmitter({\n        res,\n        stepId,\n        toolCall,\n        streamId,\n        jobCreatedAt,\n      });\n      const oauthStart = createOAuthStart({\n        flowId,\n        flowManager,","sourceCodeStart":1040,"sourceCodeEnd":1076,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/server/services/MCP.js#L1040-L1076","documentation":"The MCP tool _call wrapper throws this at MCP.js:1058 when canUseMCP returns false — i.e. the effective user lacks the USE permission on PermissionTypes.MCP_SERVERS. The check goes through userCanUseMCPServers (role-based, request-cached) or an injected mcpPermissionContext; any thrown error there also returns false, so a broken permission check fails closed.","triggerScenarios":"A user whose role does not grant USE on MCP_SERVERS invokes any MCP tool. Also fires if user.id or user.role is missing on the session, or if checkAccessWithRequestCache throws (caught and mapped to false).","commonSituations":"Role policy was tightened and MCP use was not granted to the user's role. A new SSO/role mapping leaves user.role unset. A custom role was created without the MCP capability. Test fixtures that omit role.","solutions":["Grant the user's role the USE permission for MCP_SERVERS via the admin role/permission UI.","Confirm req.user.role and req.user.id are populated by the auth middleware for this session.","Check server logs for 'Failed MCP permission check' — if present, the permission subsystem itself errored and needs fixing, not just the role grant."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"async function ensureCanUseMCP(user) {\n  if (!user?.id || !user?.role) throw new Error('authenticated user with role required');\n  const ok = await userCanUseMCPServers(user);\n  if (!ok) throw new Error('role lacks MCP_SERVERS:USE');\n}","typeGuard":"const isAuthedUser = (u) => !!u?.id && !!u?.role;","tryCatchPattern":"try {\n  await callMcpTool(...);\n} catch (e) {\n  if (e.message === 'Forbidden: Insufficient MCP server permissions') {\n    return showUpgradeOrRolePrompt();\n  }\n  throw e;\n}","preventionTips":["Grant USE on MCP_SERVERS to roles that need MCP tools.","Ensure auth middleware always populates user.id and user.role.","Monitor logs for 'Failed MCP permission check' to catch permission-subsystem failures."],"tags":["mcp","authorization","permissions","roles"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}