Bundle
dsh-mcp-orchestrator
MCP orchestration layer for DeepSeek Harness — multi-server routing, health monitoring, fallback, and tool aggregation
- Source
- AIMarshallLee
- License
- MIT
- Updated
- Updated 2 days ago
Readme
# dsh-mcp-orchestrator
MCP orchestration layer for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH) — multi-server management, health monitoring, auto-restart, tool aggregation with collision handling, fallback routing, and usage statistics.
## What It Does
DSH has built-in MCP client support, but it lacks orchestration: there's no health monitoring, no auto-restart on crash, no tool collision detection, no fallback routing, and no unified tool discovery. This plugin fills that gap.
**Key capabilities:**
- Connect to multiple stdio MCP servers simultaneously
- Health monitoring via periodic ping checks
- Auto-restart with exponential backoff on unexpected disconnection
- Tool aggregation across all servers with collision detection
- Three namespace modes for tool name conflicts (`collision`, `server`, `dot`)
- Fallback routing: when a tool call fails on one server, auto-retry on others providing the same tool
- Priority-weighted sorting: servers sorted by success rate then priority
- Usage statistics: per-server, per-tool, and overall call tracking with response times
- Four DSH management tools for the agent to discover, call, and monitor MCP tools
## Status: v0.2.0 — Orchestration
### Verified Capabilities
| Capability | Status | Test |
|-----------|--------|------|
| MCP SDK Client API (connect, ping, listTools, callTool, close) | Pass | `test/spike.mjs` |
| Multi-client support (2+ servers) | Pass | `test/spike.mjs` |
| Error handling (non-existent tool, missing args) | Pass | `test/spike.mjs` |
| ServerManager connect/disconnect/restart | Pass | `test/integration.mjs` |
| Tool discovery and calling | Pass | `test/integration.mjs` |
| Auto-restart with exponential backoff | Pass | `test/integration.mjs` |
| Tool collision detection | Pass | `test/integration.mjs` |
| Namespace modes (collision/server/dot) | Pass | `test/integration.mjs` |
| Health monitoring (ping-based) | Pass | `test/integration.mjs` |
| Zod config schema validation (incl. Phase 3 fields) | Pass | `test/integration.mjs` |
| Plugin lifecycle (apply, tools, system prompt, cleanup) | Pass | `test/integration.mjs` |
| Multi-server plugin with collision handling | Pass | `test/integration.mjs` |
| Fallback routing on server failure | Pass | `test/integration.mjs` |
| Priority-weighted candidate sorting | Pass | `test/integration.mjs` |
| Success-rate-based server ordering | Pass | `test/integration.mjs` |
| UsageTracker (record, stats, getRecent, clear) | Pass | `test/integration.mjs` |
| mcp_stats tool (summary/server/tool/all detail modes) | Pass | `test/integration.mjs` |
| Fallback disabled mode (direct routing path) | Pass | `test/integration.mjs` |
### Test Results
```
Spike: 34 passed, 0 failed
Integration: 236 passed, 0 failed
Total: 270 passed, 0 failed
```
## Architecture
```
DSH Agent (Node.js process)
└─ Cordis Framework
└─ dsh-mcp-orchestrator plugin (apply(ctx, config))
├─ Config Schema (zod: servers[], healthCheckInterval, namespaceMode,
│ enableFallback, maxFallbackAttempts, preferHealthyServers, enableStats)
├─ System Prompt: "mcp-orchestrator" (management tools + workflow guide)
├─ Tool: mcp_list_servers (status, health, tool count per server)
├─ Tool: mcp_list_tools (aggregated tools, collision info, namespaced names)
├─ Tool: mcp_call_tool (auto-resolve, fallback routing, metadata in results)
├─ Tool: mcp_stats (usage statistics: summary/server/tool/all)
├─ ServerManager
│ ├─ Multi-server stdio connections (StdioClientTransport)
│ ├─ Auto-restart (exponential backoff, max restarts)
│ ├─ Tool sync (listTools on connect/reconnect)
│ ├─ Health ping
│ └─ findServerForTool (priority-based resolution)
├─ ToolRegistry
│ ├─ Tool aggregation across all servers
│ ├─ Collision detection (same tool name on multiple servers)
│ └─ Namespace modes: collision / server / dot
├─ HealthMonitor
│ └─ Periodic ping checks (configurable interval)
├─ UsageTracker
│ ├─ Records every call (success/failure, response time, fallback)
│ ├─ Per-server, per-tool, overall statistics
│ └─ Recent call log (configurable max records)
├─ FallbackRouter
│ ├─ Resolves tool → finds all servers providing it
│ ├─ Sorts candidates by success rate (if enabled) then priority
│ ├─ preferredServer override (try specific server first)
│ └─ Sequential fallback with max attempts limit
└─ ctx.effect() cleanup (stop monitor, close all servers, clear tracker)
```
## Installation
### Prerequisites
- Node.js >= 22.19 (or >= 24)
- DSH installed: `npm install -g @deepseek-ai/dsh`
- At least one MCP server to connect to
### Build
```bash
cd dsh-mcp-orchestrator
npm install
npm run build
```
### Install into DSH
**Option A: From GitHub (recommended)**
```bash
dsh plugin --profile web add github:Daseanle/dsh-mcp-orchestrator
dsh web
```
**Option B: From local clone**
```bash
git clone https://github.com/Daseanle/dsh-mcp-orchestrator.git
cd dsh-mcp-orchestrator && npm install && npm run build
dsh plugin --profile web add file:./dsh-mcp-orchestrator
dsh web
```
### Configuration
Create or edit `cordis.patch.yml` in your DSH config directory:
```yaml
- id: dsh-mcp-orchestrator
config:
servers:
- name: filesystem
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
autoRestart: true
priority: 10
- name: memory
command: npx
args: ["-y", "@modelcontextprotocol/server-memory"]
autoRestart: true
priority: 5
healthCheckInterval: 30000
namespaceMode: collision
```
### Config Schema (zod)
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `servers` | array | `[]` | MCP server configurations |
| `servers[].name` | string | — | Unique server name |
| `servers[].command` | string | — | Executable to run |
| `servers[].args` | string[] | `[]` | Command line arguments |
| `servers[].env` | Record<string, string> | `{}` | Environment variables |
| `servers[].autoRestart` | boolean | `true` | Auto-restart on crash |
| `servers[].restartDelay` | number | `2000` | Base restart delay (ms) |
| `servers[].maxRestarts` | number | `3` | Max restart attempts |
| `servers[].priority` | number | `0` | Priority for tool resolution (higher = preferred) |
| `healthCheckInterval` | number | `30000` | Ping interval (ms) |
| `namespaceMode` | enum | `collision` | Tool name collision handling |
| `enableFallback` | boolean | `true` | Enable fallback routing on tool call failure |
| `maxFallbackAttempts` | number | `3` | Max servers to try before giving up |
| `preferHealthyServers` | boolean | `true` | Sort candidates by success rate (false = priority only) |
| `enableStats` | boolean | `true` | Register mcp_stats tool and track usage |
### Namespace Modes
| Mode | Behavior | Example |
|------|----------|---------|
| `collision` | Namespace only when same tool name exists on 2+ servers | `echo` → `server1__echo` (if collision) |
| `server` | Always namespace with `serverName__toolName` | `echo` → `server1__echo` |
| `dot` | Always namespace with `serverName.toolName` | `echo` → `server1.echo` |
## Project Structure
```
dsh-mcp-orchestrator/
├── src/
│ ├── index.ts # Plugin entry: apply(ctx, config) with zod schema
│ ├── server-manager.ts # MCP server connections, auto-restart, tool sync
│ ├── tool-registry.ts # Tool aggregation, collision detection, namespacing
│ ├── health-monitor.ts # Periodic ping-based health checks
│ ├── usage-tracker.ts # Tool call statistics (per-server, per-tool, overall)
│ ├── fallback-router.ts # Fallback routing with priority and success-rate sorting
│ └── tools/
│ ├── list-servers.ts # mcp_list_servers tool
│ ├── list-tools.ts # mcp_list_tools tool
│ ├── call-tool.ts # mcp_call_tool tool (with fallback routing)
│ └── stats.ts # mcp_stats tool (usage statistics)
├── dist/ # Compiled JavaScript (tsc output)
├── test/
│ ├── mock-server.mjs # Mock MCP server (echo, add, greet)
│ ├── mock-server-2.mjs # Second mock server (echo, subtract) for collision tests
│ ├── spike.mjs # Spike: MCP SDK API validation (34 tests)
│ └── integration.mjs # Integration: full plugin tests (236 tests)
├── cordis.patch.yml # Example plugin configuration
├── package.json
├── tsconfig.json
├── CHANGELOG.md
└── LICENSE
```
## Roadmap
| Phase | Scope | Status |
|-------|-------|--------|
| Phase 1 — Spike | MCP SDK validation, connect/listTools/callTool, multi-client | Complete |
| Phase 2 — MVP | ServerManager, ToolRegistry, HealthMonitor, auto-restart, 3 DSH tools | Complete |
| Phase 3 — Orchestration | Fallback routing, usage statistics, priority weighting, mcp_stats tool | Complete |
## License
MIT
Install
dsh plugin --profile web add github:AIMarshallLee/dsh-mcp-orchestrator#0d497dd1a67ebe19ebc026d70fc0b43dae70bc71
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-mcp-orchestrator from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.