MCP server manager (stdio / streamable-http): per-working-directory project and global config tiers; project-level MCP collapsed into 4 atomic tools through a middleware layer by default (`middleware: all` folds in global servers too, hot-switchable in the settings page); workspace isolation prevents cross-project interference; configs keep `${ENV}` references only, with no plaintext secrets on disk; runtime registration API for other plugins to inject MCP servers.
Install
# from npm (prebuilt)
dsh plugin --profile web add @wingsky-1/dsh-mcp-manager
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:wingsky-1/dsh-plugin-hub#path:/packages/dsh-mcp-manager
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
A MCP server management plugin for DSH (DeepSeek Harness): a floating window in the
top-right of the session UI + a tiered panel + quick onboarding (manual form + paste
mcpServers JSON import, no servers preconfigured). Connection and protocol come from
the official @deepseek-ai/dsh-mcp-client (mounted by name through the host cordis loader,
resolved to the copy inside the DSH installation); this plugin keeps only the configuration
surface and the model-visible surface. The official client is not redistributed with this
package, and nothing extra needs to be installed.
The model surface carries exactly four atomic tools (ws_mcp_list / ws_mcp_detail /
ws_mcp_search / ws_mcp_call): project-level, global and runtime-injected
wrapped-definition servers all go through the middleware (two-level discovery:
ws_mcp_list for a full inventory → ws_mcp_detail to pull the complete schema on
demand), falling back to the virtual global root @global when cwd has no project. The
host still registers tools as mcp__<id>__<tool> (id is an opaque short string
allocated per (workspace, server) for one plugin assembly and cannot be derived from the
server name), but those names are removed from the model's tool list — never call them
directly.
The server lists across both config tiers hot-reload without a restart
(add/remove/toggle/edit).
(The middleware / middlewarePolicy config keys were removed in #767 batch 2: writing
them has no effect, and this plugin never rewrites your config file.)
A historical session will not open after upgrading DSH to 0.1.5+ (
unclassified message source)? See Troubleshooting: a historical session will not open after upgrading (#723), one command recovers it.
Quick install
dsh plugin --profile web add @wingsky-1/dsh-mcp-manager
After install / uninstall / update, restart
dsh webonce (bundle layers are only composed at startup) for changes to take effect.
Core advantages
- Context cost under control: all MCP goes through the middleware — the model surface
carries only
ws_mcp_list/ws_mcp_detail/ws_mcp_search/ws_mcp_call, so no matter how many servers or tools you connect the system prompt never balloons (two-level discovery:ws_mcp_listfor a full inventory →ws_mcp_detailto pull the complete schema on demand) - Per-working-directory maintenance: project-level config
<project root>/.dsh/@wingsky-1/dsh-mcp-manager/mcp.jsontravels with the repo and can be committed to git for team sharing; global config<DSH_HOME>/@wingsky-1/dsh-mcp-manager/mcp.jsonstays always connected; switching sessions auto-loads the MCP set of the current directory - Workspace isolation: the middleware routes by the session's cwd to the matching connection pool, with server-full-name consistency checks against cross-workspace crosstalk; same-named servers in different directories never clash
- Secure by default: configs store only
${ENV}references, never key material (0600 permissions + atomic writes); stdio subprocess environments are sanitized so host credential-shaped variables never leak through; directory summaries and error paths go through a redactor - Low-maintenance operations: tiered status display (running / connecting / failed…);
bounded exponential-backoff auto-reconnect on disconnects; a per-server timeout override
(
toolCallTimeoutMs), while a middleware call settles at the largest in-use server timeout plus a 25s internal tail (15s + 25s = 40s by default)
Installation
Prerequisite: DeepSeek Harness installed and dsh web running normally (for running dsh
without a global install, see "Without a global dsh install" below).
Install plugins (add)
dsh plugin --profile web add @wingsky-1/dsh-mcp-manager
Uninstall plugins (remove)
dsh plugin --profile web remove @wingsky-1/dsh-mcp-manager
Update plugins (update)
dsh plugin --profile web update @wingsky-1/dsh-mcp-manager
After install / uninstall / update, restart
dsh webonce (bundle layers are only composed at startup) for changes to take effect.
Pin a version (@version)
Omitting @version installs the default latest (recommended). Only when the registry has not synced the latest yet, or the latest has issues in your environment, append @version to the package name:
dsh plugin --profile web add @wingsky-1/dsh-mcp-manager@<version>
Without a global dsh install
If there is no global dsh command on the machine, use npx to run it on the fly (dsh plugin
calls pnpm under the hood, so pnpm and Node.js must still be installed locally):
npx @deepseek-ai/dsh plugin --profile web add @wingsky-1/dsh-mcp-manager
npx @deepseek-ai/dsh plugin --profile web remove @wingsky-1/dsh-mcp-manager
npx @deepseek-ai/dsh plugin --profile web update @wingsky-1/dsh-mcp-manager
Capabilities
| Capability | Description |
|---|---|
| Top-right floating window | Status dot + count summary (MCP 2/3); click to expand the dropdown panel; auto-refreshes on session switch |
| Project-level MCP | Servers are split into "project-level / global" tiers: project-level stored in <project root>/.dsh/@wingsky-1/dsh-mcp-manager/mcp.json (travels with the project, can be committed to git); global stored in <DSH_HOME>/@wingsky-1/dsh-mcp-manager/mcp.json for persistent connection |
| Tiered display | Running / Connecting / Reconnecting / Disconnected / Disabled / Failed; each server shows transport, endpoint, and tool count |
| Server management | CRUD (project-level/global optional), connect / disconnect / reconnect; versioned JSON config, atomic write |
| Two transports | stdio (local subprocess, env supports ${ENV} references) and streamable-http (remote, header supports ${ENV} references, auto-echoes Mcp-Session-Id) |
| JSON import | Paste mcpServers JSON text to import (JSON format only; does not scan any application config files) |
| Model tools | Every server (project-level / global / runtime-injected) goes through the same four atomic middleware tools: ws_mcp_list / ws_mcp_detail / ws_mcp_search / ws_mcp_call, so workspaces never clash; the host registration name mcp__<id>__<tool> (id allocated at random per (workspace, server), stable within one assembly, opaque; names still obey the 64-char / [A-Za-z0-9_-] / hashed-suffix-on-conflict rules) is internal only — it is removed from the model's tool list and must never be called directly |
| Workspace isolation | The middleware routes by the calling session's cwd to the matching workspace connection pool; server full-name consistency checks (@<root>/<server>) prevent cross-workspace crosstalk |
| Reconnection | Exponential backoff (starts at 500ms, caps at 30s, gives up after 10 attempts and deregisters the tools) |
| Result size | This package performs no result truncation; tool results are returned as-is. The catalog boxing limits (4KB per tool / 256KB total) bound the catalog, not execution results — enforce a limit on the MCP server side or via the host compaction policy |
| Timeout fallback | Direct-connect tool call timeout defaults to 60s → 15s (overridable per server via toolCallTimeoutMs); a middleware ws_mcp_call settles at the largest in-use server timeout plus a 25s internal tail, not a fixed value |
| Push self-healing | Triple safeguard on the SSE channel: server sends a data ping heartbeat every 30s; client reconnects (closing the stale EventSource first) after 60s of frame silence (watchdog); connection is force-rebuilt when the page becomes visible again — half-open connections silently severed by mobile OS backgrounding heal on their own instead of piling up as zombies |
Configuration (floating window position)
Configuration page: Plugin Manager → dsh-mcp-manager → Configure. The floating button
(MCP pill) position and offsets (position / offset) are saved there through the plugin's
own Config; no config-file editing is needed.
Non-loopback LAN origins (for example
192.168.*:3081) intentionally do not expose a persistent settings surface, so the Configure control is hidden by DSH's security policy. Manage settings from127.0.0.1:3080/127.0.0.1:3081or an SSH loopback tunnel. Enable dsh-lan-proxyownsHostCompatonly on a trusted LAN and only when you accept the shared control-plane risk.
| Key | Allowed values | Default |
|---|---|---|
position |
top-right (top-right, default) / top-left (top-left) / bottom-right (bottom-right) / bottom-left (bottom-left) |
top-right |
offset.x |
Non-negative integer (horizontal offset, px) | 8 |
offset.y |
Non-negative integer (vertical offset, px) | 8 |
offset.blankY |
Non-negative integer (blank-session vertical offset, px) | 40 |
zIndexBase |
Integer, clamped to 1-9000 (floating window z-index base; the pill and the main panel opened on click both use this same config value; the modal manager panel is unaffected) | 10 |
Settings namespace
The DSH importer consumes the same-id dsh-mcp-manager section directly; this plugin does not run a second namespace migration. settings.yaml.imported is an audit copy of the consumed document and must not be copied wholesale.
When position = bottom-right or bottom-left, the dropdown panel expands above the
pill (bottom anchor, popping upward), does not overflow the viewport, and content stays
fully visible and clickable; at top anchors it expands downward (historical behavior,
unchanged default).
Mobile / tablet adaptation (issue #128): the breakpoint is decided from the
conversation container's viewport width rather than a window media query — on narrow
screens (<=480px, portrait phones / very narrow splits) the panel goes near full-width,
server cards reflow, and action buttons get touch targets of about 44px; the tablet tier
(<=834px) transitions; desktop is unchanged. Final floating coordinates are clamped to
the viewport in JS (safe-area semantics: the host has no viewport-fit=cover, so
env(safe-area-inset-*) is always 0 and this degrades naturally to a plain clamp);
the on-screen keyboard is followed via visualViewport resize, and orientation changes
recompute on the next frame.
Cross-package avoidance contract (from issue #116, must not be reverted): this
plugin's pill defaults to top-right at 8px from the top and ~26px tall;
dsh-provider-usage's usage capsule relies on that default position with offsetY: 48
to sit right below it (no overlap by default). Changing this plugin's default anchor /
vertical offsets breaks that avoidance — treat it as a cross-package behavioral contract
and adjust provider-usage defaults in lockstep before reverting.
Saving in the settings page takes effect immediately, without restarting dsh web and
without manually refreshing the page: the host pushes a frame over the existing SSE events
channel, and the client automatically re-fetches /api/dsh-mcp/config and updates the
floating position in place.
Configuration (middleware)
All MCP goes through the middleware (single pool, no mode switch): no server exposes a
model-visible mcp__ direct-call tool; the model surface carries four atomic tools
(two-level discovery, the standard MCP ecosystem shape) —
ws_mcp_list (full inventory of the current workspace's servers and each server's
complete tool list, not truncated by ws_mcp_search's limit; supports server
full-name/bare-name filtering; perServerLimit caps tools per server at 50 by default
/ 500 max, setting toolsTruncated when exceeded; empty results carry an explicit
message, and when a server filter matches nothing the message attributes the miss to
the filter and lists the visible project-level servers) / ws_mcp_detail (exact single-tool lookup by @<root>/<server> + bare tool
name, returning the complete inputSchema; three-way errors: discovery failed with
reason / server not connected or not found / tool does not exist) / ws_mcp_search (keyword search, search first then call; returns a truncated flag
when results hit the limit) / ws_mcp_call (invoke by @<root>/<server>, verify
argument schema with ws_mcp_detail), routed by the calling session's current cwd to
the matching workspace connection pool, so different workspaces inject different MCPs
without name clashes, and falling back to the virtual global root @global when cwd has no
project — list/search/detail always merge queries across the "project root unit +
@global unit", and call allows the @global root (global config is shared across
workspaces, so the semantics hold). The host registration name looks like
mcp__<id>__<tool> with an opaque id (read it from the tool list); it is internal only
(the model's tool list never shows it), and a wrapped definition entry
(toolDefinitions) is reached only through ws_mcp_call at @<root>/<server>.
Note: global server add/remove/edit refreshes the @global unit only after a restart or a
session touch (existing behavior).
Top-level config keys (Config schema)
Top-level keys of Config (packages/dsh-mcp-manager/src/server/config/config-schema.ts) with defaults and semantics:
| Key | Default | Semantics |
|---|---|---|
enabled |
true |
Whether the plugin is enabled (plugin-level master switch). |
announceToAgent |
true |
Whether to announce the plugin to the Agent (capability list carried by <available_mcp_servers>). |
storePath |
empty (defaults to <DSH_HOME>/@wingsky-1/dsh-mcp-manager/mcp.json) |
Global server config path; empty uses the default path. |
announceCatalog |
true |
Whether to inject the MCP capability catalog (<available_mcp_servers>). |
catalogMaxEntries |
6 |
Cap on catalog injection entries. |
debug.callStats |
false |
Whether to enable call-stats debugging and persistence (off by default, config-file only; see "Call stats and debug mode" below). |
debug.statsFile |
empty (defaults to <DSH_HOME>/@wingsky-1/dsh-mcp-manager/stats.json) |
Stats persistence path; empty uses the default path. |
ui |
see "Configuration (floating window position)" (position defaults to top-right; offset.x / offset.y default to 8, blankY to 40; zIndexBase defaults to 10, clamped to 1-9000) |
Floating window position and z-index; see "Configuration (floating window position)". |
Removed config keys (#767 batch 2): middleware (off / project / all) and
middlewarePolicy (allowTools / denyTools). The settings-page mode dropdown is gone;
writing either key neither errors nor takes effect (the keys are passed through with no
consumer), and this plugin never rewrites your config file. Per-tool disable is the only
admission gate.
Retired implementations: S1-5c retired the self-built connection stack (four files including runtime/supervisor.ts and runtime/reconnect.ts, removed as a whole; connections now go through the official engine); W11b2a removed src/types and src/integration (no migration).
Per-tool disable (floating window)
- Expanding the "Tools (N)" details of a server card shows a checkbox list; toggling
each tool persists via
PATCH /api/dsh-mcp/tool-disable(stored under<DSH_HOME>/@wingsky-1/dsh-mcp-manager/user-state.json→disabledTools, merged write, survives restarts); - Semantics: both project-level and global servers' tools can be disabled (after the
single-pool change both go through the middleware; global records are keyed by
@globaland shared across workspaces); everything is enabled by default; - Per-tool disable is independent of the server-level
enabledswitch (re-enabling a server does not clear its tool-level state); - It applies to all mcp-manager-managed MCP tools (
mcp__-prefixed direct calls and middlewarews_mcp_*calls consistently; runtime wrapped tools are covered too); plugins' own declared discipline bare-name tools are not affected; - Overlong tool names (>64 chars, hashed suffix) are irreversible → treated as unknown server, neither disabled nor mistakenly denied;
- Both the "project-level" and "global" groups in the floating window render tool switches (after the single-pool change both groups go through the middleware, so a global switch takes effect just the same);
- Both the floating window and the management panel group servers by "project-level / global" (each group further ordered by connection status).
Routes (all loopback-fenced)
| Route | Description |
|---|---|
/api/dsh-mcp/health |
Health check (note: differs from the directory name) |
/api/dsh-mcp/tool-disable |
Per-tool disable toggle (PATCH, loopback-only) |
/api/dsh-mcp/* |
Server management / connection control / tool listing / SSE events, etc. |
Runtime registration (registerServer.toolDefinitions)
Other plugins can register MCP servers at runtime via ctx.mcpManager.registerServer
(in-memory only, not persisted; idempotent for same names). The registration input
supports an optional toolDefinitions field (caller-provided wrapped tool definitions,
ToolDefinition[]; tool names are bare names):
- With
toolDefinitions: all tools of that server are registered from the wrapped definitions —executecomes from the caller (which may preprocess first and then forward to the underlying command internally), skipping the remote schema projection and the genericcallTool; the underlying real implementation is never exposed; - Without: current behavior is preserved (remote schema + generic
callTool), zero impact on other servers; - Direct calls are denied by this package's own pre-execute guard, not by convention (#1014):
mcp__<id>__<tool>is an internal registration name; the pre-execute guard denies by default everymcp__direct call that is not this package's own forwarding — it no longer relies on the model obeying a prompt, nor on declaration-surface masking (which necessarily leaks during connection flips). The single allow-path is the host-issued in-flight token: the sub-call ofws_mcp_call→ dispatch →ctx.tools.executeis admitted by itsparent, deregistered when it settles, and replaying the same token is denied. The denial text points atws_mcp_calland says not to retry the same call. - No model-visible
mcp__direct-call tool: calls only go throughws_mcp_callwith bare names (@<root>/<server>+ bare name; a wrappedexecuteis caller JS, so there is no remote implementation to call directly). The call name is still derived viapublicToolName(64-char / hash-suffix rules unchanged), but only as the name the middleware forwards when calling; - Per-tool disable / visibility / capability catalog still apply to wrapped tools
(judged by server + tool name, same as
mcp__-prefixed tools); - Consumed only by the runtime registration surface (runtimeRegistry) — never persisted to the store, never passed through mcpServers imports.
await ctx.mcpManager.registerServer({
name: "my-mcp",
transport: "stdio",
command: "my-mcp-server",
args: ["serve", "--mcp"],
toolDefinitions: [
{
name: "my_tool", // bare name
description: "Caller-provided wrapped tool",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
output: { schema: { ... }, render(args, value) { ... } },
execute: async (args) => { await prepare(); return forwarded; }, // internal forwarding, never exposed
},
],
});
Data and Security
- Server config:
<DSH_HOME>/@wingsky-1/dsh-mcp-manager/mcp.json(stores only${ENV}references, never the secrets themselves); on-disk 0600 permissions + atomic write - All
/api/dsh-mcp/*routes are restricted to loopback access (non-loopback → 403 / wrong method → 405) - stdio subprocess environment sanitization (official dsh-mcp-client semantics): sanitization
applies to the inherited parent environment only — credential-shaped names (
KEY/PASSWORD/SECRET/TOKEN) and everyDSH_*variable are stripped from the parent environment so host secrets never leak into the MCP subprocess implicitly; anenventry you declare explicitly is passed to the child verbatim (explicit layers merge after the scrub), soenvis not a redaction boundary — do not put credentials there if you want them isolated - stdio subprocess inherits host privileges: MCP server commands run under the host
process's permissions; only configure trusted servers. Trust boundary: in-process plugin
injection (
ctx.mcpManager.registerServer) shares this plugin's privileges and is not a privilege escalation; the project-levelmcp.jsonthat ships inside a repository is the side you should scrutinize - Stats carry metadata only: debug stats (
debug.callStats) record call counts / durations / outcomes plus the progressive-disclosure funnel; search terms are persisted only as SHA-256 hash buckets (h:<12 hex>, empty queries as<empty>), and plaintext keys written by older versions are dropped on read (the drop happens at read time; the next flush stops writing them back — until then an inactive stats file still holds them). Hashing is pseudonymization, not anonymization: search terms have low entropy and remain dictionary-attackable. The funnel's other two dimensions are still plaintext: thews_mcp_listserver filter and thews_mcp_detailserver/tool — those are server and tool names, already part of the config and catalog surfaces, not free text - MCP tools execute on the real server — confirm before acting; tool results are returned as-is and may contain sensitive information; treat tool descriptions/results as untrusted input
- Injection trust tiers: remote tool descriptions/results are untrusted input — render and pass as parameters only, never execute as instructions; local configuration and explicit user actions are trusted
- Middleware tool read-only boundary:
ws_mcp_list/ws_mcp_detail/ws_mcp_searchonly read the local catalog cache (never touch remote servers or execute tools);ws_mcp_callis the only entry point that executes remote tools, and it is governed by the per-tool disable table;ws_mcp_callerror messages follow an "explicit + next step" style (confirm the server connection / verify the argument schema withws_mcp_detail/ check the per-tool disable state) - Per-tool disable (three entry points consistent):
ws_mcp_call(callTool checks the disable table), the pre-execute guard (mcp__-prefixed direct calls), and plugins' own declared discipline bare-name tools all go through the singleisToolDenieddecision; disabling only affectsmcp__-prefixed tools, and the denial reason carries that semantic note; records live under<DSH_HOME>/@wingsky-1/dsh-mcp-manager/user-state.json→disabledTools(the@globalkey is shared across workspaces; merged writes never overwrite the whole table) - Call stats and debug mode (Metadata-Only): Disabled by default; when configured with
dsh-mcp-manager.debug.callStats: truein~/.dsh/settings.yaml, tool call metrics (call count, success/error, average/max duration) and progressive disclosure funnel stats (ws_mcp_searchquery frequencies,ws_mcp_list/ws_mcp_detailquery distributions) are debounced and atomically written to<DSH_HOME>/@wingsky-1/dsh-mcp-manager/stats.json, with single-line console debug logs; strictly does not persist user arguments or returned content, avoiding code or privacy leaks - The capability catalog injection includes source annotations and a "does not represent current connection status" note
- Message-source shape of the catalog injection:
sourceuses the host-registered generic shape{ kind: "plugin", plugin: "@wingsky-1/dsh-mcp-manager", form: "snapshot", sections: [{ name: "mcp-catalog", text }] }. A self-inventedsource.kindis refused by DSH's session-format v2-to-v3 migration gate (closed whitelist), which makes every session persisted before the upgrade unloadable — see the next section
Troubleshooting: a historical session will not open after upgrading (#723)
Symptom: after upgrading DSH to 0.1.5 or later, a historical session reports in the GUI:
历史加载失败:failed to observe session "session-…":
cannot safely transform unclassified message source;
source v0 artifact remains unchanged (raw log: …/session.jsonl.zstd)(gateway/internal)
and session.v3.jsonl.zstd never appears next to the original log. Cause: 0.2.x and earlier
wrote the catalog injection message as source.kind = "mcp-catalog", which DSH's v2-to-v3
migration refuses against its closed source.kind whitelist for surface messages (the original
artifact is preserved by design). This version changes the write side to the generic
host-registered shape, but artifacts already on disk need a one-time repair.
Repair (one-off, repeatable): the repository script rewrites the old source in place; it touches only source metadata, never the body or the event sequence, so DSH still performs the migration itself.
# 1) Dry run: list affected sessions and counts, change nothing
node scripts/maintenance/repair-mcp-catalog-sessions.mjs
# 2) Apply (a session.jsonl.zstd.bak-<timestamp> backup is created for every rewritten log)
node scripts/maintenance/repair-mcp-catalog-sessions.mjs --apply
# 3) Restart dsh web and open the session
- Stop
dsh webfirst: a session log being written is not guaranteed safe to rewrite - Reads
<DSH_HOME>by default (--home <dir>orDSH_HOMEoverrides it);--session <id>limits the run to one session - Idempotent: repaired artifacts no longer match; every write is self-checked (frame structure, per-line JSON, zero leftover legacy kinds)
- Rollback: overwrite
session.jsonl.zstdwith the matching.bak-<timestamp> - v3 artifacts are repaired by default too: the v3 read path does not validate
message.source, so v3 sessions with the legacy kind load fine today — but a v3 session created before the upgrade and written incrementally afterwards carries both kinds, and a future v3-to-v4 migration with a similar gate would repeat this outage. The repair only swaps source metadata, so v3 semantics are unchanged (verified with strict restore +Session.fromRestore) --legacy-onlylimits the run to v0/v1/v2; it never writes a v3 file (DSH performs the migration itself)- A trailing torn frame (crash during write) is prefix-decoded with the host's recovery semantics; a truncated last line is dropped
Verification
# Health check (loopback)
curl -s http://127.0.0.1:3080/api/dsh-mcp/health
# Source is in src/; must build after changes
pnpm --filter @wingsky-1/dsh-mcp-manager build
pnpm --filter @wingsky-1/dsh-mcp-manager test
Known Limitations
- The
mcp__registration name is internal only: servers are mounted by the official dsh-mcp-client, so the host registers tools asmcp__<id>__<tool>, whereidis a random short string allocated per (workspace, server) — stable within one plugin assembly, opaque, and not derivable from the server name; it changes on plugin reload or host restart. Those names are removed from the model's tool list, and the model reaches them throughws_mcp_call— never hardcode tool names in scripts or prompts; always resolve them throughws_mcp_list/ws_mcp_detail - Does not subscribe to the MCP
tools/list_changednotification (no long-lived SSE connection); tool list changes are re-synced on reconnect / manual refresh - The middleware catalog is a "last-good snapshot within collection bounds" (≤512 tools /
≤256KB total per server); on discovery failure
ws_mcp_listsurfaces theunavailablereason - Only bridges tool capabilities; MCP resources and prompts have no harness consumption interface yet
- With several tabs bound to different sessions, project-scoped MCP can follow only one
(open item from issue #1028): the host keeps a single
projectRoot, so tabs overwrite each other, and therebindSessionon every foreground switch amplifies the overwrite. This package does not arbitrate which tab wins. - An unresolvable current session keeps the existing binding instead of clearing it
(#1028): before the official session snapshot is ready, or while the tab is not held by
the official
mainView, the package treats the read as unknown and does not sendcwd:""— unknown is not "no project", and a wrong clear leaves the panel with global entries only and makes project-scoped imports fail withno active project session. Warning criterion: a first-frame unknown is the race where the official snapshot is not ready yet (it happens on every cold start) and stays quiet; one console warning is emitted only when a previously resolved session becomes unreadable, or when the session stays unreadable across consecutive frames — so a normal cold start and a real failure do not show the same yellow warning. - Requires Node ≥ 20
Type dependencies
Host-side and client-side types both come from the official @deepseek-ai/* packages
(cordis, dsh-host-webserver, dsh-agent, dsh-tools, dsh-system-prompt,
dsh-llm, dsh-client-ui-slots, dsh-api-session-controller,
dsh-client-ui-session; versions are pinned in the repository's pnpm-workspace.yaml
catalog and upgraded with DSH releases): import type only, compile-time usage —
build artifacts contain zero official runtime imports. The package declares this host
coupling as optional peerDependencies; consumers running type checks against the plugin
must be able to resolve these official packages (skipping type checking is unaffected).
The client's "current session" read goes through the single seam
src/client/core/current-session.ts, using the official criterion
retainedBy.mainView > 0 and anchored to the official SessionListState /
SessionSummary types (no self-declared mirror types): since DSH 0.1.7-rc.2 the
session list snapshot no longer has a current field and the official ISessions
exposes no current-session accessor, so the package stopped hand-rolling a
{current, byId} shape.
License
MIT
Links
More in this category
Tencent/WeKnora#dsh-weknora★ 31680
Four read-only tools over a WeKnora knowledge base: list knowledge bases, hybrid passage search, reassemble one document's chunks in order, and WeKnora's own cited RAG or ReAct-agent answer with a resumable session id.
superdesigndev/treg★ 3995
Tool catalog for agents: search ~2,600 external endpoints (SEO and SERP, backlinks, social, people and company enrichment, ad libraries, scraping) by the task you want done, read each one's parameters and per-call price, then call it with the credential injected server-side. Ships the skill plus an MCP row that stays disabled until TREG_TOKEN is set.
TencentCloudBase/CloudBase-AI-Toolkit#dsh-plugin★ 1130
Tencent CloudBase backend for DeepSeek Harness — scaffold and deploy full-stack apps from chat, render query results as table cards with paging, sorting and CSV export, preview a deployment on its domain, and call the CloudBase MCP toolset (`mcp__cloudbase__*`) with device-code login.
gitroomhq/postiz-agent#dsh-postiz★ 499
Connects DeepSeek Harness to Postiz over MCP: list connected social media channels, fetch per-platform posting rules, and schedule, draft, or publish posts to X, LinkedIn, Instagram, Facebook, Threads, TikTok, YouTube, Reddit, Bluesky, Mastodon, Discord, Slack, Telegram and more; adds a postiz workflow skill.
EthanYoQ/Invoice-Downloader#dsh-invoice-downloader★ 477
Local IMAP invoice download, OCR, archive, and Excel reimbursement summaries for DeepSeek Harness.
anysearch-team/anysearch-dsh★ 443
AnySearch-powered real-time web and vertical search provider for DeepSeek Harness.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.