> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runtype.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runtype.com/_mcp/server.

# MCP servers

> Connect flows and agents to external Model Context Protocol servers

Use Model Context Protocol (MCP) servers to connect flows and agents to external tools and data sources. Runtype lists the tools that each server exposes and passes each tool's input schema to the model. You can save a server for reuse or pass its configuration at runtime.

This page covers calling external MCP servers from Runtype. To expose your own Runtype product as an MCP server instead, see [Setting up an MCP surface](/user-guide/products-surfaces/setting-up-an-mcp-surface).

## Choose a server type

Choose a server type based on how you supply its configuration:

| Server type | Use it when                                       | How to reference it                                                 |
| ----------- | ------------------------------------------------- | ------------------------------------------------------------------- |
| **Saved**   | You reuse the same server across flows or agents. | Add its tool IDs to `toolIds`, such as `mcp:SERVER_NAME:TOOL_NAME`. |
| **Runtime** | The server URL or credentials vary by request.    | Add its configuration to `mcpServers`.                              |

## Use saved MCP servers

Save a custom MCP server to reuse its tools across flows and agents.

### Add a saved server

Choose a dashboard or API workflow:

#### Dashboard

To add a saved server from the dashboard, follow these steps:

1. On **Tools**, click **Create Tool**.
2. In the **Type** menu, select **MCP Server**. The dashboard opens the server form.
3. In **Server URL**, enter the MCP server endpoint.
4. In **Display name**, enter a name for the server.
5. In **Environment**, select **All environments**, **Development**, or **Production**. For more information, see [Use environment-specific servers](#use-environment-specific-servers).
6. In **Authentication**, select an authentication type and enter its credentials.
7. Click **Discover Tools**. The dashboard lists the tools that it finds.
8. Click **Add Server**. The dashboard saves the server.

> **Tip**
>
> If you already have the server in a Claude or Cursor client config, paste the JSON, such as `{"mcpServers": {...}}`, into **Server URL**. The dashboard reads only the first server in `mcpServers`. When that server has a `url`, the dashboard fills in the URL, display name, and authentication headers. When it has no `url`, the dashboard pastes the text unchanged.

#### API

Send a `POST` request to create the saved server:

**`cURL`**

```bash title="cURL"
curl -X POST https://api.runtype.com/v1/mcp/servers \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "customer_support",
    "url": "https://example.com/mcp",
    "auth": {
      "type": "bearer",
      "token": "YOUR_MCP_TOKEN"
    },
    "timeout": 30000
  }'
```

Replace the placeholders with your values:

* `YOUR_API_KEY`: Your Runtype API key.
* `YOUR_MCP_TOKEN`: The token that the MCP server accepts.

Runtype stores the name in lowercase, with spaces replaced by underscores. For the other fields that this request accepts, see [Saved server configuration](#saved-server-configuration).

### Discover tools from a saved server

To verify a saved server and list its tools, send a `POST` request:

**`cURL`**

```bash title="cURL"
curl -X POST https://api.runtype.com/v1/mcp/servers/customer_support/test \
  -H "Authorization: Bearer YOUR_API_KEY"
```

The API returns a response similar to the following:

**`Response`**

```json title="Response"
{
  "success": true,
  "toolsDiscovered": 2,
  "tools": [
    {
      "name": "search_articles",
      "description": "Search support articles"
    },
    {
      "name": "create_ticket",
      "description": "Create a support ticket"
    }
  ]
}
```

Replace `YOUR_API_KEY` with your Runtype API key.

A failed discovery still returns HTTP `200`. Check the `success` field, not only the status code:

**`Failed discovery response`**

```json title="Failed discovery response"
{
  "success": false,
  "error": "Connection refused",
  "tools": [],
  "toolsDiscovered": 0
}
```

The `error` value varies with the failure. When no saved server has that name, the API returns `404` with the message "Custom MCP server not found".

### Discover tools from a URL

To list a server's tools before you save it, send the URL to the discover endpoint:

**`cURL`**

```bash title="cURL"
curl -X POST https://api.runtype.com/v1/mcp/discover \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/mcp",
    "auth": { "type": "bearer", "token": "YOUR_MCP_TOKEN" },
    "timeout": 30000
  }'
```

Replace the placeholders with your values:

* `YOUR_API_KEY`: Your Runtype API key.
* `YOUR_MCP_TOKEN`: The token that the MCP server accepts.

The request body accepts `url` (required), `auth`, `timeout`, and `serverName`. When you pass `serverName` without `auth`, Runtype uses the credentials of a server with that name that you saved. It doesn't use credentials that a teammate saved. The API returns a response similar to the following:

**`Response`**

```json title="Response"
{
  "url": "https://example.com/mcp",
  "tools": [
    {
      "name": "search_articles",
      "description": "Search support articles",
      "parametersSchema": {
        "type": "object",
        "properties": { "query": { "type": "string" } }
      }
    }
  ],
  "total": 1
}
```

The Runtype MCP server offers the same discovery through its `discover_mcp_server_tools` tool. For more information, see [Runtype MCP server](/developer-guides/integrations/runtype-mcp-server).

### Use saved tools in a flow

Add saved MCP tool IDs to the `tools` object in a prompt step. The following examples use the `customer_support` server:

Use the TypeScript SDK to dispatch a flow with saved MCP tools:

**`TypeScript SDK`**

```typescript title="TypeScript SDK"
import { FlowBuilder, RuntypeClient } from '@runtypelabs/sdk'

const client = new RuntypeClient({
  apiKey: process.env.RUNTYPE_API_KEY,
})

const result = await new FlowBuilder()
  .createFlow({ name: 'Customer support agent' })
  .prompt({
    name: 'Support agent',
    model: 'claude-sonnet-5',
    userPrompt: 'Find the open support tickets for this customer',
    tools: {
      toolIds: ['mcp:customer_support:search_articles', 'mcp:customer_support:create_ticket'],
    },
  })
  .run(client, { streamResponse: true })
```

This example reads the API key from the `RUNTYPE_API_KEY` environment variable.

Use the Python SDK to dispatch the same flow:

**`Python SDK`**

```python title="Python SDK"
import os

from runtype import RuntypeClient

client = RuntypeClient(api_key=os.environ["RUNTYPE_API_KEY"])

for event in client.dispatch({
    "flow": {
        "name": "Customer support agent",
        "steps": [{
            "type": "prompt",
            "config": {
                "model": "claude-sonnet-5",
                "userPrompt": "Find the open support tickets for this customer",
                "tools": {
                    "toolIds": [
                        "mcp:customer_support:search_articles",
                        "mcp:customer_support:create_ticket"
                    ]
                }
            }
        }]
    }
}):
    print(event)
```

This example reads the API key from the `RUNTYPE_API_KEY` environment variable.

Send the same flow with cURL:

**`cURL`**

```bash title="cURL"
curl https://api.runtype.com/v1/dispatch \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "flow": {
      "name": "Customer support agent",
      "steps": [{
        "type": "prompt",
        "config": {
          "model": "claude-sonnet-5",
          "userPrompt": "Find the open support tickets for this customer",
          "tools": {
            "toolIds": [
              "mcp:customer_support:search_articles",
              "mcp:customer_support:create_ticket"
            ]
          }
        }
      }]
    }
  }'
```

Replace `YOUR_API_KEY` with your Runtype API key.

### Use passthrough mode

To attach every tool that a saved server exposes, add a wildcard entry to `toolIds`:

**`Passthrough tool configuration`**

```json title="Passthrough tool configuration"
{
  "tools": {
    "toolIds": ["mcp:customer_support:*"]
  }
}
```

The wildcard expands into concrete tool IDs at execution time. This behavior means:

* New tools from the MCP server are available without editing the flow.
* Approval rules, `toolConfigs`, `perToolLimits`, and usage tracking use concrete tool IDs.
* When `toolIds` contains both the wildcard and a curated ID for one server, Runtype uses the wildcard and ignores the curated ID.

Choose passthrough mode when you trust every tool on the server and want to receive new tools without changing the flow. Choose curated tool IDs when you need to review each tool.

Use the TypeScript SDK to attach passthrough tools:

**`TypeScript SDK`**

```typescript title="TypeScript SDK"
const result = await new FlowBuilder()
  .createFlow({ name: 'Customer support agent' })
  .prompt({
    name: 'Support agent',
    model: 'claude-sonnet-5',
    userPrompt: 'Help me manage support requests',
    tools: {
      toolIds: ['mcp:customer_support:*'],
    },
  })
  .run(client, { streamResponse: true })
```

Send the same passthrough configuration with cURL:

**`cURL`**

```bash title="cURL"
curl https://api.runtype.com/v1/dispatch \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "flow": {
      "name": "Customer support agent",
      "steps": [{
        "type": "prompt",
        "config": {
          "model": "claude-sonnet-5",
          "userPrompt": "Help me manage support requests",
          "tools": { "toolIds": ["mcp:customer_support:*"] }
        }
      }]
    }
  }'
```

Replace `YOUR_API_KEY` with your Runtype API key.

### Share saved servers

Saved MCP servers in an organization are shared with its members. Members can list and use them, view metadata, test connections, and discover tools. Runtype encrypts saved credentials and does not return credential values in API responses.

Server owners and organization admins can perform these actions:

* Edit the server configuration, including the URL, timeout, transport, and allowed tools.
* Rotate or replace credentials.
* Refresh or reconnect the OAuth2 connection.
* Turn the server on or off.
* Delete the server.

Other members can view server details but cannot manage them. A management request from another member returns `403` with this message: "This MCP server was added by a teammate. Only the person who added it or an org admin can change it."

Use the following fields in `GET /v1/mcp/servers` and `GET /v1/mcp/servers/:name` responses to control management actions in client code:

| Field                | Description                                                      |
| -------------------- | ---------------------------------------------------------------- |
| `ownedByCurrentUser` | True when the authenticated user registered the server.          |
| `canManage`          | True when the user is the server owner or an organization admin. |

> **Note**
>
> Servers that you register outside an organization stay private to your account and are not visible
> to other users.

When an organization has duplicate server names, an admin's by-name `DELETE` request returns `409` with candidate IDs. Pass the optional `id` query parameter, as in `DELETE /v1/mcp/servers/:name?id=SERVER_ID`, to identify the registration to remove.

## Use runtime MCP servers

Pass a server configuration inline when its URL or credentials vary by request.

### Choose runtime servers

Use runtime MCP servers for these cases:

* Pass per-user credentials in a multi-tenant application.
* Test a server before saving it.
* Configure a one-off integration.
* Set a server URL at request time.

### Configure a runtime server

Pass the server configuration in the prompt step's `tools` object:

**`TypeScript SDK`**

```typescript title="TypeScript SDK"
const mcpServers = [
  {
    id: 'user_notion',
    name: 'User Notion',
    url: 'https://example.com/mcp',
    auth: {
      type: 'bearer',
      token: userCredentials.mcpToken,
    },
    timeout: 30000,
    transport: 'streamable_http',
    allowedTools: ['search_articles', 'create_ticket'],
  },
]

const result = await new FlowBuilder()
  .createFlow({ name: 'User support agent' })
  .prompt({
    name: 'Support agent',
    model: 'claude-sonnet-5',
    userPrompt: 'Help me manage my support requests',
    tools: {
      mcpServers,
    },
  })
  .run(client)
```

Pass the per-user token from your application in `userCredentials.mcpToken`.

Use the Python SDK to pass the same runtime configuration:

**`Python SDK`**

```python title="Python SDK"
mcp_servers = [{
    "id": "user_notion",
    "name": "User Notion",
    "url": "https://example.com/mcp",
    "auth": {
        "type": "bearer",
        "token": user_credentials["mcp_token"]
    },
    "timeout": 30000,
    "allowedTools": ["search_articles", "create_ticket"]
}]

for event in client.dispatch({
    "flow": {
        "steps": [{
            "type": "prompt",
            "config": {
                "model": "claude-sonnet-5",
                "userPrompt": "Help me manage my support requests",
                "tools": {
                    "mcpServers": mcp_servers
                }
            }
        }]
    }
}):
    print(event)
```

Pass the per-user token from your application in `user_credentials["mcp_token"]`.

Send the runtime configuration with cURL:

**`cURL`**

```bash title="cURL"
curl https://api.runtype.com/v1/dispatch \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "flow": {
      "steps": [{
        "type": "prompt",
        "config": {
          "model": "claude-sonnet-5",
          "userPrompt": "Help me manage my support requests",
          "tools": {
            "mcpServers": [{
              "id": "user_notion",
              "url": "https://example.com/mcp",
              "auth": {
                "type": "bearer",
                "token": "YOUR_MCP_TOKEN"
              },
              "timeout": 30000
            }]
          }
        }
      }]
    }
  }'
```

Replace the placeholders with your values:

* `YOUR_API_KEY`: Your Runtype API key.
* `YOUR_MCP_TOKEN`: The token that the MCP server accepts.

An Agent accepts the same entries in its `tools.mcpServers` list, including an Agent that you define with `defineAgent` and converge with `ensure`. For an example, see [Connect inline MCP servers](/user-guide/agents/manage-agents-as-code#connect-inline-mcp-servers).

## Authentication types

Choose one of the following authentication types for a custom MCP server:

| Type            | Fields                                | Example                                                                                                    |
| --------------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `bearer`        | `token`                               | `{"type": "bearer", "token": "YOUR_MCP_TOKEN"}`                                                            |
| `api_key`       | `headerName`, `token`                 | `{"type": "api_key", "headerName": "X-API-Key", "token": "YOUR_API_KEY"}`                                  |
| `basic`         | `username`, `password`                | `{"type": "basic", "username": "YOUR_USERNAME", "password": "YOUR_PASSWORD"}`                              |
| `custom_header` | `headerName`, `token`                 | `{"type": "custom_header", "headerName": "X-Custom", "token": "YOUR_TOKEN"}`                               |
| `headers`       | `headers`                             | `{"type": "headers", "headers": {"X-Api-Key": "{{secret:API_KEY}}", "X-Base-URL": "https://example.com"}}` |
| `oauth2`        | Managed by Runtype for saved servers. | Use the dashboard authorization-code flow or register client credentials through the API.                  |
| `none`          | None.                                 | `{"type": "none"}`                                                                                         |

Replace every credential placeholder in the table with a value that the server accepts. Replace the name inside each `{{secret:NAME}}` reference with a managed secret name from your account.

Every credential field in `auth` (`token`, `username`, `password`, and each `headers` value) accepts a `{{secret:NAME}}` reference, which Runtype resolves from your [managed secrets](/user-guide/settings/managing-secrets) when it calls the server. Put MCP credentials here, not in a saved MCP tool's config, which rejects `{{secret:NAME}}` references.

Use the `headers` type when a server requires two or more HTTP headers. Each header value can contain a `{{secret:NAME}}` reference, which Runtype resolves from your managed secrets when it sends the request. The `headers` field is valid only with `type: "headers"` and must contain at least one valid HTTP header.

A saved server's auth header values can also send the verified identity of the end user that an agent run serves. Use `{{_identity.token}}` for a short-lived JWT that Runtype signs for each connection, or `{{_tenant.id}}` and `{{_endUser.id}}` for the plain IDs:

**`Saved server auth that sends the verified identity`**

```json title="Saved server auth that sends the verified identity"
{
  "type": "headers",
  "headers": {
    "Authorization": "Bearer {{_identity.token}}",
    "X-Tenant-Id": "{{_tenant.id}}"
  }
}
```

Runtype fills in these values when it lists the server's tools and when it calls a tool. The agent must have a tenancy strategy, and the server URL must use `https`. When a run has no verified identity, Runtype doesn't call the server. The token's `aud` is the server's canonical resource URI, for example `https://mcp.example.com/mcp`, not its host name. For the conditions and the token's claims, see [Send the assertion to a saved MCP server](/developer-guides/guides/end-user-identity#send-the-assertion-to-a-saved-mcp-server).

> **Note**
>
> In the dashboard, open **Advanced authentication** and select **Multiple headers**. Runtype
> encrypts saved header values and hides them. To edit them, enter a complete replacement set. The
> same `headers` record works with `POST /v1/mcp/servers`, inline `tools.mcpServers`, and full
> product object (FPO) agent configurations.

## Machine-to-machine OAuth2

For an MCP server that accepts OAuth2 client credentials, register the connection through the API. Runtype resolves your managed secrets and requests access tokens itself, so the client secret and access token never reach the model or sandbox code.

In an organization, only an organization admin can register a client-credentials server or change its credentials, URL, or transport. An API key that registers a server with managed-secret references needs the `SECRETS:READ` scope in addition to `TOOLS:WRITE`.

To register the server, create managed secrets named `TEAMBRIDGE_CLIENT_ID` and `TEAMBRIDGE_CLIENT_SECRET` in **Settings > Secrets**, and then send the following request:

**`Register a machine-to-machine server`**

```bash title="Register a machine-to-machine server"
curl -X POST https://api.runtype.com/v1/mcp/servers \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "teambridge_context",
    "url": "https://mcp.example.com/mcp/",
    "auth": {
      "type": "oauth2",
      "grantType": "client_credentials",
      "tokenUrl": "https://tenant.example.com/oauth/token",
      "clientId": "{{secret:TEAMBRIDGE_CLIENT_ID}}",
      "clientSecret": "{{secret:TEAMBRIDGE_CLIENT_SECRET}}",
      "audience": "https://api.example.com/",
      "scope": "read:api"
    }
  }'
```

Replace `YOUR_API_KEY` with your Runtype API key. Replace the example MCP URL, token URL, audience, and scope with your provider's values. The two secret references name the managed secrets you created. `audience`, `resource`, and `scope` are optional. `audience` and the RFC 8707 `resource` parameter are distinct, and Runtype sends each one separately. Your token endpoint must accept `client_secret_post` client authentication and return a bearer token.

Bind the returned `server.id` to an agent's `config.tools`, or a flow step's `config.tools`, without repeating the auth configuration:

**`Bind a registered server`**

```json title="Bind a registered server"
{
  "mcpServers": [
    { "id": "SERVER_ID", "url": "https://mcp.example.com/mcp/" }
  ]
}
```

Replace `SERVER_ID` with the returned `provkey_` ID. Keep `auth` absent. Runtype resolves the saved registration in the execution's organization and environment; its saved endpoint and credentials take precedence over the URL in the binding. Add `allowedTools` to select named tools, or use `toolIds: ["mcp:SERVER_ID:*"]` instead of `mcpServers` to bind without a URL.

Runtype requests a token on first use and reuses it until shortly before it expires. It requests a new token after expiry, or once after the MCP server returns HTTP `401`. Runtype doesn't reuse a token that has no `expires_in` value. Your token endpoint can receive more than one token request for the same server. When a secret is missing or the token endpoint fails, Runtype stops the request instead of calling the MCP server without authentication.

Rotate the managed secrets without editing each bound agent. To change the token URL, audience, or scope, send the complete `auth` object to `PATCH /v1/mcp/servers/teambridge_context`. The registry encrypts auth at rest and does not return credentials in list, create, or update responses. Token endpoints must use public HTTPS URLs and cannot redirect credential requests.

Configure client-credentials auth on the saved server only. Inline `mcpServers[].auth` and an external tool's `auth` field don't accept OAuth2. Bind the saved server by ID instead.

## OAuth 2.1 authentication

Use the dashboard OAuth2 flow when an MCP server requires OAuth instead of a static token.

### Detect OAuth2 on URL entry

On the dashboard, enter the MCP server URL. Runtype probes the server for OAuth2 metadata through [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728) protected-resource discovery.

When Runtype finds OAuth2 metadata, the dashboard shows **Connect with OAuth2** instead of manual token fields. It displays the discovered issuer and supported scopes.

### Authorize in the browser

Click **Connect with OAuth2**. The dashboard opens a popup for sign-in and consent. Runtype uses PKCE for the authorization-code exchange, so the browser does not handle a client secret.

After you approve access, the popup closes and the dashboard discovers tools for selection.

### Keep the connection active

When an access token expires and the server issued a refresh token, Runtype refreshes the token automatically. You don't need to reconnect on a schedule. When the authorization server rejects the refresh token, for example because access was revoked, runs that use the server fail with the `MCP_REAUTH_REQUIRED` code. To restore the connection, open the tool's detail page under **Tools** and click **Reconnect OAuth2** in the **Sign-in** section, or reconnect the server from the MCP server sheet.

### Use discovery diagnostics

When Runtype does not detect OAuth2, expand **OAuth2 not detected. View discovery details**. The panel lists each discovery phase, the URL that Runtype probed, the response status, and any error. Use these details to troubleshoot an MCP server that supports OAuth2 but is not detected.

### Find OAuth2 setup

Use the OAuth2 setup in any of these locations:

* On the **Tools** page, when you create an **MCP Server** tool.
* In the **agent tool-selection modal**, when you add a server while choosing tools for an agent.
* On the detail page of a saved `mcp` tool. The **Sign-in** section shows the server URL, transport, and configured auth, checks the server for OAuth2, and shows **Connect with OAuth2**, or **Reconnect OAuth2** once signed in. The sign-in is saved as the MCP server connection named after the tool. Agents use it through that server's tools. A saved tool run directly does not use it yet.

Configured OAuth2 servers appear in the **agent tool-selection modal** with their discovered tool counts.

## Tool ID format

Use the following format for a saved custom server tool ID:

**`Saved MCP tool ID`**

```text title="Saved MCP tool ID"
mcp:SERVER_NAME:TOOL_NAME
```

For example:

* `mcp:customer_support:search_articles`: A tool on the saved `customer_support` server.
* `mcp:customer_support:create_ticket`: Another tool on the same saved server.

Replace `SERVER_NAME` with the saved server name and `TOOL_NAME` with the MCP tool name. Runtype stores a saved server name in lowercase, with spaces replaced by underscores. A server that you name `Customer Support` has tool IDs such as `mcp:customer_support:search_articles` and the path `/v1/mcp/servers/customer_support`.

Runtime server tool IDs use the `custom_` prefix:

**`Runtime MCP tool ID`**

```text title="Runtime MCP tool ID"
mcp:custom_SERVER_ID:TOOL_NAME
```

Replace `SERVER_ID` with the runtime server's `id` value and `TOOL_NAME` with the MCP tool name.

Use the `*` value as the passthrough wildcard for saved servers:

**`Passthrough MCP tool ID`**

```text title="Passthrough MCP tool ID"
mcp:SERVER_NAME:*
```

## Saved server configuration

The `POST /v1/mcp/servers` and `PATCH /v1/mcp/servers/:name` requests accept the following fields:

| Field          | Required         | Description                                                                                                                                                   |
| -------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`         | Yes, on create   | Server name. Runtype stores it in lowercase, with spaces replaced by underscores. You can't change it later.                                                  |
| `url`          | Yes, on create   | MCP server endpoint URL.                                                                                                                                      |
| `auth`         | No               | Authentication configuration. For the supported types, see [Authentication types](#authentication-types).                                                     |
| `timeout`      | No               | Request timeout in milliseconds. The default is 30000.                                                                                                        |
| `transport`    | No               | `streamable_http` (default) or `rest`.                                                                                                                        |
| `environment`  | No               | `development` or `production`. On create, omit it to apply the server to every environment. On `PATCH`, send `null` to apply the server to every environment. |
| `allowedTools` | No               | Tool names to expose. Runtype exposes all discovered tools when you omit this field.                                                                          |
| `iconUrl`      | No               | An `http` or `https` URL for the server icon. On `PATCH`, send `null` to remove it.                                                                           |
| `isActive`     | No, `PATCH` only | Set to `false` to turn the server off, or `true` to turn it back on.                                                                                          |

To turn off a saved server without deleting it, send a `PATCH` request:

**`cURL`**

```bash title="cURL"
curl -X PATCH https://api.runtype.com/v1/mcp/servers/customer_support \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "isActive": false }'
```

Replace `YOUR_API_KEY` with your Runtype API key.

A turned-off server doesn't appear in the `GET /v1/mcp/servers` list. To turn it back on, send `{ "isActive": true }` to the same path.

`PATCH` doesn't accept the `environment` query parameter. When one name has registrations in more than one environment, a `PATCH` request can change any one of them. To change a specific registration, delete it with the `environment` query parameter and create it again.

## Runtime server configuration

Configure runtime MCP servers with the following fields:

| Field          | Required | Description                                                                                                                    |
| -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `id`           | Yes      | Unique identifier for the server instance. Runtype uses it in tool IDs.                                                        |
| `name`         | No       | Display name for the dashboard and logs.                                                                                       |
| `url`          | Yes      | MCP server endpoint URL.                                                                                                       |
| `auth`         | No       | Authentication configuration. Runtime servers don't accept `oauth2`.                                                           |
| `timeout`      | No       | Request timeout in milliseconds. The default is 30000, and the maximum is 300000. For more information, see [Limits](#limits). |
| `transport`    | No       | `streamable_http` (default) or `rest`.                                                                                         |
| `allowedTools` | No       | Tool names to expose. Runtype exposes all discovered tools when you omit this field.                                           |
| `iconUrl`      | No       | URL of an icon for the server.                                                                                                 |
| `enabled`      | No       | Set to `false` to skip the server. The default is `true`.                                                                      |

## Use environment-specific servers

Assign an environment to a saved server when you need separate development and production configurations:

**`cURL`**

```bash title="cURL"
curl -X POST https://api.runtype.com/v1/mcp/servers \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "customer_support",
    "url": "https://example.com/mcp",
    "auth": { "type": "bearer", "token": "YOUR_DEVELOPMENT_TOKEN" },
    "environment": "development"
  }'

curl -X POST https://api.runtype.com/v1/mcp/servers \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "customer_support",
    "url": "https://example.com/mcp",
    "auth": { "type": "bearer", "token": "YOUR_PRODUCTION_TOKEN" },
    "environment": "production"
  }'
```

Replace the placeholders with your values:

* `YOUR_API_KEY`: Your Runtype API key.
* `YOUR_DEVELOPMENT_TOKEN`: The token for the development server.
* `YOUR_PRODUCTION_TOKEN`: The token for the production server.

Add the environment to the dispatch request to select a saved server configuration:

**`Dispatch environment`**

```json title="Dispatch environment"
{
  "options": {
    "environment": "production"
  }
}
```

A saved server without an environment applies to every environment. When a dispatch sets an environment, Runtype uses the server registered for that environment and falls back to the server without one. When a dispatch omits `options.environment`, Runtype uses only servers that have no environment.

To get or delete one registration of a name, add the `environment` query parameter, as in `GET /v1/mcp/servers/customer_support?environment=production`. Without the parameter, the request targets the registration that has no environment. If you create a second server with the same name and environment, the API returns `409` with a message such as "A custom MCP server named "customer_support" already exists for production environment".

## Limits

Runtype applies these limits to runtime MCP configuration:

| Limit                               | Value                                                         |
| ----------------------------------- | ------------------------------------------------------------- |
| Maximum custom MCP servers per step | 5                                                             |
| Maximum timeout                     | 300 seconds (background runs); 30 seconds (synchronous calls) |
| Tool discovery cache                | 30 seconds                                                    |

A background run continues after the original request returns, such as an Agent Loop turn that runs in the background or a detached subagent run. A synchronous call holds the original request open while the tool runs, so Runtype caps its timeout at 30 seconds and logs the reduction.

## Combine MCP tools with other tools

Add saved tools, built-in tools, runtime tools, and runtime MCP servers to one prompt. This `tools` object combines these tool sources:

**`Combined tool configuration`**

```typescript title="Combined tool configuration"
const tools = {
  toolIds: ['mcp:customer_support:search_articles', 'builtin:openai_web_search', 'YOUR_TOOL_ID'],
  mcpServers: [
    {
      id: 'runtime_server',
      url: 'https://example.com/mcp',
    },
  ],
  runtimeTools: [
    {
      name: 'get_customer',
      description: 'Get customer information',
      toolType: 'external',
      parametersSchema: {
        type: 'object',
        properties: {},
      },
      config: {
        url: 'https://example.com/customer',
        method: 'GET',
      },
    },
  ],
}
```

Replace `YOUR_TOOL_ID` with the ID of a saved tool.

## Protect MCP credentials

Use these practices to protect MCP credentials:

* Store saved-server credentials in the server configuration. Runtype encrypts them before storage.
* Keep runtime credentials out of logs and persistent storage. Use environment variables or `{{secret:NAME}}` references instead of hardcoded tokens.
* Set `allowedTools` to limit the tools that a server exposes.

## Troubleshoot MCP servers

A saved server is required when a step references its tools in `toolIds`. When a required server can't load its tools, the run stops with a message that names the server and a recovery action. Timeouts and temporary outages get at most one discovery retry. Runtype stops the run without trying model fallbacks, prompt fallbacks (including fixed-message fallbacks), or additional agent turns. Reconnect or repair the server before you run the flow or agent again.

Structured run errors include `error.details.mcpFailure` with the `serverId`, `serverName`, `stage`, `code`, `retryable`, and `diagnosticId` fields. Keep the `diagnosticId` value when you investigate a failed run. Browser voice tests display the same message and a **Check SERVER_NAME connection** button that opens the server in **Tools**. These messages don't include upstream response bodies or credentials.

The `stage` field is one of `configuration`, `token_refresh`, `connection`, or `tool_discovery`. The following table lists the `code` values:

| Code                      | Meaning                                                                                      | Action                                                           |
| ------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `MCP_REAUTH_REQUIRED`     | The server rejected the credentials or the OAuth2 token.                                     | Reconnect the server from **Tools**, or replace its credentials. |
| `MCP_ACCESS_DENIED`       | The server denied access to the connection.                                                  | Check the permissions and scopes that the connection uses.       |
| `MCP_TIMEOUT`             | The server didn't respond within the timeout. Retryable.                                     | Try again, or increase `timeout`.                                |
| `MCP_UNAVAILABLE`         | The server was unreachable, rate-limited the request, or returned a server error. Retryable. | Try again after the server recovers.                             |
| `MCP_INVALID_RESPONSE`    | The server returned a response that isn't valid MCP.                                         | Check the server URL and `transport` setting.                    |
| `MCP_CONFIGURATION_ERROR` | The saved server is missing, turned off, or couldn't be loaded.                              | Check that the server exists and is turned on in **Tools**.      |
| `MCP_DISCOVERY_FAILED`    | Tool discovery failed for another reason.                                                    | Test the server with `POST /v1/mcp/servers/:name/test`.          |

Use these checks to troubleshoot common MCP server failures:

#### Connection timeout

Check these settings:

* Confirm that the server URL is reachable.
* Increase the `timeout` value, up to 300000 milliseconds. A value above 30000 takes effect only in background runs. For more information, see [Limits](#limits).
* Confirm that firewall and network rules allow the connection.

#### Authentication failed

Check these settings:

* Confirm that the token is valid and has not expired.
* Confirm that the auth type matches the server's requirements.
* For `api_key`, confirm that `headerName` matches the server's header.

#### Permission denied (\`403\`)

Check these settings:

* Confirm that the server owner or an organization admin manages the server.
* Check `canManage` in the `GET /v1/mcp/servers` response.
* Ask the server owner or an organization admin to make the change.
* Confirm that your API key has the scope that the endpoint requires. For the scope of each endpoint, see [API reference](#api-reference).

#### Tools do not appear

Check these settings:

* Send a `POST` request to `/v1/mcp/servers/:name/test` to verify discovery, and check the `success` field.
* Check the `allowedTools` filter when you set it.
* Confirm that the server implements the `tools/list` method.

#### Runtime server rejected at validation

Runtype validates `tools.mcpServers` before the run starts. Match the error to its fix:

* "Maximum 5 custom MCP servers per step": Split the servers across steps, or save some servers and reference their tool IDs.
* "MCP server missing required "id" field": Add an `id` value to each server.
* "missing required "url" field" or "has invalid URL format": Set `url` to a complete URL, such as `https://example.com/mcp`.
* "has invalid auth type": Use `api_key`, `bearer`, `basic`, `custom_header`, `headers`, or `none`.
* "Inline MCP OAuth2 is unsupported": Save the server with OAuth2, and then bind its ID without `auth`. For more information, see [Machine-to-machine OAuth2](#machine-to-machine-oauth2).
* "timeout exceeds the 300s limit": Set `timeout` to 300000 milliseconds or less.

## API reference

Use these endpoints to manage saved servers and discover tools. When you call an endpoint with an API key, the key needs the listed scope:

| Endpoint                          | Scope           | Description                                                                                                |
| --------------------------------- | --------------- | ---------------------------------------------------------------------------------------------------------- |
| `GET /v1/mcp/servers`             | `TOOLS:READ`    | Lists saved custom MCP servers.                                                                            |
| `POST /v1/mcp/servers`            | `TOOLS:WRITE`   | Creates a saved custom MCP server. Returns `409` when the name already exists in that environment.         |
| `GET /v1/mcp/servers/:name`       | `TOOLS:READ`    | Gets saved server details. Use the optional `environment` query parameter to select a registration.        |
| `PATCH /v1/mcp/servers/:name`     | `TOOLS:WRITE`   | Updates saved server configuration.                                                                        |
| `DELETE /v1/mcp/servers/:name`    | `TOOLS:WRITE`   | Deletes a saved server. Use the optional `environment` and `id` query parameters to select a registration. |
| `POST /v1/mcp/servers/:name/test` | `TOOLS:EXECUTE` | Tests a saved server and lists discovered tools.                                                           |
| `GET /v1/mcp/tools`               | `TOOLS:READ`    | Lists configured integration tools.                                                                        |
| `POST /v1/mcp/discover`           | `TOOLS:READ`    | Discovers tools from a server URL.                                                                         |

## Next steps

Continue with these guides:

#### [Working with tools](/developer-guides/guides/working-with-tools)

Add MCP tools and other tool types to flows.

#### [Runtime tools](/developer-guides/guides/runtime-tools)

Define tools inline for a request.

#### [Agent tools](/user-guide/agents/agent-tools)

Add saved MCP tools to an Agent.

#### [Creating and editing flows](/user-guide/flows/creating-and-editing-flows)

Build a flow that uses MCP tools.

#### [Connecting AI model providers](/user-guide/integrations/connecting-ai-model-providers)

Configure the models that run your flows.