Skip to content

feat(mcp): connected tools, the owner's own MCP servers for chosen bots - #202

Merged
httpsphl merged 10 commits into
mainfrom
feat/external-mcp
Oct 5, 2026
Merged

httpsphl merged 10 commits into
mainfrom
feat/external-mcp

Conversation

@httpsphl

@httpsphl httpsphl commented Oct 5, 2026

Copy link
Copy Markdown
Owner

What

Bots run with --strict-mcp-config, so an MCP server the owner added (a LinkedIn reader, an internal system) never loaded, and nothing said why. This adds connected tools (spec 25): only the owner can register one, in the app, and attach it to chosen bots. The generated mcp.json carries it; --strict-mcp-config stays.

  • Register and attach. mcp.servers, mcp.save, mcp.delete, bot.mcp.set. Nothing a bot can call registers or attaches a tool. A program (stdio) saves only after an "I understand and trust it"; an address (http) says what leaves the computer.
  • Secrets. Header and variable values live in secrets/mcp and in the environment of the attached bots only. mcp.json holds ${BOTLOFT_MCP_…}; the database, the rules and the log never see a value.
  • Approvals. The tools of these servers are not in --allowedTools: each use asks the owner. "Allow always" covers one tool of one server, for one bot, and goes when the server is deleted or renamed.
  • State. A bot with connected tools asks its process for mcp_status at start; the answer reaches the app as bot.mcp ("Connected" / "Did not connect", the reason under Details). The configuration in that answer carries expanded secrets and is never read.
  • App. Settings > Connected tools (paste the .mcp.json, edit name and purpose, remove), a switch per tool in a bot's details, texts in English, Portuguese and Spanish.

Spec section 25 is in the same PR, with 9.2, 12, 13, 18 and 19 updated.

Checked against Claude Code 2.1.287

Recorded in spec section 19, with a real claude -p and test servers: ${VAR} expands in env and in headers; a tool of the owner's outside --allowedTools reaches permission_prompt as mcp__<slug>__<tool>; system/init and the mcp_status control request report each server (status, and error when it fails), the latter before any turn.

Test

cargo fmt, clippy -D warnings and cargo test --workspace pass (new: store, workspace files, connected_tools and connected_tools_state against FakeRuntime). pnpm check passes (new: pasting, the settings page and the bot switches against FakeBotloft).

Manual step (needs the real Claude Code): run the dev daemon and app, connect a tool in Settings > Connected tools, turn it on for a bot, send the bot a message that needs the tool, and check that it asks for approval and that the tool runs. Then remove the tool and check that the bot restarts without it.

Not in this PR

  • The tools are not in the backup yet (spec 25.6 says the registration will be, the secrets will not).
  • Editing changes only the name and purpose; to change what a tool runs or its passwords, remove it and connect it again.
  • Sign-in by browser for remote servers, allowing a whole server at once and choosing some tools of a server (spec 25.8).

Bots run with --strict-mcp-config, so a server the owner added (LinkedIn,
an internal system) never loaded and nothing said why. Section 25 lets
only the owner register one in the app and attach it to chosen bots; the
generated mcp.json carries it, secrets stay in secrets/mcp and the bot's
environment, and every use still goes through permission_prompt.
…through its environment

The owner registers a server and attaches it to chosen bots; each
bot restarts to read it. Header and variable values live in
secrets/mcp and the bot's environment only. Spec 25.6 now names the
typed save params this uses.
The three open points of section 19 hold with a real claude -p:
expands in env and headers, the owner's tools reach permission_prompt
by their mcp__<slug>__<tool> name, and system/init reports each server.
…one at a time

A bot with connected tools asks its process for mcp_status when it
starts and the answer goes to the app as bot.mcp; the configuration in
the answer, which holds expanded secrets, is never read. Allow always
covers one tool of one server, and what was allowed goes when the
server is deleted or renamed.
… Claude Code 2.1.287

The fake daemon carries the new states.
…t's details

The owner pastes the settings of a tool, sees what it is and what it can
do on their computer, and says they trust it before a program is saved.
Each bot's details list the tools with how they came up and the reason
when one did not. Texts in English, Portuguese and Spanish.
@httpsphl
httpsphl merged commit 5576b38 into main Oct 5, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant