DSH Rice on a Stick
DSH Rice on a Stick
English | 中文
Operate a running DeepSeek Harness (dsh) from any MCP client: the plugin exposes dsh's session center, model/preset catalog, workspaces, and live activity as an MCP server, so Claude Code, Cursor, Cline, or your own agent can create and steer real dsh sessions — the same sessions the dsh UI shows. The same tool surface is also registered as native tools in this instance, so dsh's own sessions can operate themselves.
Claude Code / Cursor / Cline / your agent
│ Streamable HTTP · 127.0.0.1:8090/mcp
▼
dsh-rice-on-a-stick
│ sessionController · agents · tools · workspaces
▼
dsh host — the same sessions the UI shows
Highlights
- Real sessions, not a shell wrapper — tools go through the host's session controller: create, prompt, queue, fork, archive, model switch.
- Async orchestration —
session_submit / session_poll / session_result; a client timeout only stops the wait, never the dsh turn; stopping work goes through session_cancel.
- Approvals —
approval_list / approval_answer / approval_policy; approvalControl decides who answers approvals for sessions this plugin created or resumed: exclusive (default) means the caller only — the UI no longer shows the request; fallback is UI first, handing over to the caller when the UI cannot answer; off is display-only.
- Self-use — the same surface registers as native
rice_ tools inside this instance; http: false gives a self-use-only deployment.
- Tools-first by default — binds
127.0.0.1, optional Bearer auth, Host/Origin allowlists, idle transport-session reaping; resource-first mode is opt-in, so clients that only understand tools see no change.
The exact tool and resource surfaces are defined in src/mcp/tools/ and src/mcp/resources.ts; agents should call dsh_get_started first — it carries the dsh crash course, recipes, and error recovery.
Requirements
- DSH
>= 0.2.1-rc.2 (declared as engines.dsh). A web/desktop profile is needed for the settings panel and the full session surface; minimal/headless profiles can still run the MCP server. stdio-only clients need a Streamable HTTP bridge.
Install
The package is not published on npm; install from a built checkout:
git clone https://github.com/Leawind/dsh-rice-on-a-stick.git
cd dsh-rice-on-a-stick
npm install
npm run build
dsh plugin --profile web add link:"$(pwd)"
Restart dsh web, then open Settings → MCP Service. To remove: dsh plugin --profile web remove dsh-rice-on-a-stick.
Connect an MCP client
Default endpoint http://127.0.0.1:8090/mcp. Auth is off until a token is configured; when on, send the token from Settings → MCP Service as a Bearer credential:
{
"mcpServers": {
"dsh": {
"type": "http",
"url": "http://127.0.0.1:8090/mcp",
"headers": { "Authorization": "Bearer <token>" }
}
}
}
Typical loop:
{ "name": "model_list", "arguments": {} }
{ "name": "session_create", "arguments": { "cwd": "/path/to/project", "provider": "…", "model": "…", "preset": "standard" } }
{ "name": "session_submit", "arguments": { "sessionId": "…", "task": "…" } }
{ "name": "session_poll", "arguments": { "sessionIds": ["…"], "waitMs": 20000 } }
{ "name": "session_result", "arguments": { "sessionId": "…", "requestId": "…" } }
New sessions require explicit provider + model + preset from model_list — the plugin never backfills defaults. Resuming a sessionId reuses that session's model and preset.
Configuration
Fields and defaults live in src/core/config.ts — the single source of truth. The settings panel covers every config field (no omissions): volatile fields are saved in place without reloading (MCP connections stay up); the structural ones (listen address and port, external MCP switch, resource-first mode, approval answerer and wait limit, transport idle TTL, Host header allowlist) are written and reload the plugin automatically when you leave the field or close the settings dialog — there is no Apply button, and invalid values are reported in place instead of being written. Key defaults: resourceFirst: false (tools first), approvalControl: exclusive (the caller answers approvals), sessionTtlMs: 604800000 (one week). Transport overrides go into the profile's cordis.patch.yml:
- id: dsh-rice-on-a-stick
config:
http: true
port: 8090
host: 127.0.0.1 # localhost only by default; add auth before exposing
# authToken: 'your-secret-token'
Security
[!WARNING]
This plugin exposes local code execution. It binds 127.0.0.1 only by default, but with auth off any local process that can reach the port can drive dsh.
- Set
authToken; never bind 0.0.0.0 or expose to LAN/WAN without a reverse proxy + TLS + auth.
- No directory whitelist: sessions may work in any
cwd the caller specifies.
- Native
rice_ tools bypass HTTP/auth — every session in this instance can call them; turn off the registration switch if that is unwanted.
Development
npm install
npm run build # compile src/ to lib/ and src/client/ to client/
npm run dev # watch both TypeScript projects
npm test # build + smoke
npm run typecheck # type-check src/, src/client/, test/ and scripts/
npm run smoke:ui # browser harness for the settings panel
Layout: src/ host half (MCP server, tools, resources, engine) and src/client/ settings-panel source; client/ is the generated panel bundle (build output), cordis.yml bundle patch, test/ smoke + e2e + UI harness, docs/ architecture notes. Design constraints that are not obvious from code: docs/architecture.zh.md (Chinese). test/e2e.ts is a separate real-host check, not part of npm test.
Acknowledgements
Started as a copy of chushixixin/dsh-harness-mcp-server (MIT, thanks @chushixixin), now an independent project.
License
MIT