Skip to main content
Glama
README.md
# dsh-dispatch

**English** | [中文](#中文)

HTTP **MCP Streamable** dispatch server for [DeepSeek Harness (DSH)](https://github.com/deepseek-ai): parallel ACP workers, optional LLM review, and spend/send guardrails.

Bind address is hard-coded to `127.0.0.1` (local only). Auth is Bearer token from `./.token`.

## Requirements

- Node.js ≥ 18
- DeepSeek Harness (`dsh`) installed locally, typically at `~/.npm-global/lib/node_modules/@deepseek-ai/dsh`  
  Override with `DSH_INSTALL` / `DSH_HOME` if needed.

## Install

```bash
git clone https://github.com/16601134718/dsh-dispatch.git
cd dsh-dispatch
cp config.example.json config.json   # optional: edit deny list
# Token: either copy .token.example → .token, or let the server auto-create .token on first start
chmod +x start.sh stop.sh approve.sh
```

Or run from a clone / checkout path with Node directly (`node server.mjs`).  
`npx` is not required; this package has no npm runtime dependencies of its own (it loads MCP/ACP/zod from your DSH install).

## Start / stop

```bash
./start.sh          # foreground
./start.sh -d       # daemon (writes server.pid, logs to logs/server.out)
./stop.sh
```

Default MCP URL: `http://127.0.0.1:18790/mcp`  
Port override: `DSH_DISPATCH_PORT=18790`

Show health (needs Bearer token):

```bash
TOKEN=$(cat .token)
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:18790/healthz
```

## MCP tools

| Tool | Purpose |
|------|---------|
| `dsh_dispatch` | Dispatch a task to an existing DSH session id or `session:"new"` |
| `dsh_followup` | Follow up in the same session as a job / session id |
| `dsh_spawn` | Fan out multiple tasks across parallel ACP workers |
| `dsh_wait` | Wait for one or more jobs (`all` / `any`) |
| `dsh_result` | Full job result (text, tool_calls, usage, review) |
| `dsh_status` | Job list + worker pool |
| `dsh_sessions` | List real DSH sessions from local index (marks denied) |
| `dsh_guard_check` | Dry-run guardrail check on task text |
| `dsh_health` | Service health |

## Guardrails

Tasks matching **spend money**, **external send/publish**, or **expose network** are held as `needs_confirmation`.

1. Server writes `approvals/apr-xxxx.pending.json`
2. A human on the same machine runs: `./approve.sh apr-xxxx` and types `YES`
3. Resubmit the tool call with `approval_id: "apr-xxxx"`

Runtime tool permissions that look risky are also denied inside the ACP worker.

### Deny list (protected sessions)

Do **not** hardcode personal session ids in code. Use:

- Env: `DSH_DISPATCH_DENY=prefix-or-id,another`
- Or `config.json` (see `config.example.json`): `deny_sessions`, `deny_title_patterns`

## Connect from Dot / Muse / Grok Bot

Point the MCP HTTP client at:

- **URL:** `http://127.0.0.1:18790/mcp`
- **Auth:** `Authorization: Bearer <contents of .token>`
- **Transport:** MCP Streamable HTTP

The client and this server must reach the same loopback (same machine, or a secure local forward you set up yourself).

### Optional tunnel (not required)

A tunnel (e.g. cloudflared) is **optional** and **not** part of the default setup. Prefer SSH port-forward or stay on localhost. Exposing this endpoint publicly is discouraged; guardrails treat tunnel/public-bind language as risky.

## Environment

| Variable | Default | Meaning |
|----------|---------|---------|
| `DSH_HOME` | `~/.dsh` | DSH data home |
| `DSH_INSTALL` | `~/.npm-global/lib/node_modules/@deepseek-ai/dsh` | DSH package root |
| `DSH_DISPATCH_PORT` | `18790` | Listen port |
| `DSH_DISPATCH_MAX_WORKERS` | `4` | Max parallel ACP children |
| `DSH_DISPATCH_DENY` | _(empty / config)_ | Comma-separated session id/prefix deny list |
| `DSH_DISPATCH_CONFIG` | `./config.json` | Optional JSON config path |
| `NODE_BIN` | `node` on PATH | Node binary for `start.sh` |

## Safety notes

- Never commits `.token`, `jobs.json`, `logs/`, `work/`, `approvals/`, or pid files (see `.gitignore`).
- Does **not** write `~/.dsh/bridge/*` or other bridge endpoint files.
- Does **not** spend money or send external messages by itself; such tasks need human `./approve.sh`.

## License

MIT © 2026 陈子龙 (16601134718)

---

## 中文

面向 **DeepSeek Harness (DSH)** 的 HTTP **MCP Streamable** 调度服务:多 ACP worker 并行、可选审查、以及花钱/对外发送护栏。

默认只监听 `127.0.0.1`,用 `./.token` 做 Bearer 鉴权。

### 依赖

- Node.js ≥ 18
- 本机已安装 DSH(可用 `DSH_INSTALL` / `DSH_HOME` 覆盖路径)

### 安装与启动

```bash
git clone https://github.com/16601134718/dsh-dispatch.git
cd dsh-dispatch
cp config.example.json config.json   # 可选:配置拒绝会话列表
chmod +x start.sh stop.sh approve.sh
./start.sh          # 前台
./start.sh -d       # 后台
./stop.sh
```

MCP 地址:`http://127.0.0.1:18790/mcp`  
鉴权头:`Authorization: Bearer <token>`

### MCP 工具

`dsh_dispatch` / `dsh_followup` / `dsh_spawn` / `dsh_wait` / `dsh_result` / `dsh_status` / `dsh_sessions` / `dsh_guard_check` / `dsh_health`

### 护栏

匹配「花钱 / 对外发送发布 / 暴露公网」的任务会变成 `needs_confirmation`,需本机执行 `./approve.sh apr-xxxx` 并输入 `YES`,再用 `approval_id` 重提。

受保护会话请用环境变量 `DSH_DISPATCH_DENY` 或 `config.json`(见 `config.example.json`),不要把真实 session id 写进代码。

### 给 Dot / Muse / Grok Bot 连接

- URL:`http://127.0.0.1:18790/mcp`
- Bearer:读取本目录 `.token`
- 隧道(cloudflared 等)**可选、非必需**;默认建议仅本机或 SSH 端口转发。

### 许可

MIT © 2026 陈子龙 (16601134718)

## Desktop GUI sessions (2026-10-29)

Dispatch prefers the **DeepSeek Harness desktop** API (`session/create` + `session/prompt` on localhost `/api`, authenticated with the Electron `dsh-auth-*` cookie). New sessions land in the untitled-folder workspace sidebar as `session-…` (format v4). See `gui-client.mjs`. Set `DSH_DISPATCH_GUI=0` to force ACP fallback. Toonflow / `fc9d02d8` remain denied.

Maintenance

ActivityMaintained
ResponsivenessNo issues