Skip to content

Commit 3f9b721

Browse files
committed
fix: ensure disabled servers are visible in UI but not usable
- Modified getServers() to filter out disabled servers (for prompt system) - getAllServers() returns all servers including disabled (for UI) - Updated updateServerConnections to create connection objects for disabled servers - Fixed toggleServerDisabled to properly handle re-enabling servers - Added test coverage for getAllServers() method This ensures disabled servers appear in the UI with visual indicators while preventing their use in prompts and tool calls.
1 parent f6d0f5a commit 3f9b721

File tree

12 files changed

+847
-28
lines changed

12 files changed

+847
-28
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
## Architecture Review for PR #6037
2+
3+
### Module Boundaries
4+
5+
1. **Separation of Concerns**
6+
7+
- ✅ Backend logic (McpHub.ts) handles connection state management
8+
- ✅ UI logic (McpView.tsx) handles visual representation
9+
- ✅ Clear separation between server state and UI state
10+
- Good adherence to module boundaries
11+
12+
2. **State Management**
13+
- The disabled state is properly stored in the server configuration
14+
- State changes flow correctly: Config → Backend → UI
15+
- No violations of data flow patterns
16+
17+
### Dependency Analysis
18+
19+
1. **No New Dependencies**
20+
21+
- The PR doesn't introduce any new external dependencies
22+
- Uses existing patterns and methods
23+
- No risk of dependency conflicts
24+
25+
2. **Internal Dependencies**
26+
- Relies on existing methods: `deleteConnection()`, `connectToServer()`
27+
- No circular dependencies introduced
28+
- Clean dependency chain maintained
29+
30+
### Architectural Concerns
31+
32+
1. **State Synchronization Complexity**
33+
34+
- The disabled state is checked in multiple places:
35+
- `updateServerConnections()` - during initialization/updates
36+
- `toggleServerDisabled()` - during state changes
37+
- `getStatusColor()` - for UI display
38+
- This distributed checking could lead to inconsistencies
39+
40+
2. **Missing Centralized Validation**
41+
42+
- The `connectToServer()` method doesn't check disabled state
43+
- This means other code paths could potentially connect disabled servers
44+
- Architectural weakness: validation should be centralized
45+
46+
3. **Race Condition Potential**
47+
- No locking mechanism during toggle operations
48+
- Rapid toggling could lead to race conditions
49+
- The PR doesn't address concurrent state changes
50+
51+
### Impact on System Architecture
52+
53+
1. **Performance Impact**
54+
55+
- ✅ Positive: Disabled servers won't consume system resources
56+
- ✅ Reduces unnecessary process spawning
57+
- ✅ Improves overall system efficiency
58+
59+
2. **Scalability Considerations**
60+
61+
- The solution scales well with multiple servers
62+
- No performance degradation with many disabled servers
63+
- Clean resource management
64+
65+
3. **Maintainability**
66+
- ⚠️ The distributed disabled checks could make maintenance harder
67+
- Future developers might miss updating all check locations
68+
- Would benefit from centralization
69+
70+
### Architectural Patterns
71+
72+
1. **Observer Pattern**
73+
74+
- The PR maintains the existing observer pattern
75+
- State changes properly notify observers via `notifyWebviewOfServerChanges()`
76+
- No pattern violations
77+
78+
2. **Command Pattern**
79+
- Toggle operations follow command-like pattern
80+
- Clear action → state change → notification flow
81+
- Consistent with existing architecture
82+
83+
### Recommendations
84+
85+
1. **Centralize Disabled Check**
86+
87+
- Move the disabled check into `connectToServer()` method
88+
- This ensures no code path can bypass the check
89+
- Reduces maintenance burden
90+
91+
2. **Add State Validation**
92+
93+
- Before toggling, validate current state
94+
- Prevent unnecessary operations (e.g., disabling already disabled server)
95+
- Add guards against invalid state transitions
96+
97+
3. **Consider State Machine**
98+
99+
- Server states could benefit from formal state machine
100+
- States: disconnected, connecting, connected, disabled
101+
- Would prevent invalid state transitions
102+
103+
4. **Add Concurrency Protection**
104+
- Consider adding a flag to prevent concurrent toggle operations
105+
- Or queue state change operations
106+
- Prevents race conditions
107+
108+
### Overall Assessment
109+
110+
The PR follows most architectural patterns correctly but has some concerns:
111+
112+
- ✅ Maintains module boundaries
113+
- ✅ No dependency issues
114+
- ✅ Improves resource management
115+
- ⚠️ Distributed validation logic
116+
- ⚠️ Potential race conditions
117+
- ⚠️ Could benefit from centralization
118+
119+
The architecture remains sound but could be improved with centralized validation and better state management.

.roo/temp/pr-6037/comments.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]

.roo/temp/pr-6037/final-review.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# PR Review: Fix disabled MCP servers issue (#6037)
2+
3+
## Executive Summary
4+
5+
This PR addresses issue #6036 where disabled MCP servers were incorrectly starting processes and showing incorrect status indicators. The implementation is functional and fixes the reported issue, but there are several areas for improvement regarding code organization, redundancy, and architectural consistency.
6+
7+
## Critical Issues (Must Fix)
8+
9+
### 1. Centralize Disabled State Validation
10+
11+
The disabled state check is distributed across multiple locations rather than being centralized:
12+
13+
- [`src/services/mcp/McpHub.ts:977-984`](src/services/mcp/McpHub.ts:977) - Check for new servers
14+
- [`src/services/mcp/McpHub.ts:991-993`](src/services/mcp/McpHub.ts:991) - Check for config changes
15+
- [`src/services/mcp/McpHub.ts:1266-1272`](src/services/mcp/McpHub.ts:1266) - Toggle logic
16+
17+
**Recommendation**: Move the disabled check into the [`connectToServer()`](src/services/mcp/McpHub.ts:555) method itself to ensure no code path can bypass this validation.
18+
19+
### 2. Race Condition Risk
20+
21+
The [`toggleServerDisabled()`](src/services/mcp/McpHub.ts:1244) method doesn't protect against concurrent operations. Rapid toggling could lead to race conditions where multiple connect/disconnect operations overlap.
22+
23+
**Recommendation**: Add a state flag or queue mechanism to prevent concurrent toggle operations on the same server.
24+
25+
## Pattern Inconsistencies
26+
27+
### 1. Redundant Visual Indicators
28+
29+
The UI implementation adds a grey color for disabled servers in [`getStatusColor()`](webview-ui/src/components/mcp/McpView.tsx:220), but the parent div already handles opacity changes for disabled servers (line 281).
30+
31+
**Recommendation**: Choose one visual indicator approach for consistency. The opacity change is likely sufficient.
32+
33+
### 2. Unnecessary Status Check
34+
35+
In [`toggleServerDisabled()`](src/services/mcp/McpHub.ts:1266), the code checks if the server status is "connected" before disconnecting, but [`deleteConnection()`](src/services/mcp/McpHub.ts:915) already handles non-existent connections gracefully.
36+
37+
**Recommendation**: Remove the redundant status check.
38+
39+
## Test Coverage Issues
40+
41+
### 1. Missing Edge Cases
42+
43+
The tests don't cover:
44+
45+
- Toggling a server that's already in the target state
46+
- Error handling during toggle operations
47+
- Concurrent toggle operations
48+
49+
### 2. No UI Tests
50+
51+
The [`getStatusColor()`](webview-ui/src/components/mcp/McpView.tsx:220) changes are not covered by tests.
52+
53+
**Recommendation**: Add tests for these scenarios to ensure robustness.
54+
55+
## Architecture Concerns
56+
57+
### 1. State Management Complexity
58+
59+
The disabled state validation is spread across multiple methods, making it harder to maintain and potentially leading to inconsistencies.
60+
61+
### 2. Missing State Validation
62+
63+
The implementation doesn't validate whether a state change is necessary before performing it (e.g., disabling an already disabled server).
64+
65+
## Minor Suggestions
66+
67+
### 1. Improve Error Messages
68+
69+
Consider adding more specific error messages when operations fail due to disabled state.
70+
71+
### 2. Add Logging
72+
73+
Add debug logging for state transitions to help with troubleshooting.
74+
75+
### 3. Consider State Machine Pattern
76+
77+
For better state management, consider implementing a formal state machine for server states (disconnected, connecting, connected, disabled).
78+
79+
## Positive Aspects
80+
81+
✅ The fix correctly addresses the reported issue
82+
✅ Tests are well-organized and follow existing patterns
83+
✅ The implementation maintains module boundaries
84+
✅ Resource management is improved by not starting disabled servers
85+
✅ State changes properly trigger UI updates
86+
87+
## Conclusion
88+
89+
While this PR successfully fixes the immediate issue, it would benefit from centralizing the disabled state validation and addressing the potential race conditions. The test coverage should be expanded to include edge cases and UI changes. With these improvements, the implementation would be more robust and maintainable.
90+
91+
**Recommendation**: Request changes to address the critical issues before merging.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"author": { "id": "MDQ6VXNlcjQ5MTAzMjQ3", "is_bot": false, "login": "hannesrudolph", "name": "Hannes Rudolph" },
3+
"body": "## App Version\nLatest (based on current codebase analysis)\n\n## API Provider\nNot Applicable / Other\n\n## Model Used\nN/A\n\n## 🔁 Steps to Reproduce\n\n1. Open VSCode with Roo Code extension\n2. Navigate to the MCP Servers view (click MCP icon in sidebar)\n3. Toggle any MCP server to disabled state using the toggle switch\n4. Observe the server row - note the status indicator color\n5. Check system processes (Activity Monitor on macOS, Task Manager on Windows)\n6. Look for the MCP server process still running\n7. Restart VSCode\n8. Check processes again - disabled MCP servers are still launched\n\nInclude:\n- The disabled server still shows a green status indicator (connected state)\n- The server process continues running in the background\n- After VSCode restart, disabled servers are started again despite being disabled\n\n## 💥 Outcome Summary\n\nExpected: Disabled MCP servers should not start processes, should show appropriate disabled status (grey/red indicator), and should not consume system resources\nActual: Disabled servers start processes, show green \"connected\" status, and continue consuming resources even when disabled\n\n## 📄 Relevant Logs or Errors\n\nNo specific error messages - the issue is silent resource consumption and incorrect UI state.\n\n---\n\n## 🛠️ Contributing & Technical Analysis\n\n✅ **I'm interested in providing technical analysis**\n✅ **I understand this needs approval before implementation begins**\n\n### Root Cause / Implementation Target\n\nThe issue stems from incomplete handling of disabled MCP servers in multiple areas:\n\n1. **Process Management**: In `src/services/mcp/McpHub.ts` (lines 975-992), the `updateServerConnections()` method doesn't check if a server is disabled before calling `connectToServer()`\n2. **UI Status Display**: In `webview-ui/src/components/mcp/McpView.tsx` (lines 220-229), the `getStatusColor()` function only considers connection status, not disabled state\n3. **Server Filtering**: While `getServers()` filters out disabled servers (line 410), the UI still receives all servers including disabled ones\n\n### Affected Components\n\n- **Primary Files:**\n - `src/services/mcp/McpHub.ts` (lines 975-992): Server connection logic\n - `webview-ui/src/components/mcp/McpView.tsx` (lines 220-229, 275): Status display logic\n\n- **Secondary Impact:**\n - All components that display MCP server status\n - System resource management\n - User experience when managing multiple MCP servers\n\n### Current Implementation Analysis\n\nThe current code properly stores the disabled state but fails to act on it in several critical places:\n\n1. PR #5922 added checks in `updateServerConnections()` but these checks were incomplete\n2. The UI receives disabled servers but doesn't differentiate their visual state\n3. Disabled servers are filtered from the agent's view but still consume resources\n\n### Proposed Implementation\n\n#### Step 1: Fix process spawning for disabled servers\n- File: `src/services/mcp/McpHub.ts`\n- Changes: Add disabled check before `connectToServer()` calls in `updateServerConnections()`\n- Rationale: Prevents disabled servers from starting processes\n\n#### Step 2: Update UI status indicators\n- File: `webview-ui/src/components/mcp/McpView.tsx`\n- Changes: Modify `getStatusColor()` to check disabled state first\n- Rationale: Provides clear visual feedback about server state\n\n#### Step 3: Handle server state transitions\n- File: `src/services/mcp/McpHub.ts`\n- Changes: When toggling disabled state, properly disconnect running servers\n- Rationale: Ensures immediate resource cleanup\n\n### Code Architecture Considerations\n- Follow existing patterns for server state management\n- Maintain backward compatibility with existing configurations\n- Ensure consistent state between backend and UI\n\n### Testing Requirements\n- Unit Tests:\n - [ ] Test case 1: Disabled servers don't start processes during initialization\n - [ ] Test case 2: Toggling disabled state properly disconnects servers\n - [ ] Test case 3: UI correctly displays disabled state\n- Integration Tests:\n - [ ] Test scenario 1: Multiple servers with mixed enabled/disabled states\n - [ ] Test scenario 2: State persistence across VSCode restarts\n- Edge Cases:\n - [ ] Edge case 1: Server disabled while actively processing a request\n - [ ] Edge case 2: Rapid toggling of disabled state\n\n### Performance Impact\n- Expected performance change: Positive - reduced resource consumption\n- Benchmarking needed: No\n- Optimization opportunities: Lazy loading of disabled server configurations\n\n### Security Considerations\n- No security implications - this is a resource management fix\n\n### Migration Strategy\nNot applicable - this is a bug fix that maintains existing configuration format\n\n### Rollback Plan\nIf issues arise, the fix can be reverted without data loss as it doesn't change configuration schema\n\n### Dependencies and Breaking Changes\n- External dependencies affected: None\n- API contract changes: None\n- Breaking changes for users: None\n\n### Implementation Complexity\n- Estimated effort: Small\n- Risk level: Low\n- Prerequisites: None\n\n## Acceptance Criteria\n\nGiven I have MCP servers configured in my settings\nWhen I disable a server using the toggle switch\nThen the server process should immediately stop\nAnd the status indicator should show grey/disabled state\nAnd no system resources should be consumed by that server\nBut the server configuration should remain in settings\n\nGiven I have disabled MCP servers\nWhen I restart VSCode\nThen disabled servers should not start processes\nAnd they should show as disabled in the UI\nAnd they should not appear in the agent's available servers list\nBut I should be able to re-enable them at any time\n\nGiven I toggle a server from enabled to disabled\nWhen the server is currently processing a request\nThen the current request should complete or timeout gracefully\nAnd the server should then disconnect\nAnd no new requests should be accepted\nBut no data corruption should occur\n\n---\n\n**Note:** This issue supersedes and expands upon #2797, which focused only on the process starting aspect. This comprehensive issue addresses all aspects of disabled MCP server behavior including UI state and resource management.",
4+
"number": 6036,
5+
"state": "OPEN",
6+
"title": "Disabled MCP servers still start processes and show incorrect status indicators"
7+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
## Pattern Analysis for PR #6037
2+
3+
### Similar Existing Implementations
4+
5+
1. **Disabled State Handling Pattern**
6+
7+
- Found similar disabled state handling in [`webview-ui/src/components/ui/toggle-switch.tsx`](webview-ui/src/components/ui/toggle-switch.tsx:32-51)
8+
- The toggle switch component already implements disabled state with opacity changes
9+
- Pattern: Use `disabled` prop to control visual state and interaction
10+
11+
2. **Server Connection Management**
12+
13+
- The `updateServerConnections()` method already handles server lifecycle
14+
- Pattern: Check configuration before connecting, handle errors gracefully
15+
16+
3. **Toggle State Management**
17+
- Found similar toggle patterns in [`McpToolRow.tsx`](webview-ui/src/components/mcp/McpToolRow.tsx:87-95) for tool enabling/disabling
18+
- Pattern: Toggle state updates both UI and backend configuration
19+
20+
### Established Patterns
21+
22+
1. **Configuration Validation Before Connection**
23+
24+
- The codebase validates server configurations using `validateServerConfig()` before attempting connections
25+
- This PR correctly follows this pattern by checking `disabled` state
26+
27+
2. **Disconnection Before Reconnection**
28+
29+
- Pattern seen in `restartConnection()` and config changes: always disconnect before reconnecting
30+
- This PR follows this pattern in `toggleServerDisabled()`
31+
32+
3. **UI State Synchronization**
33+
- Pattern: Backend state changes trigger `notifyWebviewOfServerChanges()`
34+
- This PR correctly notifies the webview after toggling disabled state
35+
36+
### Pattern Deviations
37+
38+
1. **Inconsistent Disabled Check Placement**
39+
40+
- The disabled check is added in `updateServerConnections()` but only for new servers and config changes
41+
- Missing disabled check in the initial connection logic during server initialization
42+
- Should be more centralized in `connectToServer()` method itself
43+
44+
2. **UI Color State Logic**
45+
- The UI adds disabled check at the beginning of `getStatusColor()` which is good
46+
- However, the opacity change is already handled by the parent div (line 281)
47+
- This creates redundant visual indicators
48+
49+
### Redundancy Findings
50+
51+
1. **Disabled State Visual Indicators**
52+
53+
- The PR adds grey color for disabled servers in `getStatusColor()`
54+
- But the parent div already sets `opacity: server.disabled ? 0.6 : 1` (line 281)
55+
- Both visual indicators might be redundant
56+
57+
2. **Connection State Checks**
58+
- The PR checks `connection.server.status === "connected"` before disconnecting
59+
- But `deleteConnection()` already handles non-existent connections gracefully
60+
- The check might be unnecessary
61+
62+
### Organization Issues
63+
64+
1. **Test Organization**
65+
66+
- New tests are correctly placed within the existing "server disabled state" describe block
67+
- Tests follow the existing pattern of mocking transport and client
68+
- Good organization - no issues here
69+
70+
2. **Logic Distribution**
71+
- Disabled check logic is spread across multiple places:
72+
- `updateServerConnections()` - for new/changed servers
73+
- `toggleServerDisabled()` - for toggling state
74+
- `getStatusColor()` - for UI display
75+
- Could be more centralized

0 commit comments

Comments
 (0)