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

# MCP Access Tokens

> How to generate, verify, and use MCP access tokens to connect AI clients like Claude Desktop and Cursor to the Prizm platform.

<script type="application/ld+json">
  {`{
            "@context": "https://schema.org",
            "@type": "TechArticle",
            "headline": "MCP Access Tokens",
            "description": "How to generate, verify, and use MCP access tokens to connect AI clients like Claude Desktop and Cursor to the Prizm platform.",
            "url": "https://docs.dqlabs.ai/ai/mcp-access-tokens",
            "publisher": {
              "@type": "Organization",
              "name": "DQLabs Inc",
              "logo": "https://media.brand.dev/332adc35-5bc4-4d2b-bf78-256aa4a5e414.svg"
            }
            }`}
</script>

## Overview

Prizm issues two distinct token types for programmatic access: **API access tokens** for REST integrations, and **MCP access tokens** for MCP clients such as Claude Desktop, Cursor, and `mcp-remote`. The two types must not be used interchangeably.

|                          | API access token                  | MCP access token                                 |
| ------------------------ | --------------------------------- | ------------------------------------------------ |
| **UI / `generated_for`** | `API`                             | `MCP`                                            |
| **JWT `token_type`**     | `api_access_token`                | `mcp_authorization`                              |
| **Purpose**              | REST APIs (Postman, integrations) | MCP clients (Claude Desktop, Cursor, mcp-remote) |
| **Copied as**            | Plain JWT string                  | `mcpServers` JSON config (JWT embedded inside)   |
| **Tool scoping**         | N/A                               | Optional `tools` list in JWT claims              |
| **Auth header style**    | `Authorization: Bearer <jwt>`     | MCP proxy uses `Authorization: Basic <jwt>`      |

***

## Generating an MCP Access Token

### Via the Prizm UI

<Steps>
  <Step title="Open Access Tokens">
    Navigate to **Settings → Organization → Access Tokens** and click **Add token**.
  </Step>

  <Step title="Configure the token">
    Set:

    * **Key alias** — a descriptive name, for example `claude-desktop-mcp`
    * **Generated for** — select `MCP`
    * **Expiry** — choose an appropriate expiration date
    * **Tools** — select at least one MCP tool (required for MCP tokens)
  </Step>

  <Step title="Copy the token">
    After creating the token, use the copy action from the table. For MCP tokens, copy returns the full `mcpServers` JSON config — not a bare JWT.
  </Step>
</Steps>

### Via the API

Use a normal logged-in session or API bearer token for these calls — not the MCP token itself.

**Step 1 — List available MCP tools (for scoping)**

```http theme={null}
GET {{baseUrl}}api/v1/ai_agent/mcp/tools
Authorization: Bearer <API_OR_SESSION_TOKEN>
```

Example response:

```json theme={null}
{
  "success": true,
  "message": "MCP tools retrieved successfully",
  "data": [
    { "name": "search_assets", "description": "...", "domain": "asset" },
    { "name": "create_metrics", "description": "...", "domain": "metrics" },
    { "name": "run_metric", "description": "...", "domain": "metrics" }
  ]
}
```

Use the `name` values when populating the token's `tools` array.

**Step 2 — Create the MCP access token**

```http theme={null}
POST {{baseUrl}}api/v1/auth/access_token/
Authorization: Bearer <API_OR_SESSION_TOKEN>
Content-Type: application/json
```

Request body:

```json theme={null}
{
  "key_alias": "claude-desktop-mcp",
  "generated_for": "MCP",
  "expired_at": "2027-01-01T00:00:00Z",
  "is_active": true,
  "purpose": "MCP client access",
  "tools": [
    "search_assets", "create_metrics", "run_metric",
    "get_lineage", "summary"
  ]
}
```

The response `data.token` contains the `mcpServers` config ready to paste into your client:

```json theme={null}
{
  "mcpServers": {
    "prizm-ai": {
      "command": "/bin/bash",
      "args": [
        "-c",
        "while true; do npx mcp-remote https://<saas-host>/mcp/ --header 'Authorization: Basic <MCP_JWT>'; sleep 10; done"
      ],
      "enabled": true,
      "autoConnect": true
    }
  }
}
```

**Retrieve tokens later**

```http theme={null}
# Get a single token
GET {{baseUrl}}api/v1/auth/access_token/{{accessTokenId}}
Authorization: Bearer <API_OR_SESSION_TOKEN>

# List all MCP tokens
POST {{baseUrl}}api/v1/auth/access_token/list
Authorization: Bearer <API_OR_SESSION_TOKEN>
Content-Type: application/json

{
  "pagination": { "page": 1, "pageSize": 10 },
  "filters": [{ "column": "generated_for", "operator": "equals", "value": "MCP" }]
}
```

***

## Token Verification

When `generated_for = MCP`, the copied value is not a bare JWT — it is the `mcpServers` config with the JWT embedded in the `args` string:

```json theme={null}
{
  "mcpServers": {
    "prizm-ai": {
      "command": "/bin/bash",
      "args": ["-c", "while true; do npx mcp-remote <url> --header 'Authorization: Basic <MCP_JWT>'; sleep 10; done"],
      "enabled": true,
      "autoConnect": true
    }
  }
}
```

Extract the JWT from the `args` string — it is the value that follows `Authorization: Basic`.

**Decode the JWT locally:**

```bash theme={null}
# macOS / Linux — decode payload (middle segment)
python3 - <<'PY'
import base64, json, sys
token = sys.argv[1]
payload = token.split(".")[1]
payload += "=" * (-len(payload) % 4)
print(json.dumps(json.loads(base64.urlsafe_b64decode(payload)), indent=2))
PY "<MCP_JWT>"
```

Or paste it into [jwt.io](https://jwt.io) (decode only — never share secrets in external tools).

### Expected JWT claims

| Claim                            | Expected value                          |
| -------------------------------- | --------------------------------------- |
| `token_type`                     | `mcp_authorization`                     |
| `purpose`                        | `Model Context Protocol Authentication` |
| `organization_id`                | Your org UUID                           |
| `organization_name`              | Your org name                           |
| `tools`                          | List of allowed tool names (if scoped)  |
| `user_id` / `email` / `username` | Present when created by a user          |
| `exp` / `iat`                    | Expiry / issued timestamps              |

<Note>
  If `token_type` is `api_access_token`, this is an API token — it will not work as an MCP client credential.
</Note>

### Verification checklist

Before connecting a client, confirm:

* `generated_for` is `MCP`
* Copied payload contains `mcpServers.prizm-ai`
* JWT `token_type` is `mcp_authorization`
* JWT `tools` matches the tools you selected
* JWT is not expired (`exp` is in the future)
* Token row shows `is_active = true` in the Access Tokens UI or API

***

## Client Integration

<Steps>
  <Step title="Copy the mcpServers config">
    From **Settings → Organization → Access Tokens**, copy the MCP token. This returns the full `mcpServers` JSON.
  </Step>

  <Step title="Paste into your MCP client config">
    For Claude Desktop, open `claude_desktop_config.json` and paste the `mcpServers` block. The config already embeds the auth header and points `mcp-remote` at the Prizm MCP gateway.

    Prizm AI MCP server path: `{{baseUrl}}api/v1/ai_agent/mcp/prizm-ai`
  </Step>

  <Step title="Restart the client">
    Restart your MCP client and confirm that only the tools included in the token's scope appear in the tools list.
  </Step>
</Steps>

### Tool scope enforcement

The Prizm MCP server enforces tool scope at request time using `MCPAuthenticationMiddleware`:

* The JWT is verified on every request
* If the JWT has a `tools` claim, only those tools are callable or listed
* Tokens without a `tools` claim are treated as unrestricted

Calling a tool outside the granted scope returns:

```text theme={null}
Tool '<tool_name>' is not permitted for this access token.
```

***

## Available MCP Tools

### Prizm AI MCP tools (user-facing, token-scoped)

These tools are exposed via Prizm AI MCP and are selectable when creating an MCP access token (`GET /api/v1/ai_agent/mcp/tools`). The live list may grow — always fetch from the API for the current set.

| Tool                            | Domain     |
| ------------------------------- | ---------- |
| `search_assets`                 | asset      |
| `list_assets_by_scope`          | asset      |
| `create_source`                 | source     |
| `create_metrics`                | metrics    |
| `run_metric`                    | metrics    |
| `metrics_collect`               | metrics    |
| `recommend_business_metrics`    | metrics    |
| `manage_metric_alert_mute`      | metrics    |
| `get_lineage`                   | lineage    |
| `manage_schedule`               | schedule   |
| `change_schedule_state`         | schedule   |
| `search_governance`             | governance |
| `create_domain`                 | governance |
| `create_glossary`               | governance |
| `create_categories`             | governance |
| `create_terms`                  | governance |
| `create_tags`                   | governance |
| `create_products`               | governance |
| `recommend_terms`               | governance |
| `recommend_governance_entities` | governance |
| `recommend_semantic_metric`     | governance |
| `link_semantic_to_assets`       | governance |
| `unlink_semantic_from_assets`   | governance |
| `extract_term_rules`            | governance |
| `create_dashboard`              | chart      |
| `summary`                       | common     |

### Metrics MCP tools (service / internal)

A separate FastMCP server in `prizm-metrics` used by platform pipelines at `{{baseUrl}}api/v1/metrics/mcp`. These are write-oriented service tools and are not part of a user's MCP access token scope.

| Tool              | Purpose                                                            |
| ----------------- | ------------------------------------------------------------------ |
| `create_metrics`  | Bulk create metric run values                                      |
| `create_alerts`   | Bulk create/update alerts (upsert on asset + metric\_detail + run) |
| `create_profiles` | Bulk create/update profiles                                        |

<AccordionGroup>
  <Accordion title="create_alerts — example payload">
    ```json theme={null}
    {
      "alerts": [
        {
          "asset_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "metric_detail_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
          "run_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
          "value": 12.5,
          "threshold": { "operator": ">", "value": 5 },
          "priority": "HIGH",
          "marked_as": "ACTIVE",
          "message": "Threshold breached"
        }
      ]
    }
    ```
  </Accordion>

  <Accordion title="create_metrics — example payload">
    ```json theme={null}
    {
      "metrics": [
        {
          "name": "Null Percentage — customer_id",
          "metric_type": "CONDITIONAL",
          "metric_detail_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "value": 4.2
        }
      ]
    }
    ```
  </Accordion>

  <Accordion title="create_profiles — example payload">
    ```json theme={null}
    {
      "profiles": [
        {
          "asset_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "level": "TABLE",
          "dimension": "Volume",
          "category": "Row Count",
          "subcategory": "Total",
          "profile_type": "NUMERIC",
          "profile_value": { "row_count": 125000 },
          "run_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
        }
      ]
    }
    ```
  </Accordion>
</AccordionGroup>

***

## Quick Verification Flow

1. `GET /api/v1/ai_agent/mcp/tools` → pick the tool names you need
2. `POST /api/v1/auth/access_token/` with `generated_for: "MCP"` and your selected `tools`
3. Copy `data.token.mcpServers` from the response
4. Decode the JWT — confirm `token_type = mcp_authorization` and `tools` matches
5. Paste `mcpServers` into your MCP client config and restart
6. Confirm only scoped tools appear in the client
7. Call an allowed tool → success
8. Call a disallowed tool → `Tool '...' is not permitted for this access token.`
