Repository navigation
Description
Description
When a user adds or modifies a provider in their opencode.json, ALL MCP servers restart and re-activate — including ones explicitly disabled via the /mcps toggle. This forces unwanted tools into the context window, increases token consumption, and confuses the agent.
The root issue is that the MCP disabled state is only in-memory (s.status[name]) and is never persisted to disk. Any config change that triggers an Instance reload wipes this state, causing all MCPs to come back enabled.
Steps to reproduce
- Configure multiple MCP servers in
opencode.json - Disable some via
/mcpstoggle (press Space) - Edit
opencode.jsonto change a provider (e.g., switch fromopencode-gotoopenai) - Restart OpenCode (or trigger config reload)
- Run
/mcps— all previously disabled MCPs are now enabled again
Technical Root Cause
The disabled state is only stored in-memory in packages/opencode/src/mcp/index.ts:
- Toggle path:
MCP.disconnect()setss.status[name] = { status: "disabled" }(in-memory only) - Init path:
MCP.state()only reads fromcfg.mcp(config file) — no persisted disabled state consulted - Reload: Config change →
markInstanceForDisposal()→ fullInstance.disposeAll()→ freshMCP.state()→ disabled state lost
Compare with model selection, which already persists to disk via Global.Path.state/model.json — the pattern already exists in the codebase.
Expected Behavior
MCP disabled state should survive:
- Provider config changes (Instance reload)
- OpenCode restarts
/reloadcommand (once feat: add /reload slash command #9871 is merged)
Impact
- Context window: Users with many MCPs keep most disabled to save tokens. Reactivation wastes ~20-65K tokens per session.
- UX friction: Users must manually re-disable MCPs after every provider config change.
- Security surface: MCPs like
chrome-devtools(browser launch) andmorphllm-fast-apply(remote npm code) remain active against user intent.
Proposed Fix Direction
Persist disabled MCP IDs to a state file (e.g., mcp-state.json in Global.Path.state), same pattern as model.json. Read it during MCP.state() init. No changes to Instance lifecycle or reload mechanism needed.
Related Issues / PRs
- Disabling MCPs doesn't persist across sessions #13763 — "Disabling MCPs doesn't persist across sessions" (same root cause, cross-session focus)
- [FEATURE]: Let LLM enable MCP on demand, default all MCPs off #7466 — "Let LLM enable MCP on demand, default all MCPs off"
- feat: add /reload slash command #9871 — PR:
/reloadcommand (hot reload, not yet merged) - [FEATURE]: Allow disabling built-in MCP servers (chrome-devtools, morphllm-fast-apply) #22188 — "Allow disabling built-in MCP servers"
Operating System
Windows 11
Terminal
Windows Terminal
Activity
github-actions commentedon May 20, 2026
This issue might be a duplicate of existing issues. Please check: