dsh-paper
paper design mcp for deepseek harness (unofficial port)
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 20, 2026
- Updated
- Aug 20, 2026
Introduction
dsh-paper
⚠️ Not official Paper or DeepSeek stuff. This is my own freestyle build (balaleikaerina) — a small, thin wrapper I wrote for my own DeepSeek Harness setup. Use at your own risk, no warranties, no official support.
An unofficial, thin wrapper that lets DeepSeek Harness talk to Paper
(paper.design). It mounts the official @deepseek-ai/dsh-mcp-client bridge
against Paper's Streamable-HTTP endpoint and sets Paper's URL as the default.
Model-facing tools appear as mcp__paper__*.
It is deliberately a wrapper, not a reimplementation: all of the protocol,
reconnect, and tool-registration logic stays in the official mcp-client. Every
field is overridable via config.
Files
| File | Purpose |
|---|---|
dsh-paper.mjs | The wrapper plugin (name + apply). Defaults to Paper's endpoint; every field overridable. |
cordis.patch.yml | A ready-to-apply overlay that inserts the wrapper. |
fixture-http-server.mjs | Standalone Streamable-HTTP MCP server with fake tools (get_basic_info/greet) for offline verification without Paper. |
verify.mts | Standalone verification: boots a minimal composition, mounts the wrapper against the fixture, and checks that mcp__paper__* tools appear. |
Prerequisites
- A DeepSeek Harness checkout with
pnpm install. - For real use: Paper Desktop must be running — Paper owns the
/mcpserver athttp://127.0.0.1:29979/mcp.
Real use (with Paper running)
Pass the overlay to the dsh CLI, e.g. with the web profile:
pnpm --filter @deepseek-ai/dsh dev:web -- --patch cordis.patch.yml
…or merge the rows into your persistent user patch layer
($DSH_HOME/profiles/<name>/cordis.patch.yml):
- insert:
- id: dsh-paper
name: ./dsh-paper.mjs
config:
serverName: paper
url: http://127.0.0.1:29979/mcp
The file plugin is only resolved if the relative path is valid from the profile
module root; if you run into trouble, point name at an absolute path to
dsh-paper.mjs, or paste the wrapper logic inline.
Every config field is optional and overridable:
config:
serverName: paper # tool namespace: mcp__paper__*
url: http://127.0.0.1:29979/mcp
headers: {} # extra HTTP headers
toolCallTimeoutMs: 60000 # per-call timeout
failOnStartupError: false # fail the load when Paper is absent
Offline verification (no Paper needed)
node fixture-http-server.mjs 39281 # terminal 1
pnpm exec tsx verify.mts # terminal 2
Expected output:
OK: saw mcp__paper__get_basic_info and mcp__paper__greet via wrapper
Gotchas
-
serverNamemust be unique per composition. The underlying mcp-client rejects a second instance with the sameserverNameat load time. If you previously added a config-only row withserverName: paper, replace it with the wrapper row instead of keeping both. -
Config-only alternative. Strictly speaking you don't need the wrapper — the generic bridge works on its own:
- insert: - id: mcp-paper name: '@deepseek-ai/dsh-mcp-client' config: serverName: paper transport: streamable-http url: http://127.0.0.1:29979/mcpThe wrapper just bundles those defaults together so callers only need to specify the parts they change.