面向 DeepSeek Harness 的非官方 MCP 确定性录制与回放插件。
真实调用只录一次;无需凭据和网络即可离线回放;每次命中、差异与契约变化都能在 DSH 中检查。
0.1.1-rc.2
- 一个全新或明确指定的 DSH Profile
推荐先安装到隔离 Profile:
~~~bash
git clone https://github.com/bleakbelladonnals/dsh-echo.git
cd dsh-echo
npm ci
npm run build
npm pack --ignore-scripts
export DSH_HOME="$(mktemp -d)"
dsh plugin --profile web add ./dsh-echo-0.1.0.tgz
dsh --profile web --no-open
~~~
进入任意 Session 后,可以看到 **Echo / 录制回放** 页签。安装时
bindings: [],所以仅安装插件不会拦截或改变任何 MCP Server。
卸载:
~~~bash
dsh plugin --profile web remove dsh-echo
~~~
只有在你明确要安装到日常 DSH Profile 时,才应省略临时
DSH_HOME。
## 录制与离线回放
录制 stdio MCP Server,默认开启脱敏:
~~~bash
dsh-echo record -o .dsh-echo/demo.cassette.jsonl -- \
node examples/fixture/server.mjs
~~~
离线回放同一段交互:
~~~bash
dsh-echo replay .dsh-echo/demo.cassette.jsonl
~~~
未录制请求返回 JSON-RPC -32601 并以非零状态退出,且不会启动
真实 Server。只有同时显式指定 --on-miss passthrough 和真实
Server 命令时,才允许实时回退。
Streamable HTTP 通过 loopback 端点工作:
~~~bash
# 录制
dsh-echo record -o .dsh-echo/http.cassette.jsonl \
--http http://127.0.0.1:3000/mcp \
--listen 127.0.0.1:6402
# 回放
dsh-echo replay .dsh-echo/http.cassette.jsonl \
--listen 127.0.0.1:6402
~~~
## 连接一个 DSH MCP Server
当前 DSH 会直接构造 MCP Transport,因此 DSH Echo 使用可撤销 Profile
Overlay,不修改 DSH 源码,也不原地编辑你的源 Profile:
~~~bash
dsh-echo profile patch \
--source ./cordis.yml \
--out ./cordis.echo.yml \
--recovery ./cordis.echo.recovery.json \
--root ./.dsh-echo \
--server-row mcp-demo \
--cassette-id demo \
--cassette demo.cassette.jsonl \
--mode replay
~~~
生成的 replay 行不含原 Server 命令;record/passthrough 使用 argv 数组,
不拼接 Shell 字符串。源文件保持不变。恢复记录可写入另一个文件:
~~~bash
dsh-echo profile restore \
--recovery ./cordis.echo.recovery.json \
--out ./cordis.restored.yml
~~~
应用前请人工检查生成的 YAML。v0.1 支持 HTTP record/replay,有意不提供
HTTP passthrough。
## DSH 中能看到什么
对于名称形如 mcp__<serverName>__<tool> 的工具,Host
插件会写入精简的 tool/result.meta.dshCassette 引用。完整结果留在
Cassette 内,不会重复写入 Session Log。
**Echo / 录制回放** 页签展示:
- Cassette ID、模式、Transport、格式与脱敏状态;
- 每次交互的参数、结果、耗时与来源;
- recorded、hit、miss、passthrough、error;
- miss 与最近录制调用之间的结构化差异;
- Contract / Schema Drift 和 Snapshot 操作;
- 当前 Session/Trajectory 中的关联标注。
Host API 只接受已配置的 Cassette ID,不接受任意路径。所有 Cassette 与
Snapshot 必须位于指定 Root 下,数据进入浏览器前还会再次脱敏。
## 契约门禁
先保存基线:
~~~bash
dsh-echo snapshot --stdio "node examples/fixture/server.mjs" \
-f mcp-contract.snapshot.json
~~~
删除工具或出现 Breaking Schema Change 时让 CI 失败:
~~~bash
dsh-echo snapshot --check --fail-on breaking \
--stdio "node examples/fixture/server.mjs" \
-f mcp-contract.snapshot.json
~~~
仓库 CI 自带会删除工具并新增必填参数的 Fixture,并断言门禁确实失败。
## 安全导出 Fixture
原始录制默认位于 Git 已忽略的 .dsh-echo/。导出是独立、显式的
步骤:
~~~bash
dsh-echo export-fixture \
.dsh-echo/demo.cassette.jsonl \
--root ./fixtures \
--out demo.cassette.jsonl
~~~
命令会拒绝 Root 之外的路径,并在发现 Secret 时阻止复制。扫描通过仍需人工
复核:基于模式的自动脱敏是纵深防御,不等于“可以直接公开”。
## 架构
~~~mermaid
flowchart LR
DSH["DeepSeek Harness"] --> Adapter["DSH Echo Profile Adapter"]
Adapter --> Core["Record / Replay Core"]
Core --> Live["真实 MCP Server"]
Core --> Tape[("版本化 Cassette")]
Tape --> Core
Core --> Session["Session 标注"]
Session --> UI["Echo Web 检查器"]
~~~
通用 Transport 引擎仍可独立作为 CLI 使用;DSH 适配集中在
src/dsh/。生命周期、信任边界和集成取舍见
[架构说明](docs/architecture.md)。
## 开发与验收
~~~bash
npm ci
npm run lint
npm run typecheck
npm test
npm run test:e2e
npm run audit:pack
npm pack --dry-run --ignore-scripts
~~~
当前共 463 项测试,覆盖真实 stdio 录制/回放、无 Server 回放
Tripwire、Profile 恢复、路径限制、UI 二次脱敏、契约漂移、生命周期清理和
Tarball 审计。验收只使用临时 HOME、loopback、隔离 npm cache 和隔离 DSH
Profile,不读写真实用户配置。
- [完整验收记录](docs/validation.md)
- [安全模型](docs/security.md)
- [上游审计](docs/upstream-audit.md)
- [DSH 集成方案对比](docs/dsh-integration-options.md)
- [Fixture Server](examples/fixture/README.md)
## 上游与许可证
DSH Echo 派生自
[ivermin1123/mcp-cassette](https://github.com/ivermin1123/mcp-cassette),
导入 Commit 为 9e48be26cbf1f7fca5edde142673a9b102a25e86
(上游 0.4.0)。保留的引擎提供 stdio、Streamable HTTP/SSE、
匹配、脱敏、Contract Diff、安全 Lint 和 Vitest 集成。
精确归属与修改记录见 [UPSTREAM.md](UPSTREAM.md) 和 [NOTICE](NOTICE)。
项目采用 [Apache-2.0](LICENSE) 许可证。