Create an MCP server

View as Markdown
Registers an MCP server with the voice engine and stores it for the workspace. There are two ways to create one. A **custom server** needs `name` and `serverUrl`. Its approval mode defaults to `always_ask` and its transport to the voice engine's default (SSE) unless you send `transport`. Most hosted MCP servers speak streamable HTTP: with the wrong transport the server registers but never answers a tool call. A custom server reaches no agent until you call `POST /api/agents/{agentId}/mcp-servers`. A **hosted provider** (`provider`: `zapier`, `alegra` or `make`; see `GET /api/mcp-servers/providers`) needs only its token in `secretToken`: name, description, endpoint, transport (`STREAMABLE_HTTP`) and approval mode (`no_approval`) come from the catalogue. Make hosts per region, so `serverUrl` is required for it. Alegra authenticates with HTTP Basic: send `usuario:token` as `secretToken`. A provider URL pasted without `provider` is recognised from its host and held to the same rules; a token found in its query string or path is moved into the secret so the stored URL never carries a credential. A hosted provider server is attached to every provisioned agent right away (agents at their plan cap, or still provisioning, are skipped silently). Refused with `400` and the field in `details.fieldErrors`: a `transport` other than the provider's, a missing token, a `serverUrl` on another host than the provider's, a malformed Alegra secret, or a URL that is not `http(s)` or targets a private/internal address. `toolOverrides` requires `approvalMode: fine_grained`, accepts at most 50 entries and rejects `disabled` (these three answer `400` without `details`). When decisions are sent, the response carries `toolOverridesSync`; if any failed to apply the status is `207` instead of `201`, the server is still created, and `toolOverrides` shows only what was applied. **Side effects.** Creates the server in the voice engine and pushes per-tool approval decisions; with a hosted provider, also updates every agent's MCP server list in the voice engine. The token and custom headers are stored encrypted. Writes an `mcp.manage` audit entry. **Idempotency.** Not idempotent. A retry registers a second, independent server (and, for a hosted provider, attaches that copy to every agent too, using another slot of each agent's cap). After a timeout, check `GET /api/mcp-servers` before retrying. **Webhook events.** `audit.log_recorded` for the audit entry, if you subscribe to it. See [Webhooks](/webhooks). **Access** - **Required scope:** `write`. Any workspace role. - **Rate limit:** General API — 120 (Starter), 200 (Growth), 300 (Business) or 600 (Enterprise) requests/min per workspace, checked by two counters of the same size. See [Rate limits](/rate-limits). - **Plan:** Available on every plan. Automatic attachment of a hosted provider respects the MCP-servers-per-agent cap (Starter 1, Growth 3, Business 10).

Authentication

AuthorizationBearer
Workspace API key: `jl_` followed by 64 lowercase hex characters, created by the workspace owner in the dashboard (**Settings → API Keys**) and sent as `Authorization: Bearer jl_...`. The plaintext is shown once, at creation; Jelliu stores only a SHA-256 hash. A workspace can hold up to 25 active keys. | Scope | GET / HEAD | POST / PUT / PATCH / DELETE | Admin-only routes | | --- | --- | --- | --- | | `read` | Yes | No | No | | `write` | Yes | Yes | No | | `full` | Yes | Yes | Yes | Operations restricted to admins or owners reject keys without the `full` scope with `403`, and say so in their description. No key, whatever its scope, can mint or revoke API keys or rotate a webhook secret — that requires a signed-in owner session. A revoked key stops authenticating within about 10 seconds. See [Authentication](/authentication).

Request

Unknown keys are ignored. Empty or whitespace-only strings are treated as absent.

providerenumOptional

Hosted provider preset: zapier, alegra or make. When set, name and description are optional and default to the provider’s.

Allowed values:
namestringOptional1-200 characters

Display name, trimmed. Required without provider.

descriptionstringOptional<=2000 characters

Sent to the voice engine and read by the agent to decide when to use the server’s tools. Defaults to the provider’s agent-facing description when provider is set.

serverUrlstringOptionalformat: "uri"<=2000 characters

The server’s MCP endpoint (http or https). Required without provider, and for make. Must not target localhost or private/internal addresses; with a provider it must be on the provider’s host.

secretTokenstringOptional<=2000 characters

Credential, stored encrypted and never returned. Sent to the server as Authorization: Bearer <token>, or as HTTP Basic for alegra (send usuario:token). Required with a provider unless customHeaders already carries Authorization.

customHeadersmap from strings to stringsOptionalDefaults to {}

Extra HTTP headers sent to the server on every request (at most 20; names up to 200 characters, values up to 2000). Stored encrypted and never returned.

approvalModeenumOptional

Approval policy for the server’s tools: always_ask, fine_grained or no_approval. Defaults to always_ask for a custom server and to no_approval with a provider.

Allowed values:
transportenumOptional

SSE or STREAMABLE_HTTP. Fixed to STREAMABLE_HTTP for providers (a different value is refused). Omitted on a custom server, the voice engine’s default (SSE) applies and transport is stored as null.

Allowed values:
toolOverridesmap from strings to enumsOptionalDefaults to {}
Per-tool approval keyed by the tool name the server advertises: `auto_approved` or `requires_approval`. Only with `approvalMode: fine_grained`; at most 50 entries; `disabled` is rejected with 400 (remove the assignment instead). A tool the server does not advertise is reported in `toolOverridesSync.failures`.
Allowed values:

Response

Created. toolOverridesSync is present only when per-tool decisions were sent.

dataobject

A single MCP server as returned by the create, retrieve and update endpoints: the summary fields plus deleted_at and the applied per-tool decisions. secret_token and custom_headers are never returned.

toolOverridesSyncobjectOptional

What happened when per-tool decisions were pushed to the voice engine. Present only when decisions were sent, or re-applied after a re-registration or cleanup of legacy values.

Errors

400
Bad Request Error
401
Unauthorized Error
403
Forbidden Error
429
Too Many Requests Error
500
Internal Server Error
502
Bad Gateway Error