DSH Plugin dsh-workspace-mcp: Automatically Load MCP Server by Workspace

Preface

The DSH plugin mechanism allows capabilities to be separated out and maintained independently. If MCP servers are configured at the profile or global level, multiple projects will share the same set of tools; tools from project A may also appear in project B’s sessions. If you want a project’s MCP to only take effect within that project’s sessions, you need to load it per workspace.

Below we introduce Momojie-S/dsh-workspace-mcp: it reads .dsh/mcp.servers.yml from the project root, automatically loads/unloads MCP servers based on the session’s current directory, and registers tools into the agent scope.

What This Is

Momojie-S/dsh-workspace-mcp is a DSH plugin licensed under MIT.

The core problem it solves: MCP servers from different projects don’t interfere with each other. Each project’s own .dsh/mcp.servers.yml only takes effect within its own sessions; directories without this file load no MCP at all. MCP tools are registered into the agent scope and are automatically reclaimed when the agent is created or destroyed.

Core Features

  • Agent creation triggers immediate connection and registration (agent/created), so the first model request already includes these tools.
  • Automatic reconnection on disconnect: both startup failures and mid-session disconnections trigger exponential backoff reconnection with tool re-registration. During reconnection, old tools remain registered but calls will fail; once the server recovers, they are automatically replaced with new ones.
  • Session invalidation self-healing: after a streamable-http server restart or session eviction, errors like Session not found are treated as disconnections and trigger a new generation with reconnection.
  • stdio environment inheritance: child processes receive a scrubbed parent environment with the yml’s env applied as overrides on top. The parent environment has names matching KEY|PASSWORD|SECRET|TOKEN and names prefixed with DSH_* stripped; env is an overlay layer, not a complete environment.
  • When a server declares a supported outputSchema, it enters the structuredContent output contract.
  • Invalid tool lists or registration name conflicts cause the entire generation to be rejected/rolled back.
  • Automatic tool list resynchronization when the server sends a toolListChanged notification.
  • Configuration file changes are watched by chokidar, and saving triggers a reload.
  • On name conflicts with global MCPs, the agent scope shadows the global scope by tool name.
  • This plugin is a bundle package (dsh.bundle); after installing it into a profile via dsh plugin, the configuration layer is automatically appended without needing to manually write patches.
  • Items with the same name in .dsh/mcp.servers.yml can override plugin-level configuration.

Installation and Activation

Environment requirements: DSH >= 0.1.0-rc.6, verified up to 0.1.1-rc.2.

The GitHub installation command is as follows. Installing from a private repository requires git credentials; with pnpm >=10, the first add may prompt for build authorization — follow the prompt to write the package key into allowBuilds in ~/.dsh/profiles/web/pnpm-workspace.yaml, then run add again. Tarball installation has no authorization requirement.

dsh plugin --profile web add github:Momojie-S/dsh-workspace-mcp

After the installation steps above, verify that the plugin layer is in place. Use --dump-config here to check the workspace-mcp related layer:

dsh web --dump-config | Select-String workspace-mcp

The headless or tui profiles do not have workspace-mcp mounted by default; when needed, you can use --patch to temporarily mount a file:/// line pointing to its lib/index.js. Pure host-side plugins can be temporarily mounted this way, but plugins with a browser-side component cannot. The specific paths in the examples below are from reference material and may not be universally applicable — they need to be replaced with actual paths on your machine:

dsh --profile headless --patch <(echo "- insert:
    - id: workspace-mcp
      name: file:///D:/code/workspace/deepseek-harness-101/plugins/dsh-workspace-mcp/lib/index.js") "task…"

In development mode with direct source connection, the approach is to build first, then manually add lines to the profile’s cordis.patch.yml:

npm install && npm run build

When manually adding lines, name points to your local lib/index.js, and you can configure configFile and verbose. The paths in the example below are also from reference material and may not be universally applicable:

- insert:
    - id: workspace-mcp
      name: file:///D:/code/workspace/deepseek-harness-101/plugins/dsh-workspace-mcp/lib/index.js
      config:
        configFile: '.dsh/mcp.servers.yml'
        verbose: true

Typical Usage

First, create .dsh/mcp.servers.yml in the project root. stdio servers can be configured with transport: stdio, command, args, env; remote servers can be configured with transport: streamable-http, url, headers. Example:

servers:
  my-server:
    transport: stdio
    command: npx
    args: ["-y", "some-mcp-server@latest"]
    env: {}

  remote:
    transport: streamable-http
    url: https://example.com/mcp
    headers:
      Authorization: "Bearer <token>"

After saving the configuration, ask the agent to list tools in the session. Tool names follow this format:

mcp__<serverName>__<toolName>

When tools appear, it means the workspace loaded successfully; switching to a directory without .dsh/mcp.servers.yml causes these tools to disappear, confirming that isolation is working.

Same-Name Shadowing

Tool names on both sides follow mcp__<serverName>__<tool>. When project-level MCP conflicts with global MCP, the agent scope shadows the global scope by tool name.

  • Different serverName: both tool sets coexist and both are visible to the model.
  • Same serverName (tool name collision): project-level takes priority; the model sees and calls the project version. The global version remains unaffected for other workspaces that don’t have this server configured.
  • Two entries with the same serverName in the global patch: the latter generation’s entire registration is rolled back, with an already registered log entry, and that server has no tools at all.
  • Duplicate server keys in the same yml: YAML’s later key overrides the earlier one.

If the two tool lists are not completely identical, only the overlapping names are shadowed; the remaining tools remain visible on both sides. Pointing a global server to a local dev instance is a common use case for same-name shadowing; if the name collision is unintentional, change the serverName.

Configuration

Plugin-level configuration goes in the patch’s config field. Configuration items confirmed in verified usage include configFile and verbose. Per-server overrides can configure reconnect.enabled, reconnect.initialDelayMs, reconnect.maxAttempts. Same-name items take priority over plugin-level settings:

servers:
  flaky:
    transport: stdio
    command: npx
    args: ["-y", "some-mcp"]
    reconnect:
      enabled: true
      initialDelayMs: 1000
      maxAttempts: 5

Verification and Troubleshooting

To verify isolation, first place a test server in the project root, then ask the agent to list tools in the session; switch to a directory without configuration and confirm these tools disappear.

For troubleshooting, enable verbose logging in the mount configuration:

verbose: true

In stdio scenarios, connection/registration logs appear on stderr, with common lines including:

[ws-mcp] server "xxx": registered N tools

Disconnection/reconnection logic can be verified with the test script:

npm test

The tests cover disconnection/reconnection, startup failure backoff, Session not found generation replacement with reconnection, and five official alignment tests.

Applicable Scenarios and Notes

Suitable for environments with multiple projects coexisting where each project has different MCP servers; also suitable for temporarily pointing a global server to a local dev instance for debugging.

Usage notes:

  • The plugin runs with the current DSH process permissions; review the source code, dependencies, and license before installation.
  • The env for stdio servers is only an overlay layer; when parent environment variables are needed, the parent environment is first scrubbed — names matching KEY|PASSWORD|SECRET|TOKEN and names prefixed with DSH_* are stripped.
  • During disconnection/reconnection, old tools remain visible but calls will fail.
  • The headless / tui profiles do not have this plugin mounted by default; temporary mount file:/// paths need to point to actual local directories.
  • Installing from a private GitHub repository requires git credentials; with pnpm >=10, the first add may require build authorization.
  • This plugin comes from a community GitHub repository; the community directory listing is not an official DeepSeek / High-Flyer app store.

Repository address:

https://github.com/Momojie-S/dsh-workspace-mcp
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye