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
| 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. 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 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. |
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:
idis the stable machine identifier. Vertesia uses it for install-time OAuth bindings and related runtime lookups.nameis 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:
- Shared
oauth_providersmap — Declare a named OAuth provider once at the manifest level. Multiple collections reference it by key. OneOAuthProvideris created per provider at install time. Best when multiple MCP servers share the same OAuth client (e.g. Microsoft Graph and Microsoft Teams). - Embedded
oauth_config— Declare OAuth parameters directly on the collection. Vertesia auto-creates anOAuthProviderwhen the app is installed. Best for distributing apps to multiple projects where each MCP server has its own OAuth client. oauth_appreference — Point to a manually created OAuth Provider by name. Best for full lifecycle control or sharing a single provider across multiple collections.- 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:
- Creates one
OAuthProvidernamedmy-microsoft-app-microsoft. - Computes the final scope set:
offline_access(provider default) ∪User.Read Mail.Read(graph) ∪ChannelMessage.Send(teams). - Stores a
provider_bindingsentry on the installation linking themicrosoftkey 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 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:
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
{
"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:
- Merges
oauth_configwith the credentials the installer provided. - Creates an
OAuthProviderin the installing project. - 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 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
endpointfor 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
OAuthProvideris auto-created in their project - An unauthenticated MCP server
