An unofficial DeepSeek Harness plugin for deterministic MCP record/replay.
Capture a real tool session once, replay it without credentials or network, and inspect every match and contract change inside DSH.
简体中文 · Website · Install · Quick start · Architecture · Security
0.1.1-rc.2
- a fresh or explicitly selected DSH profile
Build a local package and install it into an isolated 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
~~~
Open a Session and choose the **Echo / 录制回放** tab. Installation adds the
plugin with bindings: [], so it does not intercept or change an MCP
server until you explicitly bind one.
To remove it:
~~~bash
dsh plugin --profile web remove dsh-echo
~~~
Omit the temporary DSH_HOME only when you intentionally want to
install into your normal DSH profile.
## Record and replay
Record a stdio MCP server. Redaction is enabled by default:
~~~bash
dsh-echo record -o .dsh-echo/demo.cassette.jsonl -- \
node examples/fixture/server.mjs
~~~
Replay the same interaction offline:
~~~bash
dsh-echo replay .dsh-echo/demo.cassette.jsonl
~~~
An unrecorded request returns JSON-RPC error -32601 and exits
non-zero. The real server is not started. Live fallback exists only when you
explicitly pass --on-miss passthrough together with a real server
command.
Streamable HTTP works through a loopback endpoint:
~~~bash
# Record
dsh-echo record -o .dsh-echo/http.cassette.jsonl \
--http http://127.0.0.1:3000/mcp \
--listen 127.0.0.1:6402
# Replay
dsh-echo replay .dsh-echo/http.cassette.jsonl \
--listen 127.0.0.1:6402
~~~
## Connect one DSH MCP server
DSH currently constructs MCP transports directly, so DSH Echo uses a reversible
profile overlay instead of modifying DSH or editing your source profile in
place:
~~~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
~~~
The generated replay row does not contain the original server command.
Record/passthrough rows use argv arrays, never a shell-concatenated command.
The source file is untouched. Restore the saved row into another file with:
~~~bash
dsh-echo profile restore \
--recovery ./cordis.echo.recovery.json \
--out ./cordis.restored.yml
~~~
Review generated YAML before applying it. HTTP record/replay is supported;
HTTP passthrough is intentionally unavailable in v0.1.
## What appears in DSH
For DSH tool names shaped like mcp__<serverName>__<tool>,
the Host plugin adds a compact tool/result.meta.dshCassette
reference. Full tool payloads stay in the cassette rather than being duplicated
into the Session log.
The **Echo / 录制回放** tab shows:
- cassette identity, mode, transport, format, and redaction status;
- each interaction's arguments, result, duration, and origin;
- recorded, hit, miss, passthrough, and error state;
- a structured argument diff for the nearest miss;
- contract and schema drift, plus a snapshot action;
- the annotations attached to the current Session/Trajectory.
Host APIs accept configured cassette IDs rather than caller-provided paths.
All cassette and snapshot paths must resolve below the configured root, and
values are redacted again before reaching the browser.
## Contract gate
Capture a baseline:
~~~bash
dsh-echo snapshot --stdio "node examples/fixture/server.mjs" \
-f mcp-contract.snapshot.json
~~~
Fail CI when a tool is removed or a breaking schema change appears:
~~~bash
dsh-echo snapshot --check --fail-on breaking \
--stdio "node examples/fixture/server.mjs" \
-f mcp-contract.snapshot.json
~~~
The repository's own CI fixture deliberately removes a tool and adds a required
property, then asserts that the gate fails.
## Export a reviewable fixture
Raw recordings live under the ignored .dsh-echo/ directory.
Export is a separate, explicit step:
~~~bash
dsh-echo export-fixture \
.dsh-echo/demo.cassette.jsonl \
--root ./fixtures \
--out demo.cassette.jsonl
~~~
Export refuses paths outside the selected fixture root and blocks detected
secrets. A passing scan still requires human review: pattern-based redaction is
defense in depth, not proof that a recording is safe to publish.
## Architecture
~~~mermaid
flowchart LR
DSH["DeepSeek Harness"] --> Adapter["DSH Echo profile adapter"]
Adapter --> Core["record / replay core"]
Core --> Live["real MCP server"]
Core --> Tape[("versioned cassette")]
Tape --> Core
Core --> Session["Session annotations"]
Session --> UI["Echo Web inspector"]
~~~
The transport engine remains usable as a standalone CLI, while the DSH layer
lives under src/dsh/. See
[architecture](docs/architecture.md) for lifecycle, trust boundaries, and
integration decisions.
## Development
~~~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
~~~
The current suite covers 463 tests, including real stdio record/replay, a
no-server replay tripwire, profile recovery, path containment, UI redaction,
contract drift, lifecycle cleanup, and package inspection. Acceptance runs use
temporary homes, loopback listeners, isolated npm caches, and isolated DSH
profiles; they do not read or write the user's DSH configuration.
More detail:
- [Validation evidence](docs/validation.md)
- [Security model](docs/security.md)
- [Upstream audit](docs/upstream-audit.md)
- [DSH integration alternatives](docs/dsh-integration-options.md)
- [Fixture server](examples/fixture/README.md)
## Upstream and license
DSH Echo is derived from
[`ivermin1123/mcp-cassette`](https://github.com/ivermin1123/mcp-cassette)
at commit 9e48be26cbf1f7fca5edde142673a9b102a25e86 (upstream
version 0.4.0). The retained engine provides stdio and Streamable
HTTP/SSE record/replay, matching, redaction, contract diff, safety lint, and
Vitest integration.
See [UPSTREAM.md](UPSTREAM.md) and [NOTICE](NOTICE) for the exact import and
modification record. Licensed under [Apache-2.0](LICENSE).