bonsai

MCP servers

bonsai connects to Model Context Protocol servers over stdio (a spawned child process) or Streamable HTTP, discovers their tools at startup, and exposes each as a namespaced tool the model calls like a built-in — behind the same permission engine, with every result framed as untrusted data.

Configuration

[mcp.servers.<name>] entries in .bonsai/config.toml (project entries replace same-named global ones wholesale; project config requires workspace trust):

# Local filesystem server over stdio.
[mcp.servers.filesystem]
transport = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "./docs"]
capabilities = ["read"]          # declared read-only ⇒ lower risk tier
batching = "path_scoped"         # opt out of the serialized default
allow_tools = ["read_file", "list_directory", "search_files"]
timeout_secs = 20

# Remote docs server over Streamable HTTP.
[mcp.servers.context7]
transport = "http"
url = "https://mcp.context7.com/mcp"
headers = { Authorization = "Bearer ${CONTEXT7_API_KEY}" }  # env-expanded at connect, never stored expanded
capabilities = ["network"]

# OAuth-protected remote server — no token in this file; run /mcp auth workspace.
[mcp.servers.workspace]
transport = "http"
url = "https://mcp.example.com/mcp"
# oauth_client_id = "bonsai-public-client"   # optional; may be a Client ID Metadata Document URL
# oauth_scopes = ["mcp:tools"]
capabilities = ["read", "write", "network"]

# Parked entry — kept but not connected.
[mcp.servers.github]
transport = "stdio"
command = "docker"
args = ["run", "-i", "--rm", "-e", "GITHUB_TOKEN", "ghcr.io/github/github-mcp-server"]
enabled = false
Field Required Meaning
transport yes "stdio" or "http"
command, args, env, cwd stdio how to spawn; ${VAR} in env expands at connect time
url, headers http endpoint + headers (${VAR}-expanded the same way)
oauth_client_id, oauth_scopes http, optional public client id (or Client ID Metadata Document URL) and scopes for servers without dynamic registration; no client secret is ever stored
enabled no default true; false parks the entry
allow_tools no tool-name allowlist; empty exposes every discovered tool
capabilities no any of read, write, network, shell, irreversible, untrusted_output — see below
batching no "serialized" (default) or "path_scoped"
timeout_secs no per-call timeout, default 30

Namespacing and identity

Trust and gating

OAuth

/mcp auth <server> [file|keyring|session] runs the MCP protected-resource/authorization-server discovery flow:

Commands

bonsai doctor --online probes enabled servers’ reachability; results report only service names, versions, and pass/fail.

Where this lives in the code

Concern Location
Hub, discovery, registration src/mcp/mod.rs
Transport clients src/mcp/client.rs
The dynamic tool wrapper src/mcp/tool.rs
OAuth src/mcp/auth.rs
Capabilities → policy src/extension/capabilities.rs
Shared gate & status registry src/extension/gate.rs, src/extension/status.rs
/mcp command src/commands/mcp_cmd.rs