> ## Documentation Index
> Fetch the complete documentation index at: https://bifrost-backport-outbound-fetchers.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

> Enable AI models to discover and execute external tools dynamically. Transform static chat models into action-capable agents.

## What is MCP?

**Model Context Protocol (MCP)** is an open standard that enables AI models to seamlessly discover and execute external tools at runtime. Instead of being limited to text generation, AI models can interact with filesystems, search the web, query databases, and execute custom business logic through external MCP servers.

Bifrost provides a comprehensive MCP integration that goes beyond simple tool execution:

* **MCP Client**: Connect to any MCP-compatible server (filesystem tools, web search, databases, etc.)
* **MCP Server**: Expose your connected tools to external MCP clients (like Claude Desktop)
* **Agent Mode**: Autonomous tool execution with configurable auto-approval
* **Code Mode**: Let AI write and execute Python to orchestrate multiple tools

## Security-First Design

<Note>
  By default, Bifrost does NOT automatically execute tool calls. All tool execution requires explicit API calls, ensuring human oversight for potentially dangerous operations. However, you can enable [Agent Mode](./agent-mode) to allow automatic execution of specific tools via the `tools_to_auto_execute` configuration.
</Note>

**Key Security Principles:**

| Principle | Description |
| - | - |
| **Explicit Execution** | Tool calls from LLMs are suggestions only - execution requires separate API call |
| **Granular Control** | Filter tools per-request, per-client, or per-virtual-key |
| **Opt-in Auto-execution** | Agent mode with auto-execution must be explicitly configured |
| **Stateless Design** | Each API call is independent - your app controls conversation state |

## Key Capabilities

<CardGroup cols={2}>
  <Card title="Connect to MCP Servers" icon="plug" href="./connecting-to-servers">
    Connect to external MCP servers via STDIO, HTTP, or SSE protocols with automatic retry logic
  </Card>

  <Card title="Authentication" icon="shield-check" href="./auth/overview">
    Pick the right auth type for each MCP — None, Headers, OAuth, Per-User OAuth, Per-User Headers, Token Exchange
  </Card>

  <Card title="MCP Sessions" icon="table" href="./sessions">
    Inspect, re-authenticate, edit values, and revoke per-user MCP credentials
  </Card>

  <Card title="Tool Execution" icon="play" href="./tool-execution">
    Execute tools with full control over approval and conversation flow
  </Card>

  <Card title="Agent Mode" icon="robot" href="./agent-mode">
    Enable autonomous tool execution with configurable auto-approval
  </Card>

  <Card title="Code Mode" icon="code" href="./code-mode">
    Let AI write Python to orchestrate multiple tools in one request
  </Card>

  <Card title="Connection Resilience" icon="shield-check" href="./connecting-to-servers#connection-resilience-and-retry-logic">
    Automatic exponential backoff retry logic handles transient failures gracefully
  </Card>

  <Card title="MCP Gateway Mode" icon="server" href="#bifrost-as-an-mcp-gateway">
    Expose Bifrost as an MCP server for Claude Desktop and other clients
  </Card>

  <Card title="Tool Hosting" icon="toolbox" href="./tool-hosting">
    Register custom tools directly in your Go application
  </Card>

  <Card title="Tool Filtering" icon="filter" href="./filtering">
    Control which tools are available per request or per virtual key
  </Card>
</CardGroup>

## How MCP Works in Bifrost

Bifrost acts as both an **MCP client** (connecting to external tool servers) and optionally as an **MCP server** (exposing tools to external clients like Claude Desktop).

```mermaid theme={null}
graph TB
    App["<b>Your Application</b>"]
    Gateway["<b>Bifrost Gateway</b><br/>MCP Client | MCP Server<br/>Tool Filtering & Agent Mode"]
    Servers["<b>MCP Servers</b><br/>filesystem, web search,<br/>databases, etc."]
    Clients["<b>MCP Clients</b><br/>Claude Desktop,<br/>other apps"]

    App -->|Connect| Gateway
    Gateway -->|Connect to| Servers
    Clients -->|Connect to| Gateway

    style App fill:#E3F2FD,stroke:#0D47A1,stroke-width:2.5px,color:#1A1A1A
    style Gateway fill:#E8F5E9,stroke:#1B5E20,stroke-width:2.5px,color:#1A1A1A
    style Servers fill:#FFF3E0,stroke:#BF360C,stroke-width:2.5px,color:#1A1A1A
    style Clients fill:#F3E5F5,stroke:#4A148C,stroke-width:2.5px,color:#1A1A1A
```

For detailed architecture information, see the [MCP Architecture](/architecture/core/mcp) documentation.

## Basic Tool Calling Flow

The default tool calling pattern in Bifrost is **stateless** with explicit execution:

```
1. POST /v1/chat/completions
   → LLM returns tool call suggestions (NOT executed)

2. Your app reviews the tool calls
   → Apply security rules, get user approval if needed

3. POST /v1/mcp/tool/execute
   → Execute approved tool calls explicitly

4. POST /v1/chat/completions
   → Continue conversation with tool results
```

This pattern ensures:

* No unintended API calls to external services
* No accidental data modification or deletion
* Full audit trail of all tool operations
* Human oversight for sensitive operations

## Why Code Mode Matters

If you're planning to use **3+ MCP servers**, read the [Code Mode](./code-mode) documentation carefully.

Code Mode reduces input token usage by **up to 92.8%** and estimated cost by **up to 92.2%** compared to classic MCP by having the AI write Python code to orchestrate tools in a sandbox, rather than exposing 100+ tool definitions directly to the LLM.

***

***

<Note>
  This feature is only available on `v1.4.0-prerelease1` and above.
</Note>

<Info>
  This feature is only available in the **Gateway** deployment. It is not available when using Bifrost as a Go SDK.
</Info>

## Bifrost as an MCP Gateway

Bifrost can act as an **MCP server**, exposing all your connected MCP tools to external MCP clients like Claude Desktop, Cursor, or any other MCP-compatible application.

This enables a powerful pattern:

* Connect Bifrost to multiple MCP servers (filesystem, web search, databases, etc.)
* Expose all those tools through a single MCP endpoint
* External clients connect to Bifrost and get access to all aggregated tools

```mermaid theme={null}
graph TD
    Clients["<b>External MCP Clients</b><br/>Claude Desktop, Cursor<br/>Custom Apps"]

    Gateway["<b>Bifrost Gateway</b>"]
    Endpoints["<b>Endpoints</b><br/>POST /mcp: JSON-RPC<br/>GET /mcp: SSE Stream"]
    Registry["<b>Aggregated Tool Registry</b><br/>filesystem • web search<br/>databases • custom tools"]

    Servers["<b>External MCP Servers</b><br/>filesystem • web-search<br/>databases • custom"]

    Clients -->|MCP Protocol<br/>HTTP/SSE| Gateway
    Gateway --> Endpoints
    Gateway --> Registry
    Gateway -->|MCP Protocol| Servers

    style Clients fill:#F3E5F5,stroke:#4A148C,stroke-width:2.5px,color:#1A1A1A
    style Gateway fill:#E8F5E9,stroke:#1B5E20,stroke-width:2.5px,color:#1A1A1A
    style Endpoints fill:#E3F2FD,stroke:#0D47A1,stroke-width:2.5px,color:#1A1A1A
    style Registry fill:#FFF3E0,stroke:#BF360C,stroke-width:2.5px,color:#1A1A1A
    style Servers fill:#FFFDE7,stroke:#F57F17,stroke-width:2.5px,color:#1A1A1A
```

***

### Endpoints

| Endpoint | Method | Purpose |
| - | - | - |
| `/mcp` | POST | JSON-RPC 2.0 messages for tool discovery and execution |
| `/mcp` | GET | Server-Sent Events (SSE) for persistent connections |

### POST /mcp (JSON-RPC)

Handle JSON-RPC 2.0 messages for tool listing and execution:

```bash theme={null}
# List available tools
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list"
  }'

# Call a tool
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "filesystem_read_file",
      "arguments": {
        "path": "/tmp/test.txt"
      }
    }
  }'
```

### GET /mcp (SSE)

Establish a persistent SSE connection for real-time communication:

```bash theme={null}
curl -N http://localhost:8080/mcp \
  -H "Accept: text/event-stream"
```

The SSE endpoint sends:

* `connection/opened` message on connect
* Keeps connection alive until client disconnects

***

### External MCP Client Integration

The `/mcp` endpoint supports any MCP-compatible client that can communicate via HTTP or SSE:

* **Claude Desktop** - macOS and Windows desktop application
* **Cursor** - IDE with MCP support
* **Custom Applications** - Any app implementing the MCP protocol
* **Browser Extensions** - Tools with MCP client capability

To connect an external MCP client, configure it to connect to:

```
http://your-bifrost-gateway/mcp
```

Include any required Virtual Key authentication headers if governance is enabled.

***

### Virtual Key Authentication

Every request to `/mcp` is scoped to what its credentials allow, so different clients see different tools from the same endpoint.

<Note>
  Header credentials are one of two ways clients authenticate to `/mcp`. Clients can also connect through a browser-based OAuth flow — see [Gateway Authentication](./gateway-auth) for the `mcp_server_auth_mode` setting and the OAuth connect flow.
</Note>

### Anonymous Access (No Credentials)

When `enforce_auth_on_inference` is `false`, requests without credentials see all available tools.

### Scoped by Virtual Key

With a Virtual Key, `tools/list` returns only the tools the key allows: the clients configured on the key (see [Tool Filtering](#tool-filtering-for-mcp-clients)) plus any client marked **Allow by Default**. `tools/call` is checked against the same allow-list, and a key that is inactive or expired is refused with `403`, exactly as on the inference endpoints. An `x-bf-mcp-include-tools` header can narrow the list further for a request, never widen it.

**Authenticate with Virtual Key:**

```bash theme={null}
# Via x-bf-vk header
curl -X POST http://localhost:8080/mcp \
  -H "x-bf-vk: vk_your_virtual_key" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}'

# Via Authorization header
curl -X POST http://localhost:8080/mcp \
  -H "Authorization: Bearer vk_your_virtual_key" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}'

# Via X-Api-Key header
curl -X POST http://localhost:8080/mcp \
  -H "X-Api-Key: vk_your_virtual_key" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}'

# Via x-goog-api-key header
curl -X POST http://localhost:8080/mcp \
  -H "x-goog-api-key: vk_your_virtual_key" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}'
```

**Claude Desktop with Virtual Key:**

```json theme={null}
{
  "mcpServers": {
    "bifrost-production": {
      "url": "http://localhost:8080/mcp",
      "headers": {
        "Authorization": "Bearer vk_your_production_key"
      }
    },
    "bifrost-development": {
      "url": "http://localhost:8080/mcp",
      "headers": {
        "Authorization": "Bearer vk_your_development_key"
      }
    }
  }
}
```

***

### Tool Filtering for MCP Clients

Control which tools are exposed to MCP clients using Virtual Keys:

### Per-Virtual Key Tool Access

Configure which tools each Virtual Key can access:

```json theme={null}
{
  "governance": {
    "virtual_keys": [
      {
        "name": "production-key",
        "mcp_configs": [
          {
            "mcp_client_name": "filesystem",
            "tools_to_execute": ["read_file", "list_directory"]
          },
          {
            "mcp_client_name": "web_search",
            "tools_to_execute": ["*"]
          }
        ]
      },
      {
        "name": "admin-key",
        "mcp_configs": [
          {
            "mcp_client_name": "filesystem",
            "tools_to_execute": ["*"]
          },
          {
            "mcp_client_name": "database",
            "tools_to_execute": ["*"]
          }
        ]
      }
    ]
  }
}
```

A client marked **Allow by Default** (`allow_by_default` in its configuration) is available, with all of its tools, to every key that does not configure it explicitly. A key's own configuration for that client takes precedence, including an empty tool list, which blocks it for that key.

Learn more about Virtual Key tool filtering in [MCP Tool Filtering](../features/governance/mcp-tools).

***

### Tool Auto-Execution Is Client-Side in Gateway Mode

The `tools_to_auto_execute` field on an MCP client config controls whether Bifrost auto-runs a tool call vs. surfacing it for manual approval. **This setting only applies in [Agent Mode](./agent-mode)** — when Bifrost is also running the LLM loop and gating tool calls between model turns.

When you use Bifrost purely as an MCP Gateway (the setup this page covers — Claude Desktop, Cursor, Cline, or any other MCP host connecting to Bifrost over `/mcp`), Bifrost has no LLM loop and no concept of "auto-execute vs. wait for approval." Bifrost just exposes tools over the MCP protocol; the host application is the one running the agent loop, deciding whether each `tools/call` requires user confirmation, and surfacing the approval UI.

Configure the auto-approval policy in your MCP client's own settings:

* **Claude Desktop**: tool-approval is per-tool in the host's settings.
* **Cursor / Cline / Continue**: each has its own "auto-approve" or "trust" lists in the MCP integration config.
* **Custom MCP hosts**: the SDK you're using (mark3labs/mcp-go, @modelcontextprotocol/sdk-typescript, etc.) typically exposes a callback for tool-call confirmation that you wire up yourself.

`tools_to_auto_execute` set on the Bifrost MCP client config will be silently ignored in gateway mode — it isn't an error, just a no-op.

***

### Advanced Gateway Features

### Health Monitoring

Bifrost automatically monitors the health of connected MCP clients:

**How it works:**

* **Ping Mechanism:** Every 10 seconds (configurable), sends a ping to each connected client
* **Check Timeout:** Each ping has a 5-second timeout
* **Failure Threshold:** After 5 consecutive failed pings, client is marked as `unstable`
* **State Tracking:** Real-time state updates (connected ↔ disconnected)
* **Manual Reconnection:** Once disconnected by failed health checks, requires manual reconnect via API or UI. One exception: when a live tool call hits a clean upstream auth rejection, Bifrost force-refreshes the credential and reconnects in the background on its own (see [Auth failure recovery](./tool-execution#auth-failure-recovery))
* **`needs_reauth` is sticky:** clients whose OAuth credential permanently died are parked in `needs_reauth`, health checks won't flip them back, and Reconnect is disabled for them; an admin must [reauthorize](./auth/oauth#reauthorization) instead

**Configuration:**

```json theme={null}
{
  "mcp": {
    "health_monitor_config": {
      "check_interval": "10s",
      "check_timeout": "5s",
      "max_consecutive_failures": 5
    }
  }
}
```

When a client is disconnected after 5 consecutive failed health checks, tools from that client become unavailable. You can manually reconnect using the API or Go SDK:

**Gateway API:**

```bash theme={null}
POST /api/mcp/client/{id}/reconnect
```

**Go SDK:**

```go theme={null}
// Reconnect a disconnected MCP client
err := client.ReconnectMCPClient(context.Background(), clientID)
if err != nil {
    // Handle reconnection error
    log.Printf("Failed to reconnect client: %v", err)
}
```

### Reconnection behavior

How a client reconnects, and whether tool calls are affected while it does, depends on its connection type:

* **HTTP and SSE clients reconnect make-before-break.** Bifrost dials the new connection first; the existing connection keeps serving tool calls for the whole dial. Once the new connection is ready, the swap is atomic, and only then is the old connection closed. In practice this means credential rotation, reauthorization, and the automatic-refresh recycle described in [Automatic refresh](./auth/oauth#automatic-refresh) don't cause downtime for these clients.
* **STDIO and in-process clients reconnect close-first.** The existing connection (and, for STDIO, its subprocess) is closed before the new one is dialed, so there's a brief window where the client has no connection. This is deliberate: a STDIO reconnect spawns a new subprocess, and many STDIO servers hold exclusive resources (lockfiles, bound ports, singleton sockets) that a second instance can't acquire while the first is still running. STDIO reconnects are also almost always crash recovery, where the existing connection is already dead and there's nothing to keep serving.

Either way, a tool call that lands during a reconnect window is covered by [Auth failure recovery](./tool-execution#auth-failure-recovery) when the failure is auth-shaped; other failures during a close-first window surface as a normal connection error and are retried by the caller.

### Request ID Tracking

For Agent Mode operations, Bifrost can track intermediate tool executions:

```go theme={null}
mcpConfig := &schemas.MCPConfig{
    FetchNewRequestIDFunc: func(ctx context.Context) string {
        // Generate unique ID per agent iteration
        return fmt.Sprintf("agent-%s-%d", ctx.Value("original-id"), time.Now().UnixMilli())
    },
}
```

This enables detailed audit trails for autonomous tool execution.

### Dynamic Tool Discovery

Tools are discovered from MCP servers during:

1. **Client Connection** - Initial ListTools request
2. **Runtime Updates** - When server tool list changes
3. **Configuration Changes** - When tools\_to\_execute is updated

The MCP Server dynamically updates its tool registry from the tool manager.

Runtime updates run on a periodic tool sync per client. The cadence is the per-client `tool_sync_interval` (minutes on the API; `0` or unset inherits the global `mcp_tool_sync_interval` client setting, default 10 minutes). Server-level clients sync over their live connection; per-user clients (`per_user_oauth`, `per_user_headers`) hold no persistent connection, so the syncer uses the retained admin discovery credential for a one-shot connect, `tools/list`, disconnect cycle (see [Per-User OAuth](./auth/per-user-oauth#admin-discovery-credential) and [Per-User Headers](./auth/per-user-headers#admin-discovery-credential)). A failed sync keeps the existing tool set and retries on the next cycle.

Every discovered tool list — from the initial connect and from every periodic sync — persists to the database, so a restart doesn't lose anything a running instance had already discovered. Persistence is skipped when a sync's result is byte-identical to what's already stored, so an unchanged tick doesn't cause a write.

***

### Per-User Auth on the Gateway

When at least one upstream MCP server is configured with `per_user_oauth` or `per_user_headers`, the `/mcp` endpoint serves per-user credentials lazily, keyed to the inbound caller's identity. How that identity is established depends on the [gateway auth mode](./gateway-auth): in the default `headers` mode, clients identify themselves via headers (below); in `both` / `oauth` mode, a Bifrost-issued JWT carries the identity instead.

In `headers` mode, inbound MCP clients identify themselves via headers:

* `x-bf-vk: <vk>` (or `Authorization: Bearer <vk>` / `x-api-key: <vk>` / `x-goog-api-key: <vk>`) — VK-mode identity
* `x-bf-mcp-session-id: <opaque-string>` — session-mode identity (client-asserted, must be re-sent on every call)
* Enterprise SSO — user-mode identity, attached automatically by the auth middleware

When a tool call hits an MCP server the caller hasn't authenticated against, Bifrost returns an `mcp_auth_required` tool result with an inline URL the user must visit. The payload carries a `kind` discriminator:

* `kind: "oauth"` → `authorize_url` points at the upstream provider's consent page (via a Bifrost intermediate)
* `kind: "headers"` → `submit_url` points at a Bifrost form where the user enters their header values

The natural-language message also embeds the URL so plain-text MCP clients (curl, basic SDK wrappers) see it without having to parse the structured payload. Once the user completes the URL action, Bifrost stores the credential against the caller's identity and the next tool call executes normally.

Who can open and complete that URL depends on the flow's identity mode (frozen when the URL is minted):

* **User-mode flows** require the bound SSO user — anyone else opening the URL gets a `403`. User-owned VKs auto-promote to user-mode.
* **VK-mode and session-mode flows** are openable by anyone holding the URL. By default they still require a Bifrost dashboard session in the browser; turn on [`mcp_enable_temp_token_auth`](./auth/overview#the-mcp_enable_temp_token_auth-toggle) to let anonymous browsers complete them via a short-lived `#t=<temp-token>` URL fragment.

See [Flow mode and access rules →](./auth/overview#flow-mode-and-access-rules) for the full per-mode behavior.

<Note>
  In the default `headers` [auth mode](./gateway-auth), Claude Code may proactively POST `/oauth2/register` (RFC 7591 DCR) on `claude mcp add` and log `SDK auth failed: …` — discovery and registration aren't served in that mode, so the probe has no endpoint to hit. The `/mcp` connection itself still works. In `both` / `oauth` mode the probe is handled by Bifrost's authorization server and the message doesn't appear. See the [Claude Code bug report](https://github.com/anthropics/claude-code/issues/46640) for context.
</Note>

See [Per-User OAuth →](./auth/per-user-oauth) and [Per-User Headers →](./auth/per-user-headers) for the full flows and identity options, and [MCP Sessions →](./sessions) for managing the resulting credentials.

### Public URL configuration when behind a proxy

The URLs Bifrost surfaces (consent pages, header-submission pages, and the `redirect_uri` it registers with upstream OAuth providers) are derived from the request's `Host` header by default. Behind a reverse proxy, that's the proxy's internal address rather than its public one. Override with:

* `mcp_external_client_url` — what Bifrost registers as the `redirect_uri` with upstream OAuth providers

See [Reverse Proxy configuration →](../deployment-guides/config-json/client#reverse-proxy) for the full reference and examples.

<Warning>
  **Changing `mcp_external_client_url` breaks already-connected per-user OAuth clients.** Upstream OAuth providers lock the `redirect_uri` to whatever was registered during Dynamic Client Registration (RFC 7591). If you change this URL afterwards, existing clients fail with **"Invalid redirect URI"** at the authorize step. To recover, delete and recreate the affected MCP client so Bifrost re-runs DCR against the new URL (the [reauthorize flow](./auth/oauth#reauthorization) reuses the registered client, so it cannot fix the mismatch on its own). For manually registered credentials, add the new redirect URI at the provider's dashboard instead, then reauthorize.
</Warning>

***

### Recommended: disable auto tool injection

When Bifrost serves both inbound LLM requests **and** acts as an upstream MCP server (this page), the same tools can end up being injected twice — once because the LLM Gateway auto-includes every configured MCP tool on every inference request, and once because the inbound MCP client itself fetched the tool list from `/mcp`. The model sees the same tool name from two sources and may behave erratically (duplicate tool calls, refusal, or confused arguments).

Turn **Disable Auto Tool Injection** on in your client config. MCP tools will then only be attached to inference requests when the caller explicitly opts in via the `x-bf-mcp-include-tools` request header (and the calling Virtual Key still has to allow them). Outbound MCP clients (Claude Desktop, Cursor, etc.) keep working because they discover tools through `/mcp` directly.

<Tabs>
  <Tab title="Web UI">
    1. Navigate to **Settings → MCP** in the sidebar
    2. Toggle **Disable Auto Tool Injection** on
    3. Click **Save**

    <Frame>
      <img src="https://mintcdn.com/bifrost-backport-outbound-fetchers/WigfbQi3-8ZsYcdG/media/ui-config-mcp-disable-auto-tool-inject.png?fit=max&auto=format&n=WigfbQi3-8ZsYcdG&q=85&s=dcf78bf45cfd3785a6e069a6a8e971e1" alt="Settings → MCP panel with the Disable Auto Tool Injection toggle highlighted" width="3524" height="2400" data-path="media/ui-config-mcp-disable-auto-tool-inject.png" />
    </Frame>
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    curl -X PUT http://localhost:8080/api/config \
      -H "Content-Type: application/json" \
      -d '{
        "client_config": {
          "mcp_disable_auto_tool_inject": true
        }
      }'
    ```

    `PUT /api/config` merges the supplied `client_config` into the existing one — other fields are unchanged.
  </Tab>

  <Tab title="config.json">
    ```json theme={null}
    {
      "client": {
        "mcp_disable_auto_tool_inject": true
      }
    }
    ```
  </Tab>
</Tabs>

After flipping it on, callers that still want auto-injected tools on the inference path can opt in per-request:

```bash theme={null}
curl -X POST http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "x-bf-mcp-include-tools: filesystem-*,github-create_issue" \
  -d '{ "model": "openai/gpt-4o", "messages": [...] }'
```

***

### Security Considerations

<Warning>
  The MCP Gateway exposes tools to external clients. Consider these security measures:
</Warning>

### 1. Enable Virtual Key Enforcement

Always enable `enforce_auth_on_inference` in production:

```json theme={null}
{
  "client": {
    "enforce_auth_on_inference": true
  }
}
```

This ensures all MCP requests require a valid Virtual Key.

### 2. Use HTTPS

Deploy Bifrost behind a reverse proxy (nginx, Cloudflare, etc.) with TLS enabled:

```
MCP Client → HTTPS → Reverse Proxy → HTTP → Bifrost Gateway
```

### 3. Limit Tool Access

Use Virtual Keys to limit which tools each client can access. Follow the principle of least privilege.

### 4. Network Restrictions

Consider network-level restrictions to limit which IPs can access the MCP endpoint.

***

### Troubleshooting

<AccordionGroup>
  <Accordion title="No tools showing up">
    1. Verify MCP clients are connected in Bifrost
    2. Check that `tools_to_execute` includes the expected tools
    3. If using Virtual Keys, verify the VK has MCP tool access configured
  </Accordion>

  <Accordion title="Virtual Key authentication failing">
    1. Ensure the Virtual Key exists and is active
    2. Check the header format (Bearer prefix for Authorization)
    3. Verify `enforce_auth_on_inference` setting matches your setup
  </Accordion>
</AccordionGroup>

***

***

## Next Steps

<Steps>
  <Step title="Connect to MCP Servers">
    [Set up your first MCP client connection →](./connecting-to-servers)
  </Step>

  <Step title="Choose Authentication (if needed)">
    [Pick the right auth type for your MCP servers →](./auth/overview)
  </Step>

  <Step title="Enable Code Mode (for 3+ servers)">
    [Learn how Code Mode reduces costs by up to 92.2% →](./code-mode)
  </Step>

  <Step title="Execute Tools">
    [Learn the tool execution workflow →](./tool-execution)
  </Step>

  <Step title="Enable Agent Mode">
    [Configure autonomous tool execution →](./agent-mode)
  </Step>
</Steps>


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