feat(connectors): per-MCP enable/disable toggle in Settings UI (#1004)#1018
Merged
Conversation
d7d8c67 to
719851e
Compare
kovtcharov
previously approved these changes
May 8, 2026
Closes #1004. Part of #927. Builds on #976 (PR #998). Users can now temporarily disable a configured MCP connector without losing its credentials or per-agent grants. Toggle off the GitHub MCP during a sensitive code review, toggle back on without re-pasting the PAT — credentials and agent consent persist across the round-trip. Persistence already worked: ``mcp_servers.json`` carries a per-entry ``disabled`` flag and ``MCPClientManager.load_from_config()`` already skips disabled entries. This PR adds the API/UI/wiring to drive it. Backend: - ``McpServerHandler.set_enabled(connector_id, enabled)`` flips the ``disabled`` flag without touching keyring or grants. Reuses #976's atomic-write + chmod 0600 helpers; raises ``ConnectorsError`` on unknown / unconfigured ids - ``McpServerHandler.set_reload_callback`` setter so the FastAPI lifespan can attach a callback after the singleton handler imports - New endpoints ``POST /api/connectors/{id}/enable`` and ``/disable`` (CSRF-guarded, 400 on non-MCP types, 404 on unconfigured) - New SSE events ``connector.enabled`` / ``connector.disabled`` - ``_connector_summary`` exposes ``enabled: bool`` (defaults true for OAuth / not-yet-configured MCP so no spurious "Disabled" pills) - ``reload_all_session_agents_mcp`` broadcasts to every cached ChatAgent's per-instance MCPClientManager — wired as the handler's reload_callback at lifespan startup. Toggling takes effect live; no GAIA restart needed Frontend: - ``ConnectorRow.enabled: boolean`` on the wire - ``enableConnector`` / ``disableConnector`` API helpers - SSE consumer recognises ``'enabled' | 'disabled'`` reasons - Toggle row in MCPServerConfigureBody (only when configured), with helper text when disabled. Reuses existing ``.toggle-switch`` CSS - New ConnectorTileMenu (⋯) on each tile header for one-click enable/disable/disconnect without drilling in. Self-positioning popup, click-outside + Escape to close - New ``.connector-status.disabled`` pill in the tile header Tests: 30 new (12 handler + 14 router + 4 reload-wiring). Full connectors suite: 335 pass, 5 skipped, 1 pre-existing failure (test_oauth_pkce, unrelated).
The popup was using position:absolute inside .connector-tile which has overflow:hidden, clipping the dropdown entirely. Switch to position:fixed with coordinates from getBoundingClientRect() on the trigger button. Adds scroll+resize listeners (capture:true to catch the settings-page-body scroller) that reposition the popup while open so it stays anchored to the trigger as the user scrolls the Settings panel.
) Custom Python agents that bundle their own mcp_servers.json were invisible in Settings → Connectors — users had no way to see which servers were active without reading the file directly. A new read-only "Custom agent servers" section now appears below the managed connectors list. Each tile shows the server name, originating agent, Active/Disabled status, and expands to reveal the command + args and the config file path with an edit hint. No toggle or disconnect action — the agent's local JSON is the source of truth. Backend: GET /api/connectors/agent-mcps scans registered custom agents for mcp_servers.json, returns a flat list sorted enabled-first then alphabetical. Malformed files and non-dict entries are skipped gracefully. Frontend: AgentMcpServer type, listAgentMcps() API helper, AgentMcpsSection + AgentMcpTile components, and matching CSS. Tests: 10 new unit tests cover sorting, disabled flag, malformed JSON resilience, per-entry type guards, legacy 'servers' key, and the no-registry case.
) Neither entry had a built-in consumer: the File Agent and Web Agent use Python-native tool mixins (FileIOToolsMixin, FileSearchToolsMixin) and do not go through the connectors framework. Showing them as "Not configured" tiles confused users into thinking their File/Web agents needed setup. Custom agents that want file or web MCP access supply their own mcp_servers.json — visible in the new Custom Agent Servers section added in #1020. The catalog contract is now explicit in the module docstring: only entries with at least one built-in REQUIRED_CONNECTORS declaration belong here. Ledger test updated: KEPT_IDS shrinks from 5 → 3; the two removed ids move to DELETED_IDS with rationale comments.
50d3e34 to
3d90581
Compare
itomek-amd
approved these changes
May 11, 2026
pull Bot
pushed a commit
to bhardwajRahul/gaia
that referenced
this pull request
May 15, 2026
## Why this matters v0.18.0 ships agent memory v2 (hybrid-search second brain with LLM extraction and observability dashboard), ChatAgent split into three composable agents (Chat/FileIO/DocumentQA), parallel tool calls, and a Telegram adapter scaffold — plus fixes the RAG-on-PDF timeout with Gemma 4 that broke document Q&A since v0.17.6 and adds CI gates that enforce RAG quality baselines on every future PR. Full notes: `docs/releases/v0.18.0.mdx`. ## What's New - **Agent memory v2** ([amd#606](amd#606)) — Hybrid semantic + keyword search, LLM extraction, observability dashboard via SSE streaming ([amd#1032](amd#1032)). Per-user isolation enforced; extraction runs async so it doesn't add latency. - **ChatAgent split** ([amd#979](amd#979)) — `ChatAgent`, `FileIOAgent`, and `DocumentQAAgent` replace the monolithic class; each composable via `tools=`. Backward-compatible shim preserved. - **Parallel tool calls** ([amd#946](amd#946)) — Multiple `tool_calls` from a single LLM turn are executed concurrently, cutting round-trips for multi-tool workflows. - **Telegram adapter scaffold, Phase 0** ([amd#951](amd#951)) — `gaia telegram start|stop|status`, per-user session isolation, `[telegram]` extras. Phase 1 (message handling + allowed-users gate) tracked in [amd#889](amd#889). - **Connectors: per-MCP toggle + single-writer enforcement** ([amd#1018](amd#1018), [amd#998](amd#998)) — Disable individual MCP servers without removing them; concurrent writes serialised with actionable errors on contention. - **File navigation, web browsing, and write security** ([amd#495](amd#495)) — `FileSearchToolsMixin`, web browsing tool, and scratchpad mixin in `KNOWN_TOOLS`; write tools check `allowed_paths` before dispatch. - **Email UI and policy alerts** ([amd#995](amd#995), [amd#1039](amd#1039), [amd#952](amd#952)) — Pre-scan triage card, in-chat Connect, policy alert cards, and durable receipts for confirmation-gated actions. ## Bug Fixes - **RAG-on-PDF timeouts on Gemma 4** ([amd#1034](amd#1034), closes [amd#1030](amd#1030)) — Prompt-size budget check added at composition time; CI gates enforce it on every PR ([amd#1040](amd#1040)). - **Envelope-level parse failure crashed SD recovery** ([amd#1047](amd#1047), closes [amd#1023](amd#1023)) — Falls through to a clean recovery path with step-1 context preserved. - **Windows-path tool args corrupted** ([amd#1027](amd#1027)) — Backslash normalisation now happens after argument parsing. - **Blender `send_command` hung** ([amd#1026](amd#1026), closes [amd#1022](amd#1022)) — Read timeout applied to persistent-connection servers. - **`gaia chat init` in post-install banner** ([amd#1029](amd#1029), closes [amd#1024](amd#1024)) — Replaced with the correct `gaia init`. - **Keyring treated as required** ([amd#1028](amd#1028)) — Import guarded; optional on systems without `keyring`. - **electron-builder URLs stale** ([amd#953](amd#953)) — Three doc/installer files updated to current download paths. ## Tooling & Docs - **RAG eval CI gates** ([amd#1040](amd#1040), closes [amd#1033](amd#1033)) — RAG quality baselines + prompt-size budget enforced on every PR. - **Fork-PR authors now receive Claude review** ([amd#932](amd#932)) — `allowed_non_write_users: "*"` with prompt-injection mitigations documented. - **Eval runs mandated before merging** ([amd#1036](amd#1036)) — `CLAUDE.md` requires `gaia eval agent` for LLM-affecting changes. - **GAIA website** ([amd#369](amd#369)) — [amd-gaia.ai](https://amd-gaia.ai) live. - **Custom agent guide reorganised** ([amd#997](amd#997)), Lemonade PPA docs ([amd#801](amd#801)), broken Lemonade CLI URL fixed ([amd#996](amd#996)), WhatsApp adapter evaluation spec ([amd#950](amd#950)). ## Release checklist - [x] `util/validate_release_notes.py docs/releases/v0.18.0.mdx --tag v0.18.0` passes - [x] `src/gaia/version.py` → `0.18.0` - [x] `src/gaia/apps/webui/package.json` → `0.18.0` - [x] Navbar label in `docs/docs.json` → `v0.18.0 · Lemonade 10.2.0` - [x] All 28 commits in range (v0.17.6..HEAD) are represented in the notes - [ ] Review from @kovtcharov-amd addressed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1004. Part of #927. Builds on PR #998 — please merge that first.
Users can now temporarily disable a configured MCP connector without losing its credentials or per-agent grants. Concrete user flow: toggle off GitHub MCP during a sensitive code review → toggle back on without re-pasting the PAT or re-granting agents.
The
disabledflag was already persisted inmcp_servers.jsonandMCPClientManager.load_from_config()already skipped disabled entries. This PR adds the API/UI/live-reload wiring to drive it.What lands
POST /api/connectors/{id}/enableand/disable(CSRF-guarded, 400 on non-MCP types, 404 on unconfigured ids).manager.reload()on every cached ChatAgent's per-instanceMCPClientManager. Toggling takes effect without restarting GAIA.Test plan
python -m pytest tests/unit/connectors/test_enable_disable.py -v— 12 handler tests passpython -m pytest tests/unit/connectors/test_router_connectors.py::TestEnableDisable -v— 8 router tests passpython -m pytest tests/unit/connectors/test_handler_reload_wired.py -v— 4 wiring tests passmcp-githubwith a PAT → ChatAgent uses tools → click ⋯ on the GitHub tile → Disable → ChatAgent no longer sees GitHub tools (no restart) → Enable → tools return → restart GAIA → state persists.cd src/gaia/apps/webui && npx tsc --noEmit && npm run buildpython util/lint.py --all