Agents eagerly spawn every configured MCP server, no per-agent toggle or lazy-start
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Problem
Every loaded agent (one `buzz-acp` process per agent, e.g. multiple personas active in one Buzz Desktop instance) eagerly spawns a full `claude-agent-acp` worker process for **every** MCP server configured in the user's global `~/.claude/settings.json` + `~/.claude.json` — there is currently no way to scope which connectors a given agent needs, and no lazy-start path.
Observed impact: 5 concurrently loaded agents × ~10 configured MCP servers (Gmail, Linear, Figma, Notion, Supabase, Atlassian Rovo, Playwright, context7, etc.) × ~100MB/worker ≈ 5GB resident RAM before any agent does actual work, which pushed a 15GB dev laptop into swap and caused a multi-minute freeze.
## Root cause (traced in source)
**No per-agent MCP filtering:**
- `desktop/src/features/agents/ui/AgentDefinitionDialog.tsx` (agent-edit UI) has no MCP-related controls at all.
- A per-persona MCP merge mechanism exists — `crates/buzz-persona/src/resolve.rs::merge_mcp_servers()` (~line 275), merging a pack's `.mcp.json` with per-persona frontmatter `mcp_servers:` — but it's only invoked once, at team-pack import time (`desktop/src-tauri/src/migration.rs:1128`), never applied to live agent sessions.
- Live sessions build their MCP list via `crates/buzz-acp/src/lib.rs::build_mcp_servers()` (~line 4827), which only emits Buzz's own internal relay MCP server — the user's actual connectors are pulled in unfiltered elsewhere.
- `desktop/src-tauri/src/managed_agents/config_bridge/claude.rs::read_config_file()` reads `~/.claude/settings.json` + `~/.claude.json` and marks every `mcpServers` entry `enabled: true` unconditionally (read-only display, not a filter).
- Net effect: every "claude" runtime agent inherits the user's **entire global** connector list, with no override.
**No lazy MCP-server start:**
- `crates/buzz-agent/src/mcp.rs::McpRegistry::spawn_all()` (~line 202) spawns every configured server synchronously at session start.
- `BUZZ_ACP_LAZY_POOL` (`crates/buzz-acp/src/config.rs`, `desktop/src-tauri/src/managed_agents/runtime.rs:533`) only defers spawning the whole agent harness process, not individual MCP servers within it.
- The vendored `@agentclientprotocol/claude-agent-acp` npm package (under `~/.local/share/Buzz/node-tools/lib/node_modules/`) eagerly resolves and merges `mcpServers` in `dist/settings.js::SettingsManager` / `dist/acp-agent.js:4450`. Its own dependency, `@anthropic-ai/claude-agent-sdk`, already exposes `toggleMcpServer(name, enabled)` / `reconnectMcpServer(name)` control-protocol methods — but `claude-agent-acp` never calls or exposes them over ACP, so Buzz has no hook into lazy start/stop today.
## Suggested fix
1. Add a per-agent MCP server allow-list (surfaced in `AgentDefinitionDialog.tsx`, persisted per agent, applied wherever the live session's MCP list is actually assembled — needs tracing beyond `build_mcp_servers()`, since that function currently only handles Buzz's internal relay server).
2. Have Buzz's ACP bridge call the SDK's existing `toggleMcpServer`/`reconnectMcpServer` hooks to defer starting a connector's worker process until an agent actually invokes one of its tools, instead of eager-spawning all of them at agent load.
## Workaround (no code change)
Trim the `mcpServers` list in `~/.claude/settings.json` / `~/.claude.json` — since every agent currently shares that one global list, cutting it there reduces resident workers for all loaded agents at once. Not a real fix since it's global rather than per-agent, but it's the only lever available today.
---
Filed from investigation in a Buzz Desktop dev-build session, prompted by a real RAM/swap-induced freeze with 5 agents loaded simultaneously.
Contributor guide
Research direction
Start by tracing the live session path from desktop/src/features/agents/ui/AgentDefinitionDialog.tsx through crates/buzz-acp/src/lib.rs::build_mcp_servers() and crates/buzz-agent/src/mcp.rs::McpRegistry::spawn_all(). Read the Claude bridge files and the vendored claude-agent-acp settings and ACP code to identify where per-agent selection and SDK controls can connect. Done means each agent can use an allow-list and MCP workers no longer all start eagerly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, rust, typescript
- Domain
- desktop, devtools, performance
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100