# v1.15.0-mcp-multi — design decisions ## D1. Config file path `/data/mcp.json` (alongside `AGENTS.md` at `/data/AGENTS.md`). Both are bind-mounted from the host's `data/` directory. Override via `MCP_CONFIG_PATH` env var. File missing = no MCP (opt-in by file presence, not by env var). Simpler than the v1.14.1 approach of always-defaulting a URL. ## D2. Config schema matches opencode's `mcpServers` shape opencode uses `~/.opencode/config.json` with a `mcpServers` key. BooCode uses `mcp.json` with the same `mcpServers` key so server entries are copy-pasteable. Property names match: `type`, `url`, `command`, `args`, `env`, `headers`. BooCode adds `enabled` (boolean toggle per server, default true) which opencode doesn't have — harmless extra key. ## D3. Transport types: streamableHttp + stdio only - **streamableHttp**: For remote servers (Context7, future cloud MCP services). Uses `@modelcontextprotocol/sdk`'s `StreamableHTTPClientTransport`. - **stdio**: For local subprocess servers (codecontext, future local tools). Uses `@modelcontextprotocol/sdk`'s `StdioClientTransport` (spawns child process, NDJSON framing over stdin/stdout). - **SSE**: Skipped. Streamable HTTP supersedes SSE per the MCP spec (May 2025 protocol update). If a legacy server requires SSE, it can be added later. ## D4. Tool name prefixing: `_` Generalizes v1.14.1's `context7_` pattern. Server name comes from the config key (e.g. `"context7"`, `"codecontext"`). Collisions between servers with the same name are impossible (config keys are unique). Collisions between an MCP tool and a native tool are possible if someone names a server entry the same as a native tool prefix — but that's a user-configuration error, not a code bug. ## D5. Per-agent glob patterns: last-match-wins AGENTS.md `tools:` field already supports exact-match arrays. Globs extend the same field: ```yaml tools: [view_file, grep, context7_*] ``` Evaluation: for each tool in `ALL_TOOLS`, scan the pattern list left-to-right. A `!` prefix denies. Last matching pattern wins. This matches the roadmap's "wildcard rule matcher" language. Examples: - `[*]` — all tools (same as omitting `tools:` entirely) - `[*, !web_*]` — all tools except web - `[view_file, grep, context7_*]` — only view_file, grep, and all Context7 tools - `[*]` on Architect + `[view_file]` on Prompt Builder — each agent gets its intended scope Globs use a simple `minimatch`-style check: `*` matches any characters. No `?` or `**` — tool names are flat (no path separators). ## D6. No DB tables in v1.15 The roadmap listed `permissions`, `agent_permissions`, `session_permissions`, `mcp_servers` tables. All deferred to v2.0: - **Permission tables**: Enterprise multi-user pattern. BooChat is single-user behind Authelia. The read-only invariant guard is the BooChat-era defense. Formal permission rulesets land when BooCoder adds write tools. - **`mcp_servers` table**: In-memory registry is sufficient. No need to persist server state to DB when the config file is the source of truth and tools are re-discovered on every boot. ## D7. Stdio child lifecycle - Spawn on `initialize()`. Persistent connection for server lifetime (not per-call). - On child exit (unexpected): mark server unavailable, log error. Do NOT auto-restart. BooCode continues with remaining servers. - On BooCode shutdown (`app.addHook('onClose')`): send SIGTERM to all stdio children. Wait up to 5s, then SIGKILL. - On ENOENT (command not found): skip server with a warning. Matches the graceful-degradation pattern from v1.14.1. ## D8. v1.14.1 env vars removed `MCP_CONTEXT7_URL` and `MCP_CONTEXT7_API_KEY` are deleted from `config.ts`. They're superseded by the JSON config file's `context7` entry. The PoC was explicitly designed as throwaway. Migration path for anyone who had the env vars set: add a `data/mcp.json` with the Context7 entry. The CHANGELOG entry will note this.