---
title: "MCP Servers"
source: "https://docs.vertesiahq.com/apps/tool-collections"
markdown: "https://docs.vertesiahq.com/llms/apps/tool-collections.md"
---

# MCP Servers

[MCP (Model Context Protocol)](https://modelcontextprotocol.io) servers connect external tools to your Vertesia applications. Agents can then use the tools provided by these servers during execution.

For custom HTTP tool servers built with the Vertesia Tools SDK, use the [`endpoint`](/apps/overview) field in your app manifest instead — tools are discovered automatically from the endpoint URL.

## Quick Start

Add an MCP server to your app manifest's `tool_collections` array:

```json
{
  "name": "my-app",
  "tool_collections": [
    {
      "type": "mcp",
      "id": "example_tools",
      "url": "https://mcp.example.com/v1",
      "name": "Example Tools",
      "description": "Tools from Example service",
      "namespace": "example",
      "auth": "oauth"
    }
  ]
}
```

## MCP Configuration Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | `string` | Yes | Must be `"mcp"`. |
| `url` | `string` | Yes | The MCP server URL. |
| `name` | `string` | Yes | Human-readable name for the tool collection. Must be unique within the manifest. |
| `description` | `string` | Yes | Human-readable description of the tools provided. |
| `namespace` | `string` | Yes | Prefix added to tool names to avoid collisions (e.g., `example_search`). |
| `id` | `string` | Yes | Stable identifier for this collection. Must be `snake_case`. Used for install-time bindings and should not change after publish. |
| `auth` | `string` | No | Authentication type. Set to `"oauth"` for OAuth-protected servers. |
| `oauth_app` | `string` | No | Name of a manually created [OAuth Provider](/api/oauth-providers). Use this legacy/manual path when you need full control over the provider lifecycle. |
| `oauth_config` | `object` | No | OAuth configuration embedded directly in the manifest. Vertesia auto-creates an OAuth Provider when the app is installed. See [Embedded OAuth Configuration](#embedded-oauth-configuration) below. Mutually exclusive with `oauth_provider`. |
| `oauth_provider` | `string` | No | Key of a shared provider declared in the top-level `oauth_providers` map. Mutually exclusive with `oauth_config` and `oauth_app`. Requires `auth: "oauth"`. See [Shared OAuth Providers](#shared-oauth-providers). |
| `oauth_scopes` | `string[]` | No | Additional OAuth scopes for this collection when using `oauth_provider`. Merged with the provider's `default_scopes` and any installer-supplied scopes at install time. |

The distinction between `id` and `name` matters:

- `id` is the stable machine identifier. Vertesia uses it for install-time OAuth bindings and related runtime lookups.
- `name` is the human-readable label shown in the UI.

### Namespacing

The `namespace` field is prepended to all tool names from the MCP server. For example, if the server exposes a tool named `search` and the namespace is `crm`, the agent sees it as `crm_search`. This prevents name collisions when multiple MCP servers are configured.

## OAuth Authentication

Some MCP servers require OAuth 2.0 authentication. Vertesia handles the full OAuth flow including token storage and automatic refresh.

There are four ways to configure OAuth for an MCP collection, in order of preference:

1. **Shared `oauth_providers` map** — Declare a named OAuth provider once at the manifest level. Multiple collections reference it by key. One `OAuthProvider` is created per provider at install time. Best when multiple MCP servers share the same OAuth client (e.g. Microsoft Graph and Microsoft Teams).
2. **Embedded `oauth_config`** — Declare OAuth parameters directly on the collection. Vertesia auto-creates an `OAuthProvider` when the app is installed. Best for distributing apps to multiple projects where each MCP server has its own OAuth client.
3. **`oauth_app` reference** — Point to a manually created OAuth Provider by name. Best for full lifecycle control or sharing a single provider across multiple collections.
4. **Remote server discovery** — If no provider is configured, Vertesia can discover OAuth metadata from the remote MCP server and follow that server's flow.

## Shared OAuth Providers

Use `oauth_providers` when multiple MCP servers in the same app share a single OAuth client — for example, Microsoft Graph API and Microsoft Teams both use the same Azure OAuth provider configuration.

Declare providers once at the manifest level, then reference them from each collection using `oauth_provider`:

```json
{
  "name": "my-microsoft-app",
  "oauth_providers": {
    "microsoft": {
      "grant_type": "authorization_code",
      "client_id": "your-azure-app-client-id",
      "use_pkce": true,
      "default_scopes": ["offline_access"],
      "required_at_install": ["client_secret"]
    }
  },
  "tool_collections": [
    {
      "type": "mcp",
      "id": "ms_graph",
      "url": "https://graph.microsoft.com/mcp",
      "name": "Microsoft Graph",
      "description": "Access Microsoft 365 data",
      "namespace": "graph",
      "auth": "oauth",
      "oauth_provider": "microsoft",
      "oauth_scopes": ["User.Read", "Mail.Read"]
    },
    {
      "type": "mcp",
      "id": "ms_teams",
      "url": "https://teams.microsoft.com/mcp",
      "name": "Microsoft Teams",
      "description": "Send messages and manage channels",
      "namespace": "teams",
      "auth": "oauth",
      "oauth_provider": "microsoft",
      "oauth_scopes": ["ChannelMessage.Send"]
    }
  ]
}
```

At install time, Vertesia:

1. Creates **one** `OAuthProvider` named `my-microsoft-app-microsoft`.
2. Computes the final scope set: `offline_access` (provider default) ∪ `User.Read Mail.Read` (graph) ∪ `ChannelMessage.Send` (teams).
3. Stores a `provider_bindings` entry on the installation linking the `microsoft` key to the created OAuth Provider.

Both collections then share the same token at runtime.

### `oauth_providers` Fields

Each entry in the `oauth_providers` map uses the same fields as `oauth_config`:

| Field | Type | Description |
| ----- | ---- | ----------- |
| `grant_type` | `string` | OAuth grant type: `"authorization_code"` (user OAuth flow) or `"client_credentials"` (machine-to-machine, no user consent). |
| `authorization_endpoint` | `string` | OAuth authorize URL. Optional — auto-discovered from `.well-known/oauth-authorization-server` when omitted. |
| `token_endpoint` | `string` | OAuth token exchange URL. Optional — auto-discovered when omitted. |
| `revocation_endpoint` | `string` | Token revocation URL. Optional. |
| `client_id` | `string` | Pre-configured client ID shared across all installs. Omit if each project registers its own OAuth client. |
| `use_pkce` | `boolean` | Enable PKCE (Proof Key for Code Exchange). Defaults to `true`. |
| `default_scopes` | `string[]` | Base scopes applied to **all** collections referencing this provider. |
| `required_at_install` | `string[]` | Installer-supplied credentials. See [`required_at_install`](#required_at_install) below. |
| `name` | `string` | Name for the created `OAuthProvider`. Defaults to `{app-slug}-{providerKey}` (e.g. `my-microsoft-app-microsoft`). |
| `display_name` | `string` | Display name for the created `OAuthProvider`. |

### Scope Union

The final scope set on the created `OAuthProvider` is:

```text
provider.default_scopes ∪ collection₁.oauth_scopes ∪ collection₂.oauth_scopes ∪ installer_scopes
```

Duplicates are removed. The unified scope list is stored on the `OAuthProvider` and used for every collection that references this provider.

### Scope Changes After Install

Changing `oauth_providers[key].default_scopes` or a collection's `oauth_scopes` in the manifest **does not automatically update already-installed `OAuthProvider` documents**. To apply updated scopes, the installer must uninstall and reinstall the app — this deletes the old provider and creates a fresh one from the updated manifest.

### Mutual Exclusivity

A collection may use at most one OAuth configuration method. These combinations are rejected at manifest save time:

| Invalid combination | Error |
| ------------------- | ----- |
| `oauth_provider` + `oauth_config` | Mutually exclusive |
| `oauth_provider` + `oauth_app` | Mutually exclusive |
| `oauth_scopes` without `oauth_provider` | Not meaningful outside a shared provider |
| `oauth_provider` without `auth: "oauth"` | `auth: "oauth"` is required |
| `oauth_provider` referencing a key not in `oauth_providers` | Unknown provider |

## Embedded OAuth Configuration

Use `oauth_config` to embed OAuth parameters directly in the manifest. When a user installs the app, Vertesia automatically creates an `OAuthProvider` in their project using the configuration you provide, optionally merged with credentials the installer supplies at install time.

This is the recommended approach for apps distributed to multiple projects — each project gets its own OAuth Provider with project-scoped credentials.

`oauth_config` is install-time configuration only. At runtime, Vertesia resolves OAuth through the installation's stored binding from `collection.id` to the created OAuth Provider.

### `oauth_config` Fields

| Field | Type | Description |
| ----- | ---- | ----------- |
| `grant_type` | `string` | OAuth grant type: `"authorization_code"` (user OAuth flow) or `"client_credentials"` (machine-to-machine, no user consent). |
| `authorization_endpoint` | `string` | OAuth authorize URL. Optional — auto-discovered from `.well-known/oauth-authorization-server` when omitted. |
| `token_endpoint` | `string` | OAuth token exchange URL. Optional — auto-discovered when omitted. |
| `revocation_endpoint` | `string` | Token revocation URL. Optional. |
| `client_id` | `string` | Pre-configured client ID shared across all installs. Omit if each project registers its own OAuth client. |
| `use_pkce` | `boolean` | Enable PKCE. Defaults to `true`. |
| `default_scopes` | `string[]` | Scopes to request by default. |
| `required_at_install` | `string[]` | Parameters installers must provide at install time. Accepted values: `"client_id"`, `"client_secret"`, `"scopes"`. See below. |
| `name` | `string` | Name for the created `OAuthProvider`. Defaults to the collection `id` converted to kebab-case. |
| `display_name` | `string` | Display name for the created `OAuthProvider`. |

### `required_at_install`

Use `required_at_install` to prompt the person installing the app for credentials that cannot be stored in a shared manifest:

| Value | When to use |
| ----- | ----------- |
| `"client_id"` | Each project registers its own OAuth client with the provider (e.g., users bring their own app). |
| `"client_secret"` | The OAuth provider requires a client secret — secrets must never be embedded in a shared manifest. |
| `"scopes"` | Allow installers to specify additional scopes beyond the `default_scopes`. |

When `required_at_install` is set, Vertesia displays a credential form during the install flow before creating the OAuth Provider.

`client_secret` must never be stored in the manifest. If a secret is required, declare `"client_secret"` in `required_at_install` so the installer provides it at install time.

### Example: Shared Client ID, Secret Required at Install

```json
{
  "tool_collections": [
    {
      "type": "mcp",
      "id": "my-crm",
      "url": "https://mcp.my-crm-provider.com",
      "name": "My CRM",
      "description": "CRM tools for contacts and deals",
      "namespace": "crm",
      "auth": "oauth",
      "oauth_config": {
        "grant_type": "authorization_code",
        "client_id": "shared-client-id-from-provider",
        "use_pkce": true,
        "default_scopes": ["read", "write"],
        "required_at_install": ["client_secret"]
      }
    }
  ]
}
```

### Example: Each Installer Brings Their Own OAuth Client

```json
{
  "tool_collections": [
    {
      "type": "mcp",
      "id": "my-crm",
      "url": "https://mcp.my-crm-provider.com",
      "name": "My CRM",
      "description": "CRM tools for contacts and deals",
      "namespace": "crm",
      "auth": "oauth",
      "oauth_config": {
        "grant_type": "authorization_code",
        "authorization_endpoint": "https://auth.my-crm-provider.com/oauth/authorize",
        "token_endpoint": "https://auth.my-crm-provider.com/oauth/token",
        "use_pkce": true,
        "required_at_install": ["client_id", "client_secret"]
      }
    }
  ]
}
```

### How Auto-Provisioning Works

At install time, Vertesia:

1. Merges `oauth_config` with the credentials the installer provided.
2. Creates an `OAuthProvider` in the installing project.
3. Stores a binding (`collection id` → `OAuth Provider id`) on the installation record.

Credentials can be updated later from **Project Settings > OAuth Providers**. If an OAuth provider with the same generated name already exists, install will fail until the name conflict is resolved or `oauth_config.name` is changed.

## Manual OAuth Provider

For full control over the OAuth provider lifecycle, create one manually and reference it by name:

### Step 1: Create an OAuth Provider

Go to **Project Settings > OAuth Providers** and click **Create**. Fill in:

| Field | Description |
|-------|-------------|
| **Name** | Kebab-case identifier (e.g., `my-crm-oauth`). Used to reference the app in manifests. |
| **Display Name** | Human-readable label shown in the UI. |
| **Client ID** | OAuth client identifier from the provider. |
| **Client Secret** | OAuth client secret (encrypted at rest). Optional for public clients using PKCE. |
| **Default Scopes** | Space-separated OAuth scopes (e.g., `read write`). |
| **Use PKCE** | Enable PKCE (Proof Key for Code Exchange). Enabled by default. |
| **Authorization Endpoint** | OAuth authorize URL. Optional — auto-discovered from the MCP server's `.well-known/oauth-authorization-server` metadata when omitted. |
| **Token Endpoint** | OAuth token exchange URL. Optional — auto-discovered when omitted. |
| **Revocation Endpoint** | Token revocation URL. Optional. |

For MCP servers that publish OAuth metadata at `.well-known/oauth-authorization-server`, you only need to provide the **Client ID** (and **Client Secret** if required by the provider). The authorization and token endpoints are discovered automatically.

See the [OAuth Providers API reference](/api/oauth-providers) for programmatic management.

### Step 2: Reference the OAuth Provider in the Manifest

Add the `auth` and `oauth_app` fields to the MCP collection:

```json
{
  "tool_collections": [
    {
      "type": "mcp",
      "id": "my_crm",
      "url": "https://mcp.my-crm-provider.com",
      "name": "My CRM",
      "description": "CRM tools for contacts and deals",
      "namespace": "crm",
      "auth": "oauth",
      "oauth_app": "my-crm-oauth"
    }
  ]
}
```

The `oauth_app` value must match the **Name** of the OAuth Provider you created in Step 1.

### Step 3: Connect

Each user must authenticate individually before agents can use the MCP tools on their behalf.

**Admins** can verify the configuration works from **Project Settings > Apps**: find the installed app and click **Connect** next to the OAuth-enabled MCP collection to complete the OAuth consent flow.

**End users** connect from the **new agent form** in the Agent Runner interface before starting the agent. The form displays connect actions for any OAuth-enabled MCP collections that require authentication.

Tokens are stored securely and refreshed automatically. If a refresh token expires or is revoked, the user will need to reconnect.

## Complete Example

An app manifest combining embedded OAuth configuration and a public MCP server:

```json
{
  "name": "my-sales-app",
  "visibility": "private",
  "title": "Sales Integration",
  "description": "Connect sales tools to Vertesia agents",
  "publisher": "My Organization",
  "status": "stable",
  "endpoint": "https://my-app.example.com/api/vertesia",
  "tool_collections": [
    {
      "type": "mcp",
      "id": "crm",
      "url": "https://mcp.my-crm-provider.com",
      "name": "My CRM",
      "description": "CRM tools for contacts, deals, and companies",
      "namespace": "crm",
      "auth": "oauth",
      "oauth_config": {
        "grant_type": "authorization_code",
        "client_id": "shared-client-id",
        "use_pkce": true,
        "default_scopes": ["crm.read", "crm.write"],
        "required_at_install": ["client_secret"]
      }
    },
    {
      "type": "mcp",
      "id": "internal_tools",
      "url": "https://mcp.internal.example.com/v1",
      "name": "Internal Tools",
      "description": "Internal MCP tools",
      "namespace": "internal"
    }
  ]
}
```

This example configures:
- An `endpoint` for Vertesia SDK tools (discovered automatically)
- An MCP server with embedded OAuth configuration — the installer is prompted for a client secret at install time, then an `OAuthProvider` is auto-created in their project
- An unauthenticated MCP server