> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Control Access to MCP Tools with FGA

> Learn how to implement fine-grained authorization for your MCP server tools using Auth0 FGA with roles, groups, and temporal access.

Fine-grained authorization goes beyond simple scope-based access control by enabling sophisticated permission models based on relationships between users, roles, groups, and resources. This quickstart demonstrates how to use [Auth0 FGA](https://auth0.com/fine-grained-authorization) to implement [Relationship-Based Access Control (ReBAC)](https://docs.fga.dev/authorization-concepts#what-is-relationship-based-access-control) for your MCP server tools.

The sample application showcases five authorization patterns:

1. **Public Tools** - Accessible to all authenticated users without additional permissions
2. **Role-Based Access** - Tools assigned to specific roles (`admin`, `content_editor`)
3. **Group Membership** - Users inherit permissions through group membership (managers, marketing)
4. **Temporal Access** - Time-limited tool access with automatic expiration
5. **Resource-Specific Permissions** - Fine-grained control over tool features (e.g., viewing private documents)

By the end of this quickstart, you will have an MCP server that:

* Authenticates users with Auth0 OAuth 2.0
* Uses Auth0 FGA to determine which tools each user can access
* Dynamically filters tool lists based on user permissions
* Supports time-limited access grants that automatically expire
* Provides different data based on user roles (public vs private documents)

## Prerequisites

> **1. Create or log in to your Auth0 account**
>
> To continue with this quickstart, you need to have an [Auth0 account](https://auth0.com/signup).

> **2. Enable the Resource Parameter Compatibility Profile and Include Issuer in Authorization Responses**
>
> To use the `resource` parameter in your access tokens and the `iss` claim to identify your authorization server, you need to enable two toggles in the [Auth0 Dashboard](https://manage.auth0.com/dashboard/):
>
> 1. Navigate to **Settings** on the left sidebar.
> 2. Select [**Advanced**](https://manage.auth0.com/dashboard/#/tenant/advanced) in the top right corner.
> 3. Scroll down to the **Settings** section and enable the following toggles:
>    * **Resource Parameter Compatibility Profile**: Enables support for the `resource` parameter in authorization requests, allowing access tokens to be scoped to a specific API.
>    * **Include Issuer in Authorization Responses**: Includes the `iss` parameter identifying the authorization server in authorization responses, helping clients defend against mix-up attacks.

> **3. Install the Auth0 CLI**
>
> This guide uses [Auth0 CLI](https://auth0.github.io/auth0-cli/) to configure an Auth0 tenant for secure MCP tool access.
>
> 1. Follow the [Auth0 CLI installation instructions](https://auth0.github.io/auth0-cli/).
> 2. Log in to your account with the Auth0 CLI:
>
> ```shell wrap lines theme={null}
> auth0 login --scopes "read:client_grants,create:client_grants,delete:client_grants,read:clients,create:clients,update:clients,read:resource_servers,create:resource_servers,update:resource_servers,read:roles,create:roles,update:roles,update:tenant_settings,read:connections,update:connections"
> ```
>
> Confirm you are in the correct tenant by double-checking the tenant domain in the terminal, or run the command below:
>
> ```shell theme={null}
> auth0 tenants list
> ```
>
> If more than one tenant is configured, the default tenant will be indicated by an arrow.

> **4. Install jq**
>
> To simplify the process of interacting with the Auth0 CLI, we recommend installing [jq](https://jqlang.org/download/). This will allow you to easily parse JSON responses from the CLI.
>
> **macOS**
>
> brew install jq
>
> **Linux**
>
> sudo apt-get install jq
>
> **Windows**
>
> choco install jq

Now install and setup the dependencies for FGA:

> **1. Install the FGA CLI**
>
> This guide uses the [OpenFGA CLI](https://github.com/openfga/cli?tab=readme-ov-file#installation) to manage authorization models and permissions.
>
> 1. Install the FGA CLI:
>
> **macOS**
>
> ```shell theme={null}
> brew install openfga/tap/fga
> ```
>
> **Linux**
>
> Download the latest release from the [OpenFGA CLI releases page](https://github.com/openfga/cli/releases) and add it to your PATH.
>
> ```shell theme={null}
> # Example for Linux (replace version with latest)
> wget https://github.com/openfga/cli/releases/download/v0.6.3/fga_0.6.3_linux_amd64.tar.gz
> tar -xzf fga_0.6.3_linux_amd64.tar.gz
> sudo mv fga /usr/local/bin/
> ```
>
> **Windows**
>
> Download the latest release from the [OpenFGA CLI releases page](https://github.com/openfga/cli/releases) and add it to your PATH.
>
> 2. Verify the installation:
>
> ```shell theme={null}
> fga version
> ```

> **2. Set up Auth0 FGA or OpenFGA**
>
> You'll need an Auth0 FGA or OpenFGA store to manage fine-grained authorization for your MCP tools.
>
> **Choose your FGA provider:**
>
> * **Auth0 FGA**: Fully managed service at [fga.dev](https://fga.dev). Best for production use.
>
> * **OpenFGA**: Self-hosted open-source option. Best for local development and testing.
>
> > [!NOTE]
> >
> > Both options use the same authorization model and API. You can start with OpenFGA locally and migrate to Auth0 FGA for production.
>
> The sample application includes a complete authorization model (`fga/model.fga`) and initial permission tuples (`fga/tuples.yaml`) that will be imported using the FGA CLI.

## Configure tenant settings

> **1. Promote the connection to a domain-level connection**
>
> To allow third-party clients like MCP Inspector to use a connection such as a username-and-password database or a social connection, you need to promote the connection to a domain-level connection. [Learn more about configuring third-party applications](https://auth0.com/docs/get-started/applications/third-party-applications/configure-third-party-applications.md).
>
> **1. List Your Connection**
>
> List your connections to get their IDs
>
> ```shell theme={null}
> auth0 api get connections
> ```
>
> **2. Choose Your Connections**
>
> From the list, identify which connections you want to use for the MCP server and copy the ID.
>
> * For the username-and-password database, look for the connection with the strategy `auth0`.
> * For the Google social connection, look for the connection with the strategy `google-oauth2`.
>
> **3. Upgrade the Connection to Domain-Level**
>
> For each of those specific connection IDs, run the following command to mark it as a domain-level connection. Replace `YOUR_CONNECTION_ID` with the actual ID (e.g., `con_XXXXXXXXXXXXXXXX`).
>
> ```shell wrap lines theme={null}
> auth0 api patch connections/YOUR_CONNECTION_ID --data '{"is_domain_connection": true}'
> ```

## Create an API to represent your MCP server

An MCP server is treated just like any other [API](https://auth0.com/docs/get-started/apis) in your Auth0 tenant, which means you can use the same access control, scoping, and authorization features. The API (also known as a Resource Server) represents your protected MCP Server.

Run the following command to [create an API](https://auth0.com/docs/get-started/auth0-overview/set-up-apis.md) in Auth0:

```shell wrap lines theme={null}
auth0 api post resource-servers --data '{
  "identifier": "http://localhost:3001/",
  "name": "MCP Tools API",
  "signing_alg": "RS256",
  "token_dialect": "rfc9068_profile_authz",
  "enforce_policies": true,
  "scopes": [
    {"value": "tool:whoami", "description": "Access the WhoAmI tool"},
    {"value": "tool:greet", "description": "Access the Greeting tool"}
  ]
}'
```

Note that `rfc9068_profile_authz` is used as the [token dialect](https://auth0.com/docs/get-started/apis/enable-role-based-access-control-for-apis.md#token-dialect-options) to include the `permissions` claim in the access token, which can be useful for the API to check user permissions without making additional calls.

For more details on protecting APIs with Auth0, check our [quickstarts](https://auth0.com/docs/quickstarts.md#backend%2Fapi).

> [!NOTE]
>
> This quickstart uses two OAuth scopes for demonstration: `tool:greet` and `tool:whoami`. The `get_datetime` tool is public and doesn't require scopes, while `get_documents` uses FGA for authorization.

## Set up your FGA store

**Auth0 FGA**

**1. Create an Auth0 FGA account**

Sign up for a free account at [fga.dev](https://fga.dev).

**2. Create a store**

In the [Auth0 FGA dashboard](https://dashboard.fga.dev/), create a new store for your MCP server.

**3. Generate API credentials**

1. Navigate to **Settings** in your store.
2. In the **Authorized Clients** section, click **+ Create Client**.
3. Give your client a name and select the following permissions:
   * **Read/Write model, changes, and assertions** - To query authorization decisions
   * **Write and delete tuples** - To import tuples (user permissions)
   * **Read and query** - To import the authorization model
4. Click **Create**.
5. Save the credentials shown in the confirmation modal.

**4. Configure environment variables**

Set the following environment variables in your terminal. These will be used by the FGA CLI to connect to your store.

```shell wrap lines theme={null}
export FGA_API_URL='https://api.us1.fga.dev'
export FGA_STORE_ID='<your-store-id>'
export FGA_API_TOKEN_ISSUER='auth.fga.dev'
export FGA_API_AUDIENCE='https://api.us1.fga.dev/'
export FGA_CLIENT_ID='<your-client-id>'
export FGA_CLIENT_SECRET='<your-client-secret>'
```

Replace the placeholders with the credentials from the previous step. Note that `FGA_API_URL` may vary based on your region (e.g., `api.eu1.fga.dev` for Europe).

**OpenFGA (Local)**

**1. Install OpenFGA**

Install OpenFGA using Homebrew or Docker:

**Homebrew**

```shell theme={null}
brew install openfga
```

**Docker**

Docker installation will be used in the next step to run the server.

For other installation methods, see the [OpenFGA releases page](https://github.com/openfga/openfga/releases).

**2. Start OpenFGA**

Start the OpenFGA server:

**Homebrew**

```shell theme={null}
openfga run
```

**Docker**

```shell theme={null}
docker run -p 8080:8080 -p 8081:8081 -p 3000:3000 openfga/openfga run
```

The server will start on port 8080 by default. Leave this running in a separate terminal window.

**3. Configure environment variables**

Set the following environment variables in your terminal (in a different terminal from where OpenFGA is running):

```shell theme={null}
export FGA_API_URL='http://localhost:8080'
```

> [!NOTE]
>
> The `FGA_STORE_ID` will be set after importing the model in the next section.

## Sample app

Start by downloading or cloning the sample app for this quickstart. The sample includes a FastMCP MCP server with Auth0 OAuth and Auth0 FGA integration in JavaScript/TypeScript.

**Use sample app (recommended)**

Download auth-for-mcp fastmcp-mcp-fga-js sample code

Once downloaded, extract the files and open the project in your preferred IDE.

**Clone GitHub repository**

Clone the repository and navigate to the sample app folder:

```shell wrap lines theme={null}
git clone https://github.com/auth0-samples/auth0-ai-samples.git
cd auth0-ai-samples/auth-for-mcp/fastmcp-mcp-fga-js
```

Once cloned, open the project in your preferred IDE.

## Install packages

Install the required dependencies:

```shell theme={null}
npm install
```

## Create your environment file

From the root of your sample app directory, run the following command to create a new `.env` file with your Auth0 configuration:

```shell wrap lines expandable theme={null}
DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') \
&& touch .env \
&& echo "AUTH0_DOMAIN=${DOMAIN}" > .env \
&& echo "AUTH0_AUDIENCE=http://localhost:3001/" >> .env \
&& echo "PORT=3001" >> .env \
&& echo "MCP_SERVER_URL=http://localhost:3001" >> .env \
&& echo "" >> .env \
&& echo ".env file created with your Auth0 configuration:" \
&& cat .env
```

Next, add your FGA configuration to the `.env` file. The variables you need depend on which FGA provider you're using:

**Auth0 FGA**

Add the following to your `.env` file using the credentials from your Auth0 FGA store:

```shell .env wrap lines theme={null}
# Auth0 FGA Configuration
FGA_API_URL=https://api.us1.fga.dev
FGA_STORE_ID=YOUR_STORE_ID
FGA_API_TOKEN_ISSUER=auth.fga.dev
FGA_API_AUDIENCE=https://api.us1.fga.dev/
FGA_CLIENT_ID=YOUR_CLIENT_ID
FGA_CLIENT_SECRET=YOUR_CLIENT_SECRET
```

Replace:

* `YOUR_STORE_ID` with your store ID from the Auth0 FGA dashboard
* `YOUR_CLIENT_ID` with your client ID
* `YOUR_CLIENT_SECRET` with your client secret
* Update `FGA_API_URL` if your store is in a different region (e.g., `https://api.eu1.fga.dev` for Europe)

**OpenFGA (Local)**

Add the following to your `.env` file:

```shell .env wrap lines theme={null}
# OpenFGA Configuration
FGA_API_URL=http://localhost:8080
FGA_STORE_ID=YOUR_STORE_ID
```

Replace `YOUR_STORE_ID` with the store ID that will be generated when you import the authorization model in the next step.

> [!NOTE]
>
> If you haven't run `fga store import` yet, you can leave `FGA_STORE_ID` empty for now and add it after the import completes.

Your complete `.env` file should look like this:

**Auth0 FGA**

```shell .env wrap lines theme={null}
AUTH0_DOMAIN=YOUR_TENANT.us.auth0.com
AUTH0_AUDIENCE=http://localhost:3001/
PORT=3001
MCP_SERVER_URL=http://localhost:3001

# Auth0 FGA Configuration
FGA_API_URL=https://api.us1.fga.dev
FGA_STORE_ID=YOUR_STORE_ID
FGA_API_TOKEN_ISSUER=auth.fga.dev
FGA_API_AUDIENCE=https://api.us1.fga.dev/
FGA_CLIENT_ID=YOUR_CLIENT_ID
FGA_CLIENT_SECRET=YOUR_CLIENT_SECRET
```

**OpenFGA (Local)**

```shell .env wrap lines theme={null}
AUTH0_DOMAIN=YOUR_TENANT.us.auth0.com
AUTH0_AUDIENCE=http://localhost:3001/
PORT=3001
MCP_SERVER_URL=http://localhost:3001

# OpenFGA Configuration
FGA_API_URL=http://localhost:8080
FGA_STORE_ID=YOUR_STORE_ID
```

## Understanding the authorization model

The authorization model in this sample demonstrates how [Auth0 FGA](https://auth0.com/fine-grained-authorization) provides fine-grained access control using [Relationship-Based Access Control (ReBAC)](https://docs.fga.dev/authorization-concepts#what-is-relationship-based-access-control).

### Authorization Model Structure

The complete model is defined in `fga/model.fga`:

```typescript theme={null}
model
  schema 1.1

  type user

  # User groups
  type group
    relations
      define member : [user]

  # Roles can be linked to users or members of a user group
  type role
    relations
      define assignee : [user, group#member]

  type tool
    relations
      # Public access, role-based, and temporal access
      define can_use : [user:*, user, role#assignee, user with temporal_access, role#assignee with temporal_access]

      # Resource-specific permission for get_documents tool
      define can_view_private_documents : [role#assignee]

  # Temporal access condition
  condition temporal_access(grant_time: timestamp, grant_duration: duration, current_time: timestamp) {
    current_time < grant_time + grant_duration
  }
```

The model defines four authorization patterns:

> **1. Public Tools**
>
> Tools that are accessible to all authenticated users without requiring specific permissions.
>
> ```yaml theme={null}
> # In fga/tuples.yaml
> - user: user:*
>   relation: can_use
>   object: tool:get_datetime
> ```
>
> The wildcard `user:*` means any authenticated user can use the `get_datetime` tool.

> **2. Role-Based Access**
>
> Tools are assigned to specific roles, and users with those roles can access the tools.
>
> ```yaml theme={null}
> # In fga/tuples.yaml
> # Admin role can use all tools
> - user: role:admin#assignee
>   relation: can_use
>   object: tool:greet
>
> - user: role:admin#assignee
>   relation: can_use
>   object: tool:whoami
>
> - user: role:admin#assignee
>   relation: can_use
>   object: tool:get_documents
> ```
>
> Users assigned the `admin` role automatically gain access to these tools.

> **3. Group Membership**
>
> Users inherit permissions through group membership. Groups are assigned to roles, creating a permission chain.
>
> ```yaml theme={null}
> # In fga/tuples.yaml
> # Managers group is assigned the admin role
> - user: group:managers#member
>   relation: assignee
>   object: role:admin
>
> # Marketing group is assigned the content_editor role
> - user: group:marketing#member
>   relation: assignee
>   object: role:content_editor
> ```
>
> **Permission Chain**: User → Group → Role → Tool
>
> When you add a user to the `managers` group, they automatically inherit all permissions of the `admin` role, including access to all tools.

> **4. Temporal Access**
>
> Time-limited access to tools that automatically expires after a specified duration.
>
> ```typescript theme={null}
> // In fga/model.fga
> condition temporal_access(grant_time: timestamp, grant_duration: duration, current_time: timestamp) {
>   current_time < grant_time + grant_duration
> }
>
> // Tools can be assigned with temporal conditions
> define can_use : [user:*, user, role#assignee, user with temporal_access, role#assignee with temporal_access]
> ```
>
> When you grant temporal access (e.g., "20 seconds to use the greet tool"), FGA evaluates the condition on each request. Access is automatically revoked when the time expires.

> **5. Resource-Specific Permissions**
>
> Fine-grained permissions for specific features or data within tools.
>
> ```yaml theme={null}
> # In fga/tuples.yaml
> # Admin role can view private documents
> - user: role:admin#assignee
>   relation: can_view_private_documents
>   object: tool:get_documents
> ```
>
> The `get_documents` tool checks this permission separately to determine whether to return private documents. This allows the same tool to provide different data based on user permissions.
>
> **Example**:
>
> * Admin role: Sees all documents (public + private)
> * Content editor role: Sees only public documents

### How Authorization Works

When a user connects to the MCP server:

1. The server authenticates the user with Auth0 (validates JWT token)
2. The server queries FGA to get all tools the user can access:
   * Checks `can_use` relation for each tool
   * Evaluates group memberships, role assignments, and temporal conditions
3. The server returns only authorized tools to the MCP client
4. When the user calls a tool like `get_documents`, the server checks `can_view_private_documents` to determine what data to return

This approach ensures that authorization decisions are centralized in FGA and can be updated dynamically without changing code.

## Import the authorization model and tuples

The sample includes a complete authorization model and initial permission tuples that define:

* Public access to `get_datetime` for all users
* Role assignments (`admin`, `content_editor`)
* Group-to-role mappings (`managers` → `admin`, `marketing` → `content_editor`)
* Tool access permissions for each role

**1. Review the authorization model**

The authorization model is defined in `fga/model.fga`. It includes types for users, groups, roles, and tools, plus a temporal access condition.

The initial tuples are defined in `fga/tuples.yaml` and establish the baseline permissions.

**2. Import the model and tuples**

From the root of your sample app directory, run:

```shell wrap lines theme={null}
fga store import --file fga/store.fga.yaml
```

This command will:

1. Create a new FGA store (if using OpenFGA locally)
2. Upload the authorization model from `fga/model.fga`
3. Import the initial tuples from `fga/tuples.yaml`
4. Run tests defined in `fga/store.fga.yaml` to verify the setup

> [!NOTE]
>
> If using OpenFGA, the command output will include a store ID. Copy this ID and add it to your `.env` file as `FGA_STORE_ID`. If using Auth0 FGA with existing store, the command will update your store with the new model and tuples.

**3. Verify the import**

If the import is successful, you should see output similar to:

```json theme={null}
{
  "store": {
    "id": "01KB0NZZFAV9AX7SAPWY23KJAF",
    "name": "fastmcp-fga-example",
    "created_at": "2025-01-22T10:30:00Z",
    "updated_at": "2025-01-22T10:30:00Z"
  },
  "model": {
    "authorization_model_id": "01KED54TEMBDE753YBK7NT3DRZ"
  }
}
```

The tests at the end should show all checks passing, confirming that the authorization model is working correctly.

> [!NOTE]
>
> You can view and manage your authorization model in the [Auth0 FGA Dashboard](https://dashboard.fga.dev) if you're using Auth0 FGA. The dashboard provides a visual Model Explorer and allows you to view, add, and delete tuples in real-time.

## Run the MCP server

Start the MCP server:

```shell theme={null}
npm run start
```

The server will start on port 3001 (or the port specified in your `.env` file). You should see console output indicating:

* The server has started successfully
* FGA client has been initialized
* The server is listening for connections at `http://localhost:3001/mcp`

```
FastMCP Auth0 Example Server started
FGA client initialized for store: 01KB0NZZFAV9AX7SAPWY23KJAF
Server listening on http://localhost:3001/mcp
```

Leave the server running for testing in the next sections.

## Manage user permissions

The sample application includes helper scripts in the `fga/` directory to make permission management easier. These scripts use the FGA CLI to add or remove authorization tuples dynamically.

### Available Scripts

> **Add User to Group**
>
> Grant a user all permissions associated with a group (and its assigned role).
>
> **Usage**:
>
> ```shell theme={null}
> ./fga/add-user-to-group.sh <user-email> <group-name>
> ```
>
> **Examples**:
>
> ```shell theme={null}
> # Add user to managers group (grants admin role with full access)
> ./fga/add-user-to-group.sh user@example.com managers
>
> # Add user to marketing group (grants content_editor role)
> ./fga/add-user-to-group.sh user@example.com marketing
> ```
>
> **What it does**: Creates an FGA tuple that makes the user a member of the specified group. Since groups are assigned to roles, the user automatically inherits all role permissions.
>
> **Available groups**:
>
> * `managers` - Assigned to `admin` role (all tools + private documents)
> * `marketing` - Assigned to `content_editor` role (all tools, public documents only)

> **Remove User from Group**
>
> Revoke a user's group membership and all associated permissions.
>
> **Usage**:
>
> ```shell theme={null}
> ./fga/remove-user-from-group.sh <user-email> <group-name>
> ```
>
> **Example**:
>
> ```shell theme={null}
> # Remove user from managers group
> ./fga/remove-user-from-group.sh user@example.com managers
> ```
>
> **What it does**: Deletes the FGA tuple that grants group membership. The user immediately loses all permissions from that group's role.

> **Grant Temporal Access**
>
> Provide time-limited access to a specific tool that automatically expires.
>
> **Usage**:
>
> ```shell theme={null}
> ./fga/add-temporal-access.sh <user-email> <tool-name> <duration>
> ```
>
> **Examples**:
>
> ```shell theme={null}
> # Grant 20-second access to the greet tool
> ./fga/add-temporal-access.sh user@example.com greet 20s
>
> # Grant 1-hour access to the whoami tool
> ./fga/add-temporal-access.sh user@example.com whoami 1h
>
> # Grant 5-minute access
> ./fga/add-temporal-access.sh user@example.com greet 5m
> ```
>
> **What it does**: Creates an FGA tuple with a temporal condition. FGA evaluates the condition on each request and automatically denies access when the duration expires. No cleanup is needed.
>
> **Supported durations**: Use standard time notation (`s` for seconds, `m` for minutes, `h` for hours).
>
> **Available tools**: `greet`, `whoami`, `get_documents`
>
> > [!NOTE]
> >
> > Public tools like `get_datetime` don't need temporal access grants since they're already accessible to all authenticated users.

> **Reset Tuples**
>
> Reset all tuples to the initial state defined in `fga/tuples.yaml`.
>
> **Usage**:
>
> ```shell theme={null}
> ./fga/reset-tuples.sh
> ```
>
> **What it does**: Deletes all existing tuples and reimports the default tuples from `fga/tuples.yaml`. Useful for returning to a clean state during testing.
>
> > [!WARNING]
> >
> > This script removes all user assignments, including any custom permissions you've added. Use with caution.

### Testing Permission Changes

After running any of these scripts, you need to reload the tools:

* for MCP inspector: click 'Clear' in the MCP inspector tools panel and then 'List Tools'
* for other MCP clients: you might need to reconnect the MCP Client to see the updated tool list.

The server queries FGA on each connection to determine available tools.

> [!TIP]
>
> You can also manage tuples directly in the [Auth0 FGA Dashboard](https://dashboard.fga.dev) if you're using Auth0 FGA. The dashboard provides a visual interface for viewing, adding, and removing authorization tuples in real-time.

## Testing your MCP server

Now that your MCP server is up and running, you can test it by using tools like [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector).

> **[Learn how to test your Auth0-powered MCP server](https://auth0.com/ai/docs/mcp/guides/test-your-mcp-server-with-mcp-inspector.md)**

### Test authorization scenarios

Now test different authorization scenarios to see how FGA controls tool access. You'll need to use an MCP client like [MCP Inspector](https://github.com/modelcontextprotocol/inspector) to connect to your server.

**1. Test baseline access**

Connect to your MCP server using your user credentials. Initially, you should only see the public tool.

**Expected tools**: `get_datetime`

This demonstrates that without any role or group assignments, authenticated users only have access to public tools.

**2. Grant admin access via managers group**

Add your user to the managers group to grant admin role permissions:

```shell wrap lines theme={null}
./fga/add-user-to-group.sh YOUR_EMAIL managers
```

Replace `YOUR_EMAIL` with the email address you use to authenticate.

Reconnect in your MCP client and verify you now see all tools.

**Expected tools**: `get_datetime`, `greet`, `whoami`, `get_documents`

Call the `get_documents` tool and verify that you see both public and private documents in the response. This demonstrates resource-specific permissions based on the admin role.

> [!TIP]
>
> In MCP Inspector, you'll need to disconnect and reconnect (or refresh the connection) after changing permissions. The server queries FGA on each new connection to determine available tools.

**3. Test content editor role**

Switch from admin to content editor by changing group membership:

```shell wrap lines theme={null}
./fga/remove-user-from-group.sh YOUR_EMAIL managers
./fga/add-user-to-group.sh YOUR_EMAIL marketing
```

Reconnect in your MCP client.

**Expected tools**: `get_datetime`, `greet`, `whoami`, `get_documents`

Call the `get_documents` tool and verify that you now see only public documents (no private documents). This demonstrates how the same tool can provide different data based on user roles.

**Key difference**: Content editors have access to the same tools as admins but don't have the `can_view_private_documents` permission.

**4. Test temporal access**

Remove all group memberships and grant time-limited access to a specific tool:

```shell wrap lines theme={null}
./fga/remove-user-from-group.sh YOUR_EMAIL marketing
./fga/add-temporal-access.sh YOUR_EMAIL greet 20s
```

This grants 20 seconds of access to the `greet` tool.

**Immediately reconnect** in your MCP client.

**Expected tools**: `get_datetime`, `greet`

Call the `greet` tool to verify it works.

**Wait 25 seconds** and reconnect again.

**Expected tools**: `get_datetime` (only)

The `greet` tool should no longer appear. This demonstrates automatic expiration of temporal access without any cleanup required.

> [!WARNING]
>
> Temporal access is evaluated in real-time on each request. Once the duration expires, FGA automatically denies access even if the tuple still exists in the database.

## Next steps

* Learn about the simpler scope-based approach in [Authorization for Your MCP Server](https://auth0.com/ai/docs/mcp/get-started/authorization-for-your-mcp-server.md)
* Explore [Auth0 FGA documentation](https://auth0.com/fine-grained-authorization) to learn more about designing authorization models
* Read about [OpenFGA](https://openfga.dev/docs) for advanced modeling patterns and best practices
* Learn how to [test your MCP server with MCP Inspector](https://auth0.com/ai/docs/mcp/guides/test-your-mcp-server-with-mcp-inspector.md)
