dsh-any-agent

mcp
Security Audit
Warn
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Warn
  • process.env — Environment variable access in bin/dsh-any-agent.mjs
  • process.env — Environment variable access in bin/setup.mjs
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

MCP server that drives DeepSeek Harness (DSH) as a long-lived coding agent from any MCP client — resume-aware, interruptible, approval-capable.

README.md
dsh-any-agent — a blue-haired chibi whale-girl eating white rice beside a coding laptop

Give any MCP client a coding buddy that sticks around.

Website · English · 简体中文

npm version
node
license
dependencies
tests

Website · Quick start · Features · Tools · Live view · Usage notes · Changelog

🧪 Offline suite green in CI on Linux, Windows and macOS · 👀 new live call-chain view (watch / dashboard, with token usage) · 🔌 MCP over stdio · 📦 Zero dependencies · 📜 MIT

An MCP server that drives DeepSeek Harness as a long-lived coding agent. Hand it a goal, let it write code and run scripts, steer it mid-flight, and collect the result when you are ready.

Claude Code · Claude Desktop · Codex · Cursor · Windsurf · Zed · Gemini CLI · Antigravity · opencode · VS Code — or any client that speaks MCP over stdio.

🎯 The problem this solves

You already have a coding agent in your editor. What you do not have is one that can:

  • hand a multi-hour job to another agent and walk away — then collect the result when it's done;
  • keep the job alive across restarts of your editor, your session, your machine's idle reap (the conversation always survives; for a turn that is still running to survive the client closing or reconnecting, turn on resident process mode, DSH_MCP_DAEMON=1);
  • cut in mid-flight when it's going the wrong way, without destroying the work;
  • run several of them at once and switch between them;
  • see what it is doing without asking the agent — which tools it called, which approvals went through, how many tokens it spent.

DSH (DeepSeek Harness) can do all of that — it has file/shell tools, skills, subagents and workflows — but it is a GUI-first application. Its own sdk profile exposes only 3 requests and can't resume, cancel, or answer approvals.

This server is the missing adapter: it makes DSH into a well-behaved background agent that any MCP client can hire, supervise and collect from.

Think of it as &job — like & in a shell, but for an agent.

✨ Why it's different

Capability What you get
🔄 A dead process never kills a conversation The identity lives on disk. A crash, an idle reap, even restarting this whole server costs you nothing — the next call transparently resumes it, memory intact (verified across processes).
🗣️ You are never stuck waiting Steer a conversation mid-flight — interject to stop and redirect (~100 ms to reach idle, measured over four cancelled turns), or queue a remark for after the current turn. Interrupting never damages the conversation.
📡 Completion notification, not polling Long tasks return instantly with a run_id; when the turn ends, a sentinel file is written atomically so a background task in your host wakes you. No polling, no occupied turn.
🪟 Many conversations at once dsh_list(only_running) shows what's live; dsh_read gives cursor-based incremental output. Cycle between them like windows.
👀 You can see it yourself dsh-any-agent watch (terminal) or dsh-any-agent dashboard (local read-only web page) lays dispatched work out as a call chain — client → conversation → run → tool calls / approvals — with per-run tokens and context-window use, updating while the run is going. Separate processes, never touch the write lock, and show work from every client together.
🧠 Reasoning hidden by default You get "thought for N chars / M seconds" statistics instead of context-burning prose — and it is never logged, never written to disk.
🤫 Silent by default Not one byte on stderr, so nothing pollutes your host's logs. stdout carries the protocol and nothing else.
🧩 Capabilities compose DSH can mount its own MCP servers (IDA Pro, browsers, your internal tooling), so this is a bridge to a whole toolbox.
🛡️ Read-only that really is read-only read-only sandbox plus auto-denied approvals, for working on untrusted samples.
🔎 Caller review, not blind relay Every result carries a review ticket (checklist + evidence + dsh_review entry). The caller verifies with its own tools, then records pass / partial / fail. Advisory by default — it never blocks the next dispatch, and a failed review is not silently fed back to DSH.

🧭 Positioning: a dispatcher, not a capability aggregator

This server dispatches; it does not re-implement what DSH already does. The caller
gives a goal, and DSH decides which tools, skills, subagents or team to use. Nothing
from DSH's tool surface is proxied, duplicated or preloaded.

Owned by DSH (this server stays out) Owned by this server (dispatch semantics)
File I/O, shell, search, editing Session identity and cross-crash resume
Skills, subagents, Agent Teams, task board Async dispatch, receipts, completion sentinels
Model routing, sandbox, approval policy Incremental read, interject, interrupt, live call-chain view
Memory/context/compaction Approval bridge, write-lock governance, queue, inbox
worktrees (the agent creates them with git) Setup, status, doctor, audit

Dispatch on demand: dsh_send passes a goal, not a tool manifest, and the caller
does not need to know DSH's tool list. The DSH agent picks what it needs — including
capabilities added after this server was built (for example the experimental Agent
Teams). This server does not grow one MCP tool per DSH feature.

Team mode (opt-in since 0.5.0): off by default. Run dsh-any-agent team on
and reconnect; the profile switches to dsh-team (the experimental Agent Teams
packages), and dsh_send then adds a short "form a team if this needs parallel or
multi-role work" line; simple tasks are not forced into a team. Turn it off with
dsh-any-agent team off, or for one call with dsh_send(team=false). The team
profile disables the legacy subagent tools and replaces them with nine team
tools; teammates share one workspace.

Only dispatch semantics become tools: start, send, read, get, review, interject,
interrupt, approve, queue, inbox, status, release, takeover, doctor. No file I/O, no
shell, no editor, no task board.

When to add something outside DSH: only when you need a guarantee rather than a
behavior — for example, several top-level sessions editing the same repository need
outer worktree isolation. For collaboration, prefer letting DSH run the team itself
(mount the experimental team packages into the profile; teammates share one workspace).

Quick start

Requires Node.js ≥ 22.15 and DSH installed with a working model route and credentials. See Requirements for details.

npm install -g dsh-any-agent
dsh-any-agent-setup
dsh-any-agent-setup --yes

The second command previews the changes; --yes applies them. Reconnect your client's MCP server, then ask your agent to start a DSH conversation in your project, dispatch a task, and collect the result. The dispatch workflow shows the tool sequence.

Only using Cursor or VS Code? Add it in one click instead (runs npx -y dsh-any-agent@latest; DSH still has to be installed):

Add to Cursor
Install in VS Code

Want to see it first? Watch the 54-second promo — dispatch, interject, the sentinel landing and the caller's review, with the terminal replayed from a real run:

▶ Play the dsh-any-agent promo (54 seconds)

Before your first task: read the Usage Notes, especially the model-config and external-MCP permission boundaries. External MCP tools bypass DSH's sandbox. For a fresh machine, follow the migration guide.

Permissions: this server only dispatches; permissions follow DSH and your configuration. The default is workspace-write (writes limited to the workspace; out-of-workspace requests are auto-allowed and listed in the result). For personal use on your own machine most people just turn on full access: dsh-any-agent-setup --yes --permission danger-full-access, after which DSH asks for nothing and everything is allowed. Anyone who can call these tools can run commands on your machine (including a caller agent that got prompt-injected); use read-only for untrusted content. See Permissions & privacy.

Full contents

🧰 Tools

Tool What it does
dsh_start Create a conversation: workspace, permission tier, approval policy, reasoning effort (default max), model
dsh_send Hand it a task. Defaults to wait=false: returns a run_id + sentinel_file immediately, the turn runs in the background and the sentinel file notifies you when it's done (recommended). wait=true blocks until the turn ends; hitting timeout_ms (default 0 = wait forever) only downgrades to background — the turn is never cancelled and the result is never lost
dsh_list All conversations with live state: running / idle / detached, elapsed time, current tool, output so far. only_running=true for active ones
dsh_read Cursor-based incremental read of what a running conversation is producing right now. The cursor is a revision number: an entry whose text grew since your last read reappears — match it by seq and replace its text, don't append again
dsh_get Conversation details; with run_id, the final result of that dispatch (the "collect the result later" entry point) plus its review ticket. Run records live in memory (last 20) — use the sentinel file after a restart
dsh_review Caller review. Submit pass / partial / fail for a completed run, with notes and optional findings. The verdict is written to <state dir>/reviews/<conversation_id>/<run_id>.review.json and back into the in-memory run and sentinel. Advisory by default: it never blocks the next dsh_send
dsh_interject Interject while it's busy: interject = stop and redirect, queue = wait for the current turn, then speak. This round writes a sentinel too, and the reply carries its sentinel_file. In both modes, and on an idle conversation, it blocks until the new turn ends; to queue without blocking, use dsh_send(queue=true)
dsh_takeover Preempt the write lock. The only way out when another DSH process holds it (DSH has no steal API — preempting means killing the holder). It classifies the holder first: our own orphaned child → taken automatically; another live instance → needs force; GUI/unknown → never killed, reported instead
dsh_interrupt Stop the current turn without sending anything new (the conversation stays healthy); to stop and redirect, use dsh_interject
dsh_release Hand the conversation back (frees the write lock so you can open it in your own DSH GUI). Still resumable; forget=true writes a tombstone — by-id lookups are refused until you delete $DSH_HOME/.dsh-any-agent-forgotten/<id>.json
dsh_approval_decide Adjudicate a pending approval (only when on_approval=ask)
dsh_status Lightweight status check (single conversation), including the write-lock holder lock_holder
dsh_inbox Cross-conversation approval inbox: every pending approval with reason, input and age; decide with dsh_approval_decide
dsh_queue Inspect/modify the session queue: list / remove / update / promote (created by dsh_send(queue=true), memory only)
dsh_doctor Read-only health check: DSH version, profile, state/dir writability, orphan locks, sessions and RSS, effective config

Every tool declares all four MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint). Six only read state and are marked read-only: dsh_list, dsh_read, dsh_get, dsh_status, dsh_inbox, dsh_doctor. Tool titles, descriptions and the server instructions come in English and Chinese: they follow your system language, or set DSH_MCP_LANG=en|zh. Tool results follow the same setting; a few less common error messages are still Chinese only.

👀 Live view: see what the dispatched work is doing

The tools above are for the calling agent. You, sitting at the client, usually see one dsh_send and nothing else. Since 0.6.1 the server writes each conversation's activity to a local event stream, so you can watch the call chain without going through the agent:

claude-code  pid 8328
└─ e896d16a  temperature module  running · total 278k/17k · context 3%
   ├─ ✓ run-…-1  [send] · done · 1m24s · 8 tools · 69k↑ 4.1k↓ tok
   └─ ▶ run-…-2  [queue] · running · 156k↑ 12k↓ tok
         ✓ read   temp.js                  13ms
         ✓ edit   temp.js                  18ms
         ◆ approval auto-allow ⚠ danger-full-access  node --test
         ▶ pwsh   node --test
dsh-any-agent watch
dsh-any-agent dashboard --open
dsh-any-agent dashboard: conversations grouped by client on the left, the run timeline with a timing bar per tool call in the middle, overview, token usage, tools and files on the right (sample data)
  • watch: the call chain in your terminal, redrawn in place like top (no scrolling spam). watch <conversation id prefix> follows one conversation; --once prints once and exits.
  • dashboard: a local read-only web page; --open launches it in your default browser. Left: conversations grouped by client. Middle: the run timeline, with a timing bar per tool call and approvals/escalations highlighted. Right: overview, tool breakdown, files touched, approvals, and token usage (input / output / cache hit, context window, per-turn chart).
  • English / 中文: follows your system language by default; pass --lang en|zh to choose, or switch from the page's top-right corner.
  • Doesn't disturb running work: both are separate processes that only read event files — they never touch the write lock or DSH. Use them to watch progress, and don't open MCP-driven conversations in the DSH GUI (that takes the write lock; see usage notes 3.10).
  • Safety and privacy: the dashboard binds 127.0.0.1 only, its URL carries a one-time token, it checks the Host header, and it has no control that changes state. Command, path and prompt previews are redacted first; reasoning is never written at any level. DSH_MCP_LIVE=meta keeps only tool names and status; off disables it.

Details in Usage · side view; event format and design trade-offs in the live view design.

📚 Documentation map

Document Contents
Setup Requirements, profile bootstrap, 9 MCP clients
Usage Dispatch/collect, sentinels, many conversations, live view, reasoning
Live view design Event stream format, watch / dashboard, token source, privacy trade-offs
Team mode Default behavior, how to disable (per client), verify and revert
Permissions & privacy Tiers, approvals, GUI visibility, logging
Write lock Four holder classes, takeover, GUI contention
Environment variables Every switch and its default
Tests Offline/integration suites and coverage
Known limitations Limits, profile naming
Compatibility DSH version matrix, team-package requirements, upgrade checks
Architecture Why ACP, sdk/plugin comparison
Release process Release checklist

🧑‍🤝‍🧑 Team mode (opt-in)

Off by default. Run dsh-any-agent team on and reconnect; the profile switches
to dsh-team (the experimental Agent Teams packages) and dsh_send adds a
short "form a team when this needs parallel or multi-role work" line. Simple
tasks are not forced into a team. Turn it off with dsh-any-agent team off, or
for one call with dsh_send(team=false).

Full steps (commands, verification, rollback) are in Team mode.

📇 Listed on

dsh-any-agent MCP server on Glama M8ven Score DSH Any Agent MCP on mcprush

🙏 Acknowledgements

dsh-any-agent started from Moer2831/Deepseek-DSH-MCP (MIT), where this server was called dsh-mcp. The ACP client, the session hub, write-lock handling, sentinel files, DESIGN.md and the first test suites come from that project; client setup and restore, team mode, the live view, caller review and the release pipeline were added here. The original copyright notice is kept in LICENSE.

Star History

Star History Chart

Reviews (0)

No results found