Skip to content
dsh.fish
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

  • 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.
Source