feat(mcp): connection health toolbar with bulk Retry All / Disconnect All actions#2641
feat(mcp): connection health toolbar with bulk Retry All / Disconnect All actions#2641aashir-athar wants to merge 2 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds a McpConnectionHealthToolbar component (counts, live status, retry/disconnect bulk actions with confirmation and error alerts), integrates it into McpServersTab, supplies tests, and adds mcp.health.* translations across multiple language chunks. ChangesMCP Connection Health Toolbar
Sequence DiagramsequenceDiagram
participant User
participant McpConnectionHealthToolbar
participant McpServersTab
participant MCP_Backend as MCP Backend
User->>McpConnectionHealthToolbar: Click "Retry all" or "Disconnect all"
McpConnectionHealthToolbar->>McpConnectionHealthToolbar: Set isOperating=true, disable buttons
alt Disconnect path
McpConnectionHealthToolbar->>User: Show confirmation dialog
User->>McpConnectionHealthToolbar: Confirm disconnect
end
McpConnectionHealthToolbar->>McpServersTab: Call onReconnect/onDisconnect with server IDs
McpServersTab->>MCP_Backend: Promise.allSettled for each server ID
MCP_Backend-->>McpServersTab: Results (settled)
McpServersTab->>McpServersTab: fetchStatuses to refresh
McpServersTab-->>McpConnectionHealthToolbar: Updated statuses
McpConnectionHealthToolbar->>McpConnectionHealthToolbar: Set isOperating=false, re-enable buttons
alt Operation failed
McpConnectionHealthToolbar->>User: Display error in alert region
end
🎯 2 (Simple) | ⏱️ ~12 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add 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. Comment |
…les (fixes CI 'Type Check' format gate)
Summary
Channels → ChannelConfigPanel → McpServersTab. Surfaces aggregate per-state counts (connected / connecting / error / idle) and exposes two bulk actions that previously required clicking into each server one at a time.(N)— visible only when there are errored servers. Iterates through them viamcpClientsApi.connect(id)wrapped inPromise.allSettledso one bad apple doesn't abort the batch, then refreshes statuses once at the end.(N)— visible only when there are connected servers. Gated behind arole="dialog" aria-modalconfirmation dialog before the bulk RPC fires.role="status" aria-live="polite"region so screen-reader users hear updates as the 5-second polling loop refreshes. Status dots arearia-hidden. Buttons have descriptivearia-labels with interpolated counts.mcp.health.*mirrored across all 13 locale chunks (English values used as untranslated placeholders per the repo's standard pattern).Promise.allSettled, error surfacing throughrole="alert", and the a11y attribute contract on every interactive element.Problem
MCP servers in this app can drift into
errorstate for legitimate reasons — a key expired, a managed runtime restart cycle, a flaky upstream HTTP-remote server. Today, recovering means clicking each errored server individually in the list, navigating to its detail view, and hitting connect. With three or four servers it's tedious; with the ten-plus shape that real Smithery users hit, it's a chore.Disconnect-all is symmetric — useful during debugging ("what changes if I cut all MCP connections?"), useful during shutdown, useful for the user who just installed a server with bad env vars and wants a clean reset across the board.
There's also no aggregate at-a-glance status. The list shows per-server dots, but counting "how many am I currently connected to?" requires scanning. For users with a dozen servers, that scan happens visually every time they open the tab.
Solution
New component
McpConnectionHealthToolbar.tsxRenders only when
statuses.length > 0— preserves the existing "empty install + Browse catalog CTA" empty state by not competing for vertical space.Layout (compact, fits the 224px left pane):
Status pills use the existing color vocabulary from
McpStatusBadge(sage/amber/coral/stone). Dots flow on aflex flex-wraprow so the layout doesn't break at narrower widths.Aggregation (in
computeHealthCounts, exported as a pure helper):statusesproducingconnectedIds,errorIds, and counts forconnecting/disconnected.useMemokeyed onstatusesso the bulk action targets don't recompute on unrelated re-renders.connectedIdsanderrorIdsare arrays (not just counts) — the same memoization payload powers both the visual badges and the bulk-action callbacks, so there's no risk of the displayed count diverging from the IDs that would be acted on.Bulk action flow (Retry All):
Retry all (N)— callsonReconnect(errorIds); setsisOperating=trueto disable both buttons.McpServersTab.handleBulkReconnect) doesPromise.allSettled(errorIds.map(id => mcpClientsApi.connect(id)))followed byfetchStatuses().isOperating=false; the next render reflects the new statuses; the buttons re-enable.setOpError(err.message)displays the failure in arole="alert"paragraph below the summary. Falls back tot('mcp.health.opErrorGeneric')for non-Error throws.Bulk action flow (Disconnect All):
Disconnect all (N)— opens confirmation dialog withrole="dialog" aria-modal="true"and explicitaria-labelledby/aria-describedbyreferencing the title and body IDs.onDisconnectnever fires.Promise.allSettledorchestration viaonDisconnect(connectedIds).Wiring in
McpServersTab.tsxhandleBulkReconnectandhandleBulkDisconnectasuseCallbacks alongside the existinghandleInstallSuccess/handleUninstalledhandlers. Both callPromise.allSettledon per-server RPC thenfetchStatuses()for one round-trip refresh.<McpConnectionHealthToolbar>above<InstalledServerList>in the left pane, after the existingloadErrorblock.i18n
15 new keys under the
mcp.health.*namespace added toapp/src/lib/i18n/en.tsAND toapp/src/lib/i18n/chunks/en-1.ts(the runtime chunk that already holds the existingmcp.*keys). All 12 non-English locale chunks (ar-1.ts…zh-CN-1.ts) get the same six keys with the English value as the untranslated placeholder, per the project pattern thatscripts/i18n-coverage.tsenforces.Verified locally:
Submission Checklist
McpConnectionHealthToolbar.test.tsx. Cover: empty-state return-null path; correct count aggregation across mixed status sets; conditional rendering of connecting / error pills only when non-zero; conditional rendering of Retry All only when errors exist; conditional rendering of Disconnect All only when connected exist; "Retry all" callsonReconnectwith exactly the errored IDs; "Disconnect all" opens a confirmation dialog rather than firing directly; cancel closes the dialog without callingonDisconnect; confirm firesonDisconnectwith exactly the connected IDs and closes the dialog; both action buttons are disabled during a pending bulk operation; errors thrown fromonReconnectsurface viarole="alert"; non-Error throws fall back to a generic message; the summary region hasrole="status"+aria-live="polite"+ a descriptivearia-label; the confirmation dialog body interpolates the correct connected count.McpConnectionHealthToolbar.tsxand the newhandleBulkReconnect/handleBulkDisconnectcallbacks inMcpServersTab.tsxare exercised by the test suite. Local Vitest: 91/91 passing across the full MCP suite (8 test files); no regression in any pre-existing test.## Related— N/A.mcpClientsApi.connect/mcpClientsApi.disconnectround-tripped through the existing JSON-RPC.Closes #NNNin## Related— no specific issue; organic UX improvement on the MCP surface.Impact
McpServersTabis desktop-only viaChannelConfigPanel. No iOS / web impact.Promise.allSettled— strictly equivalent to a user manually triggering N connects/disconnects, just dispatched together. No new polling loop.role="dialog" aria-modal). The dialog body explicitly states secrets and configurations are preserved, addressing the "did I just lose my install state?" anxiety.nullwhenstatuses.length === 0, preserving the existing zero-installed flow byte-for-byte. All pre-existing MCP tests still pass unchanged.untranslatedtotal).aria-labels with interpolated counts on action buttons;role="dialog" aria-modal aria-labelledby aria-describedbyon the confirmation modal; decorativearia-hiddenstatus dots;role="alert"for operation errors.Related
mcp.health.*keys across the 12 non-English locales (currently fall back to English placeholders; flagged in each locale'suntranslatedcount).AI Authored PR Metadata
Linear Issue
Commit & Branch
feat/mcp-connection-health-toolbarValidation Run
All four key gates passed locally:
pnpm --filter openhuman-app compile— clean (tsc --noEmit, no output = success).pnpm --filter openhuman-app lint— clean for new files. The full repo currently produces 62 warnings (0 errors), of which zero are in the files this PR adds or modifies; the single warning atMcpServersTab.tsx:70:18is the pre-existingsetLoading(false)inside the initial-loaduseEffect, untouched by this PR.pnpm vitest run src/components/channels/mcp/— 91/91 passing including the 17 new tests and all pre-existing MCP component tests (no regression).pnpm i18n:check— exit 0, every locale at1:1206/1206parity, 0 missing keys, 0 extra keys, 0 drift.Validation Blocked
command:pnpm --filter openhuman-app format:check(chainscargo fmt --checkvia the workspace script) and the husky pre-push hook (which runspnpm format→cargo fmt).error:'cargo' is not recognized as an internal or external command, operable program or batch file.— no Rust toolchain installed on the dev machine.impact:Usedgit push --no-verifyper CLAUDE.md's allowance for unrelated pre-existing breakage. This PR touches zero Rust files, socargo fmt --checkwould have been a no-op for the changed files. Prettier on the changed TS files runs in CI on a clean Linux checkout with LF line endings; verified locally that the new files were written with LF.Behavior Changes
Parity Contract
statuses.length === 0, the toolbar returnsnull— the existing layout renders exactly as before. All pre-existing MCP tests pass unchanged. Per-server connect/disconnect via the existing detail view is untouched.Promise.allSettledensures partial failures within a bulk action don't abort the rest; the next poll tick reconciles any drift; thrown errors at the orchestration boundary surface throughrole="alert"rather than being swallowed.Duplicate / Superseded PR Handling
Summary by CodeRabbit
New Features
Accessibility
Localization
Tests