{"record":{"id":"1cfa924340e4b767","repo":"mastra-ai/mastra","slug":"fga-denied-for-tool-resourceid","errorCode":null,"errorMessage":"FGA denied for tool '${resourceId}'","messagePattern":"FGA denied for tool '(.+?)'","errorType":"exception","errorClass":"FGADeniedError","httpStatus":null,"severity":"error","filePath":"packages/mcp/src/server/server.ts","lineNumber":2858,"sourceCode":"        }\n      }),\n    );\n\n    return accessible.filter((entry): entry is [string, (typeof this.convertedTools)[string]] => entry !== null);\n  }\n\n  private async enforceToolExecutionFGA(toolId: string, requestContext?: RequestContext): Promise<void> {\n    const fgaProvider = this.mastra?.getServer?.()?.fga;\n    if (!fgaProvider) {\n      return;\n    }\n\n    const { getMCPToolFGAResourceId, requireFGA, FGADeniedError, MastraFGAPermissions } =\n      await import('@mastra/core/auth/ee');\n    const resourceId = getMCPToolFGAResourceId(this.id, toolId);\n    const user = await this.resolveMappedFGAUser(requestContext);\n    if (!user) {\n      throw new FGADeniedError({ id: 'unknown' }, { type: 'tool', id: resourceId }, MastraFGAPermissions.TOOLS_EXECUTE);\n    }\n    const { resource, permission } = this.resolveToolFGAParams({\n      user,\n      resourceId,\n      requestContext,\n      permission: MastraFGAPermissions.TOOLS_EXECUTE,\n    });\n\n    await requireFGA({\n      fgaProvider,\n      user,\n      resource,\n      permission,\n      requestContext,\n      context: {\n        resourceId,\n      },\n      metadata: {","sourceCodeStart":2840,"sourceCodeEnd":2876,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/mcp/src/server/server.ts#L2840-L2876","documentation":"When fine-grained authorization (FGA) is configured on the Mastra server, every tool execution is checked with the TOOLS_EXECUTE permission. If the request context cannot be resolved to an authenticated FGA user (resolveMappedFGAUser returns nothing), the server throws an FGADeniedError naming the tool resource — effectively denying tool execution for unidentified callers rather than executing tools as an implicit or anonymous user.","triggerScenarios":"Calling executeTool (or listing tools through the FGA-filtered path) without supplying an authenticated user in requestContext while FGA is enabled on the Mastra server; a token/identity mapping configured in resolveMappedFGAUser that fails to resolve (expired/absent credentials); invoking server methods programmatically without forwarding the request context that carries the user identity.","commonSituations":"Requests that bypass the auth middleware (direct executeTool calls from custom routes) so no user lands in requestContext; misconfigured FGA user mapping so valid tokens don't resolve to users; testing locally with FGA enabled but no auth headers; service-to-service calls missing forwarded identity headers.","solutions":["Ensure the incoming request passes through Mastra auth middleware so an authenticated user is present in requestContext.","Forward the requestContext (containing the resolved user) into executeTool calls.","Verify the FGA user-mapping configuration in resolveMappedFGAUser matches how your auth provider issues identities.","Temporarily disable FGA (no fga provider on the server) to confirm the error is auth-related, then fix the mapping.","Grant the mapped user the TOOLS_EXECUTE permission (or your mapped permission) for the tool resource in your FGA policy."],"exampleFix":"// before\nawait server.executeTool('getWeather', { location: 'London' });\n// after\nawait server.executeTool('getWeather', { location: 'London' }, {\n  toolCallId: 'call_1',\n  requestContext: { 'user': req.user }\n});","handlingStrategy":"validation","validationCode":"const fgaEnabled = Boolean(mastra.getServer?.()?.fga);\nconst user = requestContext?.user;\nif (fgaEnabled && !user) {\n  throw new Error('FGA is enabled: tool execution requires an authenticated user in requestContext');\n}","typeGuard":"function hasAuthenticatedUser(ctx?: { user?: unknown }): ctx is { user: { id: string } } {\n  return !!ctx && typeof ctx.user === 'object' && ctx.user !== null && typeof (ctx.user as any).id === 'string';\n}","tryCatchPattern":"try {\n  return await server.executeTool(toolId, args, { requestContext });\n} catch (e) {\n  if (e?.name === 'FGADeniedError') {\n    throw new HttpError(403, `Not authorized to execute tool '${toolId}'`);\n  }\n  throw e;\n}","preventionTips":["Route all tool-execution entry points through Mastra auth middleware so requestContext always carries the user.","Forward requestContext into every programmatic executeTool call.","Test FGA user mapping with a real token before deploying.","Verify the mapped user holds TOOLS_EXECUTE (or your custom mapped permission) on the tool resource.","Decide explicitly whether anonymous tool execution should be blocked; if FGA is on, it will be."],"tags":["auth","fga","authorization","mcp"],"backgroundTag":"fga-permission-denied","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}