DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

Zenjibad /

dsh-mcp-toggle

Verified

Enable/disable MCP servers directly from DSH Settings: a 'MCP Servers' page that stops/starts each @deepseek-ai/dsh-mcp-client connection live and persists the change across restarts.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: master@f3de6d28

dsh-mcp-toggle · Enable/Disable MCP Servers from DSH Settings

Turn MCP servers on and off directly from Settings → MCP Servers: an additive settings page that stops/starts each @deepseek-ai/dsh-mcp-client connection immediately (its mcp__* tools unregister/register live) and persists the change so it survives a DSH restart. 在 DSH 设置 → MCP 服务器页面直接启用/停用 MCP:即时停止/启动每个 MCP 客户端连接,并持久化,重启后依旧生效。

中文文档: README.zh.md · LLM index: llms.txt · Agent guide: AGENTS.md

dsh-plugin DeepSeek Harness license install

Keywords: dsh-plugin · deepseek-harness-plugin · mcp · mcp-client · settings · enable · disable · toggle · MCP 服务器 · 启用 · 停用


📑 Table of Contents

  • ✨ Features
  • 🏗️ How it works
  • 🚀 Quick start
  • ⚙️ Configuration
  • ❓ FAQ
  • ⚠️ Security notes
  • 📦 Project structure
  • 🙏 Credits

✨ Features

Feature Description
🎚️ MCP Servers settings page Additive Settings page (id mcp-toggle, order 70) listing every @deepseek-ai/dsh-mcp-client server the user has configured — with a toggle per row
🔄 Live toggle Flipping the switch calls the Cordis Loader's Entry.update({disabled}) — the MCP connection fiber is disposed (stop) or started immediately, its mcp__* tools unregister/register live, no DSH restart
💾 Persists across restarts Each change is appended to the home patch layer ($DSH_HOME/cordis.patch.yml) — the layer that outranks every profile, so the state survives a DSH restart regardless of where the MCP row originated
📊 Status at a glance Each row shows the MCP server name, an Enabled/Disabled tag, and the connection phase (Connected / Stopped / Connecting / Connection failed)
🔒 Safety guard The loader's include entry, non-MCP entries, and this plugin itself are guarded; unknown ids return 404, locked ids return 403
🌗 Theme-aware All colors use --dsw-alias-* design tokens; follows light/dark automatically
♨️ Survives restarts Real profile-bundled plugin: install once with dsh plugin add, auto-loads on every DSH boot — no per-session define, no cordis_define

🏗️ How it works

Settings → MCP Servers (additive page, id `mcp-toggle`)
                                  │
Client bundle (browser)           ▼
  └─ fetch GET /mcp-toggle/api → list of MCP client entries
  └─ one row per server: name + Enabled/Disabled tag + connection phase + toggle
  └─ toggle flipped → fetch POST /mcp-toggle/api { entryId, disabled }
                                  │
Host half (DSH process)           ▼
  └─ webServer route POST /mcp-toggle/api
  └─ filter: entry.options.name === '@deepseek-ai/dsh-mcp-client'
  └─ loader.resolve(entryId).update({ disabled })
       └─ disposes the mcp-client fiber (stop: transport closed, mcp__* tools
          unregistered) or starts it (enable) — live, no restart
  └─ appends `- id: <rawId>` / `disabled: <bool>` to $DSH_HOME/cordis.patch.yml
       (the HOME user patch layer, applied AFTER every profile layer → wins at boot)
  └─ returns { ok, entryId, serverName, disabled, fiberPhase, persisted }
                                  │
Client bundle (browser)           ▼
  └─ toast: "Disabled MCP server <name>" / "Enabled …" (or the error) → reload
  • Live + persistent, decoupled: Entry.update() (entry-level) does not write the loader tree back to any config file — the live effect is in-memory only, and persistence is the append to the home patch layer. No patch flattening, no duplicate rows.
  • Home patch outranks profile: the web profile composes patches in order bundle → profile cordis.patch.yml → HOME $DSH_HOME/cordis.patch.yml → overlays. MCP rows are split across the home and profile files; a disabled row in the home file wins for every MCP regardless of origin. Both files are HMR-watched (hot-apply without restart).
  • Persistence: ships dsh.bundle (cordis.patch.yml) + dsh.client (exports["./client"], bundled) so it installs as a real profile plugin that the DSH client-modules scanner loads on every boot.

🚀 Quick start

Standard install: dsh plugin add (persists across restarts)

Install the package from this GitHub repo:

# local directory (from the parent of this repo):
dsh plugin --profile web add ./dsh-mcp-toggle

# or directly from GitHub (any DSH machine):
dsh plugin --profile web add github:Zenjibad/dsh-mcp-toggle
# or:
dsh plugin --profile web add git+https://github.com/Zenjibad/dsh-mcp-toggle.git

dsh plugin add is a pnpm add into the profile plus a dsh.profile.bundles reconcile: seeing this package's dsh.bundle declaration, it appends dsh-mcp-toggle to the bundle stack. Restart DSH, then hard-refresh the browser tab (Ctrl+F5). On boot the client-modules scanner resolves exports["./client"] and the MCP Servers page appears in Settings. No per-session define, survives restarts.

⚠️ Important: after installing (or updating) a client plugin, a hard page refresh (Ctrl+F5) is required — the DSH client HMR only hot-swaps already-loaded bundles and does not pull in new bundles into an open tab.

Manual profile mount (alternative)

  1. git clone https://github.com/Zenjibad/dsh-mcp-toggle.git (any location).
  2. Add to ~/.dsh/profiles/web/package.json dependencies: "dsh-mcp-toggle": "link:<repo-path>", then pnpm install in the profile dir.
  3. Restart DSH.

Requirements

  • A DSH web profile with at least one @deepseek-ai/dsh-mcp-client row configured (any server name the user defined in their patch layer).
  • No MCP servers configured → the page shows "No MCP servers are configured."

⚙️ Configuration

No config file, no persisted settings of its own. Behaviour is fixed by constants in the source:

Knob Location Default
HTTP route src/index.ts `GET
MCP plugin filter MCP_CLIENT_PLUGIN in src/index.ts @deepseek-ai/dsh-mcp-client
Locked entries LOCKED / LOCKED_NAMES in src/index.ts include, cordis:include, dsh-mcp-toggle
Settings page src/client/index.tsx settings.section id mcp-toggle, order 70
Toast duration src/client/index.tsx 6 s
Persistence target $DSH_HOME/cordis.patch.yml (home patch layer) appended rows

❓ FAQ

Q: The "MCP Servers" page is missing? A: Restart DSH (if the host half isn't mounted yet), then hard-refresh the browser tab (Ctrl+F5). New client bundles only appear on a full page reload — the HMR client does not add new bundles to an already-open tab.

Q: I disabled a server but its tools are still there? A: The toggle is live — the mcp-client fiber is disposed and its tool registrations are removed. If a tool from that server still appears, it may be from a different server (server names are namespaced mcp__<server>__<tool>) or the page session hasn't refreshed its tool list.

Q: Does the change survive a restart? A: Yes. Each toggle appends a - id: <entry> / disabled: <bool> row to the home patch layer ($DSH_HOME/cordis.patch.yml), which outranks every profile layer. If the append failed, the toast says "not persisted across restart" and only the current session is affected.

Q: Why can't I toggle some entries? A: Only @deepseek-ai/dsh-mcp-client rows are listed. The loader's include entry and this plugin itself are locked (403); unknown ids are 404; a non-MCP entry returns 400.

Q: Will disabling a server uninstall it? A: No — it only stops the Loader entry and adds a disabled override. The MCP row stays configured; re-enabling starts the connection again.

Q: How do I remove the toggle plugin itself? A: dsh plugin --profile web rm dsh-mcp-toggle (or delete the profile dependency + bundle entry) and restart DSH. Previously persisted $DSH_HOME/cordis.patch.yml rows remain (they are the persistence layer, independent of this plugin).

⚠️ Security notes

  • No Remote seam, no writes to loader config: the client only calls the same-origin /mcp-toggle/api route; the host never writes cordis.yml or any bundle patch — only appends rows to the home user patch layer.
  • Input validated: entryId must resolve in the loader and must be an MCP client entry; locked ids (include, self) are rejected with 403; unknown ids with 404.
  • Small payloads: POST bodies are capped at 1 MB.
  • Live-stop is intentional: disabling a server disposes its mcp-client fiber immediately — the same operation cordis_stop performs; re-enabling restarts it.

📦 Project structure

dsh-mcp-toggle/
├── src/
│   ├── index.ts            # host half: MCP entry list, loader.resolve().update(), home patch append, route
│   └── client/index.tsx    # client bundle: MCP Servers settings page, toggle switches, toast
├── cordis.patch.yml        # dsh.bundle patch (inserts the plugin row on boot)
├── tsdown.config.ts        # bundles host (node ESM) + client (CJS ModuleLoader)
├── package.json            # name, exports["./client"], dsh.client + dsh.bundle
├── lib/                    # build output (index.js, client.js)
├── AGENTS.md               # repository guide for AI agents
├── llms.txt / llms-full.txt
├── README.md / README.zh.md
└── LICENSE

🙏 Credits

  • DeepSeek Harness — the DSH plugin/dynamic runtime, Cordis Loader, Slots, theme, webServer, client-modules, @deepseek-ai/dsh-mcp-client.
  • headroom-stats-plugin — reference for the packaged client-plugin build pattern (tsdown host/client split, cordis.patch.yml, dsh.client).
  • dsh-plugin-toggle — sibling plugin; same Loader-toggle mechanics for plugins, this plugin extends it to MCP servers.

📄 License

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit f3de6d2886df

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout