dsh-project-mcp
Per-project MCP servers: a project declares servers in its own documents (`.dsh/mcp.json` by default; the local and global file lists are settings), and they are mounted only for the sessions working in that project — on the first turn of a session, released when it goes idle. A right-sidebar tab an
Install
dsh plugin --profile web add dsh-project-mcp
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
dsh-project-mcp
Per-project MCP servers for DeepSeek Harness.
DSH normally configures MCP once per profile (cordis.patch.yml), so every
session of the process sees the same servers. This plugin adds the missing
plane: a project declares its MCP servers in its own files, and those servers
are mounted only for the sessions working in that project.
Which files a project is read from is a setting: localFiles lists documents
relative to the project root, globalFiles lists the ones read before them. The
shipped default reads one document — <project>/.dsh/mcp.json — and nothing
global, so a project mounts exactly what it declares. A Kimi Code project (or any
other tool's file) is one config line away, never an implicit second source.
// <project>/.dsh/mcp.json
{
"mcpServers": {
"rider": {
"type": "http",
"url": "http://127.0.0.1:64343/stream",
"headers": { "IJ_MCP_SERVER_PROJECT_PATH": "/abs/path/to/project/src/App" }
},
"playwright": { "command": "npx", "args": ["-y", "@playwright/mcp@latest"] },
"tracker": {
"command": "uvx",
"args": ["yandex-tracker-mcp@latest"],
"env": { "TRACKER_TOKEN": "${YANDEX_TOKEN}" }
}
}
}
Table of contents
- [Install](#install)
- [Sources and priority](#sources-and-priority) — [entry mapping](#entry-mapping), [variables](#variables)
- [Configuration](#configuration) — [
profileWins](#profilewins) - [Runtime status](#runtime-status)
- [Usage counters](#usage-counters)
- [Tool policy: mode and pins](#tool-policy-mode-and-pins)
- [Tool activation and
mcp_search_tools](#tool-activation-and-mcp_search_tools) - [Project guidance in the system prompt](#project-guidance-in-the-system-prompt)
- [Lazy mounting and idle release](#lazy-mounting-and-idle-release)
- [Sidebar panel](#sidebar-panel) — [settings page](#settings-page), [writing entries](#writing-entries)
- [Diagnostics](#diagnostics)
- [Resource behaviour](#resource-behaviour)
- [Runtimes](#runtimes)
- [Verifying](#verifying)
- [Releasing](#releasing)
- [Limitations](#limitations)
- [Dogfooding](#dogfooding)
Implementation notes: [how it works](#how-it-works) · [bundle format](#bundle-format-do-not-fix-this) · [layout](#layout)
Install
pnpm install && pnpm check # typecheck + build + tests under the coverage gate + resource audit pnpm coverage # the same suite with the coverage report only pnpm pack # -> dsh-project-mcp-<version>.tgz (builds first, via prepack) mv dsh-project-mcp-<version>.tgz ~/.dsh/packages/ dsh plugin --profile web add file:$HOME/.dsh/packages/dsh-project-mcp-<version>.tgz
pnpm check runs the suite through --coverage, and vitest.config.ts gates all
four readings at 80% over src/**: a surface added without its tests fails
the command a reviewer runs, not a later reading of a report.
Bun works as the package manager and runner too:
bun install && bun run build bun test tests # same suite through the Bun test runner
dsh plugin add appends the bundle to dsh.profile.bundles and reconciles
~/.dsh/profiles/web/package.json; the bundle's own cordis.patch.yml mounts
the row. Restart the web GUI afterwards. To iterate without re-packing, install
with link:/abs/path/to/dsh-project-mcp and rebuild (pnpm build).
Sources and priority
Read for the project of each session, lowest priority first — a later document
overrides an earlier entry with the same serverName. The order is exactly the
globalFiles list followed by the localFiles list:
# · Document · Setting
1 … · the global documents this deployment names · globalFiles, default [] — none read
… n · the project's own documents, in list order · localFiles, default ['.dsh/mcp.json']
A spec is read the way a shell reads it: ~/… is $HOME/…, $DSH_HOME/… is the
plugin's own home, an absolute path is itself, and anything else is relative to
the base it belongs to — the project root for localFiles, $HOME for
globalFiles. So localFiles: ['.kimi-code/mcp.json', '.dsh/mcp.json'] reads a
Kimi Code project's file first and lets the DSH file override it, and
globalFiles: ['~/.dsh/mcp.json'] adds a machine-wide document below both.
A document may be { "mcpServers": { ... } }, { "servers": { ... } }, or a
bare name → entry map. Unknown fields are ignored; a broken row never blocks
the rest of the document — it surfaces as an error row.
Entry mapping
Input · Result
command / args / env / cwd · transport: 'stdio', cwd defaults to the project root
url / headers · transport: 'streamable-http'
type: 'stdio' \ · 'http' \ · 'streamable-http' \ · 'sse' · explicit transport; otherwise inferred from url
enabled: false / disabled: true · row stays visible as disabled, never mounted
serverName · the mcpServers key; must match [A-Za-z0-9_-]{1,32}, otherwise it is slugified with a warning
"${VAR}" · the project's own .env files → process.env.VAR → the credentials file, else an entry error
"${input:NAME}" · plugin inputs.NAME → the same chain as ${VAR}
invalid JSON / bad row · error row with the reason; siblings still mount
${...} references are expanded in command, args, env, cwd, url and
headers. Secrets stay out of the project document: they live in
process.env, in the project's own .env files, or in
~/.dsh/.credentials.yaml.
Variables
A value a reference needs is looked up in one fixed order, project-local first:
# · Source · Gate
1 · <project>/.dsh/.env · envFiles (default true)
2 · <project>/.env · envFiles (default true)
3 · process.env · —
4 · KEY in the credentials file · credentialsFile (default $DSH_HOME/.credentials.yaml)
Plugin inputs sit above all
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::6,最后更新 2026-11-02