Skip to main content
Glama
README.md
# DSH ACP MCP Bridge

把 DeepSeek Harness 的 ACP 服务接入支持 stdio 的 MCP 宿主,提供会话、模型选择、后台任务、取消和子代理观察。Codex 是可用宿主之一;桥接不依赖 Codex,也不会读取或修改 Codex 配置。

版本 **0.5.0** 面向 **Harness 0.1.3-alpha.1**。[源码](https://github.com/krkr521/dsh-acp-mcp-bridge) · [Releases](https://github.com/krkr521/dsh-acp-mcp-bridge/releases)。项目未发布到 npm,`private: true` 防止误发;从源码或 Release 压缩包安装。

## ACP 与 MCP 分别负责什么

```text
ACP 客户端 ── ACP stdio ──> Harness ACP profile
MCP 宿主 ── MCP stdio ──> 本桥接 ── ACP stdio ──> Harness ACP profile
```

Harness 的 ACP 服务可以直接接受 ACP 客户端,不需要此桥接。桥接为 MCP 宿主启动一个 ACP 子进程;启动命令始终使用构建后的 Harness CLI 和 `--profile acp`,不直接启动 ACP 包。

基础会话和模型工具不要求子代理扩展,但仍受 ACP 服务实际提供的标准方法限制。完整的子代理树和持久化事件读取需要配套 [dsh-acp-extensions](https://github.com/krkr521/dsh-acp-extensions);它针对 Harness 0.1.3-alpha.1 提供自定义 ACP API,需要按其 README 适配和构建 Harness,不能只安装桥接就获得这些能力。

## 安装与配置

需要 Node.js `^22.19.0 || >=24.0.0`,以及已安装依赖、完成构建、可以正常启动 ACP profile 的 Harness。先配置该 profile 的模型提供方和凭据;桥接本身不提供订阅登录或模型服务。

源码安装:

```powershell
git clone https://github.com/krkr521/dsh-acp-mcp-bridge.git
cd dsh-acp-mcp-bridge
pnpm install --frozen-lockfile
pnpm build
pnpm test
```

Release 的 `.tgz` 可在独立目录中作为本地依赖安装,随后用 `node <安装目录>/node_modules/dsh-acp-mcp-bridge/server.mjs` 启动。源码安装直接使用仓库内的 `server.mjs`。服务通过 stdin/stdout 收发 MCP,不能用浏览器打开。

参考 [mcp-server.example.json](mcp-server.example.json) 配置宿主。所有路径必须替换为本机实际绝对路径,宿主的配置文件格式以其自身说明为准:

```json
{
  "mcpServers": {
    "dshacp": {
      "command": "node",
      "args": ["/absolute/path/to/dsh-acp-mcp-bridge/server.mjs"],
      "env": {
        "DSH_ACP_ROOT": "/absolute/path/to/prepared-harness",
        "DSH_ACP_PROFILE": "acp",
        "DSH_HOME": "/absolute/path/to/private-dsh-home",
        "DSH_ACP_REQUIRE_EXTENSIONS": "1"
      }
    }
  }
}
```

Windows 路径在 JSON 中可写 `D:/apps/prepared-harness`,或对反斜杠转义。桥接继承宿主进程环境,ACP 子进程继承桥接环境;请在宿主配置中显式传入所需的 `DSH_HOME` 等变量。

**多个 Harness 版本建议各用独立 `DSH_HOME`,ACP 与 Web 也建议独立配置,以免共享 SDK fallback、会话锁或不兼容数据。** 迁移时自行备份并按对应 Harness 版本要求迁移配置、凭据和会话资料;桥接不会复制、升级或删除这些资料。私人 home、密钥和宿主个人配置都不要上传到仓库。

| 环境变量 | 用途 |
| --- | --- |
| `DSH_ACP_ROOT` | 必填,已构建 Harness 根目录,需存在 `apps/cli/lib/bin.js`。 |
| `DSH_ACP_PROFILE` | 默认 `acp`,由 Harness CLI 加载。 |
| `DSH_HOME` | 传给 Harness 的独立私有配置与数据目录。 |
| `DSH_ACP_REQUIRE_EXTENSIONS` | `1` 要求子代理扩展握手成功,否则连接失败;默认 `0` 允许基础 ACP 模式。 |
| `DSH_ACP_STARTUP_TIMEOUT_MS` | initialize 等待时间,默认 30000,范围 1–300000 毫秒。 |
| `DSH_ACP_DEFAULT_MODEL_VALUE` | 新会话的默认 opaque model value,直接使用发现结果。 |
| `DSH_ACP_DEFAULT_PROVIDER` / `DSH_ACP_DEFAULT_MODEL` | 默认路由的便捷写法,必须成对提供,不能与 MODEL_VALUE 同时设置。 |
| `DSH_ACP_DEFAULT_REASONING_EFFORT` | 默认推理强度,使用该模型实际公布的值。 |

## 使用顺序

1. 调用 `status`,确认 `connected`、`agentCapabilities` 和 `subagentObservation`。这会启动 ACP,但不调用模型。
2. 调用 `list_models` 获取 `modelChoices[].value`,然后在 `new_session` 或 `set_session_model` 传 `model_value`。值属于 ACP 服务,不应自行拼接;`providers` 只是可解码 DSH 路由的便利视图,其他 opaque 值仍保留在 `modelChoices`。
3. 用 `prompt` 等待单轮结果;较长任务用 `start_prompt`,持有返回的 `runId`,通过 `activity` 查看进度。将响应 `nextCursor` 原样传回下次请求的 `after_cursor`;状态变化可以返回空事件页。
4. 需要停止时调用 `cancel_prompt`,继续读取 `activity` 直到终态。结束会话用 `close_session`,持久化历史仍由 Harness 保存;后续可 `resume_session`。
5. 增强 ACP 模式下,调用 `list_subagents`,从 `entries` 取 `kind: "child"` 的 `id`,再传给 `read_subagent.subagent_session_id`。将 `nextSeq` 传回 `after_seq`;该序号属于持久化会话日志,与 MCP run cursor 不通用。

共 17 个 MCP 工具:`status`、`list_models`、`default_route`、`set_default_route`、`run`、`new_session`、`session_options`、`set_session_model`、`prompt`、`start_prompt`、`activity`、`cancel_prompt`、`list_sessions`、`resume_session`、`list_subagents`、`read_subagent`、`close_session`。

`set_default_route` 只改变当前 MCP 进程后续新建会话的默认选择,不修改已有会话,也不写入配置。持久默认值使用环境变量;未设置桥接默认值时,由 Harness profile 决定。

## 扩展与生命周期约定

桥接在 initialize 的 `_meta["_deepseek.ai/dsh"]` 中发送 `{ "subagents": true }`。只有服务返回版本 `1`,且公布 `_deepseek.ai/dsh/subagents/list` 和 `_deepseek.ai/dsh/subagents/activity` 两个方法时,`subagentObservation` 才为 `true`。基础模式下调用两个子代理工具会返回明确的 MCP `isError`,不会把普通会话接口冒充子代理观察。严格模式用于希望启动即发现适配缺失的部署。

子代理请求由增强 ACP 服务检查当前连接拥有的根会话及其后代关系;桥接原样返回扩展结果。Harness 0.1.3 的持久化 `assistant/message` 包含 `data.stream` 和 `data.message.content`,读取的是已提交事件,不保证正在生成的每一个 token 都立即出现在子代理日志中,也不会构造旧版 `assistant/chunk` 序号。

模型发现和默认路由校验会创建临时会话,按服务公布的能力关闭,并仅在支持 delete 时删除。0.1.3 的 close 保留持久化记录,因此列表中可能出现空探测会话。若服务既不提供 close 也不提供 delete,发现操作会在创建会话前失败。其他可选标准方法以 ACP 服务是否实现为准,未实现时返回协议错误。

同一会话的操作串行执行。宿主取消同步 `prompt` 或 `run` 请求时,桥接向对应 ACP 任务发送取消;`run` 在创建会话期间收到取消则关闭新会话,不发模型请求。`start_prompt` 返回后由 `cancel_prompt` 显式管理后台任务。排队期间或恢复会话期间取消,不会继续发出模型 prompt。MCP 宿主关闭 stdin 或进程收到退出信号时,桥接先结束 ACP stdin 并等待退出,超过 5 秒终止该子进程;Windows 启动隐藏控制台。后台 run 与其进度保存在桥接进程内存中,记录总数超过 100 时优先淘汰最早创建的已结束记录,活动任务不会被淘汰;重启后不可继续使用旧 runId,应通过持久化 sessionId 恢复会话。

桥接不实现交互式批准界面,ACP `requestPermission` 一律返回 `cancelled`,同时记录到任务结果的 `permissionRequestsCancelled`。需要批准才能执行的工具会被拒绝;不要把本桥接当作自动批准器。

## 验证

`pnpm test` 包括模型路由测试和真实 ACP/MCP stdio fixture;fixture 使用临时目录,不访问私人 DSH home,不调用付费模型。`pnpm build` 对直接运行的 ESM 源文件做 Node 语法检查,无编译产物要求。`pnpm pack --pack-destination artifacts` 生成本地发布包并执行同一检查。

已完成检查及其范围见 [VALIDATION.md](VALIDATION.md)。显式设置 Harness 环境后可运行 `pnpm smoke:live`,它连接实际 ACP 并查询能力与模型目录,不发送 prompt;会按上述约定创建并释放探测会话。

本项目采用 MIT,来源与依赖说明见 [NOTICE.md](NOTICE.md) 和 [LICENSE](LICENSE)。