Files
dguiducci efb5b1dc33
Nightly Build / build (push) Successful in 7m44s
feat: let an agent ask what its connectors are, instead of guessing
An agent that wanted to know which MCP servers it had called
`list_mcp_servers` — a tool that has never existed anywhere in this
repo — and got "unknown tool". It was not a random hallucination: the
prompt block says "the system prompt shows available servers", and
`render_mcp_list` returned an empty string when nothing was connected.
The model read a promise, found no table, and invented the discovery
tool the text implied. The `mcp` kinds of `list_items`/`toggle_item`
had been removed to close the §14 RCE vector, which was right for the
write half and left no read half at all.

So `list_items` gains `type: "mcp"` and returns the whole picture in
one call, split into four buckets that each answer a different
question: what is already loaded (call its tools directly), what is
ready for `activate_tools`, what is installed but unusable and why,
and what the user could still activate. Conflating the first two is
what produced the original failure, so they stay apart. Every entry
carries a derived note and a next step; when the step is a human one,
it says so and names the UI page, because there is no tool for it.

Read-only, and structurally so: `toggle_item` deliberately gains
nothing, and the new `McpDirectory` trait exposes exactly one method.
Enabling a connector from a tool is the thing §14 removed, and a wider
seam here is how it would come back. Deny-by-default survives the
report — an ungranted connector is not named at all, since a listing
of what to ask for is itself a leak — except for a catalogue manager,
who cannot administer what they cannot see.

Three sources answer three questions and none is redundant: the
registry says what exists and who may have it, the owner database says
what was activated, and the live runtimes say what is connected right
now — a row can read `ready` while its process is dead. The live half
reaches the tool through the turn's extension map, alongside the pool
and the fs view; with no live view the durable picture still renders,
so freshness is an improvement and never a precondition.

The static `__MCP_LIST__` table stays as it was, because it is frozen
per conversation for prompt-cache stability. Its empty case now says
so out loud and points at the tool.
2026-08-04 19:41:18 +01:00

45 lines
3.7 KiB
Markdown

# Connectors
A **connector** gives you tools that reach outside this instance — a mailbox, a calendar, a web search, a messaging account. Internally they are MCP servers, but nobody calls them that in the interface: the sidebar entry is **Connectors**, so use that word when talking to a user.
Before saying anything about which connectors exist or work, call `list_items({"type": "mcp"})`. It reports the real state for the person you are talking to, and its answer beats any assumption — including anything written below.
## Two kinds, and the difference is about whose account
- **Shared connectors** run centrally on the server, under credentials the admin owns (web search is the usual example). They are not tied to anyone's account, and everyone granted one gets the same thing.
- **Per-user connectors** run inside that person's own private container and are bound to *their* account. Gmail means their mailbox, never another member's. This is why setting one up needs them to sign in personally: an admin cannot do it on their behalf, and a grant only authorizes them to set it up.
## Who has one
Installing a connector hands it to everyone straight away, and the admin then removes it from whoever should not have it — the full rules, including the role switch that keeps children out of the automatic hand-out, are in [access.md](access.md).
Being granted a per-user connector is not the same as having it working: the person still has to activate it and sign in.
## Setting one up
All of it happens in the web UI, on the **Connectors** page in the sidebar. There is no way to do it by asking the assistant, and no tool for it — if someone asks you to enable, configure or activate a connector, explain the steps and let them do it.
1. Open **Connectors** and pick one from the list.
2. Activate it. Some connectors ask for a value (an API key, a URL); the form says which.
3. Finish the sign-in, if it needs one. Two shapes exist:
- **Sign-in with an account** (Gmail, Calendar): a button opens the provider's consent page in a browser, which ends by showing a code. Paste that code back into the connector's page. The round trip is deliberate — this instance has no public address for the provider to call back to.
- **Device pairing** (WhatsApp): the connector's page shows a QR code to scan with the phone app, the same way that app pairs any other device.
An admin has one extra job: the catalogue itself. New connectors are installed from the **Marketplace** (reached from the Add-connector menu on the Connectors page), and account-based sign-ins need the provider's credentials entered once, under **Sign-in providers**.
## When a connector does not work
`list_items({"type": "mcp"})` puts each one in a bucket and says what to do. The states worth recognising:
- **Waiting on a sign-in** — activated, but step 3 above was never finished, so there is no stored credential. Nothing will work until the person completes it.
- **Not running** — activated and configured, but its process is not up. Signing out and back in usually restarts it.
- **Available, never activated** — the person is allowed to have it but has not set it up yet.
A connector that is missing from the report entirely was never granted. That is the admin's call, so the answer is to ask them, not to look for a workaround.
## Using one
A connector's tools are not loaded until you ask for them: `activate_tools(["<id>"])` loads them for the rest of the session, and they are then called as `mcp__<id>__<tool>`. You do not need to explain any of this to the user — to them, the connector either works or does not.
See also: [access.md](access.md) for grants and roles, and [index.md](index.md) for the rest of the documentation.