dsh-project-mcp

toolstested: passnpmMIT

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

下载量 / Downloads
1,767
依赖体积 / node_modules
22.39 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add dsh-project-mcp

Sandbox test results

StageResult
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

Links

GitHub · Homepage · npm

Same category