Skip to main content
Glama

codex-mcp-dsh

Codex CLI / Claude Code 这类 MCP 客户端把任务交给 DeepSeek Harness(dsh) 执行的本地桥。 支持 原生 Web(推荐,进度可见)ACP(默认,向后兼容)。Web 提供 9 个工具,包含模型选择和持久化长任务;ACP 保留原执行工具,模型工具会明确返回不支持。

Codex / Claude Code --MCP stdio--> codex-mcp-dsh --+-- 原生 Web(DSH_BRIDGE_TRANSPORT=web)
                                                    |     HTTP + /api/remote.mux WebSocket
                                                    |     自动拉起/复用自己的 dsh web 服务
                                                    |
                                                    +-- ACP stdio(默认)
                                                          dsh --profile acp

两种传输共用 dsh_start / dsh_workspace / dsh_run / dsh_session / dsh_status。 Web 还支持 dsh_model,以及 dsh_submit / dsh_job / dsh_cancel。 切换只改一个环境变量DSH_BRIDGE_TRANSPORT=web


快速开始(推荐:原生 Web,进度能在原生页面里看)

不需要手工运行 dsh web不需要找 token,不需要复制任何凭据。

// Codex 配置:见下方 “### Codex” 一节
[mcp_servers.dsh.env]
DSH_BRIDGE_TRANSPORT = "web"

然后照常调用:

// 1. 启动/复用桥自己管理的本地 Web 服务,并自动在默认浏览器打开原生 Web UI
dsh_start({})
// -> { "ok": true, "running": true, "transport": "web",
//      "web_url": "http://127.0.0.1:53421/",       // 干净 URL,绝不含 token
//      "browser_opened": true,
//      "web": { "owned": true, "pid": 12345, "connected": true } }

// 2. 建立/复用一个真实工作区(目录 + 原生 Workspace + 挂在其上的原生会话)
dsh_workspace({ "path": "D:/PROJECT/my-new-project" })
// -> { "ok": true, "created": true, "cwd": "D:\\PROJECT\\my-new-project",
//      "session_id": "session-...", "workspace_id": "...", "web_url": "http://127.0.0.1:53421/" }

// 3. 短任务可同步执行。在 web_url 中展开工作区,并选中返回的会话,观察实时工具调用与文本流
dsh_run({ "session_id": "上一步返回的 session_id", "task": "在这个工作区里做……" })

耗时不确定的修改任务优先用 dsh_submit,拿到 job_id 后用 dsh_job 读取进度与结果。每次读取最多等待 20 秒,MCP 断开不影响独立 worker;同一 request_id 同参数只执行一次。需要停止时调用 dsh_cancel,以原生终态确认结果。

任务本身仍有执行期限,默认取 DSH_BRIDGE_GATEWAY_JOB_TIMEOUT_MSDSH_BRIDGE_TIMEOUT_MS(未配置时为 30 分钟);显式 timeout_ms 会覆盖默认值。持久化任务解决客户端同步等待被截断的问题,并不绕过原生权限或无限延长期限。

server-web.mjs 默认将长任务范围限制在 DSH_WORKSPACE(未配置则启动目录),多工作区可显式配置 DSH_BRIDGE_ALLOWED_ROOTS。其它入口需显式配置允许范围。模型选择示例与完整流程见 模型、进度与长任务。新增工具在 MCP 重新连接、重新读取工具列表后可用。

这一条链路是通用的:任何用户只要装上 dsh 并设置 DSH_BRIDGE_TRANSPORT=web 就能用, token 由桥在内部捕获、换成 HttpOnly cookie 并保存到私有文件,用户永远不需要看到它。

管理服务的所有权与清理(web)

  • 桥只管理自己启动的服务:默认端口 0(由操作系统选空闲端口),所以永远不会和用户已有的服务 (例如 3080 上的)冲突,也绝不会停止或替换别人的服务。

  • 桥启动的服务记录在私有连接状态文件里(默认 $DSH_HOME/bridge-web.json,权限 0600): 干净 URL + 浏览器 cookie + token 化的 launch URL + pid。

  • MCP 断开时,桥自己启动的服务会继续运行,这样用户还能继续在同一个页面看历史; 只有显式设置 DSH_BRIDGE_WEB_STOP_ON_EXIT=1 才会在断开时停止它。

  • 这条「继续运行」是真的独立进程:桥用 detached 方式启动 dsh web,并把它的 stdout/stderr 重定向到 一个私有的 0600 捕获文件(读到 launch URL 后立即 unlink),不使用 MCP 父进程的管道。 Windows 上非 detached 的子进程会绑定在父进程的 console/job 上,父进程一退出就被一起杀掉 (child.unref() 只影响事件循环,不足以让子进程独立);用管道还会在父进程关闭读端后让服务写入失败。 桥只在启动失败/超时时清理这个半启动的子进程。

  • 状态文件里的服务如果已经不在监听了,下一次 dsh_start自动重启一个新的管理服务,不会要求用户手工启动。

  • 会话映射按「服务 authority + 目录」记录:桥只复用自己记录过的那个原生会话。原生 registry 是跨进程共享的, 里面可能有同目录、running:false 看起来空闲、但写持有者属于别人的会话(用户另一个 Web 服务、正在跑的 ACP 委派); 桥绝不自动挂接这种会话,而是直接在已存在的原生 Workspace 上新建一个原生会话,其他会话原样保留。

  • 自己管理的服务如果死掉并被替换,只有它自己记录过、且属于那个已死 authority 的会话会在新服务上重新挂接 (旧写持有者已经消失);若原生服务拒绝挂接,则退化为新建会话。别的 authority 的映射不会被隐式复用。

  • 用户显式传 session_id 时,若该会话正被别的进程持有,会如实报错(不会静默换一个会话)。

  • dsh_session close 只是桥侧解绑:原生历史保留、共享服务不动、不会停止原生任务。

浏览器打开行为

  • dsh_start 在 web 模式下默认打开发送一次(每个服务最多一次,不会反复抢焦点); 用 dsh_start({ "open_browser": false }) 关闭,或 { "open_browser": true } 显式再开一次。

  • 并发的默认 dsh_start 共享同一次打开动作(authority 在 await 之前就被占位),所以默认一次启动流程最多只开一个窗口。

  • 打开用的是操作系统默认浏览器(与 dsh web 相同的原生 handoff),打开的是原生 DSH Web UI, 不是任何自定义面板。

  • 只有桥自己管理的服务会自动打开;用 DSH_WEB_URL 显式挂接别人的服务时不会抢焦点(可显式传 open_browser:true)。

权限与确认(web)

Web 传输下权限保持原生:桥不会替你自动放行任何权限请求,原生 Web UI 会自己弹出确认, 需要人点确认时任务就会等在那里。这与 ACP 传输的 DSH_BRIDGE_PERMISSION 策略不同,是刻意的设计。


Related MCP server: dsh-orchestrator

快速开始(默认:ACP,向后兼容)

不设置 DSH_BRIDGE_TRANSPORT 时行为与以前完全一致(dsh --profile acp),dsh 子进程延迟启动: MCP 连接和 tools/list 不依赖 dsh,dsh_start(或第一次 dsh_run / dsh_workspace)才会启动并完成 initialize 握手。子进程生命周期绑定在 MCP 连接上,同一个工作区的多轮对话复用同一个 DSH 会话。

dsh_start({})                                      // -> running:true, state, version
dsh_workspace({ "path": "D:/PROJECT/my-new-project"})  // 目录不存在会连同父目录创建;已存在则安全复用
dsh_run({ "session_id": "...", "task": "在这个工作区里做……" })

要点:

  • dsh_start 无必需参数,连续或并发调用只会启动一个 dsh 进程;启动失败返回明确错误,MCP 仍然可用, 再次调用即为干净重试。

  • dsh_workspacepath 必须是绝对目录路径;空/相对/文件/磁盘根目录会被拒绝。重复调用同一目录 复用同一个会话。

  • dsh_run 直接调用(不带 session_id)也会自动确保 dsh 已启动,旧用法不受影响;dsh_run/dsh_workspace 创建的会话以该目录为 cwd 实际执行。


安装

cd D:/PROJECT/codex-mcp-dsh
npm install

要求:Node >= 22.19(本机 v24.19 已验证)、dsh 在 PATH、~/.dsh 已配置好模型凭据。

工具

工具

说明

dsh_start

显式启动/连接 DSH 并完成握手(幂等:连续或并发调用只启动一个)。transport=acp(默认)启动 dsh --profile acptransport=web 复用自己的管理服务,或新起一个 dsh web(默认 --port 0,隐藏窗口,私有捕获 launch URL),并默认在默认浏览器打开原生 Web UI(open_browser:false 可关)。返回 running/state/transport,web 下另返回干净 web_urlweb 连接信息。失败返回明确错误且桥保持可调用,可重试。

dsh_workspace

path(必需,绝对目录)建立/复用工作区:缺失目录连同父目录创建,已有目录安全复用、绝不覆盖文件;必要时自动启动/连接 DSH。web 下还会创建真实的原生 Workspaceworkspace_id)并把原生会话挂到它上面,重复/并发调用复用同一个 session_id;没有本桥自己的映射时新建一个原生会话(绝不抢占 registry 里同目录但属于别人的空闲会话)。返回 created / cwd / session_id(web 另含 workspace_id / web_url)。

dsh_run

原生工具卡片标题 Dsh run。执行一个任务并返回最终答复。若未启动会自动启动;默认复用当前 cwd 的会话。它是一个同步的 tools/call:保持 pending 直到原生回合给出最终结果(或超时/取消),客户端应等待这一个请求,而不是轮询/重复提交。仅当客户端提供 _meta.progressToken 时才发送 progress 通知(起始 → connecting/executing → 空闲心跳 waiting,见下);web 下进度来自原生事件流(工具调用 + 文本增量),最终答复只取一次持久化文本(不会把流式和落盘文本拼在一起),推理内容不会进入答复或普通进度。

dsh_session

action=list/resume/close/status,管理会话。list/status 未启动时也能答(缓存视图),并可用 cwd/session_id 收窄结果:只筛选已经存在(running 或缓存)的会话行,不创建目录、不隐式启动/恢复,无匹配返回空数组;不带过滤参数时仍是完整视图(含原生错误行)。cwd 按规范化绝对路径比较(Windows 忽略大小写)。resume/close 需要正在运行。web 的 close 是桥侧解绑(保留原生历史、不动共享服务);有回合在跑(含结果未知)时拒绝解绑

dsh_model

原生模型目录与选择(仅 web transport;ACP 明确返回 UNSUPPORTED_TRANSPORT,不会假成功)。action=list 读公开目录;action=statuscwd/session_id 读该会话 modelSelection projection 的 next/lastUsed,并以目录 default 兜底(current = next ?? default,与原生 Web UI 一致);action=select 先按实时目录校验 provider/model/reasoning_effort 再调用一次 session/selectModel,随后回读并给出 verified。该原生 API 同时作用于本会话下一次请求尝试保存全局默认(保存失败只由原生记日志),因此不是 session-only。本工具不创建/恢复/启动会话、不修改 settings.yaml、不以模型自述作为身份依据。详见 docs/dsh-model-and-approval.md

dsh_status

只读,不会隐式启动/连接任何东西。running/state 区分 stopped/starting/running/errorok=true 表示健康。并保留 dsh 路径、版本、活会话数、会话能力、配置来源;web 下另含 web_url(干净)或 web_target,以及 permissions 说明。传输真的断了(mux 关闭 / HTTP 不可达 / 子进程退出)会如实变为 error,不会永远报健康。

dsh_run 入参:task(必填,不超过 16000 字符)、cwdsession_idnew_sessiontimeout_msdsh_workspace 只有 path 一个参数;dsh_start 只有可选 open_browserdsh_model 只有 actionsession_id/cwd/provider/model/reasoning_effort。不引入任意命令/凭据类配置。

看网页就用 dsh_start 返回的 web_url:那是本桥正在驱动的那个原生 Web 服务。不要假设端口(例如用户机器上的 3080 可能是另一个本桥没有连接的服务);请在返回的 URL 里选择同一个 workspace/session,才能看到同一段对话、 工具活动和权限提示。

双入口:WebCodex 网关(异步)与 Web-GPT 咨询

除了上面的 6 个工具,本仓库还有两个独立入口,详细集成说明见 docs/dual-entry.md

入口

启动

工具

B. WebCodex 网关(ChatGPT 网页 → 本机 DSH)

src/server-webcodex.mjs

dsh_submit / dsh_job / dsh_cancel / dsh_status / dsh_lock只读

C. Web-GPT 咨询(只出方案/评审,不执行)

src/server-planner.mjs

planner_status / planner_models / planner_consult

两条真实用法

  1. Codex → planner → Codex → DSH:Codex 调 planner_consult 拿网页 6 Pro 的方案/评审文本,自己决策后 把要执行的步骤交给原生桥的 dsh_run(入口 A,同步执行);planner 只出文本、不读文件也不执行, 因此不需要共享 cwd 锁。

  2. 网页 6 Pro → WebCodex → gateway → DSH:ChatGPT 网页的 WebCodex Runner 通过 dsh Provider 驱动 dsh_submit/dsh_job(入口 B,异步执行,worker 断线存活)。配置见 examples/webcodex-runner.tomlRunner TOML,不是 mcpServers JSON)。

实测验收(外部 SDK → 本地 WebCodex Runner → DSH):短任务 3.572 秒、长任务 143.249 秒(断线后 worker 存活并写出终态)、首次 dsh_submit 13 毫秒返回;真实取消 requested → confirmed(job 终态 cancelled,锁已释放); 运行中同 request_id 重试返回原 job未实测:ChatGPT 账号登录 / 6 Pro 选择 / 远端连接,planner 入口目前 未登录、未发送过真实咨询——所以本文档不宣称「ChatGPT 侧端到端全部可用」。

入口 B 的核心约束(为什么长这样):

  • 没有同步 dsh_run:WebCodex 0.4.1 的单次 tools/call 硬等待约 125 秒且不转发 progress, 所以 dsh_submit 只做有界校验 + 落盘 + 启动 detached worker,立即返回; dsh_job 最多等 20 秒waited_ms真实已等待时间),长回合跑在 worker 里,断开后仍存活;

  • request_id 原子幂等requests/<hash>.json 用独占创建做「一个 request_id 一个 claim」。 同 key 同参数(即使正在运行或结果未知)返回同一个 job,绝不抛 WORKSPACE_BUSY、绝不重放; 同 key 不同参数原子拒绝(REQUEST_ID_CONFLICT);claim 成功但 record 缺失 (claim 后崩溃)→ JOB_RECORD_MISSING不会启动第二个 worker;

  • dsh_lock 只读:MCP 侧没有任何解锁写操作;手工解锁只能由本机操作者运行 node scripts/unlock-workspace.mjs --cwd <dir> --confirm-native-terminal --evidence "<你核对到了什么>" (持有者进程仍存活时拒绝,需要 --force 才能越过;也可以 npm run unlock -- --cwd ...);

  • allowed roots 是路由范围,不是 OS 沙箱readJob/request_id 反查/dsh_cancel/dsh_job/列表 在读取或 reconcile 之前,都用真实路径验证记录 cwd 位于当前 DSH_BRIDGE_ALLOWED_ROOTS 内; 收窄配置后历史越界任务不可查看/取消/泄露(列表先过滤再 limit),配置不可用时 fail closed。 它不能替代 DSH 原生权限策略:原生确认/权限配置仍然完全适用;该变量只由 gateway(入口 B)用来守范围, 原生入口 A 用 DSH_WORKSPACE 指定默认工作区;

  • 终态真相:只有 completed 才返回 answer;连接丢失/超时/未确认取消/已 admission 的未知错误 一律 unknown 并保留围栏,明确预提交失败才是 failed;取消在 admission 前到达(not-sent) 判定为 cancelled 并释放围栏(原生根本没收到)。

入口 C 的规则:模型必须来自 live UI 的精确枚举;写入后再读 UI,必须读到非空且与 requested 完全一致的 current model 才允许发送——null/空(读不到,点击成功也只证明点到了菜单)与矛盾现值一律拒绝,零 write 零 submit; 请求档位本身必须是 Pro(配置成 Thinking 也不会通过),观察档位要用第三方真模块isProTier; 非空 response ≠ 完成,只有 submission.completed===true && sent===true 才返回答案,否则 unknown

等待体验与 MCP 协议(Codex 原生工具卡片)

  • 客户端做一次 tools/call dsh_run,界面上就是一个 Dsh run 原生工具卡片;桥让这个请求一直 pending, 直到 DSH 产生权威的终止结果(或超时/取消)才返回最终答复。就是标准 MCP 请求/响应:没有异步邮箱、 任务队列、自定义面板或额外协议。

  • initialize 会带上 instructions(≤2000 字符、自包含):说明这是用户授权的 DSH 委派、dsh_run 保持 pending、 应当等待而不是轮询或起 shell 包装、尊重用户给定的路径与范围;并明确「错误或结果未知不构成重新提交的授权」。 桥不要求客户端绕过权限/配额,也不承诺不消耗 token。

  • progress 通知只在客户端提供 _meta.progressToken 时发送(数字 0 也是合法 token)。同一次 dsh_run 只有一个严格递增的计数器,真实事件(助手文本、工具状态)与空闲心跳共用;并发请求各自绑定自己的 token, 绝不串号。顺序为:立即 startingconnectingexecuting → 空闲心跳(默认 10s, DSH_BRIDGE_PROGRESS_INTERVAL_MS 可调、0 关闭)。心跳只说明「已等待多久 / 多久没有原生事件」, 不编造百分比、总数、模型思考或完成状态;调用一旦返回、报错或被取消就立刻停表,之后不再发送任何通知。

  • 心跳是活动信息:不会改变客户端自身的超时/配额/用量限制,也不能让 Codex 的额度提示消失。工具卡片、 配额/余额提示以及断开后的中断都由客户端渲染与决定;桥无法模拟它们,也不保证被中断后还能继续跑完。

配置

环境变量(都可选):

通用

变量

默认

含义

DSH_BRIDGE_TRANSPORT

acp

acp(默认,向后兼容)或 web(原生 Web,推荐)

DSH_BIN

dsh

可执行文件;Windows 上会自动把 npm 的 dsh.cmd 垫片解析成它包裹的 Node 入口,避免 cmd.exe 与参数插值

DSH_HOME

用户目录下的 .dsh

dsh 配置与凭据目录

DSH_PROFILE

acp

ACP 传输使用的 profile

DSH_WORKSPACE

启动目录

默认工作区

DSH_MODEL

空(用 dsh settings)

会话级 model 覆盖

DSH_BRIDGE_TIMEOUT_MS

1800000

单轮超时;客户端的 tool_timeout_sec 要比它多留启动握手 + 取消宽限的余量

DSH_BRIDGE_CANCEL_GRACE_MS

5000

发出取消后等待「权威终止事件」确认的宽限;到期即返回 unknown 且会话仍 busy

DSH_BRIDGE_PROMPT_RESPONSE_GRACE_MS

5000

ACP session/prompt 请求本身的额外预算

DSH_BRIDGE_STARTUP_TIMEOUT_MS

60000

启动握手 / session/newsession/resume 预算

DSH_BRIDGE_CLOSE_TIMEOUT_MS

60000

单次 session/close 预算

DSH_BRIDGE_CLOSE_ALL_BUDGET_MS

120000

退出时关闭全部会话的总预算

DSH_BRIDGE_SHUTDOWN_WAIT_MS

5000

MCP 断开时若还在启动,等待/中止握手的上限(避免留下晚启动的子进程)

DSH_BRIDGE_MAX_OUTPUT_CHARS

60000

返回给客户端的答复上限(超出截断)

DSH_BRIDGE_PROGRESS_INTERVAL_MS

10000

dsh_run 空闲心跳间隔;0 关闭周期性心跳(起始/阶段通知仍然发送)。在客户端提供 progressToken 时生效

DSH_BRIDGE_PERMISSION

allow

仅 ACP:权限请求自动应答 allow/deny;其它取值按 deny 处理

DSH_BRIDGE_LOG

info

debug 会打印 dsh stderr 与每条事件;silent 全关

DSH_BRIDGE_SESSIONS_FILE

$DSH_HOME/bridge-sessions.json

ACP 会话缓存(跨重启 resume 用)

Web 传输

变量

默认

含义

DSH_WEB_URL

高级挂接模式:显式指定已有服务(可以是带 token= 的 URL)。设置后桥不会启动/替换服务;若该服务不可达或拒绝鉴权,返回可操作的错误。

DSH_WEB_URL_FILE

$DSH_HOME/bridge-web.json

私有连接状态 / launch URL 文件(0600,不要提交到版本库)。支持桥自己写的 JSON,也支持纯文本的一行 URL。

DSH_BRIDGE_WEB_HOST

127.0.0.1

仅允许回环;非回环/非 http 会被拒绝

DSH_BRIDGE_WEB_PORT

0

管理服务的端口;0 由系统选空闲端口(默认,绝不与用户服务冲突)

DSH_BRIDGE_WEB_OPEN_BROWSER

true

是否在 dsh_start 时打开默认浏览器展示原生 Web UI

DSH_BRIDGE_WEB_LAUNCH_TIMEOUT_MS

60000

等待 dsh web 打印 launch URL 的预算;超时会终止这个半启动的子进程

DSH_BRIDGE_WEB_REQUEST_TIMEOUT_MS

20000

单次 HTTP 请求 / root token 换 cookie 的预算

DSH_BRIDGE_WEB_PREFLIGHT_TIMEOUT_MS

15000

发 prompt 前的预检(follow 快照 + 原生注册表)预算,避免无上限等待

DSH_BRIDGE_WEB_BUSY_RECHECK_MS

1500

原生 session/list 报 running 时,重复确认多久才判定为「外部正在跑」并拒绝

DSH_BRIDGE_WEB_STOP_ON_EXIT

0

是否在 MCP 断开时停止自己启动的服务(默认不停,留给用户继续看历史)

DSH_BRIDGE_WEB_STOP_TIMEOUT_MS

10000

停止管理服务的等待预算

DSH_BRIDGE_WEB_SESSIONS_FILE

$DSH_HOME/bridge-web-sessions.json

Web 会话缓存(与 ACP 缓存分开,互不覆盖)

WebCodex 网关(入口 B)

变量

默认

含义

DSH_BRIDGE_ALLOWED_ROOTS

空(未配置=拒绝一切提交

JSON 数组,本桥允许提交/续跑/读取/取消/列出的工作区根。按真实路径判断;收窄后历史越界任务不可查看/取消/泄露,配置不可用时 fail closed。这是路由/会话范围,不是操作系统文件沙箱:原生 DSH 权限策略仍然适用

DSH_BRIDGE_GATEWAY_DIR

$DSH_HOME/bridge-gateway

私有 job 状态目录(record/spec/cancel/worker 日志/request claim)

DSH_BRIDGE_WORKSPACE_LOCK_DIR

空(围栏关闭)

跨进程工作区围栏目录;入口 A/B/C 用同一个值才能互斥

DSH_BRIDGE_GATEWAY_WAIT_MAX_MS

20000

dsh_job 单次等待上限(代码再取 min(该值, 20000);网关硬等待 125s)

DSH_BRIDGE_GATEWAY_JOB_TIMEOUT_MS

0(用 DSH_BRIDGE_TIMEOUT_MS

单个 worker 拥有的原生回合超时

DSH_BRIDGE_GATEWAY_CANCEL_POLL_MS

500

worker 轮询取消请求文件的间隔

DSH_BRIDGE_GATEWAY_START_GRACE_MS

30000

仍为 queued 且没有活 worker 多久后如实报 unknown

DSH_BRIDGE_GATEWAY_MAX_STAGES / _MAX_LISTED / _PROGRESS_WRITE_MS

12 / 50 / 1000

进度条目数、列表条数、进度写盘节流

DSH_BRIDGE_GATEWAY_OPEN_BROWSER

true

每个 authority 只打开一次原生 Web UI(真实进度看那里)

DSH_BRIDGE_ENTRY

只用于记录/诊断(codex/webcodex/…),不用于授权

WebCodex 0.4.1 的 Provider 配置是 Runner TOML[mcp] / [[mcp.providers]]),不是 mcpServers JSON: 完整可合并示例见 examples/webcodex-runner.tomlenv_from_envTOML 内联表,只把父 Runner 进程已有的同名变量透传给 Provider 子进程, 所以要在启动 Runner 之前在父进程环境里设置 DSH_BRIDGE_ALLOWED_ROOTS(必填)、 DSH_BRIDGE_WORKSPACE_LOCK_DIR(用户私有,与入口 A 同值)、DSH_BRIDGE_WEB_SESSIONS_FILE(用户私有单独文件)、 DSH_BRIDGE_GATEWAY_OPEN_BROWSER=false,以及 SYSTEMROOT/COMSPEC/PATH/TEMP 等基础变量。

WEBCODEX_MCP_COMPACT_SCHEMAS=trueWEBCODEX_MCP_TEXT_JSON_COMPAT=true 写在 WebCodex Server 自身的 server.env(不在 Provider 的 env 里):0.4.1 内置 cargo_fmt/cargo_check/cargo_test/go_test 的输出 schema 里有 enum: [],标准 SDK 解析会失败; 这与本桥的 dsh_status 空 inputSchema 无关。

Planner(入口 C)

变量

默认

含义

CHATGPT_WEB_MCP_ROOT

第三方 chatgpt-web-mcp 的 checkout;只读动态 import <root>/src/browser.js,不复制/不修改/不新增依赖

DSH_BRIDGE_PLANNER_TIMEOUT_MS

900000

单次咨询上限(上游 Pro 路径会一直等,适配器自带 AbortController)

DSH_BRIDGE_PLANNER_PROBE_TIMEOUT_MS

60000

status/models 探测上限

DSH_BRIDGE_PLANNER_ANSWER_TIER

Pro

必须是 Pro:非 Pro 取值会在发送前被拒绝(不会因为配置成 Thinking 而放行)

DSH_BRIDGE_PLANNER_MAX_CHARS

16000

task/context 上限

Web 传输的连接与鉴权规则(实现约束)

  • 鉴权只走「root token → 服务签名的 HttpOnly cookie」:不支持 Bearer,也不合成 cookie、不读 .credentials.yaml

  • 只允许回环 httpDSH_WEB_URL 指向远程地址会被拒绝(cookie 是 host-only 且非 Secure)。

  • 端口 0 的管理服务:launch URL(含 token)只进私有状态文件,普通日志、工具返回、错误信息里都不会出现 token/cookie

  • 已有 cookie 未过期时优先复用 cookie;否则才用 token 换一次。状态文件里的 launch URL 会在重连时保留,不会被写空。

  • 缓存 cookie 被服务拒绝(过期/轮换)时,桥会用同一 authority 的私有 launch URL里的 token 走一次正常的 root 换 cookie 并再次探测,用户不需要手工输入 token;显式挂接(DSH_WEB_URL)的被拒 token 仍然如实失败。

  • 复用旧 cookie 不会延长记录里的过期时间(服务端绝对过期时间不变);只有真的换到新 cookie 才会刷新。

  • 会话的「结果未知」围栏(见下)会持久化:桥断开/重连后,只有拿到该回合持久的 turn/end 才会解除, 不会因为 registry 暂时显示空闲(排队回合还没开始跑)就把已入队但结果未知的 prompt 再放一次。

权限语义(仅 ACP):allow 时优先选 allow_once,其次 allow_alwaysdeny 时优先 reject_always,其次 reject_once。选项的 kind 是语义来源:显式但未知或与策略矛盾的 kind 不会被 optionId 字面值“救回”; 没有任何可接受选项时回 ACP 的 cancelled(fail closed)。

Codex

ACP(默认):

[mcp_servers.dsh]
command = "node"
args = ["D:/PROJECT/codex-mcp-dsh/src/server.mjs"]
startup_timeout_sec = 60
# 不能写成与 DSH_BRIDGE_TIMEOUT_MS/1000 相等:桥在单轮超时后还要等 cancelGrace 才能给出 timeout
# 结果,客户端若先到点结束,就看不到这个结果。至少预留启动握手 + 取消宽限的余量。
tool_timeout_sec = 1900
enabled_tools = ["dsh_start", "dsh_workspace", "dsh_run", "dsh_session", "dsh_status"]

[mcp_servers.dsh.env]
DSH_HOME = "C:/Users/<you>/.dsh"

原生 Web(推荐;一行环境变量即可):

[mcp_servers.dsh]
command = "node"
args = ["D:/PROJECT/codex-mcp-dsh/src/server.mjs"]
startup_timeout_sec = 60
# 桥的后端单轮预算是 DSH_BRIDGE_TIMEOUT_MS=1800000ms(1800s),另外还要等启动握手(≤60s)
# 和取消宽限(≤5s);1900s 给客户端留出余量。设成刚好 1800s 会让客户端先到点,看不到桥的 timeout/unknown 结果。
tool_timeout_sec = 1900
enabled_tools = ["dsh_start", "dsh_workspace", "dsh_run", "dsh_session", "dsh_status"]

[mcp_servers.dsh.env]
DSH_BRIDGE_TRANSPORT = "web"
# 可选:DSH_BRIDGE_WEB_OPEN_BROWSER = "false"(脚本/无人值守时)
# 可选:DSH_WEB_URL = "http://127.0.0.1:3080/?token=..."(高级:挂接已有服务,不替换它)

等价的专用入口(强制 web 传输,注册时可替代上面的 src/server.mjs + 环境变量):

[mcp_servers.dsh]
command = "node"
args = ["D:/PROJECT/codex-mcp-dsh/src/server-web.mjs"]
startup_timeout_sec = 60
tool_timeout_sec = 1900

也可以用便捷入口(等价于强制 web 传输):

node src/server-web.mjs                 # = DSH_BRIDGE_TRANSPORT=web
node src/server-web.mjs --acp           # 临时切回 ACP
node src/server-web.mjs --web-url "http://127.0.0.1:3080/?token=..."
npm run start:web

Claude Code

claude mcp add dsh --transport stdio -- node "D:/PROJECT/codex-mcp-dsh/src/server.mjs"
# 原生 Web:
claude mcp add dsh-web --transport stdio --env DSH_BRIDGE_TRANSPORT=web -- node "D:/PROJECT/codex-mcp-dsh/src/server-web.mjs"

验证

npm test              # 离线回归全套 + 真实 MCP 握手冒烟(不调模型)
npm run test:acp      # 只验证 ACP 握手与建会话,不调模型
npm run test:sessions    # 回合结算 / 取消 / cwd / 缓存(fake ACP,不调模型)
npm run test:permissions # 权限策略 fail-closed(不调模型)
npm run test:crash       # 真实子进程:超时不再打死桥(不调模型)
npm run test:mcp-cancel  # 真实 MCP 内存传输:取消穿透到 ACP(不调模型)
npm run test:mcp-progress # 真实 MCP 内存传输 + fake ACP:initialize.instructions / Dsh run 标题 /
                         # pending 期间的单调 progress(起始/阶段/心跳,含数字 0 token)、并发隔离、
                         # 结束/报错/中断后停表且中断仍穿透到 ACP(不调模型)
npm run test:lifecycle   # 延迟启动 / 幂等并发启动 / 失败重试 / 退出重启 / 启动中关闭
npm run test:workspace   # dsh_workspace:新建/复用/非法路径/并发/失败诚实报告 + run 按新目录执行
npm run test:web         # 原生 Web:鉴权/凭据脱敏/原生 workspace/相关性结算/实时进度/重复文本抑制/
                         # 取消与网络未知/外部占用拒绝/回执丢失/管理服务重启与复用/浏览器一次性打开/
                         # 自有服务在真实 MCP 父进程退出后仍存活(含 stopOnExit 回收)
npm run test:workspace-lock # 跨进程工作区围栏:互斥 / 假前缀 / 死持有者不自动解锁 / not-sent 释放 / root 过滤
npm run test:planner     # 入口 C:精确模型 + 矛盾现值拒绝 / 只认 Pro(真模块 isProTier)/ 非终态=unknown / 不重放
npm run test:gateway     # 入口 B:真实 MCP + 真实 detached worker(fake DSH Web):只读 dsh_lock、
                         # root 过滤、request_id 幂等与冲突、unknown 不伪装完成、waited_ms 真实值、断开存活
npm run test:dual-entry  # 审查修复回归:allowed-roots 读取门禁 / request_id 原子 claim(两个真实子进程)/
                         # classifyError 真相 / waited_ms(worker 指向不存在的 dsh,不启动服务、不调模型)
npm run test:gate     # 端到端 7 项(**会调 2 次模型**,需本机凭据)

npm test 只跑离线部分(所有项目测试都用隔离的临时会话缓存,不碰真实用户缓存,也不碰用户已有服务: web 测试用端口 0 或自带 fake 服务)。真实模型验收只有显式跑 npm run test:gate / acp-smoke --prompt 才会发生, 本项目不会声称未运行过的模型验收已通过。

注意:test/mcp-smoke.mjs 会用管道 stdio 拉起 src/server.mjs。在禁止创建管道(spawn EPERM)的 受限沙箱里这一步会失败,这是环境限制而非桥的缺陷;test/web.test.mjs 用文件描述符实现了等价的 stdio 冒烟(ACP 与 web 两个入口都覆盖),所以在那种沙箱里 npm test 的最后一步仍可能报 EPERM。

本机实测结论(dsh 0.1.5-rc.1 + Node v24.19)

  • dsh --profile acp 直接可用,ACP initialize 通告 sessionCapabilities: {close, list, resume}mcpCapabilities.http: trueauthMethods: []

  • ACP 的 session/prompt 响应就是回合结果(等模型跑完才返回,带 stopReason),不是仅入队回执——它是桥唯一承认的回合结束信号;session/update.turn_endedsession/status 只是信息,不能提前释放 busy,也不能改写 stop_reason;

  • Web 的 session/prompt 只是入队回执{accepted:true}):桥先开 session/follow 拿快照,再用 requestId 与持久 user/message.source.rpcId 对齐回合,只有该回合的持久 turn/end 才算结束; 历史事件、别人的回合、工具结果、HTTP 回执都不会让调用提前返回;

  • Web 的 session/follow 实时帧里:startturnchunk/end 只有 attemptId(没有 turn), 所以必须自己把 attemptId → turn 映射起来,否则实时文本会丢;

  • 图片提示词不支持(promptCapabilities.image=false),桥只接受文本;

  • 会话跨进程可恢复(ACP 实测用 bridge-sessions.json 里的 id session/resume 成功后继续跑)。

设计取舍

  • 不用 @agentclientprotocol/sdk:ACP 就是换行分帧的 JSON-RPC,字段已实测,手写客户端少一个依赖面;

  • Web 传输独立成 web-client / web-sessions / web-runtime,不把 Web 语义塞进 ACP 契约:ACP 的 prompt 是「等结果」,Web 的 prompt 是「等回执 + 靠事件流结算」,两者只在 app.mjs 的 5 个工具后面统一;

  • 不暴露 DSH 内部工具:只给 dsh_run 这类粗粒度入口;

  • stdout 只有 MCP 帧,所有日志走 stderr;

  • 默认端口 0 的管理服务:绝不占用/覆盖用户已有服务;launch token 私有捕获、私有换 cookie; 重连优先复用 cookie 与已记录的服务,用户不需要任何 token 操作;服务以 detached + 私有文件捕获启动, 因此父 MCP 进程退出后它仍然真实存活(DSH_BRIDGE_WEB_STOP_ON_EXIT=1 时才主动回收);

  • Windows 启动器安全解析dsh.cmd 垫片会被解析成它包裹的 Node 入口(node <bin.js> ...), 直接用 process.execPath 启动——既不需要 cmd.exe,也不会把 agent 名/任务/cwd 之类的内容插值进命令行; ACP 与 Web 共用这套解析;垫片指向已删除的 bin.js 时会立即返回可操作的安装错误,不再等待握手超时; 清理半启动子进程时先直接杀这个真实子进程(受限环境里 taskkill 可能被拒绝,树杀只是兜底);

  • dsh 延迟启动,由 runtime 模块统一管理:MCP 连接不依赖 dsh;dsh_start/dsh_run/dsh_workspace 通过同一个 startup promise 启动,连续/并发调用只起一个进程;dsh_status 只读。传输真的断了(子进程退出、 mux 关闭、HTTP 不可达)时状态如实变为 error,但 MCP 服务继续可用,dsh_start 可重新连接;

  • dsh_workspace 只做目录 + 原生 workspace/会话:只用 fs API(不拼 shell),创建缺失父目录、安全复用已有目录, 不做 Git 初始化/模板/注册等副作用;会话创建失败时保留已创建目录并如实报告 created,不回滚删除;

  • 超时/取消语义(两种传输一致):单轮超时或调用方 abort 都只发一次取消(并清掉另一个触发计时器); 本地超时触发的 stop_reason 始终是 timeout。ACP 用 prompt 响应确认;Web 用对应回合的 turn/end 确认, session/cancel{accepted:true} 只是「已请求」。宽限到期仍未确认则返回 cancel_state: unknown会话保持 busy、拒绝新回合;网络中断、回执丢失同样保持 busy 且绝不自动重放 prompt;

  • dsh_session close(web)只解绑:原生历史保留、共享服务不动、native_task_stopped:false; 回合在跑时拒绝解绑,避免把「结果未知」的证据抹掉;

  • 会话映射按 authority 作用域保留:桥只重新采纳自己记录过的同一个原生会话;别的 authority/别人的会话 绝不被隐式复用,没有自己的映射时就在已有 Workspace 上新建一个;

  • 「结果未知」跨重连围栏:回执丢失、取消未确认、连接断开导致的 cancel_state: unknown 会把该会话标记 fence; 重连/换 runtime 后仍然保守拒绝新回合,直到从持久事件流拿到我们那条 user/message 对应的 turn/end 才解除。 需要立刻绕开时用 dsh_run({ new_session: true });这不会削弱任何安全性:宁可拒绝,也不重放;

  • 权限默认 allow(仅 ACP),Web 权限交给原生 UI:Web 不自动绕过任何确认;

  • dsh_run 的进度是每请求独立计数器:绑定客户端给的 progressToken(无 token 则完全不发), 真实事件与空闲心跳共用一个严格递增的 progress,不发百分比/总数,返回/报错/取消即停表; 心跳只是活动信息,不改变客户端超时/配额,也不能替代或模拟客户端自己的额度提示。

已知限制

  • 单会话串行:同一会话有回合在跑时,新的 dsh_run 直接报错,不会排队;

  • 取消未确认(cancel_state: unknown)后会话保持 busy,直到对应回合的终止事件到达;期间拒绝新回合。 ACP 下连接退出可以释放;Web 下共享服务不会因为桥断开而结束,所以需要原生 turn/end,或重连后由原生注册表再次确认 (此时会以「外部正在运行」拒绝,而不是重放)。曾经入队但结果未知的回合会留下持久 fence,重连后仍保守拒绝, 直到持久 turn/end 出现;期间可用 new_session: true 开一个新会话继续;

  • Web 的 session/list 参数名以安装版本的生成描述符为准(当前为 _request),桥带 request 兜底;

  • Web 传输下 turns 只统计正常结束(end_turn/max_tokens/blocked)的回合;插件扩展的未知终止原因 会以 unknown:<kind> 如实上报且不计入;缺失终止原因会被当作失败而不是成功;

  • 不支持图片入参;

  • MCP 声明透传(把 Codex 的 MCP server 转发进原生会话)尚未实现,mcpServers 目前固定传空数组。

  • WebCodex 网关(入口 B):DSH_BRIDGE_ALLOWED_ROOTS 只是路由/会话范围,不是 OS 文件沙箱, 也不能替代 DSH 原生权限策略;围栏(DSH_BRIDGE_WORKSPACE_LOCK_DIR)没有过期时间、不会按 PID 自动解锁, 结果未知时故意保留,只能由本机操作者用 scripts/unlock-workspace.mjs 带证据解锁(MCP 的 dsh_lock 只读); 收窄 allowed roots 会让越界历史任务不可读/不可取消/不可列出(fail closed,这是有意为之)。

  • Planner(入口 C):需要本机已登录的 ChatGPT 网页;模型名必须来自 planner_models 的实时枚举, 没有默认值也不会替换;非 Pro 档位在发送前就被拒绝。

Available Tools

6 tools
dsh_modelDsh modelA

原生模型目录与选择(仅 web transport 可用;ACP 明确返回 UNSUPPORTED_TRANSPORT,绝不假装成功)。action=list 读取公开模型目录(provider/model/reasoning effort 与部署默认值);action=status 用 cwd 或 session_id 查看某个已有会话的 modelSelection projection(next/lastUsed),并以目录 default 作为尚无选择时的回退(current = projection.next ?? catalog.default,与原生 Web UI 一致);action=select 为已有会话选择 provider/model/可选 reasoning_effort:先按实时目录校验所有 id(禁止猜测),再调用一次原生 session/selectModel,然后回读 projection 与目录默认值并给出 verified。该原生 API 同时选择「本会话下一次请求」并尝试把同一选择保存为全局默认(保存失败仅由原生记日志),因此不是 session-only。本工具不创建/恢复/启动会话,不修改 settings.yaml,也不使用模型的自我描述作为身份依据。

ParametersJSON Schema
NameRequiredDescriptionDefault
cwdNostatus/select 的目标目录;与 session_id 同时给出时两者必须指向同一目录
modelNoselect 必填:该 provider 下确实存在的 model id(禁止猜测)
actionYes模型操作:list=读取公开模型目录;status=查看已有会话的当前选择;select=为已有会话选择模型
providerNoselect 必填:模型目录中确实存在的 provider id(禁止猜测)
session_idNostatus/select 的目标会话 id;必须是已存在的会话,本工具不会创建、恢复或启动任何会话
reasoning_effortNoselect 可选:该 model 暴露的 reasoning effort id;不传则由原生选择决定

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and delivers exceptionally. It discloses the transport constraint and exact failure mode (ACP returns UNSUPPORTED_TRANSPORT, never pretends success), the select-side-effect of also attempting to persist a global default (with failure only natively logged, hence not session-only), the status fallback formula (current = projection.next ?? catalog.default), the validation-before-write sequence, and the read-back verified result. No behavioral trait is left hidden.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Every sentence earns its place — there is no filler — and the core purpose plus transport caveat is front-loaded in the first clause. However, it is a single dense multi-clause paragraph in Chinese with nested parentheticals and no bullet or line-break structure, which makes it harder for an agent to parse than its information density justifies. Slightly restructured formatting would earn a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the real complexity (3 actions, 6 parameters, side effects, fallback logic, transport restrictions) and the absence of both annotations and an output schema, the description is remarkably complete. An agent receives everything needed to invoke correctly: action semantics, parameter constraints, failure modes, side-effect disclosure, and explicit non-behaviors. There is no material gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description adds genuine operational meaning on top — it maps each action to its parameter set, explains that select validates every id against the live catalog (禁止猜测), and that status accepts either cwd or session_id with an explicit fallback computation. The reasoning_effort defaulting behavior ('不传则由原生选择决定') reinforces the schema. The per-parameter descriptions in the schema already carry the basic semantics, and the description complements rather than repeats them.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource statement ('原生模型目录与选择' — native model catalog and selection) and precisely defines each of the three actions (list/status/select) with distinct semantics. It also draws scope boundaries against siblings by stating what the tool does not do (does not create/resume/start sessions, does not modify settings.yaml), so an agent can distinguish it from dsh_start/dsh_session/dsh_workspace.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear per-action routing is given: list for reading the public catalog, status for an existing session's current selection, select for choosing a model on an existing session, with the requirement that target sessions already exist. The description also gives explicit when-not conditions (no session creation/restoration, no settings.yaml changes, web transport only). It stops short of naming sibling tools as named alternatives — e.g., it never says 'use dsh_start to create a session' — so routing relies on exclusions rather than explicit alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dsh_runDsh runA

把任务交给 DeepSeek Harness 执行并返回最终答复。若 dsh 尚未启动会自动启动;默认复用当前 cwd 的会话。这是一个同步的 tools/call:保持 pending,直到原生回合给出最终结果(或超时/取消),不要轮询、不要并发重复提交。仅当客户端提供 progressToken 时才回传 progress 通知(起始/阶段/空闲心跳),它只是活动信息,不代表完成,也不改变客户端超时或配额。web transport 下若原生回合在等待权限审批,进度会显示 waiting_for_approval;审批只在原生 Web UI(dsh_start 返回的 web_url)里回答,本桥不会自动批准、也不会修改原生权限配置;因等待审批而超时时,错误里会说明并且不会重发任务。较长或预计耗时不确定的任务优先用 dsh_submit + dsh_job,避免同步调用被客户端期限截断。

ParametersJSON Schema
NameRequiredDescriptionDefault
cwdNo绝对工作区路径;不同 cwd 使用不同会话
taskYes完整、自包含的任务描述(上限 16000 字符)
session_idNo续跑指定会话(与 new_session 互斥)
timeout_msNo本轮超时,默认取 DSH_BRIDGE_TIMEOUT_MS
new_sessionNotrue = 强制开新会话
open_browserNoWeb 模式自动打开正确服务;false 关闭,true 强制打开

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and delivers extensively: it discloses auto-start behavior, default cwd session reuse, synchronous pending semantics, progress notification conditions and meaning, approval waiting behavior in web transport, and timeout handling without resubmission. This is exemplary transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with its purpose and every sentence adds important behavioral context, from synchronous semantics to progress notifications and approval handling. It is somewhat long, but the density of critical guidance justifies the length; no sentence feels wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having no output schema and no annotations, the description covers all operational aspects an agent needs: sync behavior, polling prohibition, progress notification semantics, approval flow, timeout consequences, and alternative routing. The only minor gap is the exact return payload shape, but '返回最终答复' is sufficient for a task-execution tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds only marginal parameter-related context, such as '默认复用当前 cwd 的会话', which largely restates the existing cwd schema description. It does not materially enhance understanding of parameters beyond what the schema already provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: '把任务交给 DeepSeek Harness 执行并返回最终答复' – clearly stating it submits a task to DeepSeek Harness and returns the final answer. It also distinguishes itself from siblings by explicitly contrasting with dsh_submit + dsh_job for long-running tasks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use this tool ('这是一个同步的 tools/call'), what not to do ('不要轮询、不要并发重复提交'), and when to prefer an alternative ('较长或预计耗时不确定的任务优先用 dsh_submit + dsh_job'). This provides clear routing guidance with no ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dsh_sessionManage DeepSeek Harness sessionsA

查看/恢复/关闭 DSH 会话。list/status 始终可答(未启动时返回缓存视图),并可用 cwd/session_id 收窄结果:过滤只作用于已经存在(running 或缓存)的会话行,绝不创建目录、不隐式启动或恢复任何会话,无匹配时返回空数组;不带过滤参数时仍返回完整视图(包含原生错误行)。resume/close 需要 dsh 正在运行。

ParametersJSON Schema
NameRequiredDescriptionDefault
cwdNolist/status:只保留该目录的会话(规范化路径比较,Windows 忽略大小写)
actionYes会话操作
session_idNolist/status:只保留该会话;resume/close 必填
new_sessionNo仅 resume 之外使用;与 session_id 互斥

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure and does so exceptionally well. It explicitly promises no directory creation, no implicit session start/resume, cached-view behavior before startup, empty array on no match, full view including native error rows, and the runtime requirement for resume/close. These are concrete behavioral guarantees beyond the basic action names.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense yet efficient: two sentences with no filler. The main verb and resource are front-loaded, followed by edge-case guarantees that an agent needs. Every clause adds value, even though the sentence is information-dense rather than broken into separate sections.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no annotations and no output schema, the description covers return behavior, side-effect guarantees, filter semantics, and prerequisites remarkably well. The main gap is not addressing the overlapping dsh_status sibling tool or providing more detail on new_session beyond the schema, which leaves slight ambiguity in a sibling-rich context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds meaningful extra semantics by explaining how filter parameters affect results—only existing running/cached rows are filtered, no match yields an empty array, and omitting filters returns the full view. It also clarifies the runtime prerequisite for resume/close. These additions exceed the schema's brief descriptions, though the schema already covers the enum and mutual exclusion.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb set and resource: 查看/恢复/关闭 DSH 会话 (view/resume/close DSH sessions), and distinguishes list/status from resume/close actions. It is clear what the tool operates on, but it does not explicitly differentiate itself from the sibling dsh_status tool, which could overlap with the status action.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives concrete usage context: list/status are always answerable and safe, while resume/close require dsh to be running. It also warns that filtering never implicitly starts or resumes sessions and returns empty arrays on no match he. This is clear context, though it does not name sibling alternatives such as dsh_start or dsh_status, so explicit when-not-to-use routing is missing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dsh_startStart DeepSeek Harness (dsh)A

显式启动/连接本机 DSH 并完成握手(幂等:连续或并发调用只启动一个)。transport=acp(默认)启动 dsh --profile acp;transport=web(DSH_BRIDGE_TRANSPORT=web)会自动管理一个本地 Web 服务:复用已记录的服务,或(默认端口 0)新起一个 dsh web 子进程并把它捕获的 token 私密换成浏览器 cookie。完成后返回 running:true、state、web_url(不含 token);web 模式下默认会在用户默认浏览器里打开原生 Web UI,可用 open_browser:false 关闭。返回的 web_url 就是本桥正在驱动的那个原生 Web 服务:请用这个 URL(不要假设固定端口——用户机器上的 3080 可能是另一个未被本桥连接的服务),并在其中选择同一个 workspace/session 观察同一段对话与权限提示。失败返回明确错误且桥保持可调用,可重试。

ParametersJSON Schema
NameRequiredDescriptionDefault
open_browserNoweb 模式:本轮是否打开默认浏览器(默认 true;同一次启动最多打开一次)

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does an excellent job: it discloses idempotency, subprocess management for web mode, token-to-cookie handling, browser opening, URL safety warnings, and failure/retry behavior. This goes well beyond what the schema or annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every clause adds value; it is front-loaded with the core action and idempotency. It would benefit from structured separation of the transport modes and return-value notes, but it is not padded or redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite lacking an output schema and annotations, the description covers the important runtime context: return fields, absence of token in web_url, port ambiguity, browser behavior, and retry safety. This is sufficient for an agent to invoke the tool and interpret the result correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds meaningful context beyond the schema by explaining that open_browser only applies in web mode, defaults to true, and opens at most once per start. This gives the parameter operational meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('显式启动/连接本机 DSH 并完成握手') and the resource (DSH), and adds the idempotency property. It does not explicitly differentiate itself from sibling tools like dsh_run or dsh_status, so it stops short of the 5-level sibling distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for two operational modes (transport=acp and transport=web) and explains the open_browser behavior in web mode. It does not explicitly say when to avoid this tool or when a sibling tool would be more appropriate, so it lacks explicit exclusion guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dsh_statusDeepSeek Harness bridge statusA

只读状态,不会隐式启动 dsh。running/state 可区分 stopped/starting/running/error;ok=true 表示 dsh 健康(未启动为 false);并保留二进制、版本、活会话数、会话能力、配置来源。

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It does this well by explicitly stating the tool is read-only, will not implicitly start dsh, and explaining the state semantics (running/state distinguishes stopped/starting/running/error; ok=true means healthy, false when not started). It also discloses what additional information is preserved (binary, version, active session count, session capabilities, config source). This is strong behavioral transparency for a status tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence that packs in the key behavioral facts: read-only, no implicit start, state values, ok semantics, and preserved fields. It's front-loaded with the most important information (read-only, no start). It's slightly dense with the list of preserved fields, but each element earns its place by helping the agent understand what the status output contains.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter status tool with no output schema, the description is quite complete. It explains the state machine (stopped/starting/running/error), the health flag semantics, and what data is preserved. The only minor gap is that it doesn't describe the exact output format or structure, but for a status tool this is acceptable given the description already covers the key semantics.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the schema provides no parameter information. The description doesn't need to explain parameters, but it does explain what the tool reports (state, ok flag, binary, version, session count, capabilities, config source), which gives the agent a sense of what the output will contain. With 0 params, the baseline is 4, and the description adds value by describing the output semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies this as a read-only status tool for the DeepSeek Harness bridge, and explicitly states it will not implicitly start dsh. It distinguishes itself from sibling tools like dsh_start and dsh_run by emphasizing the read-only nature and the no-start guarantee. However, it doesn't explicitly name a sibling alternative, so it gets a 4 rather than a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: when you need status information without side effects. The explicit statement '不会隐式启动 dsh' (will not implicitly start dsh) serves as a usage guideline, telling the agent this is safe to call for status checks. It doesn't explicitly say 'use dsh_start instead when you need to start it,' but the contrast with siblings is implied through the read-only framing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dsh_workspaceCreate or open a DeepSeek Harness workspaceA

为给定绝对目录建立/复用一个 DSH 会话:缺失目录连同父目录创建,已有目录安全复用且绝不覆盖已有文件;必要时自动启动/连接 DSH。返回 created(本次是否新建目录)、cwd(规范绝对路径)、session_id 与成功状态;web transport 下还会创建真实的原生 Workspace(workspace_id)并把原生会话挂到它上面,另返回不含 token 的 web_url。

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes必需的绝对目录路径(Windows 路径、空格、中文均可);父目录可以不存在
open_browserNoWeb 模式自动打开正确服务;false 关闭,true 强制打开

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden. It discloses key behaviors: never overwrites existing files, safe reuse, auto-start/connect, and web-transport-specific workspace creation. It also details return fields, providing transparent expectations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single well-organized paragraph that front-loads the core purpose and then details behaviors and returns. Every sentence adds value, with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the main return values and behavioral nuances, including web transport specifics. It doesn't mention error conditions or prerequisites, but given the tool's complexity and lack of output schema, it provides sufficient context for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters. The description reiterates the absolute path requirement and open_browser's web-mode control but doesn't add substantive new meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: create or reuse a DSH session for a given directory, with explicit behaviors like directory creation, safe reuse, and no overwriting. It distinguishes itself from siblings like dsh_start (service startup) and dsh_session (session management) by focusing on workspace establishment.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for establishing/reusing a workspace, but it doesn't explicitly compare with sibling tools or state when NOT to use it. It mentions auto-starting DSH when necessary, but gives no guidance on choosing this over dsh_start or dsh_session.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.0
    • First observeddsh_model
    • First observeddsh_run
    • First observeddsh_session
    • First observeddsh_start
    • First observeddsh_status
    • First observeddsh_workspace

TDQS

A4.1/5.0

Scored across 6 tools

Disambiguation4/5

Each tool maps to a distinct lifecycle area (start, run, session, status, workspace, model), and the descriptions are detailed enough to resolve most ambiguity. However, dsh_session's list/status view overlaps conceptually with dsh_status, and dsh_run's auto-start behavior blurs the boundary with dsh_start.

Naming Consistency4/5

All tools share a clear dsh_ prefix and consistent snake_case, making the family easy to recognize. The pattern is slightly mixed, though: start/run are verbs while session/status/workspace/model are nouns, so it is not a uniform verb_noun convention.

Tool Count5/5

Six tools is a well-scoped set for this domain. Each tool covers a distinct concern with no obvious redundancy, and the count falls comfortably within the ideal range.

Completeness3/5

The core surface covers starting, running, session management, status, workspace setup, and model selection. Notable gaps exist, however: there is no explicit stop/shutdown operation, and dsh_run's guidance to prefer dsh_submit + dsh_job for long tasks references async tooling that is absent from this server.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Exposes DeepSeek Harness agent capabilities as an MCP server, letting any MCP client drive Harness to execute real coding tasks with structured results, context isolation, and parallel execution.
    74 npm
    12
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    In-process DeepSeek Harness plugin that exposes a local Streamable HTTP MCP server, allowing MCP clients like Codex to submit tasks executed by DSH child agents using DSH's existing tools.
    164 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables external MCP clients to drive DeepSeek Harness agents for real coding tasks, providing tools for task execution and queueing, session management, sandboxed file access, preset switching, and usage statistics.
    357 npm
    2
    GPL 3.0