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

# Token Scoping

> Control which connections and operations a token can access — by user, workspace, or any custom dimension.

<Warning>
  **Preview** — Token Scoping is in preview. API surface may change.
  [Join our Discord](https://discord.gg/Afd38S5p9A) for support and feedback.
</Warning>

Service tokens let you safely expose Smithery to browsers, mobile apps, and AI agents without leaking your API key. Each token carries **constraints** that restrict which namespaces, resources, operations, and metadata it can access.

For general Smithery setup, see [Connect to MCPs](/docs/use/connect).

## Scope a Token to a User

When your app serves multiple users, you'll want each user's token to only access their own connections. You do this by tagging connections with `metadata` (e.g., `{ userId: "user-123" }`) when you create them, then creating a token with the same metadata constraint. The token will only be able to see connections whose metadata matches.

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    smithery auth token --policy '[{
      "namespaces": "my-app",
      "resources": "connections",
      "operations": ["read", "execute"],
      "metadata": { "userId": "user-123" },
      "ttl": "1h"
    }]'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const { token, expiresAt } = await smithery.tokens.create({
      policy: [
        {
          namespaces: 'my-app',
          resources: 'connections',
          operations: ['read', 'execute'],
          metadata: { userId: 'user-123' },
          ttl: '1h',
        },
      ],
    })

    // Send `token` to your client — safe for browser use
    ```
  </Tab>

  <Tab title="cURL" icon="globe">
    ```bash theme={null}
    curl -X POST https://api.smithery.ai/tokens \
      -H "Authorization: Bearer $SMITHERY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "policy": [
          {
            "namespaces": "my-app",
            "resources": "connections",
            "operations": ["read", "execute"],
            "metadata": { "userId": "user-123" },
            "ttl": "1h"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

This token can list and call tools on connections in `my-app` where `metadata.userId` is `user-123` — nothing else. Even if the client tries to access another user's connection, the request is denied.

You can also match on multiple metadata fields at once. Fields within a single metadata object are AND'd, so the token below only matches connections where both `userId` and `tier` match:

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    smithery auth token --policy '[{
      "namespaces": "my-app",
      "resources": "connections",
      "operations": ["read", "execute"],
      "metadata": { "userId": "user-123", "tier": "pro" },
      "ttl": "1h"
    }]'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const { token } = await smithery.tokens.create({
      policy: [
        {
          namespaces: 'my-app',
          resources: 'connections',
          operations: ['read', 'execute'],
          metadata: { userId: 'user-123', tier: 'pro' },
          ttl: '1h',
        },
      ],
    })
    ```
  </Tab>

  <Tab title="cURL" icon="globe">
    ```bash theme={null}
    curl -X POST https://api.smithery.ai/tokens \
      -H "Authorization: Bearer $SMITHERY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "policy": [
          {
            "namespaces": "my-app",
            "resources": "connections",
            "operations": ["read", "execute"],
            "metadata": { "userId": "user-123", "tier": "pro" },
            "ttl": "1h"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

## Multi-Level Access (Workspace / Org)

Real apps often have multiple access levels. For example, a user should see:

* Their own connections
* Connections shared with their workspace
* Global connections configured by an admin

Pass **multiple constraints** in the `policy` array. Each constraint is an independent grant — the token can access anything that matches **any** of them.

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    smithery auth token --policy '[
      {
        "namespaces": "my-app",
        "resources": "connections",
        "operations": ["read", "execute"],
        "metadata": { "userId": "user-123" },
        "ttl": "1h"
      },
      {
        "namespaces": "my-app",
        "resources": "connections",
        "operations": ["read", "execute"],
        "metadata": { "workspaceId": "ws-acme" },
        "ttl": "1h"
      },
      {
        "namespaces": "my-app",
        "resources": "connections",
        "operations": ["read", "execute"],
        "metadata": { "scope": "global" },
        "ttl": "1h"
      }
    ]'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const { token } = await smithery.tokens.create({
      policy: [
        // Grant 1: user's own connections
        {
          namespaces: 'my-app',
          resources: 'connections',
          operations: ['read', 'execute'],
          metadata: { userId: 'user-123' },
          ttl: '1h',
        },
        // Grant 2: workspace-shared connections
        {
          namespaces: 'my-app',
          resources: 'connections',
          operations: ['read', 'execute'],
          metadata: { workspaceId: 'ws-acme' },
          ttl: '1h',
        },
        // Grant 3: global connections (admin-configured)
        {
          namespaces: 'my-app',
          resources: 'connections',
          operations: ['read', 'execute'],
          metadata: { scope: 'global' },
          ttl: '1h',
        },
      ],
    })
    ```
  </Tab>

  <Tab title="cURL" icon="globe">
    ```bash theme={null}
    curl -X POST https://api.smithery.ai/tokens \
      -H "Authorization: Bearer $SMITHERY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "policy": [
          {
            "namespaces": "my-app",
            "resources": "connections",
            "operations": ["read", "execute"],
            "metadata": { "userId": "user-123" },
            "ttl": "1h"
          },
          {
            "namespaces": "my-app",
            "resources": "connections",
            "operations": ["read", "execute"],
            "metadata": { "workspaceId": "ws-acme" },
            "ttl": "1h"
          },
          {
            "namespaces": "my-app",
            "resources": "connections",
            "operations": ["read", "execute"],
            "metadata": { "scope": "global" },
            "ttl": "1h"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

The token holder sees connections matching **any** of the three grants. This replaces the need for separate tokens per access level.

<Note>
  For this to work, tag your connections with the right metadata when you create them:

  * User connections: `metadata: { userId: 'user-123' }`
  * Workspace connections: `metadata: { workspaceId: 'ws-acme' }`
  * Global connections: `metadata: { scope: 'global' }`
</Note>

## Narrow a Token

You can create a narrower token from an existing service token. The new token can only have **equal or fewer** permissions — it cannot exceed the parent token's scope.

This is useful when your backend holds a broad token and needs to hand out more restricted tokens per request. For example, using the multi-level token from the previous section as the starting point:

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    # Narrow the broad token to just one user's connections
    SMITHERY_API_KEY=$BROAD_SERVICE_TOKEN smithery auth token \
      --policy '[{
        "resources": "connections",
        "operations": "read",
        "metadata": { "userId": "user-123" },
        "ttl": "20m"
      }]'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    // Broad token from earlier — covers user, workspace, and global connections
    const smitheryWithBroadToken = new Smithery({ apiKey: token })

    // Narrow it to just this user's connections, read-only, shorter TTL
    const { token: userToken } = await smitheryWithBroadToken.tokens.create({
      policy: [
        {
          resources: 'connections',
          operations: 'read',
          metadata: { userId: 'user-123' },
          ttl: '20m',
        },
      ],
    })

    // userToken can only read user-123's connections —
    // the workspace and global grants from the parent are excluded
    ```
  </Tab>

  <Tab title="cURL" icon="globe">
    ```bash theme={null}
    # Narrow the broad token to just one user's connections
    curl -X POST https://api.smithery.ai/tokens \
      -H "Authorization: Bearer $BROAD_SERVICE_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "policy": [
          {
            "resources": "connections",
            "operations": "read",
            "metadata": { "userId": "user-123" },
            "ttl": "20m"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

**When to use this:** Your backend mints one broad token at startup (e.g., all connections in a namespace). Per request, it narrows that token for the specific user or context before passing it to client code.

## Operation Scoping

Control what operations a token can perform on each resource.

| Resource      | Operations      | Description                         |
| ------------- | --------------- | ----------------------------------- |
| `connections` | `read`          | List and get connections            |
| `connections` | `write`         | Create and delete connections       |
| `connections` | `execute`       | Call MCP tools through a connection |
| `servers`     | `read`, `write` | Server metadata and configuration   |
| `namespaces`  | `read`, `write` | Namespace management                |

### Read-Only Dashboard Token

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    smithery auth token --policy '[{
      "namespaces": "my-app",
      "resources": "connections",
      "operations": "read",
      "ttl": "1h"
    }]'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const { token } = await smithery.tokens.create({
      policy: [
        {
          namespaces: 'my-app',
          resources: 'connections',
          operations: 'read',
          ttl: '1h',
        },
      ],
    })
    ```
  </Tab>

  <Tab title="cURL" icon="globe">
    ```bash theme={null}
    curl -X POST https://api.smithery.ai/tokens \
      -H "Authorization: Bearer $SMITHERY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "policy": [
          {
            "namespaces": "my-app",
            "resources": "connections",
            "operations": "read",
            "ttl": "1h"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

### Execute-Only Agent Token

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    smithery auth token --policy '[{
      "namespaces": "my-app",
      "resources": "connections",
      "operations": "execute",
      "metadata": { "userId": "user-123" },
      "ttl": "30m"
    }]'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const { token } = await smithery.tokens.create({
      policy: [
        {
          namespaces: 'my-app',
          resources: 'connections',
          operations: 'execute',
          metadata: { userId: 'user-123' },
          ttl: '30m',
        },
      ],
    })
    ```
  </Tab>

  <Tab title="cURL" icon="globe">
    ```bash theme={null}
    curl -X POST https://api.smithery.ai/tokens \
      -H "Authorization: Bearer $SMITHERY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "policy": [
          {
            "namespaces": "my-app",
            "resources": "connections",
            "operations": "execute",
            "metadata": { "userId": "user-123" },
            "ttl": "30m"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

### Multi-Resource Token

A single token can grant access to multiple resources by passing multiple constraints in the `policy` array:

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    smithery auth token --policy '[
      {
        "namespaces": "my-app",
        "resources": "connections",
        "operations": ["read", "execute"],
        "metadata": { "userId": "user-123" },
        "ttl": "1h"
      },
      {
        "namespaces": "my-app",
        "resources": "servers",
        "operations": "read",
        "ttl": "1h"
      }
    ]'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const { token } = await smithery.tokens.create({
      policy: [
        {
          namespaces: 'my-app',
          resources: 'connections',
          operations: ['read', 'execute'],
          metadata: { userId: 'user-123' },
          ttl: '1h',
        },
        {
          namespaces: 'my-app',
          resources: 'servers',
          operations: 'read',
          ttl: '1h',
        },
      ],
    })
    ```
  </Tab>

  <Tab title="cURL" icon="globe">
    ```bash theme={null}
    curl -X POST https://api.smithery.ai/tokens \
      -H "Authorization: Bearer $SMITHERY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "policy": [
          {
            "namespaces": "my-app",
            "resources": "connections",
            "operations": ["read", "execute"],
            "metadata": { "userId": "user-123" },
            "ttl": "1h"
          },
          {
            "namespaces": "my-app",
            "resources": "servers",
            "operations": "read",
            "ttl": "1h"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

## Constraint Reference

The `policy` array contains **constraints** — each one is a self-contained grant describing what the token can access.

```typescript theme={null}
interface Constraint {
  namespaces?: string | string[]
  resources?: 'connections' | 'servers' | 'namespaces' | 'skills'
    | ('connections' | 'servers' | 'namespaces' | 'skills')[]
  operations?: 'read' | 'write' | 'execute'
    | ('read' | 'write' | 'execute')[]
  metadata?: Record<string, string>
    | Record<string, string>[]
  ttl?: string | number  // e.g., "1h", "30m", "20s", 3600
}
```

Two rules govern every constraint:

* **Adding a field narrows** (AND). Each field adds a condition. More fields = more restrictive.
* **Adding to a list widens** (OR). Each list element adds an alternative. More elements = more permissive.

```typescript theme={null}
// Adding fields narrows the grant
{ resources: 'connections' }
// → any operation on connections

{ resources: 'connections', operations: 'read' }
// → only read connections

{ resources: 'connections', operations: 'read', metadata: { userId: 'user-123' } }
// → only read user-123's connections

// Adding to a list widens the grant
{ operations: ['read', 'write'] }
// → read OR write

{ metadata: [{ userId: 'user-123' }, { workspaceId: 'ws-acme' }] }
// → userId=user-123 OR workspaceId=ws-acme
```

When you pass **multiple constraints** in the `policy` array, each is an independent grant. The token can access anything matching **any** constraint.

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    # Two grants: read alice's connections OR read/write servers
    smithery auth token --policy '[
      {
        "resources": "connections",
        "operations": "read",
        "metadata": { "owner": "alice" }
      },
      {
        "resources": "servers",
        "operations": ["read", "write"]
      }
    ]'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    // Two grants: read alice's connections OR read/write servers
    const { token } = await smithery.tokens.create({
      policy: [
        {
          resources: 'connections',
          operations: 'read',
          metadata: { owner: 'alice' },
        },
        {
          resources: 'servers',
          operations: ['read', 'write'],
        },
      ],
    })
    ```
  </Tab>

  <Tab title="cURL" icon="globe">
    ```bash theme={null}
    # Two grants: read alice's connections OR read/write servers
    curl -X POST https://api.smithery.ai/tokens \
      -H "Authorization: Bearer $SMITHERY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "policy": [
          {
            "resources": "connections",
            "operations": "read",
            "metadata": { "owner": "alice" }
          },
          {
            "resources": "servers",
            "operations": ["read", "write"]
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

<Note>
  Metadata within a single object is AND'd: `{ owner: 'alice', env: 'prod' }` means owner is alice **and** env is prod. Use a list for OR: `[{ owner: 'alice' }, { env: 'prod' }]` means owner is alice **or** env is prod.
</Note>

## Security Best Practices

* **Always set a TTL.** Tokens expire after the TTL (max 24 hours). Shorter is better — mint fresh tokens per session.
* **Scope to the minimum needed.** A token for calling tools only needs `connections:execute`, not `connections:write`.
* **Use metadata for row-level filtering.** Don't rely on connection IDs alone — metadata constraints are enforced server-side.
* **Narrow before passing to untrusted code.** If you hand a token to a browser, agent, or sandbox, restrict it to the specific user and operations needed.
* **Tokens cannot mint other tokens from nothing.** Only API keys or existing tokens can create tokens, and child tokens can never exceed their parent's scope.
