# v1.15.0-mcp-multi tasks ## B1 — Backups - [ ] `mcp-client.ts`, `config.ts`, `index.ts`, `agents.ts`, `mcp-client.test.ts` ## B2 — MCP config file schema + loader - [ ] NEW `apps/server/src/services/mcp-config.ts` (~50 lines) - [ ] Zod schema for `mcp.json`: `McpServerConfig` with `type`, `url/command/args/env`, `headers`, `enabled` - [ ] `loadMcpConfig(configPath: string, log): McpServerConfig[]` — reads JSON, validates, returns enabled servers - [ ] Graceful: file missing → log info, return empty array (no MCP) - [ ] Graceful: parse error → log warn with details, return empty array ## B3 — Config.ts: replace MCP env vars - [ ] Remove `MCP_CONTEXT7_URL` and `MCP_CONTEXT7_API_KEY` from Zod schema - [ ] Add `MCP_CONFIG_PATH: z.string().optional()` (no default — opt-in) ## B4 — Refactor mcp-client.ts to multi-server registry - [ ] Replace module-level singleton with `Map` - [ ] `initialize(servers: McpServerConfig[], log)` — iterate servers, connect each, discover tools, wrap with `_` prefix, apply read-only guard - [ ] Streamable HTTP transport: reuse existing pattern from v1.14.1 - [ ] Stdio transport: use `@modelcontextprotocol/sdk`'s `StdioClientTransport` (check SDK exports; fallback to `child_process.spawn` + NDJSON if SDK doesn't expose it) - [ ] `callTool(prefixedName, args)` — extract server name from prefix, route to correct client - [ ] `getTools()` — return all tools from all servers, flattened - [ ] `getMcpServers()` — return status of each server (name, type, toolCount, connected) - [ ] Per-server graceful degradation: catch per-server errors, log, skip; continue with others - [ ] `shutdown()` — kill stdio child processes, close HTTP clients - [ ] `app.addHook('onClose')` calls shutdown ## B5 — Startup wiring (index.ts) - [ ] Read config: `const mcpConfigPath = config.MCP_CONFIG_PATH ?? '/data/mcp.json'` - [ ] `const mcpServers = loadMcpConfig(mcpConfigPath, app.log)` - [ ] `await mcpClient.initialize(mcpServers, app.log)` - [ ] `appendMcpTools(mcpClient.getTools())` - [ ] Log summary: "mcp: N servers connected, M tools registered" - [ ] `app.addHook('onClose', () => mcpClient.shutdown())` ## B6 — AGENTS.md glob patterns - [ ] `apps/server/src/services/agents.ts` — in tool whitelist validation, skip validation for entries containing `*` (can't validate against runtime-discovered tools) - [ ] NEW helper `matchToolGlob(toolName: string, patterns: string[]): boolean` — supports `*` wildcard and `!` deny prefix, last-match-wins - [ ] Wire into `executeStreamPhase` (stream-phase.ts) where agent tools are filtered: replace exact-match `.includes()` with `matchToolGlob()` - [ ] Export `matchToolGlob` for test access ## B7 — Example config file - [ ] NEW `data/mcp.json` with Context7 entry (enabled: true, with URL, no API key) - [ ] Comment in the file noting it's bind-mounted at `/data/mcp.json` inside the container ## B8 — Tests - [ ] Update `mcp-client.test.ts` for multi-server wrapping (tools from two servers, prefix routing) - [ ] Test: server A fails, server B succeeds — only B's tools registered - [ ] Test: callTool routes to correct server by prefix - [ ] Test: shutdown kills stdio transports - [ ] NEW `apps/server/src/services/__tests__/mcp-glob.test.ts` - [ ] Test: exact match ("grep" matches "grep") - [ ] Test: wildcard ("context7_*" matches "context7_query-docs") - [ ] Test: deny ("!web_*" excludes "web_search") - [ ] Test: last-match-wins ("*" then "!web_*" → web tools excluded) - [ ] Test: empty pattern list → nothing matches (agent gets no tools — same as current behavior for explicit whitelists) ## B9 — Verification - [ ] `npx tsc --noEmit -p apps/server` — 0 errors - [ ] `pnpm -C apps/server test` — all passing - [ ] `pnpm -C apps/web build` — green (no web changes) ## B10 — Deploy + smoke - [ ] Create `/data/mcp.json` on the host with Context7 enabled - [ ] Update docker-compose bind mount if needed (data/ already mounted) - [ ] `docker compose up --build -d` - [ ] Check logs for multi-server init - [ ] Live-smoke: Context7 tool call from chat - [ ] Disable Context7 in config, restart, confirm zero MCP tools ## B11 — Docs + tag - [ ] `CHANGELOG.md` entry - [ ] `boocode_roadmap.md` retrospective bullet on v1.15 section - [ ] `CLAUDE.md` — update MCP references - [ ] Commit, tag `v1.15.0-mcp-multi`, push, rebuild