dsh-dispatch
by 16601134718
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.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues