# Harness Relay MCP [English](README.md) | 简体中文 **让外部 Agent 委派并持续监控 DeepSeek Harness 任务。** 让任何支持 MCP 的 Agent 向 DeepSeek Harness 委派长时间任务,并持续监控直至完成。 Harness Relay MCP 将 MCP 客户端直接连接到 DeepSeek Harness 原生会话与事件模型。推荐形态是安装为 Harness 树外内部 bundle;它不包装 CLI、不修改 Harness 源码,也不接管 Harness 进程。 ```text MCP Agent │ ├─ start_run ── Provider / 模型 / 推理强度 / preset / 权限 │ ├─ status_run / wait_run / steer_run / cancel_run │ └─ 持久结果 + 原生 Harness Web 会话链接 ``` ## 定位:Harness 控制平面,而不是模型包装器 Harness Relay MCP 是独立的第三方项目,并非由 DeepSeek AI 开发、背书或提供支持。 > **这不是 DeepSeek 模型包装器,而是 DeepSeek Harness 的 MCP 控制平面。** 请区分三种完全不同的接入方向: - DeepSeek Harness 官方仓库当前记录的是 [`mcp-client`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/mcp/README.md),用途是让 Harness 消费外部 MCP Server;这与把 Harness 暴露为可由 MCP 控制的工作 Agent 方向相反。 - 简单 DeepSeek MCP Server 直接调用模型 API 并返回模型输出,不会进入 Harness 原生会话、插件、工作区、权限和事件生命周期。 - Harness Relay MCP 连接现有的官方 Harness Host,把该 Host 的原生能力提供给外部 MCP Agent。 截至 2026-08-20,官方 [`dsh` 启动器源码](https://github.com/deepseek-ai/deepseek-harness/blob/master/apps/cli/src/args.ts)只提供 profile 启动和插件管理,没有记录可对外控制 Harness 的 `dsh mcp` Server 命令。DeepSeek Harness 仍处于开发者预览阶段,依赖本对比前应重新核对官方仓库。 **对比核验日期:2026-08-20。** | 能力 | 当前官方 Harness | 简单 DeepSeek MCP | Harness Relay MCP | |---|---|---|---| | 主要方向 | Harness 消费 MCP 工具 | MCP 客户端调用 DeepSeek 模型 | MCP 客户端控制运行中的 Harness Host | | 原生 Harness 会话和事件 | 内部原生存在,但没有通过文档化 MCP Server 对外提供 | 不支持 | 支持 | | Harness 插件、工具和沙箱 | Harness 内部原生能力 | 不支持 | 由 Harness 原生执行 | | Provider/模型/推理强度/preset | Harness UI 和 API 内可用 | 通常只有少量固定模型参数 | 从 Host 发现并选择 | | 原生权限 preset | Harness 内部行为 | 没有工作区权限体系 | `read-only`、`workspace-write`、`danger-full-access` | | 长任务生命周期 | 在 Harness 内操作 | 通常一次请求返回一次结果 | 启动、查询、等待、纠偏、回复、取消、重新打开 | | 持久监控和恢复 | Harness 保存会话历史 | 通常没有 | Relay 运行标识、幂等、对账和重启恢复 | | Harness Web 会话链接 | 原生 UI | 没有 | 返回并可验证 | | 安装与维护 | 只使用 Harness 时最低 | MCP 方案中最简单 | 组件更多,需要持续适配 Harness | ### 如何选择 - 只需要分类、提取、总结或快速第二意见,而且模型文本输出已经足够时,使用简单 DeepSeek MCP Server。 - 任务必须在 DeepSeek Harness 内运行,并需要已登记工作区、工具、插件、Provider 目录、原生权限、持久会话、长任务监控、故障恢复或 Web 查看时,使用 Harness Relay MCP。 - 不要仅为替代一次普通 Chat Completions 请求而安装 Relay;额外的 Host、状态、认证和 proxy 层不会在这种场景中产生足够的控制面价值。 ## 主要能力 - 使用 Harness 原生会话和持久事件,不解析 CLI 输出。 - 完整异步生命周期:启动、查询、等待、纠偏、回复、取消和重新打开。 - 在首条任务提示词前选择 Provider、模型、推理强度、Agent preset 和原生权限。 - 直接支持 Harness 的 `read-only`、`workspace-write`、`danger-full-access` 三档权限。 - 支持有序文本和内联图片提示词,并对 base64 和大小进行有界校验。 - 持久保存运行标识,MCP Server 重启后可恢复监控。 - 返回稳定的 Harness Web 会话链接;随附 Skill 会在分享前验证页面确实可见。 - 兼容 Codex、Claude Code、OpenCode、Cursor 及其他符合标准的 MCP 客户端。 - 内部 bundle 使用 Harness 0.1.2 的直接 Typert Gateway 和原生权限服务;外部 Agent 通过认证 HTTP 或无状态 stdio proxy 调用。 - 保留独立 `dsh-relay` 模式用于旧版 Harness 和显式回滚。 ## 运行要求 - Node.js `^22.19` 或 `>=24`。 - 内部模式要求 DeepSeek Harness `>=0.1.3-alpha.2 <0.2.0`、`web` profile,并只允许 `127.0.0.1` 绑定。该最低版本已包含上游 Windows 后台子进程修复,模型调用 `rg` 等普通命令时不会再弹出短暂控制台窗口。Relay 0.2.6 及更早版本依赖已移除的 rc.7 ApiProxy 接口,无法在此 Harness 版本线加载。 - 独立兼容模式要求已在本机回环 HTTP 地址运行的 DeepSeek Harness Web Host。 - 目标工作区必须已在 Harness 中登记,或属于明确配置的允许根目录。 默认 Host 地址: ```text http://127.0.0.1:3080/ ``` ## 安装 ### 安装为 Harness 内部 bundle(推荐) 使用 Harness 官方 profile 命令从 npm 安装已发布包,检查组合后的配置,再启动该 profile: ```powershell dsh plugin --profile web add harness-relay-mcp dsh --profile web --dump-config dsh --profile web ``` 离线安装或需要锁定本地文件时,可下载 Release tarball,并将第一条命令中的 `harness-relay-mcp` 替换为本地 `.tgz` 路径。 配置输出应包含 `id: harness-relay-mcp` 和 `name: 'harness-relay-mcp'`。因此 Harness 插件列表显示为无斜杆的 `harness-relay-mcp`。如果 `dsh web` 已在运行,安装或升级后需要重启该 Host 才会加载新 bundle。启动后,bundle 会继续在兼容路径 `$DSH_HOME/plugins/dsh-relay/web/relay-endpoint.json` 发布不含密钥的端点描述;Bearer token 单独保存在 Host 专属状态目录。 卸载不会取消已提交的 Harness 任务: ```powershell dsh plugin --profile web remove harness-relay-mcp ``` 不要把 Relay 再配置进同一 Harness 的 MCP client,否则会形成 `Harness → Relay → Harness` 递归。 ### 安装 Codex 插件 Codex 插件是外部调用层,不能替代前面的 Harness 内部 bundle。先确认 `dsh --profile web` 已加载 `harness-relay-mcp`,再从本仓库 Marketplace 安装 Codex 插件: ```powershell codex plugin marketplace add tonytanglab/deepseek-harness-relay-mcp codex plugin add deepseek-harness-relay@harness-relay codex plugin list ``` 第一条命令登记本项目的 GitHub Marketplace;第二条命令从 npm 获取同版本插件包,并为 Codex 加载 `.mcp.json` 与 `delegate-to-deepseek-harness` Skill。Codex 侧只启动无业务状态的 `dist/dsh-relay-proxy.mjs`,它通过端点描述连接已经运行的 Harness 内部 bundle;这个流程不会修改 DeepSeek Harness 源码、`web` profile 的内部 bundle 配置或 `cordis.patch.yml`。 若更新后原生工具消失,且 Codex 报 `connection closed: initialize response`,先检查任务引用的缓存目录是否仍包含 `dist/dsh-relay-proxy.mjs`。新缓存目录存在不代表运行中的宿主已切换。使用桌面应用对应的 Codex CLI 从已确认的 Marketplace 重装;如果新任务仍引用已移除的缓存,保存进行中的工作后重启应用。必须验证原生 `doctor` 和工具目录后再宣称恢复,不得改用临时 Relay 客户端。 如果 personal Marketplace 指向本地源码目录,Codex 安装器只复制现有文件,不会运行 TypeScript/esbuild 构建。每次拉取源码后必须先在该目录执行 `pnpm run prepare:codex-local`;命令会构建并校验三套 `dist` 产物的内嵌版本及 proxy 的完整工具目录,然后才能生成 cachebuster 并执行 `codex plugin add`。否则可能出现 manifest 和安装记录显示新版、实际 MCP 进程仍运行旧 bundle 的假升级。正式使用优先采用上面的仓库 Marketplace/npm 安装路径。 #### Codex 内置 MCP 的生成规范(不要写错入口) Windows 偶发控制台弹窗还需检查 Harness 本体:启用原生 Job 子进程管理时,Node runner 必须设置 `windowsHide: true`,原生 `CreateProcessW`/`CreateProcessAsUserW` 目标必须使用 `CREATE_NO_WINDOW`。仅更新 Relay 或修复 Harness 的普通 spawn 回退入口不足以覆盖这条路径;更新 Harness 后须重启实际 Host,并验证控制台可见性及输出、退出和清理行为。 Codex 插件 manifest 必须同时引用 Skill 和包内 MCP 声明: ```json { "skills": "./skills/", "mcpServers": "./.mcp.json" } ``` 随插件发布的 `.mcp.json` 必须使用下面的相对入口: ```json { "mcpServers": { "harness-relay-mcp": { "command": "node", "args": ["./dist/dsh-relay-proxy.mjs"], "cwd": "." } } } ``` `cwd: "."` 由 Codex 解析到当前已安装插件的版本根目录。不要写开发机绝对路径或 `%USERPROFILE%\.codex\plugins\cache\...` 版本缓存路径;不要在 Codex 用户 `config.toml` 再注册第二份同名 MCP。最重要的是,Codex 只能启动 `dsh-relay-proxy.mjs`:不能指向 `dsh-relay-harness.mjs`(Harness 内部 bundle),不能指向会另建独立控制面的 `dsh-relay.mjs`,也不能由 Agent 手工启动第二个 Harness Web。proxy 通过 `$DSH_HOME/plugins/dsh-relay/web/relay-endpoint.json` 发现 authority;从 0.2.8 起,只有旧 owner 可证明已死亡且回环端口确认空闲时,proxy 才会复用上一任 embedded Host 发布的精确启动契约安全拉起 Harness。端口已占用或无法探测时仍安全失败。客户端配置不保存 bearer token。 安装后新建 Codex 任务,正确调用链是: ```text doctor → list_workspaces → list_capabilities → start_review(分析/审核,只读)或 start_run(明确要求实施时使用 workspace-write) → wait_run(循环到终态)→ 读取 assistantText → 主进程复核 ``` 上述操作只能直接调用已安装插件暴露的原生 MCP 工具;严禁生成临时 `.tmp/harness-*-call.mjs`,也不得通过 `node`、PowerShell、Python 或其它 shell 调用、轮询 Relay,否则会绕过托管后台传输,并可能在 Windows 弹出可见控制台。若原生工具不可用,应修复或重装插件并新建 Codex 任务,不能回退到 shell 客户端。 用户明确指定 Harness/模型审核当前或命名的已注册工作区,即授权 Harness 在该范围内自行读取。主任务只通过内置 MCP 传递工作区、文件/目录位置、审查或实施范围、验收条件以及路由/权限元数据;Harness 必须在已授权工作区内自行读取。无论使用 `read-only` 还是 `workspace-write`,都禁止把源码正文、diff、文件转储、源码编码或仓库归档嵌入 `task`、文本 `content`、`steer_run` 或 `reply_run` 参数,也不应误报为“Codex 上传源码”。写权限只改变 Harness 可执行的操作,不改变源码传递边界。这项授权不包含凭据、秘密或无关路径。只有用户明确要求 Harness 修改、修复、实现或重构时,才调用 `start_run` 并选择 `permissionPreset: "workspace-write"`;单纯“调用 Harness”仍默认 `start_review`。 安装后重启 Codex,并新建一个 Codex 任务,让新任务加载 MCP Server 和 Skill。可在新任务中要求: ```text 调用 Harness Relay 的 doctor 和 list_workspaces,只做只读检查,确认 Harness Host、Relay 端点和工作区是否可用。 ``` 升级仓库 Marketplace 与 Codex 插件时: ```powershell codex plugin marketplace upgrade harness-relay codex plugin add deepseek-harness-relay@harness-relay ``` 然后再次重启 Codex 并新建任务。不要把 Relay 配置为同一个 Harness 的 MCP client;Codex 插件应连接 Relay proxy,而 Harness 仍通过 `dsh plugin --profile web add harness-relay-mcp` 管理内部 bundle。Codex Marketplace 的官方格式与命令参见 [OpenAI 插件打包文档](https://developers.openai.com/plugins/build/plugins)。 #### 让 AI 分析并协助安装 尚未安装插件的用户可以把下面提示词直接交给具备终端权限的 Codex。AI 应先只读检查环境、说明将发生的改动并获得用户确认,再执行安装;不得修改 DeepSeek Harness 产品源码或把 Relay 配回 Harness MCP client: ```text 请阅读 https://github.com/tonytanglab/deepseek-harness-relay-mcp/blob/main/README.zh-CN.md 的“安装”章节,协助我安装 Harness Relay MCP。 先只读检查操作系统、Node.js 版本、dsh、Codex CLI、Harness web profile 和 127.0.0.1:3080,不要修改任何文件。 列出检测结果、缺失依赖、拟执行命令和影响范围,获得我确认后再操作。 Harness 侧只能使用 dsh plugin --profile web add harness-relay-mcp 安装内部 bundle,不修改 DeepSeek Harness 源码,不把 Relay 添加为 Harness MCP client。 Codex 侧使用仓库 Marketplace tonytanglab/deepseek-harness-relay-mcp,安装 deepseek-harness-relay@harness-relay。 Codex 插件 manifest 必须引用包内 .mcp.json;.mcp.json 只能以 cwd "." 启动 node ./dist/dsh-relay-proxy.mjs。不要指向 dsh-relay-harness.mjs 或 dsh-relay.mjs,不要在用户 config.toml 重复注册 MCP,也不要由 Agent 手工启动第二个 Harness Web;旧 owner 已死亡时交给 proxy 执行受控单实例恢复。 当我明确指定 Harness/模型审核或修改当前或命名的已注册工作区时,Harness 在该范围内自行读取;Codex 只传 workspace、文件/目录位置、审查或实施范围、验收条件、模型、权限和幂等信息。read-only 与 workspace-write 都禁止把源码正文、diff、文件转储、源码编码或仓库归档放入 task/content/steer_run/reply_run 参数。若我明确要求 Harness 修改代码,使用 start_run + workspace-write;普通审核使用 start_review。 安装后验证 dsh --profile web --dump-config、codex plugin list,并提醒我重启 Codex、新建任务后运行 doctor 与 list_workspaces。遇到错误时停止并报告原始错误,不扩大权限、不删除现有配置。 ``` ### 本地开发 ```powershell pnpm install pnpm run build ``` 内部 bundle 启动后,让 MCP 客户端启动通用 stdio proxy: ```json { "mcpServers": { "harness-relay-mcp": { "command": "node", "args": ["C:/Users/you/plugins/deepseek-harness-relay-mcp/dist/dsh-relay-proxy.mjs"], "env": { "DSH_RELAY_CLIENT_PRINCIPAL_ID": "cursor:project" } } } } ``` proxy 默认读取 `$DSH_HOME/plugins/dsh-relay/web/relay-endpoint.json`;未设置 `DSH_HOME` 时统一回退到用户目录下的 `.dsh`,空白 `DSH_PROFILE` 回退到 `web`。自定义状态目录时显式设置 `DSH_RELAY_ENDPOINT_DESCRIPTOR`。客户端配置不保存 token。`harness-relay-mcp` 包根入口是 Harness bundle,同时提供 `harness-relay-mcp`、`harness-relay-mcp-proxy` 命令;旧 `dsh-relay` 命令作为兼容别名保留。 0.2.3 起,内部 bundle 会在 endpoint 同目录原子发布不含凭证的 `relay-status.json`。stdio proxy 先启动本地 MCP;`tools/list` 与本地 `doctor` 不等待远端连接或 Harness 自动恢复。proxy 从 embedded Relay 的同一组注册定义生成完整产品工具目录,因此恢复期间 Codex 仍能发现 `list_capabilities`、`start_review`、`wait_run` 和其他原生工具。当 endpoint 缺失、状态失败、owner epoch 不匹配、token 不可读或 POST 返回 401/404/405/503 时,除 `doctor` 外的调用在路由恢复前统一返回 `RELAY_ROUTE_UNAVAILABLE`。Host 恢复后,同一个 proxy 会重新连接并发送 `tools/list_changed`,让客户端刷新远端元数据变化。 ## 快速开始 先读取 Harness 原生工作区注册表,不要把 Host 进程目录当成授权清单: ```json { "tool": "list_workspaces", "arguments": {} } ``` 然后读取 Host 实际能力,不要猜测路由名称: ```json { "tool": "list_capabilities", "arguments": {} } ``` 然后使用 Kimi K3/MAX 发起只读审查: ```json { "tool": "start_review", "arguments": { "workspace": "D:/work/project", "task": "读取 README.zh-CN.md、skills/delegate-to-deepseek-harness 与 src/mcp-server;审查任务契约和权限边界,只返回可复现的发现。", "provider": "kimi-coding", "model": "k3", "reasoningEffort": "max", "agentPreset": "standard", "idempotencyKey": "review-2026-08-19-001" } } ``` 保存返回的 `runId`、`sessionId` 和 `webUrl`,并持续调用 `wait_run` 直到终态。单次最多等待 30 秒;超时且 `status: running` 只是切片。若 `hostPollContract.hostMustCallWaitRunAgain` 为 true,必须立刻再调 `wait_run`。给出 `webUrl` 不等于完成: ```json { "tool": "wait_run", "arguments": { "runId": "", "timeoutMs": 30000 } } ``` 活动运行需要补充或纠正时调用 `steer_run`。运行进入终态后,通过 `reply_run` 在同一个原生 Harness 会话中继续对话。 同时省略 `sessionId` 和 `sessionMode` 时,会在所选 Harness 工作区内创建新会话。需要延续现有项目对话时,先调用 `list_workspace_sessions` 并传入其中空闲的 `sessionId`,或者传入 `sessionMode: "latest-idle"`,复用最新的非空、空闲、未归档会话。显式 `sessionId` 不能与 `sessionMode` 同时使用。 ## 运行生命周期 ```text start_run │ ├─ 预留会话 ├─ 选择模型和原生权限 preset ├─ 持久化 runId + prompt rpcId ├─ 提交 session.prompt └─ 与持久历史对账 running ── status/wait/steer/cancel ──> succeeded | incomplete | failed | cancelled | needs_attention │ └─ 终态 ── reply_run ──> 同一会话中的新运行 ``` `promptAdmission` 表示提示词接纳状态: | 值 | 含义 | | --- | --- | | `pending` | 运行标识已经持久化,但提示词提交尚未完成。 | | `accepted` | Harness 已接纳提示词,或已观察到其持久消息。 | | `unknown` | 传输响应不可用;应按 `rpcId` 对账,不能重复提交任务。 | | `rejected` | Harness 未接纳或未持久化提示词。 | ## `start_run` 参数 | 参数 | 是否必需 | 说明 | | --- | --- | --- | | `workspace` | 是 | Relay 策略允许的绝对工作区路径。 | | `task` | 两种提示词形式选一 | 仅包含文件/目录位置、审查或实施范围与验收条件的纯文本任务;禁止源码正文、diff、文件转储、源码编码或仓库归档;与 `content` 互斥。 | | `content` | 两种提示词形式选一 | 同样遵循仅位置/范围契约的有序文本/图片块;图片只用于任务本身要求的非工作区证据,不能替代 Harness 自行读取工作区源码;与 `task` 互斥。 | | `sessionId` | 否 | 复用所选工作区内的空闲会话。 | | `sessionMode` | 否 | `fresh` 或 `latest-idle`;默认为 `fresh`,不能与 `sessionId` 同时使用。 | | `provider` | 与 `model` 同时提供 | `list_capabilities` 返回的准确 Provider ID。 | | `model` | 与 `provider` 同时提供 | `list_capabilities` 返回的准确模型 ID。 | | `reasoningEffort` | 否 | 适配器支持的强度,例如 `low`、`high` 或 `max`。 | | `agentPreset` | 否 | Harness Agent preset,只能在创建新会话时选择。 | | `permissionPreset` | 否 | 原生权限 preset,默认为 `read-only`。 | | `confirmedDangerousPermission` | 完全访问时必需 | 使用 `danger-full-access` 前必须显式设为 `true`。 | | `idempotencyKey` | 建议提供 | 调用方稳定键;相同请求重试时返回原操作,不会重复提交。 | | `openBrowser` | 否 | 默认保持 `false`;仅当用户明确要求打开原生会话 URL 时设为 `true`。 | ### 图片提示词 使用不带 `data:` URL 前缀的规范 base64: ```json { "workspace": "D:/work/project", "content": [ { "type": "text", "text": "审查这张截图。" }, { "type": "image", "mediaType": "image/png", "data": "", "name": "screen.png" } ] } ``` 支持 PNG、JPEG、WebP 和 GIF。图片字节会发送给 Harness,但不会保留在 Relay 运行快照或状态文件中。 ## 原生权限 preset | Preset | 适用场景 | | --- | --- | | `read-only` | 审查、诊断、研究、比较和规划;任务参数只传位置与范围。 | | `workspace-write` | 仅在授权工作区和写路径内实施修改;仍只传位置与范围,不传源码正文。 | | `danger-full-access` | Harness 完全访问;仅在调用方明确授权时使用。 | 在 embedded 模式下,DSH Relay 会在需要时激活目标 Session,直接调用原生权限服务,并在提交首条任务提示词前确认最终 preset。提示词中的文字声明不会被当作权限边界;权限 preset 也不会放宽仅位置/范围的任务传递契约。 `start_review`、`start_run` 和 `reply_run` 可携带结构化范围声明:`reviewTargets` 是审核对象,`contextReadScope` 是可按需检索和读取的支持材料范围,`excludedPaths` 是排除路径,`writeScope` 是写入范围。审核计划文件时,目标文件不等于读取白名单;除非用户明确要求只读该文件,否则可把授权仓库或相关子树列入 `contextReadScope`。这些字段会进入 Harness 提示并随 `reply_run` 继承,但它们不是逐路径文件系统强制策略。Harness 的原生权限控制读写模式;所选模型仍可能经其配置的提供商处理读取内容,Relay 使用回环地址不代表全部模型处理均在本地。 `start_review` 强制要求精确的 `provider`、精确的 `model` 和 `authorizationBasis: explicit-user-request`。用户明确要求 Harness 或点名 Harness 模型审查已识别的工作区或文件,即已授权所选目的地处理范围内的读取内容;调用方不得仅因模型提供商在外部处理内容而再次索要确认。该标记为 Codex 审批记录既有选择,不扩大工作区、上下文、权限、处理目的地或允许的外部操作。`start_run` 与 `reply_run` 为兼容非审查流程仍保留可选标记。 ## MCP 工具 | 工具 | 用途 | | --- | --- | | `doctor` | 检查 Relay 包、Host 连接、工作区策略和持久状态。 | | `setup_plan` | 生成经过验证且不写入磁盘的客户端配置补丁。 | | `setup_doctor` | 将 setup 计划和调用方提供的探针结果转换为机器可读报告。 | | `start_service` | 将授权工作区附加到 Harness;必要时 proxy 会先执行受控 Host 恢复。 | | `open_service` | 打开 Host 根地址。 | | `list_services` | 列出已恢复的工作区附加记录。 | | `list_workspaces` | 列出用于路由的 Harness 原生工作区注册表。 | | `list_workspace_sessions` | 列出指定已登记工作区的直接会话,不读取对话内容。 | | `stop_service` | 只移除 Relay 附加状态,不停止 Harness。 | | `list_capabilities` | 列出 Provider/模型/推理强度、Agent preset 和原生权限模式。 | | `start_run` | 创建或复用会话并提交受跟踪任务。 | | `start_review` | 固定使用 Harness 原生 `read-only` 权限提交审查任务,并区分审核目标与支持材料读取范围。 | | `steer_run` | 向活动运行插入纠偏指令。 | | `get_run` | 读取并对账运行;推荐使用的运行状态入口。 | | `get_run_summary` | 将运行投影为稳定的状态、模型、权限、耗时和下一步字段。 | | `status_run` | 已弃用的兼容别名;请迁移到 `get_run`,计划在 0.3.0 删除。 | | `open_run` | 打开原生 Harness Web 会话链接。 | | `wait_run` | 最长等待 30 秒以获取运行进展。超时只是切片;若 `hostPollContract.hostMustCallWaitRunAgain` 为 true,必须立刻再调 `wait_run`。运行仍为 running 时不得结束宿主回合。 | | `list_runs` | 对账并列出已持久化运行。 | | `get_operation` | 读取一条持久化的 start、reply、steer 或 cancel 幂等操作。 | | `reconcile_operation` | 根据 Harness 持久事件解析不确定操作,且不重复提交请求。 | | `reconcile_permissions` | 重试恢复已过期或中断的 Harness 原生权限租约。 | | `reply_run` | 在已完成会话中创建新的受跟踪运行。 | | `cancel_run` | 请求 Harness 原生取消。 | | `read_notifications` | 从指定游标开始重放当前进程的有界通知投影。 | ## 客户端配置与监控投影 `setup_plan` 支持 Codex、Claude Code、Cursor,以及显式标记版本的 OpenCode V2 配置结构。它接收已经解析的 Node 与 Relay 入口绝对路径,只返回结构化最小补丁,绝不直接编辑客户端配置。启动器平台必须与配置平台一致;`pnpm.exe`、`pnpm.cmd` 等包管理器 shim 不能充当 Node 运行时。 `setup_doctor` 同样无副作用。文件系统、Broker、Host、工作区、模型和权限事实必须由获得授权的调用方提供;未提供的探针会标记为 `skipped`,不会猜测结果。 `get_run_summary` 消费 Relay 权威运行快照并输出版本化监控投影。`read_notifications` 重放当前 MCP Server 进程保留的通知,并在游标缺口时返回明确的重同步元数据。原生运行通知 transport 尚未启用,因此通知缓冲为空属于正常情况,客户端必须自动降级到 `get_run_summary`、`wait_run` 或 `get_run` 轮询。 ## 持久化与故障恢复 默认状态文件: ```text %LOCALAPPDATA%/dsh-relay/state.json ``` 状态会经过 schema 校验、带所有者校验的跨进程锁和原子替换,并在支持的平台上使用限制性文件权限;旧写入者不能回退已停止服务、终态运行、待处理状态、操作或权限租约。损坏文件会被隔离而不是覆盖。默认不持久化提示词文本和图片字节。Relay 重启后会恢复运行与操作标识,并与 Harness 原生历史重新对账。对账得到的 Assistant 文本会按当前 turn 的事件顺序保留,不再只返回最后一条 Assistant 消息。活动运行在配置时间内没有持久进展时会进入 `needs_attention` 并给出 `attentionReason: run_stalled`;后续一旦出现新进展会自动恢复为 `running`。 embedded Host 还会发布不含凭据的启动契约,仅记录绝对 Node/dsh 入口、源码启动所需的官方 Node loader 参数、profile、工作目录和 Relay 运行路径。构建后的 `lib/bin.js` 入口继续使用普通 Node;`apps/cli/src/bin.ts` 入口必须保留精确的 tsx ESM loader 向量,raw Node 源码启动器会被拒绝。遇到 `OWNER_DEAD` 或 Host 已正常停止时,stdio proxy 会先获取跨进程启动锁并复查状态,再确认已记录的回环端口为空闲、校验启动器结构和文件,最后用隐藏窗口和 `--no-open` 拉起 Harness。并发客户端只会收敛到一次启动;启动器缺失或无效、owner 状态未知、端口占用以及启动失败都会继续以明确诊断安全失败。 多个本地 MCP Server 进程可以共享一个状态文件;写入会按稳定标识串行化并合并。遗留锁会安全失败,而不会仅因时间过长就被删除。需要运行隔离时,再为不同客户端配置独立的 `DSH_RELAY_STATE_FILE`。 ## 会话链接 每个运行都会返回如下原生 URL: ```text http://127.0.0.1:3080/?sessionId= ``` HTTP 200 只能证明 Host 已响应,不能证明超长实时对话已经完成浏览器渲染。随附 Skill 默认保持 Harness 无弹窗运行并直接分享可点击的会话链接;仅当用户明确要求打开或显示页面时才调用 `open_run` 并验证可见的工作区和会话。Harness 成功选择会话后可能把地址栏规范化回 Host 根地址,但选中的会话仍然保持不变。 ## 配置 | 环境变量 | 默认值 | 用途 | | --- | --- | --- | | `DSH_RELAY_HOST_URL` | `http://127.0.0.1:3080/` | 本机回环 Harness Host 地址。 | | `DSH_RELAY_AUTO_START` | `true` | owner 与端口安全检查通过后,允许 stdio proxy 重启上一任 Harness Web 启动器。 | | `DSH_RELAY_AUTO_START_TIMEOUT_MS` | `120000` | 等待受控 Host 恢复发布 ready Relay 端点的最长时间。 | | `DSH_RELAY_ALLOWED_WORKSPACE_ROOTS` | Harness 工作区目录 | 操作系统分隔的额外授权绝对根目录列表;未配置时只接受 Harness 已登记工作区。 | | `DSH_RELAY_STATE_FILE` | `%LOCALAPPDATA%/dsh-relay/state.json` | Relay 持久状态位置。 | | `DSH_RELAY_PERSIST_PROMPT_TEXT` | `false` | 明确接受本地留存时持久化提示词摘要。 | | `DSH_RELAY_CLIENT_PRINCIPAL_ID` | `local-user` | 与幂等键共同使用的稳定本地调用方标识。 | | `DSH_RELAY_PERMISSION_LEASE_MS` | `86400000` | 复用会话权限租约的记录时限。 | | `DSH_RELAY_RPC_TIMEOUT_MS` | `30000` | Host RPC 超时。 | | `DSH_RELAY_POLL_INTERVAL_MS` | `750` | 活动运行轮询间隔。 | | `DSH_RELAY_MAX_HISTORY_PAGES` | `100` | 单次对账最多读取的持久历史页数。 | | `DSH_RELAY_RUN_STALL_MS` | `300000` | 活动运行无进展多久后标记为 `needs_attention`;恢复进展时自动回到运行态。 | | `DSH_RELAY_MAX_TASK_CHARACTERS` | `100000` | 单条提示词的最大文本字符数。 | | `DSH_RELAY_MAX_ASSISTANT_TEXT_BYTES` | `256000` | 返回的 Assistant 文本尾部最大字节数。 | | `DSH_RELAY_MAX_IMAGE_BYTES` | `5242880` | 单张图片最大解码字节数。 | | `DSH_RELAY_MAX_IMAGES` | `20` | 每条消息最大图片数。 | | `DSH_RELAY_MAX_MESSAGE_IMAGE_BYTES` | `104857600` | 每条消息中图片的最大解码总字节数。 | 只接受本机回环 HTTP Host。工作区路径会先经过文件系统解析,再执行包含关系检查。 ## 安全模型 - Harness Relay MCP 不读取或存储 Harness 凭据。 - 现有 Harness Host 仍然是模型、权限、会话、附件和任务执行的权威来源。 - 默认权限 preset 为 `read-only`。 - 未配置显式 roots 时,以 Harness 工作区注册表作为路由授权真源;配置 roots 后仍执行更严格的本地边界。 - `stop_service` 不会停止 Harness,也不会删除会话。 - Harness 输出属于证据;最终复核和高风险决策仍由调用方 Agent 负责。 - Relay 无法保证 Codex 或其他 MCP 客户端是否请求批准或触发 auto-review;这仍由客户端、客户端策略和具体操作共同决定。 ## 与 Harness 插件标准的边界 Harness Relay MCP 采用双层兼容结构:`harness-relay-mcp` 包根入口是遵循 Harness/Cordis 标准的树外内部 bundle,导出 `Config/apply(ctx)` 并通过 `dsh.bundle` 与 `cordis.patch.yml` 安装。0.2.9 绑定 0.1.2 Host 服务(`typertGateway`、Session/Workspace/Settings controllers、Agent Presets、WebServer 和 Permission Presets),将 `session.follow/page` 与 `workspace.follow` 转换为 Relay 语义网关;已移除的 rc.8 mux stream 不可用时,仍以持久历史轮询作为权威对账路径。外部 Agent 通过认证 HTTP 或无业务状态的 proxy 使用同一内部 authority,standalone 入口只作为兼容和回滚路径。整个方案不复制或修改 Harness 产品源码。 参见 DeepSeek Harness 官方文档:[创建 Harness 插件](https://deepseek-harness.github.io/deepseek-harness/develop/basic/)和[发布 bundle](https://deepseek-harness.github.io/deepseek-harness/develop/basic/publish)。 ## 开发与验证 `version.json` 是唯一可编辑版本源。构建会先同步 npm 与 Codex 清单,再生成自包含 MCP bundle。 ```powershell pnpm run test pnpm run build pnpm run test:mcp pnpm run check:package pnpm pack --dry-run ``` `prepack` 会执行严格 TypeScript 检查、构建 bundle,并验证显式发布白名单。敏感目录、运行时产物、敏感文件和符号链接会被拒绝;展开后的默认总字节上限为 8 MiB。发布自动化可通过 `DSH_RELAY_PACKAGE_MAX_BYTES` 调整门限,但提高上限应经过审查,不能用于掩盖异常包体增长。`test:mcp` 每次都会先重新构建,再启动 stdio 冒烟测试。 ## 标识 | 使用位置 | 名称 | | --- | --- | | 产品名 | Harness Relay MCP | | 仓库名 | `deepseek-harness-relay-mcp` | | Codex 插件 ID | `deepseek-harness-relay` | | npm 包 | `harness-relay-mcp` | | MCP Server ID | `harness-relay-mcp` | | Skill | `delegate-to-deepseek-harness` | ## 许可证 MIT