Skip to content

fix(mcp): isolate plugin server lifecycle#1597

Merged
zerob13 merged 1 commit intodevfrom
codex/plugin-status-toggle
May 9, 2026
Merged

fix(mcp): isolate plugin server lifecycle#1597
zerob13 merged 1 commit intodevfrom
codex/plugin-status-toggle

Conversation

@zerob13
Copy link
Copy Markdown
Collaborator

@zerob13 zerob13 commented May 9, 2026

Summary by CodeRabbit

  • Documentation

    • Added comprehensive specification, implementation plan, and task checklist for plugin MCP lifecycle isolation.
  • New Features

    • Plugin-owned MCP servers now operate independently of the global MCP on/off switch and continue running when global MCP is disabled.
    • Plugin MCP server errors are now visible in plugin settings UI.
  • Bug Fixes

    • Plugin MCP connection failures no longer trigger global error notifications.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 9, 2026

📝 Walkthrough

Walkthrough

This pull request implements plugin MCP lifecycle isolation: plugin-owned MCP servers now operate independently of the global MCP enable/disable toggle, including error tracking per-server, conditional error-notification suppression, and persistent tool/resource visibility in the renderer when global MCP is disabled.

Changes

Plugin MCP Lifecycle Isolation

Layer / File(s) Summary
Type Contracts
src/shared/types/plugin.ts, src/shared/types/presenters/legacy.presenters.d.ts
PluginMcpRuntimeStatus gains optional lastError field; IMCPPresenter gains optional getServerLastError(serverName) method.
Server Error Tracking
src/main/presenter/mcpPresenter/serverManager.ts
Add serverLastErrors map and public methods (getServerLastError, setServerLastError, clearServerLastError). On startServer failure, record error and suppress global notification for plugin-owned configs. Clear error on stopServer.
MCP Presenter Lifecycle
src/main/presenter/mcpPresenter/index.ts
Add isPluginOwned helpers; load mcpEnabled during initialize(); start servers when config exists and (MCP enabled OR plugin-owned); return plugin-only tools/prompts/resources when MCP disabled; allow plugin-owned prompt/resource access when disabled.
Tool Manager
src/main/presenter/mcpPresenter/toolManager.ts
Add isPluginOwnedClient helper; clear per-server errors before tool enumeration passes; suppress global error notifications for plugin-owned client failures.
Plugin Presenter
src/main/presenter/pluginPresenter/index.ts
Match MCP servers for deactivation by plugin-sourced origin; remove getMcpEnabled() check from startPluginMcpServersIfReady; populate lastError in runtime status reporting.
Renderer MCP Store
src/renderer/src/stores/mcp.ts
Enable tools/clients/resources queries by config.ready only (not mcpEnabled); always merge custom and MCP prompts; skip auto-start for plugin-owned servers; on setMcpEnabled(false) stop only non-plugin servers; allow plugin-owned prompt/resource access when disabled.
UI Error Display
plugins/cua/settings/assets/index.js, src/renderer/settings/components/PluginsSettings.vue
Display per-server lastError in CUA settings message; list plugin MCP errors in plugin settings.
Tests & Documentation
test/main/presenter/*, test/renderer/*, docs/issues/plugin-mcp-lifecycle-isolation/*
Add comprehensive test coverage for plugin-owned server isolation (initialize, enable/disable, tool definitions, error suppression, renderer visibility); document architecture, spec, and implementation tasks.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • ThinkInAIXYZ/deepchat#1099: Modifies MCP presenter, store, and related lifecycle logic; shares code-level dependencies in presenter initialization and store query management.

Poem

🐰 A rabbit's ode to plugin freedom:

When global MCP sleeps at night,
Plugin servers keep burning bright,
Errors tracked, not lost in air,
Each server gets its own fair share,
Now plugins dance while others rest! 🌙✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(mcp): isolate plugin server lifecycle' directly and concisely summarizes the main change: isolating plugin-owned MCP servers from global MCP lifecycle control, which is the central theme across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/plugin-status-toggle

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/renderer/src/stores/mcp.ts (2)

314-327: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Inconsistent server status clearing when MCP is disabled.

Line 316 clears all server statuses when mcpEnabled changes to false via syncConfigFromQuery, but lines 555-559 in setMcpEnabled(false) preserve plugin-owned server statuses. This inconsistency means:

  • User toggle → plugin-owned statuses preserved (correct)
  • External config change → plugin-owned statuses cleared (likely incorrect)

Both code paths should preserve plugin-owned server statuses when MCP is disabled.

🔧 Proposed fix to preserve plugin-owned server statuses
       } else {
         // MCP disabled: clear state and refresh queries to get empty results
-        serverStatuses.value = {}
+        serverStatuses.value = Object.fromEntries(
+          Object.entries(serverStatuses.value).filter(([serverName]) =>
+            isPluginOwnedServerName(serverName)
+          )
+        )
         toolInputs.value = {}
         toolResults.value = {}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/stores/mcp.ts` around lines 314 - 327, The branch in
syncConfigFromQuery that handles mcpEnabled turning false currently wipes
serverStatuses entirely; instead, mirror the behavior in setMcpEnabled(false) by
preserving plugin-owned statuses: when mcpEnabled is false, replace
serverStatuses.value with a filtered map that keeps entries whose owner
indicates a plugin (match the same ownership check used in setMcpEnabled), while
removing all other servers; then clear toolInputs/toolResults and refetch
toolsQuery, clientsQuery, resourcesQuery and promptsQuery and handle errors as
done already. Update the logic in syncConfigFromQuery to reference
serverStatuses, setMcpEnabled, and the same owner predicate so both paths behave
consistently.

594-609: ⚠️ Potential issue | 🟠 Major

Fix early return to allow tool auto-management for plugin-owned servers when global MCP is disabled.

The early return at line 57–59 prevents tool enable/disable logic (lines 61–76) from running when mcpEnabled is false, affecting both user-owned and plugin-owned servers. However, design spec requires plugin-owned tools to remain in the agent tool list when global MCP is disabled. The check should mirror line 595:

if (!config.value.mcpEnabled && !isPluginOwnedServerConfig(serverConfig)) {
  return
}

This allows plugin-owned server tools to auto-enable/disable based on server status even when global MCP is off.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/stores/mcp.ts` around lines 594 - 609, The early return
prevents plugin-owned servers from having their tools auto-managed when global
MCP is disabled; update the early-return guard in the block around serverConfig
so it only returns when mcp is disabled AND the server is NOT plugin-owned
(i.e., change the condition to match the earlier check: if
(!config.value.mcpEnabled && !isPluginOwnedServerConfig(serverConfig) { return
}), then allow the subsequent calls to mcpClient.isServerRunning,
serverStatuses.value assignment, loadTools/loadClients and the isRunning-based
enable/disable logic to run for plugin-owned servers.
🧹 Nitpick comments (1)
docs/issues/plugin-mcp-lifecycle-isolation/plan.md (1)

24-27: 💤 Low value

Consider varying sentence structure in the test strategy section.

The static analysis tool flagged that three consecutive bullet points begin with "Add," which can make the text feel repetitive. Consider varying the phrasing for better readability.

✍️ Optional rewording suggestion
 ## Test Strategy
 
-- Add main-process tests for global switch isolation and plugin start behavior.
-- Add error-notification tests for plugin-owned connection and tool-list failures.
-- Add renderer tests for disabled-global MCP state with plugin tools still visible.
-- Add CUA settings regression coverage for MCP error state.
+- Add main-process tests for global switch isolation and plugin start behavior.
+- Verify error-notification suppression for plugin-owned connection and tool-list failures.
+- Test renderer behavior when global MCP is disabled but plugin tools remain visible.
+- Add CUA settings regression coverage for MCP error state.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/issues/plugin-mcp-lifecycle-isolation/plan.md` around lines 24 - 27, In
the "test strategy" bulleted list within the plan document, three consecutive
bullets start with the verb "Add", making the phrasing repetitive; edit those
bullets so their opening verbs vary (for example, change one to "Include",
another to "Cover" or "Validate", or rephrase to passive/nominal forms like
"Main-process tests for..." and "Renderer tests covering...") while preserving
the same meaning about global switch isolation, error-notification/plugin-owned
connection failures, renderer behavior when MCP is disabled, and CUA settings
regression coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/renderer/src/stores/mcp.ts`:
- Around line 314-327: The branch in syncConfigFromQuery that handles mcpEnabled
turning false currently wipes serverStatuses entirely; instead, mirror the
behavior in setMcpEnabled(false) by preserving plugin-owned statuses: when
mcpEnabled is false, replace serverStatuses.value with a filtered map that keeps
entries whose owner indicates a plugin (match the same ownership check used in
setMcpEnabled), while removing all other servers; then clear
toolInputs/toolResults and refetch toolsQuery, clientsQuery, resourcesQuery and
promptsQuery and handle errors as done already. Update the logic in
syncConfigFromQuery to reference serverStatuses, setMcpEnabled, and the same
owner predicate so both paths behave consistently.
- Around line 594-609: The early return prevents plugin-owned servers from
having their tools auto-managed when global MCP is disabled; update the
early-return guard in the block around serverConfig so it only returns when mcp
is disabled AND the server is NOT plugin-owned (i.e., change the condition to
match the earlier check: if (!config.value.mcpEnabled &&
!isPluginOwnedServerConfig(serverConfig) { return }), then allow the subsequent
calls to mcpClient.isServerRunning, serverStatuses.value assignment,
loadTools/loadClients and the isRunning-based enable/disable logic to run for
plugin-owned servers.

---

Nitpick comments:
In `@docs/issues/plugin-mcp-lifecycle-isolation/plan.md`:
- Around line 24-27: In the "test strategy" bulleted list within the plan
document, three consecutive bullets start with the verb "Add", making the
phrasing repetitive; edit those bullets so their opening verbs vary (for
example, change one to "Include", another to "Cover" or "Validate", or rephrase
to passive/nominal forms like "Main-process tests for..." and "Renderer tests
covering...") while preserving the same meaning about global switch isolation,
error-notification/plugin-owned connection failures, renderer behavior when MCP
is disabled, and CUA settings regression coverage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 616daab5-0e1d-4b03-82ab-64d64eff34d6

📥 Commits

Reviewing files that changed from the base of the PR and between 66039ae and 00ec7ae.

📒 Files selected for processing (19)
  • docs/issues/plugin-mcp-lifecycle-isolation/plan.md
  • docs/issues/plugin-mcp-lifecycle-isolation/spec.md
  • docs/issues/plugin-mcp-lifecycle-isolation/tasks.md
  • plugins/cua/settings/assets/index.js
  • src/main/presenter/mcpPresenter/index.ts
  • src/main/presenter/mcpPresenter/serverManager.ts
  • src/main/presenter/mcpPresenter/toolManager.ts
  • src/main/presenter/pluginPresenter/index.ts
  • src/renderer/settings/components/PluginsSettings.vue
  • src/renderer/src/stores/mcp.ts
  • src/shared/types/plugin.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
  • test/main/presenter/mcpPresenter.test.ts
  • test/main/presenter/mcpPresenter/serverManager.test.ts
  • test/main/presenter/mcpPresenter/toolManager.test.ts
  • test/main/presenter/pluginPresenter.test.ts
  • test/renderer/components/McpIndicator.test.ts
  • test/renderer/plugins/cuaSettings.test.ts
  • test/renderer/stores/mcpStore.test.ts

@zerob13 zerob13 merged commit b483bf2 into dev May 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant