b015e70b9d
* feat(mcp): add MCP server management UI - Server CRUD: add/edit/remove with YAML/JSON Monaco editor - raw_config passthrough: zero field loss on edit/toggle - tool_details embedding: single-request card data (1+N → 1) - Auto-retry exponential backoff (2s→32s, max 5 retries) - Route safety guards (hasRoute) for dynamic sidebar - i18n: 9 languages (de/en/es/fr/ja/ko/pt/zh/zh-TW) - 19 unit tests + 8 UX browser tests - 35 files, +2933 lines * fix mcp management lifecycle --------- Co-authored-by: Crafter-feng <succeed_happu@163.com>
168 lines
9.1 KiB
Markdown
168 lines
9.1 KiB
Markdown
# feat(mcp): Add MCP Server Management UI
|
|
|
|
## Summary
|
|
|
|
Add a complete MCP (Model Context Protocol) server management interface that allows users to manage MCP servers through the web UI. This feature provides a user-friendly way to configure, monitor, and control MCP servers without editing configuration files manually.
|
|
|
|
## Features
|
|
|
|
### Core Functionality
|
|
- **Server List**: View all configured MCP servers with real-time status indicators (connected/disconnected/disabled)
|
|
- **Add Server**: Add new MCP servers with YAML or JSON configuration editor (Monaco Editor)
|
|
- **Edit Server**: Modify existing server configurations — uses `raw_config` passthrough to avoid field loss
|
|
- **Remove Server**: Delete servers with confirmation dialog to prevent accidental deletion
|
|
- **Enable/Disable**: Toggle individual servers on/off with instant feedback
|
|
- **Test Connection**: Verify server connectivity and list available tools
|
|
- **Reload**: Refresh server configuration without restarting
|
|
- **Search/Filter**: Filter servers by name for quick navigation
|
|
|
|
### User Experience
|
|
- **Monaco Editor**: Full-featured code editor with YAML/JSON syntax highlighting
|
|
- **Responsive Design**: Works on desktop (1280px), tablet (768px), and mobile (480px)
|
|
- **Auto-Retry**: Exponential backoff (2s → 4s → 8s → 16s → 32s, max 5 retries) for servers that haven't connected yet
|
|
- **Loading States**: Clear feedback during async operations
|
|
- **Error Handling**: User-friendly error messages with actionable guidance
|
|
- **Multi-language Support**: 9 languages (English, Chinese Simplified/Traditional, Japanese, Korean, German, Spanish, French, Portuguese)
|
|
|
|
### Performance Optimizations
|
|
- **`raw_config` Passthrough**: Backend returns the original config dict as-is — frontend edits/Toggles use it directly, eliminating field-rebuild bugs
|
|
- **`tool_details` Embedding**: `mcp_list` response embeds filtered `{name, description}` per server, reducing first-load from 1+N requests to 1
|
|
- **Route Safety**: `hasRoute()` guards for dynamic sidebar routes to prevent Vue runtime crashes
|
|
|
|
## Technical Implementation
|
|
|
|
### Frontend (Vue 3 + Naive UI)
|
|
- `McpManagerView.vue`: Main management component with auto-retry, search, modal management
|
|
- `McpServerCard.vue`: Server card component with status indicators, tool tags, action buttons
|
|
- `mcp.ts` (api): Type definitions (`McpServerInfo` with `raw_config`, `tool_details`) and API client
|
|
- Monaco Editor integration for configuration editing
|
|
- Reactive state management with Vue 3 Composition API
|
|
|
|
### Backend (Koa + TypeScript)
|
|
- `mcp.ts` (controller): Request handlers with input validation
|
|
- `mcp.ts` (service): Business logic layer with typed interfaces
|
|
- `mcp.ts` (routes): RESTful API endpoints
|
|
- `mcp-types.ts`: Shared type definitions
|
|
- `client.ts` (bridge): AgentBridge client methods
|
|
|
|
### Python Bridge (`hermes_bridge.py`)
|
|
- `_build_server_entry()`: Normalized server entry builder returning `raw_config` and `tool_details`
|
|
- `_mcp_list()`: Lists all MCP servers with embedded filtered tool details
|
|
- `_mcp_server_add/update/remove`: Full CRUD with config validation and atomic YAML persistence
|
|
- `_mcp_server_toggle`: Enable/disable individual servers
|
|
- `_mcp_server_test`: Connection test with tool discovery
|
|
- `_mcp_reload`: Hot-reload server connections
|
|
- Background MCP discovery on worker startup
|
|
|
|
### Testing
|
|
- `mcp-controller.test.ts`: 19 unit tests covering all controller methods
|
|
- Tests for success cases, error handling, and edge cases
|
|
- Mock-based testing for isolation
|
|
|
|
## Files Changed
|
|
|
|
```
|
|
packages/client/src/api/hermes/mcp.ts | 87 ++++
|
|
packages/client/src/components/hermes/mcp/McpServerCard.vue | 275 +++++++++
|
|
packages/client/src/components/layout/AppSidebar.vue | 16 +-
|
|
packages/client/src/components/hermes/chat/ChatInput.vue | 1 +
|
|
packages/client/src/i18n/locales/{de,en,es,fr,ja,ko,pt,zh,zh-TW}.ts | 504 +++ (9 files)
|
|
packages/client/src/i18n/messages.ts | 2 +-
|
|
packages/client/src/router/index.ts | 6 +
|
|
packages/client/src/views/hermes/McpManagerView.vue | 623 +++++++++++++++++
|
|
packages/server/src/controllers/hermes/mcp.ts | 117 ++++
|
|
packages/server/src/routes/hermes/mcp.ts | 12 +
|
|
packages/server/src/routes/index.ts | 2 +
|
|
packages/server/src/services/hermes/agent-bridge/client.ts | 31 +
|
|
packages/server/src/services/hermes/agent-bridge/hermes_bridge.py | 368 +++++++++-
|
|
packages/server/src/services/hermes/mcp-types.ts | 67 ++
|
|
packages/server/src/services/hermes/mcp.ts | 67 ++
|
|
packages/server/src/services/hermes/run-chat/session-command.ts | 22 +
|
|
tests/server/mcp-controller.test.ts | 286 +++++++++
|
|
```
|
|
|
|
**Total**: 27 files changed, ~2,900 insertions
|
|
|
|
## Testing
|
|
|
|
### Unit Tests (19/19 passing)
|
|
```
|
|
✓ MCP Controller > listServers > returns servers list from bridge
|
|
✓ MCP Controller > listServers > returns 503 on bridge error
|
|
✓ MCP Controller > addServer > sends name and config to bridge
|
|
✓ MCP Controller > addServer > returns 400 when name is missing
|
|
✓ MCP Controller > addServer > returns 400 when config is missing
|
|
✓ MCP Controller > updateServer > sends name from params and config to bridge
|
|
✓ MCP Controller > updateServer > returns 400 when config is missing
|
|
✓ MCP Controller > removeServer > sends name to bridge
|
|
✓ MCP Controller > testServer > returns tool list from bridge
|
|
✓ MCP Controller > listTools > returns tools without server filter
|
|
✓ MCP Controller > listTools > passes server filter to bridge
|
|
✓ MCP Controller > listTools > returns 503 on bridge error
|
|
✓ MCP Controller > reloadMcp > reloads all servers when no filter
|
|
✓ MCP Controller > reloadMcp > reloads specific server
|
|
✓ MCP Controller > reloadMcp > returns 500 on bridge error
|
|
✓ MCP Controller > profile handling > passes undefined profile when ctx.state.profile is missing
|
|
✓ MCP Controller > profile handling > passes undefined profile when profile.name is empty
|
|
✓ MCP Controller > response structure > mcp_list response has all required fields
|
|
✓ MCP Controller > response structure > mcp_tools_list response has tools with name/description/schema
|
|
```
|
|
|
|
### UX Browser Tests (8/8 passing)
|
|
|
|
| Test Case | Screenshot | Result |
|
|
|-----------|------------|--------|
|
|
| TC-01 Initial State | [mcp-tc01-initial-state.png](docs/images/mcp/mcp-tc01-initial-state.png) | ✅ Summary cards 1/1/0/3, github server connected |
|
|
| TC-02 Search Filter | [mcp-tc02-search-git.png](docs/images/mcp/mcp-tc02-search-git.png) | ✅ Correctly filters to github only |
|
|
| TC-03 Search Empty | [mcp-tc03-search-empty.png](docs/images/mcp/mcp-tc03-search-empty.png) | ✅ Empty state "暂无 MCP 服务器配置" shown |
|
|
| TC-04 Add Modal | [mcp-tc04-add-modal.png](docs/images/mcp/mcp-tc04-add-modal.png) | ✅ JSON/YAML toggle, config editor, Cancel/Save |
|
|
| TC-05 Edit Modal | [mcp-tc05-edit-modal.png](docs/images/mcp/mcp-tc05-edit-modal.png) | ✅ Pre-filled config with raw_config passthrough |
|
|
| TC-06 Tools Expanded | [mcp-tc06-tools-expanded.png](docs/images/mcp/mcp-tc06-tools-expanded.png) | ✅ Shows 3/26 tool tags |
|
|
| TC-07 Responsive 768px | [mcp-tc07-responsive-768.png](docs/images/mcp/mcp-tc07-responsive-768.png) | ✅ Tablet layout, no overflow |
|
|
| TC-08 Responsive 480px | [mcp-tc08-responsive-480.png](docs/images/mcp/mcp-tc08-responsive-480.png) | ✅ Mobile layout, all elements accessible |
|
|
|
|
### Build
|
|
- [x] TypeScript compilation successful
|
|
- [x] Vite build successful
|
|
- [x] No linting errors
|
|
|
|
## Architecture Decisions
|
|
|
|
### 1. `raw_config` Passthrough
|
|
**Problem**: Rebuilding config from scattered fields (command, args, env, etc.) caused field loss on edit/Toggle.
|
|
**Solution**: Backend returns `raw_config` (original dict from config.yaml), frontend edits it directly. Zero rebuild, zero field loss.
|
|
|
|
### 2. `tool_details` Embedding
|
|
**Problem**: First load required 1 API call for server list + N calls for tool details (one per server).
|
|
**Solution**: `mcp_list` response embeds `tool_details` (filtered `{name, description}` per server). Single request for full card data.
|
|
|
|
### 3. Auto-Retry with Exponential Backoff
|
|
**Problem**: MCP servers may not be connected on first page load (still initializing).
|
|
**Solution**: Auto-retry with exponential backoff (2s, 4s, 8s, 16s, 32s), max 5 retries. Manual refresh resets counter.
|
|
|
|
### 4. Route Safety Guards
|
|
**Problem**: Unknown routes (e.g., `codingAgents`, `versionPreview`) could crash Vue at runtime.
|
|
**Solution**: `hasRoute()` checks before rendering dynamic sidebar route items.
|
|
|
|
## Screenshots
|
|
|
|
### Desktop (1280px) — Initial State
|
|

|
|
|
|
### Edit Server Modal
|
|

|
|
|
|
### Responsive — Mobile (480px)
|
|

|
|
|
|
## Checklist
|
|
|
|
- [x] Code follows project style guidelines
|
|
- [x] Self-review completed
|
|
- [x] Documentation updated
|
|
- [x] Tests added for new functionality (19 unit + 8 UX)
|
|
- [x] All tests pass
|
|
- [x] No breaking changes
|
|
- [x] Multi-language support (9 languages)
|
|
- [x] Responsive design verified (desktop/tablet/mobile)
|