dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Graphical MCP server manager for the DeepSeek Harness desktop shell — add, remove, toggle, test, and scan Model Context Protocol servers
English | 简体中文
A graphical management UI for MCP (Model Context Protocol) servers in DeepSeek Harness (DSH): list, add, remove, enable/disable, test connectivity, and import servers discovered from MCP configurations already present on the machine.
It installs as a standalone bundle into a DSH profile. No official source files are modified.
The official base bundle already ships the MCP client @deepseek-ai/dsh-mcp-client, but it has no management
UI. Every MCP server has to be written by hand into the user layer of the profile's cordis.patch.yml:
- insert:
- id: mcp-filesystem
name: "@deepseek-ai/dsh-mcp-client"
config:
serverName: filesystem
transport: stdio
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "D:\\work"]
The problem is that this file is also boot input:
dsh-app-boot using js-yaml plus a custom schema, and a parse failure is fatal — the
application simply does not start, and there is no repair entry point in the UI;Hence the need for a validated graphical editing entry point: treat the configuration as structured data, validate before writing, and touch only the section this plugin owns.
| Item | Requirement |
|---|---|
| Node.js | ^22.19.0 || >=24 |
| DeepSeek Harness | Official desktop build (Windows). This plugin relies on the process.argv layout of dsh-desktop-host and on the bundled Node / pnpm |
| Official base bundle | Must include @deepseek-ai/dsh-mcp-client (the official base bundle already does) |
| Optional | @modelcontextprotocol/sdk present in the runtime node_modules; the "test connection" feature needs it |
Installation has two steps. The second step is not optional — running pnpm add alone does not add the
plugin to the bundle layer stack.
# 1. Enter the target profile directory (the official desktop build uses the desktop profile)
cd ~/.dsh/profiles/desktop
# 2. Install with the pnpm bundled with the official desktop build.
# It lives at <install dir>/resources/runtime/pnpm/bin/pnpm.cjs and can be run
# with the bundled node: node "<that path>" add ...
pnpm add "file:<absolute path to this plugin>"
It can also be installed straight from GitHub:
pnpm add "github:VCPr0j3k7/dsh-mcp-manager"
dsh.profile.bundlesEdit the package.json inside the profile directory and add the package name to the
dsh.profile.bundles array:
{
"name": "dsh-profile-desktop",
"private": true,
"dependencies": {
"dsh-mcp-manager": "file:<absolute path to this plugin>"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-mcp-manager"
]
}
}
}
dsh.profile.bundles is the profile's bundle layer stack: DSH only assembles the plugin tree from the
bundles listed here. When the package is installed but not registered, the plugin is not loaded and nothing
is reported anywhere — the only symptom is that "MCP Connector" does not appear in the sidebar. This is the
most common installation problem for this plugin.
Assembly happens at startup. After changing package.json or cordis.patch.yml the DSH desktop build must
be restarted; a running instance does not hot-reload. After the restart the sidebar should show the
"MCP Connector" entry.
cd ~/.dsh/profiles/desktop
pnpm remove dsh-mcp-manager
Then remove the dsh-mcp-manager entry from dsh.profile.bundles and restart DSH.
Uninstalling does not delete the MCP server entries already written into cordis.patch.yml — they live
inside the marked block and continue to be used by the official @deepseek-ai/dsh-mcp-client. To remove
them as well, delete that block by hand (including both marker lines).
| Half | Runs in | Loaded via |
|---|---|---|
Host half: index.js + host/ | Node.js (official host process) | Cordis plugin exporting name / inject / apply(ctx) |
Client half: client.js | Browser (SPA inside the desktop shell) | window.__ModuleLoader__.load({ id, factory }) |
The host half registers exactly one kind: 'prefix' route on ctx.webServer at
/dsh-mcp-manager/api; dispatching inside that prefix is done by host/router.mjs. This keeps the
registration point in a single place, and the framework cleans it up on unload.
Every endpoint returns the same envelope:
{ "ok": true, "data": { /* ... */ } }
{ "ok": false, "error": "human-readable message" }
Business failures also return HTTP 200; status codes only express transport-level facts (an unknown route returns 404). The request body limit is 8 MB.
The page is served by the official shell, so its origin may be the host's HTTP address, the shell's custom
scheme, or an opaque origin. The client therefore tries the candidate base URLs in order on the first
request (relative path → http://dsh.internal) and decides by whether /info reports
data.plugin equal to this plugin's id — a 200 alone is not enough, because the SPA fallback route also
answers unknown paths with 200 + HTML. Once chosen, the base URL is reused for subsequent requests.
Host events (such as MCP configuration update logs) are fetched through GET /events?since=<seq>, polled by
the client every 300 ms. SSE is not used because it cannot be confirmed whether the shell buffers response
bodies when forwarding a custom scheme; polling has no such unknown.
The actual MCP connections are made by the official @deepseek-ai/dsh-mcp-client; this plugin only writes
entries into the user layer of the profile patch. The profile's patchReload is startup, so every write
operation returns needsRestart: true and the UI shows a restart notice.
Validation before writing must use the same library the official boot path uses, otherwise the plugin could
accept text that boot rejects. host/yaml-libs.mjs therefore looks up js-yaml by absolute path (requiring
the directory entry, ignoring exports) in this order:
<runtimeDir>/node_modules (the runtime directory)node_modules under the runtime directory given in process.argv[2]node_modules under the profile directory<DSH_HOME>/profiles/node_modulesThe runtime copy takes precedence; the copy in the profile (this package's declared js-yaml dependency) is
the fallback.
The sidebar entry "MCP Connector" opens a page with three tabs:
| Tab | Contents |
|---|---|
| Connected | Cards for the servers in the current profile: transport, command or URL, entry id, connection status, tool count, raw configuration. Supports test, enable/disable and delete |
| Discover | Grouped servers that can be adopted in one click: other AI client configurations, other DSH homes, and a built-in catalog. "Use" carries the prefilled parameters into the add form |
| Add | Paste import (an mcpServers JSON snippet, or a single npx / uvx command line) and a manual form (stdio / streamable-http) |
Connection status comes from the host rather than from local guesswork: a server shows as "connected" only
when tools named mcp__<serverName>__* are actually present in the host's tool registry. A configuration
that has been written but not yet loaded shows as "pending restart".
The Add tab supports testing before writing, which avoids the "found out it cannot connect after a restart" round trip.
All routes live under /dsh-mcp-manager/api.
Common routes (provided by host/router.mjs):
| Route | Description |
|---|---|
GET /info | Plugin and host information; data.plugin is used by the client to validate the base URL |
GET /config | Read the shared configuration |
POST /config | Deep-merge write of the shared configuration |
POST /open-external | Open a URL with the system default handler (http / https only) |
POST /pick-directory | Open the system directory picker |
GET /restart-pending | Whether profile key files are newer than the host-ready timestamp |
POST /restart-host | Request a host restart. A plugin cannot restart the host process, so this route always returns an error and the UI asks for a manual restart |
GET /events?since=<seq> | Fetch host events (polled by the client every 300 ms) |
Plugin routes (registered by index.js):
| Route | Description |
|---|---|
GET /mcp/list | List the servers in the current profile with their real host-side status |
POST /mcp/add | Add a server; overwriting a same-named entry requires overwrite: true |
POST /mcp/remove | Remove a server by entry id |
POST /mcp/toggle | Enable / disable (writes the disabled field; the configuration is kept) |
GET /mcp/scan | Scan the machine for servers that can be adopted |
POST /mcp/test | Perform a real MCP handshake and return the tool list |
POST /mcp/parse | Parse a pasted JSON snippet or a single command line |
This plugin only modifies the block in cordis.patch.yml delimited by paired marker comments:
# >>> dsh-desktop:mcp —— 以下内容由桌面版维护,请勿手工编辑
- insert:
- id: mcp-filesystem
name: "@deepseek-ai/dsh-mcp-client"
config: { /* ... */ }
# <<< dsh-desktop:mcp
A few hard rules:
- insert: [...]), not a fragment. The top level of
cordis.patch.yml must be a YAML array; flattening insert: into the file makes it unparseable.The Discover tab ships a built-in catalog. It only includes servers that are official or widely used and
that start with a single npx command:
| Name | Description |
|---|---|
| Filesystem | Lets the model read and write files under a given directory (a directory must be specified, otherwise the server refuses to start) |
| Memory | A knowledge-graph based memory server: write facts in, retrieve them across sessions |
| Sequential Thinking | Breaks a complex problem into revisitable reasoning steps; useful for multi-step tasks |
| Everything | Official demo server: provides a set of example tools to verify that the MCP path works |
| Playwright browser | Lets the model actually open a browser: click pages, fill forms, take screenshots, extract content |
| Context7 docs | Fetches up-to-date official documentation and code samples by library name, reducing invented APIs |
Starting these servers for the first time requires network access so that npx can fetch the package.
Entries that need parameters come with the form fields prefilled; nothing is written until the user
confirms.
| Half | Criterion |
|---|---|
| Host half | Declares inject = ['webServer'], so the host composition must provide webServer (the official base bundle does) |
| Client half | Declares dsh.client.inject = ['@deepseek-ai/dsh-client-ui-slots'] and dsh.client.platform = 'web' |
| Both | The package name must be registered in the profile package.json's dsh.profile.bundles array |
Reading and writing MCP configuration additionally requires both the runtime directory and the profile
directory (from process.argv[2] and process.argv[3]). When either is missing, GET /mcp/list returns a
readable error message instead of throwing ENOENT.
npm test
test/check.mjs is a pure Node self-check (37 assertions) that does not depend on the DSH runtime. It covers:
package.json and the entry files they point to actually exist
(dsh.bundle.patch, exports['./client'], dsh.client.platform);name / inject / apply) and whether apply() registers the prefix
route;client.js and checked against the host
route table;data.plugin from /info, a 404 for unknown routes, and that a cleanup function is registered through
ctx.effect;githubToken field.The self-check points DSH_HOME and the profile directory at a temporary directory created for that run, so
it never reads or writes the real ~/.dsh.
End-to-end verification: after restarting the desktop build, "MCP Connector" should appear in the sidebar. Adopt a server on the Discover tab and restart — the Connected tab should then show "connected · N tools".
patchReload is startup; this is the
official composition's load ordering, not a choice made by this plugin. The UI shows a restart notice.POST /restart-host always returns an error (terminating the
host process would also lose the user's session), so the "Restart now" button in the UI receives an explicit
error and a manual exit and reopen of DSH is required.serverName is constrained. Only [A-Za-z0-9_-]{1,32} is accepted, matching the validation in the
official dsh-mcp-client. Imports from other clients substitute and truncate characters accordingly.@modelcontextprotocol/sdk/dist/esm/client under the runtime node_modules; when it is missing that one
feature returns an explicit error and nothing else is affected.npx on first use, so
those servers cannot be started offline.