MCP Servers

MCP (Model Context Protocol) 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 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:

{
  "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

FieldTypeRequiredDescription
typestringYesMust be "mcp".
urlstringYesThe MCP server URL.
namestringYesHuman-readable name for the tool collection. Must be unique within the manifest.
descriptionstringYesHuman-readable description of the tools provided.
namespacestringYesPrefix added to tool names to avoid collisions (e.g., example_search).
idstringYesStable identifier for this collection. Must be snake_case. Used for install-time bindings and should not change after publish.
authstringNoAuthentication type. Set to "oauth" for OAuth-protected servers.
oauth_appstringNoName of a manually created OAuth Provider. Use this legacy/manual path when you need full control over the provider lifecycle.
oauth_configobjectNoOAuth configuration embedded directly in the manifest. Vertesia auto-creates an OAuth Provider when the app is installed. See Embedded OAuth Configuration below. Mutually exclusive with oauth_provider.
oauth_providerstringNoKey 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.
oauth_scopesstring[]NoAdditional 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:

{
  "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:

FieldTypeDescription
grant_typestringOAuth grant type: "authorization_code" (user OAuth flow) or "client_credentials" (machine-to-machine, no user consent).
authorization_endpointstringOAuth authorize URL. Optional — auto-discovered from .well-known/oauth-authorization-server when omitted.
token_endpointstringOAuth token exchange URL. Optional — auto-discovered when omitted.
revocation_endpointstringToken revocation URL. Optional.
client_idstringPre-configured client ID shared across all installs. Omit if each project registers its own OAuth client.
use_pkcebooleanEnable PKCE (Proof Key for Code Exchange). Defaults to true.
default_scopesstring[]Base scopes applied to all collections referencing this provider.
required_at_installstring[]Installer-supplied credentials. See required_at_install below.
namestringName for the created OAuthProvider. Defaults to {app-slug}-{providerKey} (e.g. my-microsoft-app-microsoft).
display_namestringDisplay name for the created OAuthProvider.

Scope Union

The final scope set on the created OAuthProvider is:

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 combinationError
oauth_provider + oauth_configMutually exclusive
oauth_provider + oauth_appMutually exclusive
oauth_scopes without oauth_providerNot meaningful outside a shared provider
oauth_provider without auth: "oauth"auth: "oauth" is required
oauth_provider referencing a key not in oauth_providersUnknown 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

FieldTypeDescription
grant_typestringOAuth grant type: "authorization_code" (user OAuth flow) or "client_credentials" (machine-to-machine, no user consent).
authorization_endpointstringOAuth authorize URL. Optional — auto-discovered from .well-known/oauth-authorization-server when omitted.
token_endpointstringOAuth token exchange URL. Optional — auto-discovered when omitted.
revocation_endpointstringToken revocation URL. Optional.
client_idstringPre-configured client ID shared across all installs. Omit if each project registers its own OAuth client.
use_pkcebooleanEnable PKCE. Defaults to true.
default_scopesstring[]Scopes to request by default.
required_at_installstring[]Parameters installers must provide at install time. Accepted values: "client_id", "client_secret", "scopes". See below.
namestringName for the created OAuthProvider. Defaults to the collection id converted to kebab-case.
display_namestringDisplay 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:

ValueWhen 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

{
  "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

{
  "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 idOAuth 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:

FieldDescription
NameKebab-case identifier (e.g., my-crm-oauth). Used to reference the app in manifests.
Display NameHuman-readable label shown in the UI.
Client IDOAuth client identifier from the provider.
Client SecretOAuth client secret (encrypted at rest). Optional for public clients using PKCE.
Default ScopesSpace-separated OAuth scopes (e.g., read write).
Use PKCEEnable PKCE (Proof Key for Code Exchange). Enabled by default.
Authorization EndpointOAuth authorize URL. Optional — auto-discovered from the MCP server's .well-known/oauth-authorization-server metadata when omitted.
Token EndpointOAuth token exchange URL. Optional — auto-discovered when omitted.
Revocation EndpointToken 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 for programmatic management.

Step 2: Reference the OAuth Provider in the Manifest

Add the auth and oauth_app fields to the MCP collection:

{
  "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:

{
  "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

Was this page helpful?