## Overview

**MCP (Model Context Protocol)** is the open standard that lets AI assistants (Claude, IDEs, agents)
use tools and data from external systems safely. Conversa Labs ships **native** MCP, and you operate all
of it from screens — no integration code required.

There are three surfaces:

- **Account MCP connections (access profiles)** — instead of a single account-wide setting, you create
  **N** named **profiles**. The **static Bearer** connection for each profile has its own module selection,
  read-only mode, an **acting user** (an account member) and its **own URL + bearer secret**. That static
  connection operates as the profile's acting user and can only **narrow** what that user may already do.
  When native OAuth is enabled by the installation, the same profile also has a **separate OAuth URL**:
  its tools remain profile-bounded, but each call operates as the account member who approved that OAuth
  grant — never as the profile's static acting user.
- **Maestro MCP server** — exposes Maestro **departments** as `ask_<department>` tools to external
  clients, under a per-account token. The client never gains more autonomy than the department is
  already configured for.
- **Robot as an MCP client** — every robot can consume **external MCP servers** (Linear, Notion,
  Stripe, GitHub, an internal ERP) as extra tools, under the same approval (HITL), tool-budget and
  audit rules as any other capability.

The static account connection and the Maestro server use the standard `Authorization: Bearer <credential>`
header. The examples below configure that **static** Bearer path: on the account connection the credential
is the **profile secret**; on the Maestro server it is the **Maestro token**. They are configuration
examples, not proof that every product or version has been validated against this installation. Native
account OAuth is a separate, conditional resource with discovery, PKCE and browser consent; do not point
an OAuth-capable client at the static URL or assume a client supports this flow before testing it.

### Connector branding

During MCP initialization with protocol `2025-11-25`, the server sends the installation name and title,
description, website, and brand icons (a primary icon plus light/dark variants). OAuth login and consent
screens use the same identity; if the configured image cannot load, they show the installation initials.
This metadata is published only when the installation has a safe canonical public HTTPS origin. Without
one, the server omits URLs and icons rather than expose an internal or untrusted address.

The client decides whether and how to render these fields. Clients that negotiate an older MCP version
still receive the technical server name, but that protocol cannot carry icons. In Claude's **Custom
Connector**, use the name entered in its setup: the UI can continue to show that name until it uses the
server metadata. Appearance never changes scopes, consent, or credentials.

The Account, Platform and Super Admin endpoints build this safe snapshot for every MCP initialization.
After a White Label or canonical issuer change, the same versioned snapshot is queued for the direct
Maestro endpoint; its next authenticated request uses the newest persisted valid snapshot. A temporary
Maestro outage never rolls back the saved branding: the scheduled reconciler retries it. If a provider
already created a connector, disconnect and add the server again to force a new `initialize` request —
this does not rotate a token or change permissions. The icon URL must be a first-party asset on that
canonical origin, publicly fetchable over HTTPS without a login; an external CDN or another host is not
published as MCP brand metadata. A third-party client can cache the icon or elect not to render MCP icon
metadata; the server cannot override that client-side behavior.

## Prerequisites

- The **MCP** feature enabled for the account. Without the flag, the **Settings → MCP** page simply
  does not appear in the menu (and the installation's global switch must be on as well).
- An account **administrator** profile to **manage MCP connections** (the page and creating/editing
  profiles are admin-only).
- For the account connection: **no personal token**. Each **profile (MCP connection)** generates its
  **own bearer secret** at create/rotate time — that is the client's credential. The profile's **acting
  user** must be an **account member**. Robot (AgentBot) tokens and the personal API token are **not**
  the account connection's credential.
- For the optional **native account OAuth** connection: the installation owner must enable native MCP
  OAuth, apply this release's MCP OAuth database migrations, and configure a valid public **HTTPS**
  issuer, in addition to the account MCP feature and global server gate. A feature switch does not replace
  the schema migration or prove the flow. OAuth has a different URL from the static profile connection;
  the static profile secret never authenticates it. The person approving the browser consent must be an
  active member of that account.
- The issuer hostname must resolve and route through the public gateway to this same installation. It must
  serve the MCP OAuth endpoints and their Protected Resource and authorization-server discovery documents;
  a syntactically valid HTTPS address that routes elsewhere is not sufficient.
- Before adopting native OAuth in a third-party client, run its discovery, PKCE and consent flow in a
  controlled environment. A standards-based endpoint is not evidence that a particular client product,
  desktop app or hosted AI surface supports the required flow.
- For the Maestro server: **Maestro provisioned** for the account. Without it, the Maestro card is
  replaced by a hint.
- To connect an external MCP server **via OAuth**: the robot already **saved**, and the browser
  allowed to open pop-ups (the provider's consent screen opens in a window).

## Step by step

### 1. Open the MCP page

Go to **Settings → MCP**. The screen shows the **Account MCP connections** card (the access profiles)
and the **Maestro MCP server** card.

### 2. Create an MCP connection (access profile)

On the **Account MCP connections** card, click **New profile**. Each profile is an independent
connection:

1. **Name the profile** (for example `claude-code-support` or `bi-read-only`) — it helps you tell which
   client uses which connection.
2. **Choose the acting user** — an **account member**. The profile runs **as that user**: the effective
   tool list is the intersection of your selection with the Super Admin ceiling **and** with that user's
   permissions. In other words, a profile only **narrows** — it never grants more than the user already
   has. Only routes rooted at `/api/v{N}/accounts/{account}` belong to this server: personal profile,
   MFA, session and notification routes stay outside the account connection even when that user belongs
   to other accounts.
3. **Pick the modules** to expose. It is the same picker as always: the whole platform (100+ modules),
   organized into collapsible **areas** — Conversations & support, Contacts & CRM, Catalog & commerce,
   Payments, Tasks & calendar, WhatsApp, Channels & integrations, Automation & AI, Growth & sales,
   Reports, Team & administration, and Content. Use the **search** to find a module by name or
   description, and an area's **Select all** to turn the whole area on at once. Every row says what the
   module does and **how many tools it adds** (the price of the checkbox); the summary under the search
   adds up the current selection and warns you when it goes past the **tool cap** — which still applies
   **per profile**:

   A few examples (the full list is on screen, by area):

   | Example module | What it exposes |
   |---|---|
   | Conversations | read, reply, change status, assign, apply labels (on by default) |
   | Contacts | look up, create and update contacts (on by default) |
   | Reports | metrics and analytics (read-only) |
   | Tasks | native tasks module |
   | CRM Items | deals and pipeline |
   | Help Center | knowledge base articles |
   | Catalog | products |
   | Follow-up | follow-up cadences |
   | Media Library | media assets |

   Toolsets that are on out of the box carry the **default** badge. If the Super Admin did not allow a
   toolset in the global ceiling, the row is shown **disabled** with a **blocked by super admin** badge —
   you cannot check it.

   Above the list there are **starting-point** shortcuts: **Essential**, **Support**, **Sales** and
   **Everything**. They only **add** modules to the current selection — nothing is removed, and no module
   disappears from the list because a shortcut does not mention it. Use one to start and adjust by hand;
   modules blocked by the ceiling stay out, as always.
4. **Read-only mode**: tick the checkbox for the profile to expose **only tools that read data** (no
   create, update or delete).
5. **ChatGPT deep research compatibility** (optional): ChatGPT's deep research connector requires, **by
   name**, two tools called `search` and `fetch`, and refuses a server that lacks them. Tick the box only
   on the profiles that connector uses. The two tools only **describe** what the profile already exposes
   — they grant no extra access — but they take up room in every other client's tool list. Leave it off
   for Claude, Claude Code and generic clients.
6. **Save the profile.** At that moment the **bearer secret is shown in plaintext exactly once** (shape
   `mcp_...`) — copy it immediately. Only the hash and last four characters are stored; the platform
   **never shows the secret again**.
7. **Copy the connection URL**. Its shape is
   `https://YOUR-DOMAIN/api/v1/accounts/ACCOUNT_ID/mcp/c/PUBLIC_ID`, where `PUBLIC_ID` is a **non-secret**
   identifier (a slug in the URL) — the bearer secret is what authenticates, not the URL. This is the
   **static Bearer** URL.

If the installation has enabled native MCP OAuth, the same profile has a different exact resource URL:
`https://YOUR-DOMAIN/api/v1/accounts/ACCOUNT_ID/mcp/oauth/c/PUBLIC_ID`. Do not replace `mcp/c` with this
path in an existing static client and do not paste the profile secret into it. The profile still selects
the tool surface, but OAuth calls run as the account member who approves consent.

Afterwards, each profile has, on the card, **Edit** (change name, acting user, modules and read-only
mode), **Rotate token** (generates a new secret and **invalidates the previous one right away**) and
**Delete**. Disabling or deleting the profile — or the acting user losing account membership — makes the
connection **stop responding** (401/404).

### 3. Configure the Maestro MCP server

1. On the **Maestro MCP server** card, look at the **status**: *Token configured* or *No token yet*.
2. Click **Generate token** (or **Rotate token** if one already exists).
3. The **token plaintext is shown exactly once** — copy it immediately. It is never displayed again.
   Rotating **invalidates the previous token** right away.
4. **Copy the Maestro endpoint URL** (it ends in `/mcp`).
5. An external client with that URL + token sees one `ask_<department>` tool per active department of
   the account.

> If Maestro is not configured for the account, the card is replaced by a hint — provision Maestro
> first.

### 4. Connect a real MCP client with a static Bearer

This section configures only the **static Bearer** connection: choose **Streamable HTTP**, the profile's
static URL from step 2 (or Maestro's URL from step 3), and the credential in the
`Authorization: Bearer ...` header. For the account connection that credential is the **profile secret**
(the `mcp_...` revealed when you create or rotate the profile); for Maestro it is the **Maestro token**.
Client configuration formats change independently of this documentation, so validate the exact client
version in a controlled environment. None of the following snippets configures the native OAuth flow.

**Claude Code** — from the terminal:

```bash
claude mcp add --transport http helpdesk \
  https://YOUR-DOMAIN/api/v1/accounts/ACCOUNT_ID/mcp/c/PUBLIC_ID \
  --header "Authorization: Bearer PROFILE_SECRET"
```

Or in the project's `.mcp.json`:

```json
{
  "mcpServers": {
    "helpdesk": {
      "type": "http",
      "url": "https://YOUR-DOMAIN/api/v1/accounts/ACCOUNT_ID/mcp/c/PUBLIC_ID",
      "headers": { "Authorization": "Bearer PROFILE_SECRET" }
    }
  }
}
```

**Cursor** — in `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project):

```json
{
  "mcpServers": {
    "helpdesk": {
      "url": "https://YOUR-DOMAIN/api/v1/accounts/ACCOUNT_ID/mcp/c/PUBLIC_ID",
      "headers": { "Authorization": "Bearer PROFILE_SECRET" }
    }
  }
}
```

**VS Code** (agent mode) — in `.vscode/mcp.json`:

```json
{
  "servers": {
    "helpdesk": {
      "type": "http",
      "url": "https://YOUR-DOMAIN/api/v1/accounts/ACCOUNT_ID/mcp/c/PUBLIC_ID",
      "headers": { "Authorization": "Bearer PROFILE_SECRET" }
    }
  }
}
```

**MCP Inspector** — to debug the connection and see the raw tool list:

```bash
npx @modelcontextprotocol/inspector
```

In the panel: *Transport Type* = **Streamable HTTP**, *URL* = the connection URL, and under
*Authentication* enter the **Bearer Token** — the **profile secret** for the account connection, or the
**Maestro token** for the Maestro server (or an `Authorization` header whose value is
`Bearer <credential>`). Click **Connect**, then **List Tools**.

**Windsurf** — same idea: a remote server with the connection URL and `headers` carrying
`Authorization: Bearer PROFILE_SECRET` (or the Maestro token).

In all of them the client runs `initialize`, then `tools/list` (lists the exposed tools) and finally
`tools/call` to run one of them. If the client shows fewer tools than expected, that is the display
cap: use **`search_tools`** to find any other tool (it returns its input schema) and **`call_tool`** to
run it. Nothing is unreachable — it is merely unlisted.

### 4a. Connect the native account OAuth resource (conditional)

This is a separate connection path, available only when native MCP OAuth is enabled for the installation
and the account MCP feature/profile are available. It is not a setting that converts the static Bearer
connection, and it is not a fallback for a lost profile secret.

1. Configure the client with the exact OAuth resource URL:
   `https://YOUR-DOMAIN/api/v1/accounts/ACCOUNT_ID/mcp/oauth/c/PUBLIC_ID`.
2. Start with that resource's Protected Resource Metadata, not a guessed host URL:
   `https://YOUR-DOMAIN/.well-known/oauth-protected-resource/mcp/oauth/accounts/ACCOUNT_ID/connections/PUBLIC_ID`.
   It advertises the canonical authorization server only while the feature is available.
3. Discover the authorization server at
   `https://YOUR-DOMAIN/.well-known/oauth-authorization-server/oauth/mcp` (or use the issuer advertised
   by the resource metadata). The server supports the public Authorization Code flow with mandatory
   **S256 PKCE**, exact resource binding and no client secret.
   Its discovery metadata declares `authorization_response_iss_parameter_supported`: validate the
   canonical issuer returned in the `iss` parameter on successful and redirectable error callbacks.
   The signed browser handoff accepts at most **1,024 combined bytes** across its persisted authorization
   values (including `client_id`, `redirect_uri`, `resource`, and `state`). Keep `state` short and opaque;
   do not try to extend the flow with oversized URLs or state values.
4. A public client can use verified public Client ID Metadata (CIMD). Dynamic Client Registration (DCR)
   is **conditional and off by default**: it appears in discovery only after a Super Admin enables
   **Dynamic Client Registration** in **MCP Settings**. When off, discovery omits
   `registration_endpoint` and registration returns 404 — that is not an OAuth failure. When on, the
   operator reviews the client in **MCP OAuth clients** and can disable it; confirmed disablement with a
   reason and reauthentication is irreversible and revokes the consent/token family. DCR remains a
   governed test path, not a promise of vendor compatibility. Never send a profile secret, personal API
   token, Super Admin credential or a client secret to this flow.
5. In the browser, when an active dashboard session or Super Admin Console session belongs to a member of the target account, the
   server validates and reuses it: you go directly to consent review without entering the password again.
   Approval remains mandatory. A Super Admin identity enters this flow only when it also has account
   membership, and the grant/token remains limited to the account, profile, and scopes — no global
   authority is inherited. If the session is missing, expired, invalid, or belongs to another account, the
   manual form appears and requires a valid member identity. `mcp:read` is the read scope; write tools
   also require `mcp:write` **and** a profile that is not read-only. `offline_access` explicitly requests
   a rotating refresh token.
6. In **Settings → Profile → MCP connections**, a member can review and revoke their own approved
   connections. An account administrator can review all account grants and must select a closed reason
   when revoking through the administrator flow. Revocation invalidates the connected credential family.

### 4b. Verify the public resource before connecting an OAuth client

Before opening Claude.ai, Claude Code, or another remote client, an operator can verify the public
contract **without supplying any credential**:

```bash
ruby scripts/mcp_oauth_preflight.rb \
  --base-url https://YOUR-DOMAIN \
  --account-id ACCOUNT_ID \
  --profile-public-id PUBLIC_ID
```

For the separate Super Admin authority, use:

```bash
ruby scripts/mcp_oauth_preflight.rb \
  --base-url https://YOUR-DOMAIN \
  --super-admin
```

The verifier accepts only a public HTTPS DNS origin (it rejects IP literals and internal hosts), does not
follow redirects, and checks exact Protected
Resource Metadata, issuer and audience, discovery, Client ID Metadata (CIMD), PKCE `S256`, the `iss`
response parameter, scopes, and the `401` challenge from a Bearer-free JSON-RPC `tools/list`. When
discovery advertises DCR, it also checks the exact endpoint; explicit absence because the gate is off is a
valid state. Proceed to the controlled test only when it finishes with **`RESULT: PASS`**. On a failure,
fix the publication before connecting any client. That result confirms server publication; it does not
prove a third-party provider is compatible.

It does not register a client, open consent, exchange/revoke a token, or change a profile, grant, or
credential. The remote installation can append its normal secret-free audit telemetry for discovery and
the `401` challenge; that is observability, not an OAuth client created by the verifier.

#### Claude.ai — Custom Connector

After an operator enables MCP OAuth and **Settings → MCP** shows the profile's **OAuth connection
address**, use the Claude connector area for your plan:

> Use this as a controlled test for the Claude version available to your organization. Do not offer the
> connection to other people until discovery, consent, `tools/list`, one read, and a successful revocation
> have been recorded.

Claude's remote connector reaches the server from Claude's cloud infrastructure, including when you use
Claude Desktop. The issuer must therefore be public HTTPS and reachable outside a VPN/private network;
being reachable only from your own browser is not enough. Remote custom connectors are available in
Claude, Cowork, and Claude Desktop on Free, Pro, Max, Team, and Enterprise plans; Free is limited to one
custom connector. Also review the [current Claude remote-connector guide](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp).

1. On **Team/Enterprise**, an Owner or Primary Owner goes to **Organization settings → Connectors → Add →
   Custom → Web** and registers the remote MCP URL. Each member then goes to **Customize → Connectors**
   and chooses **Connect**. On **Free/Pro/Max**, use **Customize → Connectors → + → Add custom connector**
   in your own account (Free allows one connector).
2. Give it a clear name, such as `Conversa Labs — Support`, and paste the **OAuth connection address** into
   **Remote MCP URL**. Do not use the static Bearer URL.
3. **Advanced settings** are optional. On this public-client server, never fill **Client Secret** or use a
   Bearer token, profile secret, or Super Admin credential in either field. If the Claude version requires
   DCR, enable it explicitly through Super Admin first; otherwise it must use CIMD or an already
   provisioned client.
4. Add the connector, sign in as an **active member of the account**, and read/approve consent. Claude
   acts as that person, limited by the profile, that person's own roles, and the scopes.

The callback is controlled by the client and is registration information, not a URL you manually replace
on the MCP resource. Record the Claude version and the callback actually received during the test; do not
put tokens, codes, or callback parameters in evidence.

To disconnect, revoke the grant in **Settings → Profile → MCP connections** (or, as an administrator,
from the same account view). Do not rotate a static bearer token: that is a separate connection type and
does not disconnect Claude OAuth.

Do not label a third-party product as compatible merely because it has an MCP or OAuth option. Validate
the exact product, version, redirect handling and consent result end to end before enabling it for users.

#### External connector matrix — controlled test

**Every row below is unvalidated on this installation.** The matrix explains how to prepare a safe attempt;
it does not claim vendor support. Always begin with `mcp:read`, `initialize`, `tools/list`, and one read
against test data. Test a write only after explicit authorization.

| Client | External prerequisites | Controlled-test steps | Revocation | Status |
|---|---|---|---|---|
| **Claude.ai — Custom Connector** | Claude plan with custom connectors (Free: one); on Team/Enterprise an Owner/Primary Owner registers it first; public HTTPS issuer reachable from Claude's cloud and passing preflight | Use the exact OAuth URL, keep Advanced settings optional/secret-free, and complete browser/PKCE/consent | Revoke in **Settings → Profile → MCP connections** and confirm the next call fails | ⏳ unvalidated |
| **Claude Desktop** | Current Claude Desktop and an account with custom connectors; the server must also be reachable from Claude's cloud, not only the local machine | Configure only the exact OAuth URL and record version, OS, and callback/safe error | Revoke the same grant and test another call | ⏳ unvalidated |
| **Codex** | Organization/product is eligible for remote MCP and its current connection method is available | Add only the exact OAuth URL through the product's current flow; never use a Bearer secret as a client secret | Revoke the grant and confirm subsequent denial | ⏳ unvalidated |
| **ChatGPT / GPT Platform** | Eligible plan/workspace, administrator or Developer Mode when applicable, and explicit authorization for the test | Use the connector/app flow actually available, the exact OAuth URL, and browser consent | Revoke the grant and confirm subsequent denial | ⏳ unvalidated |

The **Super Admin** OAuth resource is a different authority plane and uses a different URL; never replace
the Account URL above with `/super_admin/mcp/oauth`. Follow the Operator article and run a separate test.
Record version, plan/entitlement, discovery outcome, consent, `tools/list`, read, audit event, revocation,
and the denied call — without copying tokens, codes, verifiers, or parameterized authorization URLs.

**Claude Code:** local authorization uses a loopback callback with an ephemeral port. The restricted RFC
8252 redirect policy for that callback already has a local matcher and HTTP test; a fixed
`localhost`/`127.0.0.1` URL alone does not represent the real port. This is not compatibility proof: the
external E2E remains blocked until there is a public HTTPS issuer, Inspector, and evidence from the real
client.

### 5. Give a robot external MCP servers (the robot as a client)

1. Go to **Settings → Robots**, open the robot and find the **MCP servers** section.
2. Click **Add server** and fill in:
   - **Technical name** — lowercase letters, numbers and `_`, starting with a letter (2 to 33
     characters), e.g. `github`. It prefixes that server's tools.
   - **URL** of the MCP server (the one the provider publishes).
   - **Transport**: **Streamable HTTP** (recommended) or **SSE (legacy)**.
   - **Timeout** in seconds.
3. **Authentication**: choose the type — **none**, **bearer**, **header**, **query**, **basic** or
   **OAuth**. On the types that use a secret, enter the **secret name** — never the value. The value
   stays in the secrets vault and is **never sent to the model**. The **OAuth** type has no secret
   field at all: the credential is obtained in step 6.
4. **Additional headers** (optional): key/value pairs, only if the server requires them.
5. Tick **Require approval (HITL)** so every call to this server's tools goes through human approval.
6. Click **Discover**: the platform connects to the server right now and **lists its tools** before you
   save. Large servers (Linear, Notion) return dozens of tools with long descriptions — use the
   **search** and **Select all / Clear** to curate without scrolling the whole list; the counter shows
   how many you ticked. You may **select a subset** (allowlist) — if you select none, **every** tool of
   that server is
   available.
7. **Save the robot**. Tools are discovered and stored at save time; the agent's turn never performs
   network discovery.

> For discovery to resolve already-stored secrets, **save the robot first**, then click **Discover**.

### 6. Connect an external server via OAuth (the Connect button)

Some servers (Notion, for example) accept **only** OAuth — there is no static key. In those cases:

1. On the robot's MCP server, choose **Authentication → OAuth**. The secret fields disappear — there is
   nothing to fill in.
2. **Save the robot** (the connection is stored per robot + server name).
3. Click **Connect**. A neutral authorization window opens immediately; keep it open. When the platform
   receives the provider address, that window navigates to the provider's **consent screen** in an
   isolated context — the provider cannot access the Studio tab. Sign in and authorize.
4. The window closes itself when it is done and the status flips to **Connected** (with the expiry and
   the granted scope, when the provider reports them). If it remains open after the provider confirms,
   close it so the Studio can check the status. If the browser blocks the window, allow popups for this
   site and try again.
5. Click **Discover** and carry on: the server's tools now apply to the robot.
6. **Disconnect** forgets the credentials of that robot + server pair. To switch provider account:
   disconnect and connect again.

> OAuth credentials are stored **encrypted on Maestro**, tied to the robot + server pair. They are
> never stored in Conversa Labs, never shown on screens or logs, and never sent to the model.

## Settings & options

- **Profiles (MCP connections)** for the account: each profile has a name, a **static acting user**, a
  toolset selection, read-only mode, its **static URL** (with a `public_id`) and its **own bearer secret**
  (revealed once, rotatable). The static effective selection is always
  `selection ∩ Super Admin ceiling ∩ acting user's permissions`.
- **Native account OAuth (conditional)**: the OAuth resource is the separate
  `/mcp/oauth/c/PUBLIC_ID` URL. It uses the same profile tool surface but the consenting account member,
  not the static acting user. Its grants are visible/revocable in **Settings → Profile → MCP connections**;
  existing grants remain visible for revocation if the server is later disabled.
- **Read-only mode**: per profile, exposes only read tools.
- **ChatGPT deep research compatibility**: per profile, adds the two tools `search` and `fetch` that this
  connector requires by name. They only describe what the profile already exposes. They cost **two slots
  of the tool limit** (the server reserves four instead of two when it is on), so leave it off for Claude
  and generic clients.
- **Tool cap**: there is a per-server cap (512), applied **per profile** — it caps the **listing**, not
  the access. The `search_tools` (discover, with the schema) and `call_tool` (run it by name) meta-tools
  reach everything the profile enabled, still honouring read-only mode, the acting user's permissions
  and the Super Admin ceiling.
- **Maestro token**: one per account, revealed once, rotatable at any time.
- **External servers per robot**: technical name, URL, transport, timeout, authentication, extra
  headers, approval (HITL) and a tool allowlist.
- **Authentication types (external server)**:

  | Type | How it works | When to use it |
  |---|---|---|
  | none | nothing is sent | genuinely public servers (rare) |
  | bearer | sends `Authorization: Bearer <secret>` | the most common case — the secret holds the API key |
  | header | sends a header whose name you choose, valued from the secret | the provider uses its own scheme |
  | query | sends the secret as a URL parameter | legacy providers |
  | basic | username + password (two secrets) | internal servers |
  | OAuth | **Connect** button → consent on the provider | the provider only accepts OAuth (Notion) |

- **Tool budget**: the tools of each external server **count towards the robot's tool budget** — too
  many servers blow the limit.
- **SSRF guard**: private/internal addresses are **blocked** when adding an external server.

## Use cases

- Operate the inbox from Claude Code or an IDE: list conversations, reply, resolve.
- **One profile per client**: each IDE, script or partner gets its own connection, with a minimal scope
  and — for read-only clients — read-only mode on.
- Pull the account's reports into an assistant through a **read-only** profile, run by a restricted
  acting user.
- **Revoke a single client**: rotate (or delete) that client's profile — every other profile keeps
  working.
- Give a robot access to an internal system (ERP, knowledge base) through an external MCP server, with
  human approval on sensitive actions.
- Let the robot open Linear issues or read a Notion base while it is handling a conversation.
- Let the data team ask `ask_risk` / `ask_finance` and get the department's findings without opening
  the dashboard.

## Tips, limits & best practices

- **Which authentication to pick per popular external server** (most of them answer 401 with an OAuth
  challenge, **yet also accept a plain API key** in `Authorization: Bearer` — leaving it on *none* is
  the number-one cause of a failed discovery):

  | External MCP server | Authentication to pick |
  |---|---|
  | Linear | **bearer** + secret holding the API key |
  | Stripe | **bearer** + secret holding the restricted API key |
  | GitHub | **bearer** + secret holding a personal access token (PAT) |
  | Atlassian (Jira/Confluence) | **bearer** + secret holding the API token |
  | Sentry | **header** named `Authorization`, with a secret whose **value** is `Sentry-Bearer YOUR_TOKEN` |
  | Notion | **OAuth** (**Connect** button) — no static key accepted |
  | Your own internal server | whatever the server requires |

- **Static secret versus OAuth consent**: the static profile secret carries the **static acting user's**
  permissions — never more than they already have. A native OAuth grant instead runs as the consenting
  account member and is bound to its exact OAuth resource. Treat either value as a credential and never
  swap them between the two URLs.
- **One profile per client**: that way you give each one a minimal scope and can rotate/delete a profile
  to cut off just that client, without touching the others.
- **Read-only first**: start each profile with read-only mode on and enable writes per toolset as you
  trust the client.
- **Less is more**: expose only the toolsets the client really uses — huge tool lists degrade the
  model's choices.
- **Copy the profile secret immediately**: it is never shown again. Lost it? Rotate the profile's token
  (the old one is invalidated instantly) and update the client that used it.
- **Secrets by reference**: on external MCP servers, never paste the secret value into the field —
  enter the secret's **key**.
- **Copy the Maestro token immediately**: it is never shown again. Lost it? Rotate (and update the
  clients that used the old one).
- **Approval (HITL)**: for external servers that write to critical systems, tick **Require approval**.

## Troubleshooting

- **The client shows fewer tools than the modules I enabled in the profile**: that is the server's
  **display cap**. The rest stay reachable: have the client use `search_tools` (finds the tool and
  returns its input schema) and `call_tool` (runs it by name). To see them in the list, uncheck modules
  or ask the operator to raise the cap.
- **The Maestro card shows an internal address (amber warning)**: the installation never declared
  Maestro's public address. A client on the same machine connects; an IDE outside the network does not.
  The operator must set `MAESTRO_PUBLIC_BASE_URL` to Maestro's public address (and restart the app).
- **The client connects to Maestro's public address and gets "Invalid Host header" (or a 421)**: Maestro
  only accepts the Host the installation declared. It is the same `MAESTRO_PUBLIC_BASE_URL` — once it is
  set, the public host is accepted (DNS-rebinding protection stays on).
- **A connector still shows an old or generic icon**: confirm the canonical public HTTPS origin and icon
  URL load without authentication, save the White Label settings, then reconnect the provider so it runs
  `initialize` again. The server preserves the last valid mark while Maestro retries a temporary outage;
  a provider may still cache or choose not to display its icon metadata.
- **The MCP page is not in the menu**: the **MCP** feature is off for the account (ask the operator) or
  your user is not an administrator.
- **404 on the connection endpoint**: the feature is off for the account, the installation's global
  switch is disabled, or the URL's `PUBLIC_ID` does not exist (the profile was deleted or disabled).
- **401 on the account connection**: the profile secret is wrong or was rotated (the previous one is
  invalidated instantly), the profile was deleted/disabled, or the acting user lost account membership.
  Use the secret revealed when you create/rotate the profile — a personal API token and a robot token are
  **not** this connection's credential.
- **A static client tries to log in through OAuth:** the static account URL ends in
  `/mcp/c/PUBLIC_ID` and accepts only its profile secret in `Authorization: Bearer ...`; it does not
  advertise an OAuth server. Keep that client on the static Bearer configuration.
- **The OAuth resource or discovery returns 404:** native OAuth is intentionally dark-shipped. Check the
  native OAuth enablement, the account MCP feature/profile and the public issuer first, then begin again
  at the exact Protected Resource Metadata URL. Do not substitute a static secret or a different
  authority-plane token.
- **The OAuth URL returns 401:** the OAuth bearer is missing, expired, revoked, or belongs to a different
  resource/authority plane. Read `WWW-Authenticate`: it identifies the exact Protected Resource Metadata
  (and includes `invalid_token` only when a supplied Bearer was rejected). Restart from that metadata;
  never paste the profile's static secret into this URL.
- **The OAuth URL returns 403:** the bearer is valid, but the call requested a write-capable tool without
  `mcp:write`. Request that scope during consent and confirm that the profile is not read-only; `mcp:write`
  still does not expose tools outside the profile.
- **The OAuth URL returns 413:** the JSON-RPC request or response exceeds 1 MiB. Reduce the payload or
  paginate. An oversized request is rejected before execution; a large response is measured only after the
  operation returns, so do not blindly retry a write — inspect the resource or audit trail first.
- **An OAuth-capable client still cannot complete consent:** record the client and version, redirect URI,
  discovery result and safe error code in a controlled test. Do not bypass PKCE, resource binding or
  browser consent; compatibility is only established after an end-to-end proof.
- **Toolset greyed out with a “blocked” badge**: the Super Admin did not allow that toolset in the
  global ceiling. Only they can release it.
- **Lost the profile secret**: generate a new one with **Rotate token** on the profile — the previous
  one is invalidated instantly.
- **Lost the Maestro token**: generate a new one with **Rotate token** on the Maestro card — the
  previous one is invalidated instantly.
- **Discovery (“Discover”) fails with 401**: authentication is almost always still on **none**. Pick
  **bearer** and point the secret at the provider's API key (Sentry uses **header**; Notion uses
  **OAuth**).
- **Discovery fails for another reason**: check the URL, the transport (Streamable HTTP or SSE) and the
  credentials; save the robot first if auth uses a stored secret; private/internal addresses are
  refused by the SSRF guard.
- **The Connect button opens nothing**: the browser blocked the pop-up — allow pop-ups for the domain
  and click again.
- **Connected, but the tool fails after a while**: the provider's authorization expired —
  **Disconnect** and **Connect** again.
- **An external tool fails at runtime**: the error comes back as text to the agent (which
  self-corrects) and never crashes the turn.
- **`ask_<department>` answers “disabled”**: the department is disabled for the account — enable it on
  the Account Brain screen.

## See also

- [Dashboard Apps SDK, REST API and MCP](/hc/ajuda/articles/api-developers-dashboard-apps-sdk-rest-mcp-en)
- [API reference (Swagger/OpenAPI)](/hc/ajuda/articles/api-developers-swagger-reference-en)
- [REST tokens, webhooks and authentication](/hc/ajuda/articles/api-developers-rest-tokens-webhooks-en)
- [Bots and the API channel](/hc/ajuda/articles/api-developers-agent-bots-and-api-channel-en)