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

# MCP Gateway

> Bundle multiple MCP servers behind a single MCP Gateway endpoint with a unified tool surface, aliases, and per-team tool access controls.

See [HTTP URLs and authentication](/docs/reference/base-urls.md) and the API reference for complete request and response formats.

Create a single client-facing MCP endpoint that bundles one or more **MCP Servers**. Clients connect to the MCP Gateway URL and get a unified tool surface without knowing individual server URLs or authentication details. The gateway acts as a **virtual MCP server**: it aggregates tools from multiple upstream servers behind one address.

> [!NOTE]
>
> This page covers **MCP Gateways**, client-facing endpoints that bundle upstream **MCP Servers** Toqan Router connects to. This is a different feature from Toqan Router's own MCP server, which coding assistants connect to for workspace administration.

**MCP Portal** is the **AI Gateway** area that manages **MCP Gateways** and **MCP Servers**. Open it at **AI Gateway > MCP Portal** in the sidebar; the **MCP Gateways** tab lists every gateway in the workspace, one row per gateway:

* **Name**: the gateway key
* **Servers**: the linked **MCP Servers**, as a stack of server avatars, with a `+N` count when the list is long
* **Exposed tools**: how many tools the gateway exposes to clients
* **Access**: which projects can use the gateway
* **Public URL**: the endpoint clients connect to, with a copy control

## How It Works

A **virtual MCP server** is a single endpoint that gives clients access to tools from multiple upstream **MCP Servers**. The gateway aggregates these servers behind one address, handles authentication and routing, and resolves tool-name conflicts internally. Clients connect to one URL and see all linked tools as if they came from one provider.

## Use Cases

* Exposing multiple MCP servers through a single endpoint for clients that cannot manage multiple connections.
* Aliasing server tools under consistent names so clients do not break when upstream tool names change.
* Governing tool access per team: admins build an MCP Gateway from a selected subset of tools across several **MCP Servers**, so the Marketing team and the Research team can share the same servers while reaching different tools.

## Set Up an MCP Gateway

> [tab] AI Studio
>
> Click <kbd> MCP Gateway</kbd>.
>
> **General**
>
> * **Description** (optional): a note about what this MCP Gateway provides.
> * **Key** (required): lowercase letters, digits, `-` and `_`, up to 64 characters. Forms the MCP Gateway URL and cannot change after creation.
>
> **Tools**
>
> * **Tool exposure mode**: how the MCP Gateway presents tools to connected clients. **Code mode** (default) exposes a single tool provided by the MCP Gateway that handles discovery and execution internally. **Direct** exposes each upstream tool individually.
> * **Tool naming**: how tool names are namespaced across servers. **Always prefix with server key** (default) prefixes all tools with the server's key, or its alias if one is set per-link. **Prefix only on collision** only prefixes conflicting names.
>
> **Runtime limits**
>
> * Each cap listed under [Runtime Limits](#runtime-limits), filled in with its default.
>
> Click <kbd>Create</kbd>.

> [tab] API & SDK
>
> Both `key` and `display_name` are required. The console has no display name field and sets `display_name` to the key.
>
> ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
> curl -X POST https://router.toqan.ai/eu/v2/mcp-gateways \
>   -H "Authorization: Bearer $TOQAN_API_KEY" \
>   -H "Content-Type: application/json" \
>   -d '{
>     "key": "support-tools",
>     "display_name": "Support tools",
>     "mode": "MCP_GATEWAY_MODE_CODE",
>     "tool_naming": "MCP_TOOL_NAMING_PREFIX_WITH_SERVER_KEY"
>   }'
> ```
>
> `mode` and `tool_naming` mirror the form's tool settings:
>
> * **Tool exposure mode**: `MCP_GATEWAY_MODE_CODE` (**Code mode**, the default) or `MCP_GATEWAY_MODE_DIRECT` (**Direct**).
>
> * **Tool naming**: `MCP_TOOL_NAMING_PREFIX_WITH_SERVER_KEY` (**Always prefix with server key**) or `MCP_TOOL_NAMING_PREFIX_ON_COLLISION` (**Prefix only on collision**, the API default).
>
> > [!TIP]
> >
> > See the full [Create an MCP gateway API reference](/docs/reference/mcp-gateway/create-an-mcp-gateway.md).

## After Creation

**Toqan Router** redirects to the **MCP Servers** tab of the new MCP Gateway. Click <kbd>+ Add server</kbd> to link any server already configured in [MCP Servers](/docs/ai-gateway/mcp-portal/mcp-servers.md). Only servers that have completed their initial sync can be linked.

Through the API, [PATCH /v2/mcp-gateways/{id}](/docs/reference/mcp-gateway/update-an-mcp-gateway.md) with `server_links` replaces the linked servers. An empty `server_links` array changes nothing; send `clear_server_links: true` to unlink every server. The two fields cannot be combined.

> [!NOTE]
>
> Link only **MCP Servers** whose project access covers the **MCP Gateway** project access. An **MCP Gateway** on **All projects** therefore needs **MCP Servers** on **All projects**; change a server's own scope from its **Settings** tab, as described in [MCP Servers](/docs/ai-gateway/mcp-portal/mcp-servers.md#after-creation).

The MCP Gateway detail page has four tabs:

* **Overview**: traffic for the MCP Gateway and the **Connect** section with the command clients use to reach it.
* **MCP Servers**: linked servers and the tools each one exposes.
  * Filter with **Search servers and tools...**. Each row shows `N / M` exposed tools; expand it for the tool list, **Select all**, and the `N of M tools exposed` counter.
  * Checkboxes apply immediately. Each tool carries an **Open world**, **Read only**, **Idempotent**, or **Destructive** badge.
  * The side panel shows **Traffic**, the **Alias** prefix, and **Connection** details.
* **Clients**: MCP clients authorized through [OAuth](#oauth), with the option to revoke their access.
* **Settings**: the MCP Gateway description, tool settings, [plugins and runtime limits](#security-settings), and [project access](#project-access), editable after creation.

Row menu: **View details**, **Edit**, **Delete**. Detail overflow: **Edit**, **Share**, **Delete**, where **Share** copies a link to the page.

## Roles and Permissions

Workspace roles decide who can view and manage the MCP Portal. MCP permissions follow the role and are not configurable per team or per gateway.

| Action | Admin | Developer | Researcher |
| - | :-: | :-: | :-: |
| View MCP Gateways and MCP Servers | ✓ | ✓ | ✓ |
| View authorized clients | ✓ | ✓ | ✓ |
| Create and edit MCP Servers | ✓ | ✓ | |
| Delete MCP Servers | ✓ | | |
| Create, edit, and delete MCP Gateways | ✓ | | |
| Link servers and choose which tools a gateway exposes | ✓ | | |
| Set gateway sharing, plugins, and runtime limits | ✓ | | |
| Revoke an authorized client | ✓ | | |

Authorizing a client is self-service: the person signing in approves it in the browser and holds the resulting token. Revoking an authorized client requires **Admin**.

Role permissions apply to people. [API keys](/docs/ai-gateway/configuration/api-keys.md) are authorized separately, by the access granted to the key itself.

## Project Access

> [tab] AI Studio
>
> An MCP Gateway is visible to the projects that may use it. The **Access** column of the gateway list shows the current scope: **All Projects**, **No projects**, or the shared project names. A new gateway is shared with every project.
>
> Change the scope on the **Settings** tab. Under **Access control**, pick **All projects** to share the gateway with the whole workspace, or **Custom** and set each project to **Enabled** or **Disabled**.

> [tab] API & SDK
>
> The `sharing` block on create or update replaces the scope. Send `all_projects` to share the gateway with every project, or `selected.project_ids` to list the projects that may use it. A **Disabled** project stops reaching the gateway.
>
> ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
> curl -X PATCH https://router.toqan.ai/eu/v2/mcp-gateways/<gateway-id> \
>   -H "Authorization: Bearer $TOQAN_API_KEY" \
>   -H "Content-Type: application/json" \
>   -d '{
>     "sharing": {
>       "selected": { "project_ids": ["proj_01HZXW2K7Y8Q9M0N1P2R3S4T5V"] }
>     }
>   }'
> ```
>
> Send `all_projects` instead of `selected` to share the gateway with every project.

> [!NOTE]
>
> Project scope sets which projects may reach the gateway. An API key reaches the gateways of the projects it is scoped to; a key minted for an Agent session also reaches only the gateways attached to that Agent.

## Delete a Gateway

> [tab] AI Studio
>
> Delete a gateway from the **Delete** item in the gateway list row menu, the **Delete** item in the detail page overflow menu, or the <kbd>Delete gateway</kbd> button on the **Settings** tab. Each asks for confirmation.

> [tab] API & SDK
>
> ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
> curl -X DELETE https://router.toqan.ai/eu/v2/mcp-gateways/<gateway-id> \
>   -H "Authorization: Bearer $TOQAN_API_KEY"
> ```
>
> > [!TIP]
> >
> > See the full [Delete an MCP gateway API reference](/docs/reference/mcp-gateway/delete-an-mcp-gateway.md).

## Security Settings

The **Settings** tab holds the plugins, **Guardrails**, and runtime limits that govern what the MCP Gateway forwards and how much it forwards. The same runtime limits fields appear on the **Create MCP Gateway** form.

### Plugins

Plugins attached to an MCP Gateway run on every tool call it serves. [Guardrail Rules](/docs/ai-gateway/configuration/guardrail-rules.md) do not run on tool calls. To check tool traffic, use plugins and the gateway's own [Guardrails](#guardrails).

Click <kbd>Add Plugin</kbd> to attach one. Each listed plugin has a  icon to configure it and a  icon to remove it.

| Plugin | Behavior on the MCP Gateway |
| - | - |
| **PII Redaction** | Replaces personally identifiable information in free-text tool arguments with placeholders before the call reaches the upstream **MCP Server**, then restores the original values in the tool result. Arguments whose schema pins the value (`enum`, `const`, `pattern`, `format`) are forwarded unchanged. Configure the entities to mask, the detection threshold, and the failure behavior. See [PII Redaction](/docs/ai-gateway/features/plugins/pii-redaction.md). |
| **Trace Scrubbing** | Masks the selected fields (`system`, `input`, `output`, `metadata`, `variables`, or `all`) in the traces the MCP Gateway stores for each tool call. See [Trace Scrubbing](/docs/ai-gateway/features/plugins/trace-scrubbing.md). |

> [!NOTE]
>
> Plugins enforced at workspace level apply as a floor: an MCP Gateway can add plugins or tighten their settings, but cannot remove or weaken an enforced one.

### Guardrails

**Guardrails** attached to an MCP Gateway check the tool calls it serves. Under **Guardrails**, click **Add** to pick an **Evaluator**, then set where it runs:

* **Input**: checks the tool name and arguments before the call reaches the upstream **MCP Server**. Resource reads are checked at this stage too.
* **Output**: checks the tool result before it returns to the client.
* **Both**: runs at both stages.

An **Evaluator** marked as a **Guardrail** runs on every call and blocks it when the check fails. Any other **Evaluator** runs at its sample rate and only records a score. **Guardrails** run after [PII Redaction](/docs/ai-gateway/features/plugins/pii-redaction.md), so a judge never sees masked values.

### Runtime Limits

Caps applied to traffic through the MCP Gateway. Set them on the **Create MCP Gateway** form or on the **Settings** tab of an existing gateway: every limit is console-only, and no API field or SDK method sets them. Each field takes a whole number starting at `0`.

| Limit | Default | What it caps |
| - | - | - |
| **Request timeout (ms)** | `30000` | One request from the gateway to an upstream **MCP Server**. `0` falls back to a built-in 10-minute timeout. |
| **Tool timeout (ms)** | `30000` | One `tools/call`, including the connection to the upstream server. `0` removes the per-call deadline. |
| **Max request bytes** | `1048576` | The JSON-RPC request body the gateway accepts. `0` removes the cap. |
| **Max response bytes** | `1048576` | A response from an upstream server, and each `tools/list` result. `0` removes the cap. |
| **Max tools / gateway** | `100` | Tools exposed across all linked servers. Extra tools are dropped from the catalog without an error, and `0` leaves it uncapped. A gateway created through the API stores `0`, so it has no tool cap until one is set in the console. |
| **Per-token req/min** | `60` | Requests per minute for one access token. `0` disables the check. |
| **Per-gateway req/min** | `1000` | Requests per minute for the gateway as a whole. `0` disables the check. |

Hitting a request, response, timeout, or rate limit, or losing the upstream server, answers the call with an error the MCP client displays. Three of them also change the HTTP status; the rest arrive as a `200` response carrying the error.

| Situation | HTTP status | What the client shows |
| - | - | - |
| Request body over **Max request bytes** | `413` | `request body exceeds maximum allowed size` |
| Per-token or per-gateway rate exceeded | `429` | `rate limit exceeded` |
| Rate-limit store unreachable | `503` | `rate limit check unavailable` |
| `tools/list` result over **Max response bytes** | `200` | `response exceeds maximum allowed size` |
| Upstream response over **Max response bytes** | `200` | `upstream response exceeds maximum allowed size` |
| Timeout during `tools/call` | `200` | `upstream tool call timed out` |
| Timeout on another upstream request | `200` | `upstream request timed out` |
| Upstream host unreachable | `200` | `upstream connection refused` or `upstream host not found` |
| Upstream rejects the credentials | `200` | `upstream authentication failed`, `upstream access denied`, or `upstream resource not found` |
| Upstream fails in any other way | `200` | `upstream request failed` |

A tool that runs and reports its own failure is not an error: the gateway returns a normal `tools/call` result with `isError: true` and the upstream content.

## Scope Tools

A gateway exposes one tool surface to every project it is shared with. Which tools a caller then reaches depends on the gateway's exposure and on what the caller is bound to.

| Layer | What it controls | Where to set it |
| - | - | - |
| **Gateway tool exposure** | Which tools the gateway serves, from each linked **MCP Server**. | **MCP Servers** tab, tool checkboxes. |
| **Project access** | Whether a project reaches the gateway at all. | **Settings** tab, **Access control**. See [Project Access](#project-access). |
| **API key** | Whether the key may call the gateway, per permission domain, and which projects it reaches. A key minted for an Agent session is bound to that Agent's gateways. `mcp_access` limits the key to the gateways in `allowed_mcp_gateway_ids`, or blocks every gateway with `deny_all`. | See [API Keys](/docs/ai-gateway/configuration/api-keys.md). Set `mcp_access` through the [API](/docs/reference/api-keys/update-an-api-key.md); the API key form has no field for it. |

A project either reaches the whole exposed tool surface or none of it. Browser sign-ins, and keys not bound to an Agent session, reach the full exposed surface.

### Give a Team its Own Tools

Two teams reaching the same gateway see the same tools, so give a team its own tools with a gateway of its own: create an **MCP Gateway** for the team's project, expose only the tools the team may call, and share it with that project alone. Other projects cannot reach it.

Assign projects to teams in **Settings → Organization → Teams**. See Members and teams.

### Per-User Tool Scoping

Scoping tools to an individual user is not available. Individual tools cannot be granted to or withheld from a named user. Reach follows the gateway's exposure and the projects the caller reaches.

An [OAuth](#oauth) token reaches one **MCP Gateway** as a whole rather than individual tools, and its scopes decide which methods it may call: `mcp:tools` covers tools, `mcp:resources` covers resources and skills. A call outside the token's scopes returns `403` with an `insufficient_scope` challenge that names the missing scope.

For [enterprise-managed servers](/docs/ai-gateway/mcp-portal/mcp-servers.md#enterprise-managed-authorization), the identity provider also decides whether the user can access the upstream app. A tool can appear in the gateway's catalog even when that provider denies the user's call.

## Connect a Client

Any MCP-compatible client can reach the MCP Gateway, most often a coding agent such as Claude Code, Cursor, or Codex. See Coding Agents for the full list.

**Protocol versions**

| Peer | Revisions | Transport |
| - | - | - |
| MCP client to gateway | `2026-07-28`, `2025-11-25`, `2025-06-18`, `2025-03-26`, `2024-11-05` | Streamable HTTP: `POST https://router.toqan.ai/eu/v3/mcp/<gateway-key>`, the `--transport http` option in the examples below |
| Gateway to upstream **MCP Server** | Negotiated with each server from the same set | The server's connection type, **HTTP** or **SSE**. **STDIO** is rejected. |

**Extensions**

The gateway advertises these extensions in the `extensions` capability of `initialize` and `server/discover`:

| Extension | Advertised when |
| - | - |
| `io.modelcontextprotocol/skills` | The gateway exposes skills |
| `io.modelcontextprotocol/oauth-client-credentials` | Always. See [Client credentials](#client-credentials) |
| `io.modelcontextprotocol/enterprise-managed-authorization` | Always. See [Enterprise-managed authorization](#enterprise-managed-authorization) |

A client that sends no revision, or one older than the list, is served `2024-11-05`: `initialize` replies with that revision, and the gateway answers notifications with `200` instead of the `202` that Streamable HTTP requires. A revision newer than the newest supported one returns `UnsupportedProtocolVersion` with the accepted revisions in `supported`.

> [!NOTE]
>
> The examples below use `https://router.toqan.ai/eu` as the default host. For São Paulo, use `https://router.toqan.ai/br`. The API's `public_url` field returns the full connect endpoint (which may be relative when no public base URL is configured).

Clients authenticate in one of these ways:

* [**OAuth**](#oauth) (default): browser sign-in. Use this for interactive clients.
* [**Client credentials**](#client-credentials): a pre-registered client gets short-lived tokens with no user present. Use this for services and automations.
* [**Enterprise-managed authorization**](#enterprise-managed-authorization): the company identity provider issues an ID-JAG that the client exchanges for a token, with no consent screen.
* [**API key**](#api-key): a bearer token in the client configuration. Use this for headless clients that cannot run an OAuth flow.

When calling an [enterprise-managed server](/docs/ai-gateway/mcp-portal/mcp-servers.md#enterprise-managed-authorization), use gateway OAuth or a user-owned API key whose owner has signed in through SSO. Service-account keys and federation-minted keys cannot supply the required user identity. Sign in again after an admin enables Cross App Access, or when a call returns `ENTERPRISE_AUTH_REAUTH_REQUIRED`.

### OAuth

OAuth is the default. The client signs in through the browser and receives a token scoped to this MCP Gateway and to the person who signed in, so no workspace API key is stored in the client configuration.

> [!NOTE]
>
> This flow authenticates MCP clients to the MCP Gateway. The credentials the gateway uses to reach each upstream **MCP Server** are configured on the server itself. See [MCP Servers](/docs/ai-gateway/mcp-portal/mcp-servers.md#set-up-an-mcp-server).

**1. Set up the client**

The **Connect** section on the **Overview** tab shows the gateway key and this command. Copy it from there, or run it with `<gateway-key>` replaced:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npx add-mcp https://router.toqan.ai/eu/v3/mcp/<gateway-key> --name <gateway-key>
```

Register the MCP Gateway directly in the client, replacing `<gateway-key>` with the gateway key from the **Connect** section:

> [tab] Claude Code
>
> ```bash wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
> claude mcp add --transport http <gateway-key> https://router.toqan.ai/eu/v3/mcp/<gateway-key>
> ```
>
> Claude Code opens the browser for approval on first use. Confirm with `claude mcp list`.

> [tab] Cursor
>
> Add the MCP Gateway in **Cursor Settings → Tools & MCP → New MCP Server** and paste:
>
> ```json wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
> {
>   "mcpServers": {
>     "<gateway-key>": {
>       "url": "https://router.toqan.ai/eu/v3/mcp/<gateway-key>"
>     }
>   }
> }
> ```
>
> Save the configuration and complete the browser approval when Cursor prompts for it.

> [tab] Codex
>
> ```bash wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
> codex mcp add <gateway-key> --url https://router.toqan.ai/eu/v3/mcp/<gateway-key>
> ```
>
> Run `codex mcp login <gateway-key>` to complete the browser approval.

> [tab] VS Code
>
> Add the MCP Gateway with the **MCP: Add Server** command, select **HTTP (HTTP or Server-Sent Events)**, and enter `https://router.toqan.ai/eu/v3/mcp/<gateway-key>` as the server URL. VS Code writes a `.vscode/mcp.json`:
>
> ```json wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
> {
>   "servers": {
>     "<gateway-key>": {
>       "url": "https://router.toqan.ai/eu/v3/mcp/<gateway-key>",
>       "type": "http"
>     }
>   }
> }
> ```
>
> VS Code opens the browser for approval on first connect.

**2. Approve access**

On first use the client opens the browser. The approval page names the client and the MCP Gateway it is requesting access to. Click <kbd>Approve</kbd> to issue the token, or <kbd>Deny</kbd> to reject the request.

**Manage authorized clients**

Every authorized client appears on the **Clients** tab with the client name, when it authenticated, and who created it. Choose **Revoke access** from a client's menu to stop the client refreshing its token; the access token it already holds stays valid until it expires, up to 30 minutes.

**How sign-in works**

The MCP Gateway implements the MCP authorization specification on top of OAuth 2.0:

* **Discovery**: an unauthenticated request to the gateway returns `401` with a `WWW-Authenticate` header pointing at the gateway's metadata documents. The protected-resource document at `/.well-known/oauth-protected-resource/v3/mcp/<gateway-key>` names the authorization server; the authorization-server document at `/.well-known/oauth-authorization-server/v2/auth/mcp`, which serves every gateway, lists its endpoints.
* **Dynamic client registration**: the client registers at the authorization server's registration endpoint, so no client ID or secret needs provisioning in advance.
* **Authorization code with PKCE**: sign-in uses the authorization code flow with Proof Key for Code Exchange (PKCE) and the `S256` challenge method, which binds the authorization code to the client that requested it.

The token carries the scopes the client requested, `mcp:tools` and `mcp:resources` by default, on this MCP Gateway only. A client registered with the `refresh_token` grant refreshes it without another sign-in until access is revoked; any other client signs in again when the token expires. Each refresh replaces the refresh token; presenting a replaced one more than 60 seconds later revokes the client's access, and the person signs in again.

**Authorization server metadata**

`/.well-known/oauth-authorization-server/v2/auth/mcp` advertises:

| Field | Values |
| - | - |
| `grant_types_supported` | `authorization_code`, `refresh_token`, `client_credentials`, `urn:ietf:params:oauth:grant-type:jwt-bearer` |
| `token_endpoint_auth_methods_supported` | `client_secret_basic`, `client_secret_post`, `private_key_jwt`, `none` |
| `token_endpoint_auth_signing_alg_values_supported` | `RS256`, `PS256`, `ES256` |
| `client_id_metadata_document_supported` | `true` |
| `authorization_grant_profiles_supported` | `urn:ietf:params:oauth:grant-profile:id-jag` |
| `jwks_uri` | `<issuer>/jwks.json`, the keys that sign client credentials and ID-JAG access tokens |

### Client credentials

A pre-registered client authenticates as itself and receives a 10-minute access token bound to one MCP Gateway, without a browser or a refresh token. The client is its own principal and has the same access settings as an API key: project and permissions.

**1. Register the client**

In **Settings → API Keys → OAuth Clients**, click **+ Client**. Choose the **Client credentials** grant, the access (project and permissions), and how the client authenticates:

* **Client secret (Basic)** or **Client secret (POST)**: the secret is shown once after creation. Use **Rotate secret** to replace it.
* **Private key JWT**: paste a JSON Web Key Set or a JWKS URL with the public keys. The client signs RFC 7523 assertions with `RS256`, `PS256` or `ES256`.

Only workspace Admins and management keys can register, edit or delete clients. The permissions must include MCP Gateway execution, which new clients have by default. Each client has a managed API key behind it, shown as **Managed** on the **API Keys** page; it cannot be used, edited or deleted there. Disabling or deleting the client revokes it. A gateway's **Clients** tab lists the OAuth clients that can reach it.

**2. Request a token**

Send the gateway URL as the RFC 8707 `resource`:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://router.toqan.ai/eu/v2/auth/mcp/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=client_credentials \
  -d resource=https://router.toqan.ai/eu/v3/mcp/<gateway-key> \
  -d "scope=mcp:tools mcp:resources"
```

The response carries `access_token`, `token_type`, `expires_in` and the granted `scope`. Send the token as `Authorization: Bearer <access_token>` and request a new one before it expires.

With the TypeScript MCP SDK, the providers run discovery and the token request:

> [tab] Client secret
>
> ```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
> import { Client } from '@modelcontextprotocol/sdk/client/index.js';
> import { ClientCredentialsProvider } from '@modelcontextprotocol/sdk/client/auth-extensions.js';
> import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
>
> const authProvider = new ClientCredentialsProvider({
>   clientId: process.env.TOQAN_MCP_CLIENT_ID!,
>   clientSecret: process.env.TOQAN_MCP_CLIENT_SECRET!,
>   expectedIssuer: 'https://router.toqan.ai/eu/v2/auth/mcp',
> });
>
> const transport = new StreamableHTTPClientTransport(
>   new URL('https://router.toqan.ai/eu/v3/mcp/<gateway-key>'),
>   { authProvider },
> );
> const client = new Client({ name: 'nightly-sync', version: '1.0.0' });
> await client.connect(transport);
> ```

> [tab] Private key JWT
>
> ```typescript theme={"theme":{"light":"github-light","dark":"github-dark"}}
> import { PrivateKeyJwtProvider } from '@modelcontextprotocol/sdk/client/auth-extensions.js';
>
> const authProvider = new PrivateKeyJwtProvider({
>   clientId: process.env.TOQAN_MCP_CLIENT_ID!,
>   privateKey: process.env.TOQAN_MCP_CLIENT_PRIVATE_KEY!,
>   algorithm: 'RS256',
>   expectedIssuer: 'https://router.toqan.ai/eu/v2/auth/mcp',
> });
> ```
>
> Pass `authProvider` to `StreamableHTTPClientTransport` as in the client secret example.

> [tab] Python
>
> ```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
> import httpx
>
> response = httpx.post(
>     "https://router.toqan.ai/eu/v2/auth/mcp/token",
>     auth=(CLIENT_ID, CLIENT_SECRET),
>     data={
>         "grant_type": "client_credentials",
>         "resource": "https://router.toqan.ai/eu/v3/mcp/<gateway-key>",
>         "scope": "mcp:tools mcp:resources",
>     },
> )
> access_token = response.json()["access_token"]
> ```
>
> Send `access_token` as a bearer token from any MCP client.

Choose client credentials over an [API key](#api-key) when the credential must stay short-lived, use a private key instead of a shared secret, or have its access managed with the client rather than with a long-lived key.

### Enterprise-managed authorization

The company identity provider decides which users may use which MCP clients. A client signed in through SSO asks the identity provider for an Identity Assertion JWT Authorization Grant (ID-JAG) and exchanges it at **Toqan Router** for a gateway token, so the user never sees the approval page.

**1. Connect the identity provider**

Set up the SSO connection first: Configure SSO.

**2. Trust the identity provider**

In **Settings → SSO**, open the SSO connection and enable **ID-JAG trust**. List the clients allowed to redeem ID-JAGs: pre-registered client IDs or Client ID Metadata Document URLs. Optionally limit the scopes. OIDC connections trust the SSO issuer only; SAML connections need the issuer URL the identity provider puts in its ID-JAGs.

**3. Configure the identity provider**

Register the MCP client at the identity provider and allow token exchange for **Toqan Router**. The ID-JAG must use:

* `aud`: the authorization server issuer, `https://router.toqan.ai/eu/v2/auth/mcp`.
* `resource`: the gateway URL, `https://router.toqan.ai/eu/v3/mcp/<gateway-key>`, or omit it and send `resource` in the token request.
* `client_id`: the client's ID at **Toqan Router**.

**4. Exchange the ID-JAG**

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://router.toqan.ai/eu/v2/auth/mcp/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer \
  -d assertion=$ID_JAG \
  -d resource=https://router.toqan.ai/eu/v3/mcp/<gateway-key>
```

The 15-minute token acts as the linked user, with that user's roles and project access. Only a pre-registered client with full access can reach the platform MCP server. There is no refresh token: request a new ID-JAG when it expires.

**Account linking**

**Toqan Router** links the ID-JAG `sub` to an account the first time it sees it, and reuses that link afterwards. On first use the ID-JAG must carry `email_verified: true` and an `email` in one of the SSO connection's allowed domains that matches an account already in the workspace. **Toqan Router** never creates accounts or memberships from an ID-JAG; a request with no matching member is rejected with `invalid_grant`. Changing the connection's issuer clears its links.

Each ID-JAG is accepted once, must live 10 minutes or less, and is checked against the identity provider's published keys.

### API key

Pass an API key as a bearer token instead of signing in. Set `TOQAN_API_KEY`, then register the MCP Gateway:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npx add-mcp https://router.toqan.ai/eu/v3/mcp/<gateway-key> \
  --name <gateway-key> \
  --header "Authorization: Bearer $TOQAN_API_KEY"
```

> [tab] Claude Code
>
> ```bash wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
> claude mcp add --transport http <gateway-key> https://router.toqan.ai/eu/v3/mcp/<gateway-key> --header "Authorization: Bearer ${TOQAN_API_KEY}"
> ```
>
> Set `TOQAN_API_KEY` before running the command. Confirm with `claude mcp list`.

> [tab] Cursor
>
> ```json wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
> {
>   "mcpServers": {
>     "<gateway-key>": {
>       "url": "https://router.toqan.ai/eu/v3/mcp/<gateway-key>",
>       "headers": {
>         "Authorization": "Bearer YOUR_TOQAN_API_KEY"
>       }
>     }
>   }
> }
> ```
>
> Replace `YOUR_TOQAN_API_KEY` with an API key. Save the configuration; the server connects and shows a green indicator.

> [tab] Codex
>
> ```bash wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
> codex mcp add <gateway-key> --url https://router.toqan.ai/eu/v3/mcp/<gateway-key> --bearer-token-env-var TOQAN_API_KEY
> ```
>
> Export `TOQAN_API_KEY` in the shell that launches Codex.

> [tab] VS Code
>
> ```json wrap theme={"theme":{"light":"github-light","dark":"github-dark"}}
> {
>   "inputs": [
>     {
>       "type": "promptString",
>       "id": "toqan-api-key",
>       "description": "Toqan Router API Key",
>       "password": true
>     }
>   ],
>   "servers": {
>     "<gateway-key>": {
>       "url": "https://router.toqan.ai/eu/v3/mcp/<gateway-key>",
>       "type": "http",
>       "headers": {
>         "Authorization": "Bearer ${input:toqan-api-key}"
>       }
>     }
>   }
> }
> ```
>
> VS Code prompts for the API key on first connect and stores it in the OS secret store.

## Sessions

Each MCP request stands on its own. There is no gateway session for a client to initialize, keep alive, resume after a reconnect, or clean up.

## Monitor Usage

The **Overview** tab reports how clients use the MCP Gateway. It opens on the last 7 days, and every card compares that window against the one before it. Change the window with the time range picker in the top right.

| Card | Description |
| - | - |
| **Tool calls** | Tool invocations routed through the MCP Gateway. |
| **Success** | Invocations that completed successfully. |
| **Errors** | Invocations that returned an error. |
| **P95 latency** | 95th percentile duration of successful invocations. |

**Traffic and reliability** breaks the same window down further:

* **Tool calls by outcome**: call volume over time, split into successes and errors.
* **Tools leaderboard**: the most called tools with their call count and P95 latency, listed under their namespaced names.

**Performance** adds **Tool latency**, P50 and P95 over the window, and **Calls by upstream server** ranked per server.

## Audit Changes

Changes to the MCP Gateway are recorded in Audit Logs, so a change to the exposed tool surface can be traced back to whoever made it.

Entries are written under two entity types:

| Entity type | Recorded when |
| - | - |
| **MCP Gateway** | A gateway is created, updated, or deleted, including changes to its linked servers. |
| **MCP Server** | A server is created, updated, or deleted. |

Filter by either entity type on the Audit Logs page to see only MCP Portal activity. Entries for both entity types can be exported as a file; see Export audit logs.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.