Attaching
mcps is a field of the agent config, alongside tools and kb_ids. Each entry
names an integration:
active and must be one that lends tools; Telegram is
refused with is not MCP-capable and cannot be attached as a tool. Attaching the
same integration twice in one config is refused too.
Attaching takes a publish. Live traffic runs the last published version, so
the tools are not in front of the model until you publish. Writes replace the
whole config, so read it, add to mcps, and send the result back:
The inline shorthand
An entry can carry a server definition instead of an id:custom_mcp integration and the entry
is replaced by {"integration_id": "…"} in the stored config. It is a
convenience for building an agent and its servers in one request, not a second
kind of attachment — read the config back and you will find the id. The
integration it made is an ordinary one, editable on the Integrations page, which
is where its tool approval lives. Inline servers are API-key-shaped only; an
OAuth provider has nowhere to keep a refresh token and must be a real
integration. Details in custom MCP servers.
Seeing what a server offers
GET /v1/integrations/{integration_id}/mcp-tools connects to the server and
lists everything it exposes. It is a live call, so it also proves the connection
works.
crm, that comes back as:
name is the server’s own name — that is what approval is keyed on.
exposed_name is what the model is shown — that is what a prompt has to say.
The two are the same string only when the namespace is blank, or when the
server’s names already start with it.
The listing is deliberately unfiltered: it is what you choose an approval
from, so it has to include the tools nobody has approved. An integration that is
not active answers 400; a server that cannot be reached answers 502 with the
underlying failure.
Approving tools
Which of a server’s tools an agent may call isallowed_tools on the
integration. It is approved once and shared by every agent attached to it.
nullmeans all of them. A new connection starts there.- A
PATCHreplaces the list wholesale. It is a set, not an accumulation: send the full list you want, every time. - It can never be empty. “Approve nothing” is not a state; that is what disabling the integration means, and an empty list would read as “no filter” to the MCP client — the exact opposite.
- It is live. Narrowing the list reaches every already-published agent on its next turn. There is nothing to republish.
mcp-tools instead.
Why narrowing is worth the trouble
Every approved tool is described to the model on every turn. A voice agent choosing from ninety tool descriptions is slower and less accurate than one choosing from six, and it pays for those descriptions in input tokens on each turn of every call. Some vendor servers expose a very large surface. Approve the handful the agent’s job actually needs.Approval matches the server’s own name
allowed_tools is filtered first, on the tool’s own name, and the namespace is
applied afterwards. So approve search, not crm_search — and changing the
namespace later never invalidates an approval.
Namespacing
The model does not see a server’s tool names raw. Each is prefixed with the integration’stools_namespace:
asana, hubspot,
google_calendar) and nothing for a custom server, which has no name to
derive one from.
The rules, all of them:
- A blank namespace leaves names untouched.
""is a real value meaning “the server’s own names”, not an unset field. - A tool that already starts with the prefix is not prefixed again. Tavily’s
own tools are
tavily_searchandtavily_extract, so they stay that way rather than becomingtavily_tavily_search. - The value must match
^$|^[a-z][a-z0-9_]{0,23}$— empty, or lowercase starting with a letter, up to 24 characters. - On a
PATCH, omitting the field keeps the current namespace and sending""clears the prefix. Those are different requests. Read the field back after any change you are not sure of.
Two servers cannot share a namespace
If two attached servers present their tools under the same prefix, every name they share reaches the model twice and the session dies before the agent speaks. So the config is refused when you save it:What happens on a call
The connection is made when the session starts, in parallel with everything else the agent needs. Each request to an MCP server — the tool listing at connect, and every tool call after it — has a five-second budget. A server that is down or slow to connect does not fail the call. The agent starts without that server’s tools and the failure is logged. From the caller’s side nothing is wrong; from the model’s side the tools simply are not in its list, and it will improvise around a prompt that still talks about them. This is the strongest argument for keeping the prompt honest about what the agent does when a lookup fails. A tool call that exceeds the budget comes back to the model as a failed tool call, and the model decides what to say. The native Google Calendar tools are the exception to all of this: they run against Google directly, with their own retry and error handling. For an OAuth provider, the access token is minted per request. If the provider answers 401, the token is refreshed once and the request retried; if that fails too, the integration is moved toneeds_reconnect and stays broken until someone
reconnects it.
In the dashboard
Integrations lists every connection with its status, the account it is signed in as, its namespace and how many of its tools are approved. Clicking a row — or Tools in its menu — opens the approval modal, which reads the live tool list, shows each tool under the name the model will see with the server’s own name beneath it, and saves the ticked names and the namespace together. The namespace field previews the exposed names as you type it. The modal will not save an empty selection. It says so: “Approve at least one tool, or disable the integration instead.”Field reference
Next
Custom MCP servers
Point an agent at a server you run yourself.
Google Calendar
The nine native calendar tools, and how to prompt an agent to book.
Prompting
Telling the model when to reach for a tool, and what to say while it runs.