@sunshaobei/dsh-mcp-manager 0.0.0-stage → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -0
- package/README.en.md +482 -0
- package/README.md +385 -2
- package/cordis.patch.yml +9 -0
- package/lib/THIRD-PARTY-LICENSES +43 -0
- package/lib/client/core/api.d.ts +42 -0
- package/lib/client/core/constants.d.ts +58 -0
- package/lib/client/core/current-session.d.ts +39 -0
- package/lib/client/core/dom.d.ts +19 -0
- package/lib/client/core/i18n.d.ts +12 -0
- package/lib/client/core/session.d.ts +27 -0
- package/lib/client/core/state.d.ts +120 -0
- package/lib/client/float/float.d.ts +126 -0
- package/lib/client/float/panel.d.ts +31 -0
- package/lib/client/float/quick-add.d.ts +38 -0
- package/lib/client/float/servers.d.ts +60 -0
- package/lib/client/index.d.ts +26 -0
- package/lib/client/locales.d.ts +123 -0
- package/lib/client/settings/settings-card.d.ts +47 -0
- package/lib/client.js +2469 -0
- package/lib/index.d.ts +86 -0
- package/lib/index.js +10298 -0
- package/lib/server/api/deps.d.ts +36 -0
- package/lib/server/api/impl/health/type.d.ts +12 -0
- package/lib/server/api/impl/service/index.d.ts +28 -0
- package/lib/server/api/interface.d.ts +27 -0
- package/lib/server/api/routes-controllers.d.ts +61 -0
- package/lib/server/api/routes-helpers.d.ts +8 -0
- package/lib/server/api/routes.d.ts +58 -0
- package/lib/server/catalog/deps.d.ts +51 -0
- package/lib/server/catalog/impl/cache-view/index.d.ts +48 -0
- package/lib/server/catalog/impl/digest/index.d.ts +19 -0
- package/lib/server/catalog/impl/directory/index.d.ts +168 -0
- package/lib/server/catalog/impl/entries/index.d.ts +129 -0
- package/lib/server/catalog/impl/entries/type.d.ts +19 -0
- package/lib/server/catalog/impl/history/index.d.ts +36 -0
- package/lib/server/catalog/impl/injection/index.d.ts +45 -0
- package/lib/server/catalog/impl/search/type.d.ts +59 -0
- package/lib/server/catalog/impl/service/index.d.ts +25 -0
- package/lib/server/catalog/interface.d.ts +45 -0
- package/lib/server/catalog/search.d.ts +108 -0
- package/lib/server/config/config-schema.d.ts +85 -0
- package/lib/server/config/impl/env/index.d.ts +24 -0
- package/lib/server/config/impl/env/policy.d.ts +54 -0
- package/lib/server/config/impl/model/type.d.ts +39 -0
- package/lib/server/config/impl/ui/type.d.ts +20 -0
- package/lib/server/config/import.d.ts +20 -0
- package/lib/server/config/interface.d.ts +15 -0
- package/lib/server/config/normalize.d.ts +24 -0
- package/lib/server/config/sources-sync.d.ts +32 -0
- package/lib/server/config/sources.d.ts +50 -0
- package/lib/server/connection/interface.d.ts +95 -0
- package/lib/server/connection/orchestrator/deps.d.ts +93 -0
- package/lib/server/connection/orchestrator/impl/service/index.d.ts +27 -0
- package/lib/server/connection/orchestrator/interface.d.ts +25 -0
- package/lib/server/connection/orchestrator/manager.d.ts +502 -0
- package/lib/server/connection/orchestrator/tool-names.d.ts +14 -0
- package/lib/server/connection/runtime/deps.d.ts +142 -0
- package/lib/server/connection/runtime/impl/middleware/type.d.ts +45 -0
- package/lib/server/connection/runtime/impl/service/index.d.ts +28 -0
- package/lib/server/connection/runtime/interface.d.ts +29 -0
- package/lib/server/connection/runtime/limits.d.ts +19 -0
- package/lib/server/connection/runtime/middleware.d.ts +196 -0
- package/lib/server/erasure/impl/guard/index.d.ts +35 -0
- package/lib/server/erasure/interface.d.ts +31 -0
- package/lib/server/inject/deps.d.ts +54 -0
- package/lib/server/inject/impl/call-timeout/index.d.ts +1 -0
- package/lib/server/inject/impl/image-admission/index.d.ts +81 -0
- package/lib/server/inject/impl/service/index.d.ts +25 -0
- package/lib/server/inject/interface.d.ts +27 -0
- package/lib/server/inject/middleware-register.d.ts +114 -0
- package/lib/server/pipeline/deps.d.ts +27 -0
- package/lib/server/pipeline/impl/args/index.d.ts +26 -0
- package/lib/server/pipeline/impl/authorize/index.d.ts +43 -0
- package/lib/server/pipeline/impl/msg/index.d.ts +8 -0
- package/lib/server/pipeline/impl/project/index.d.ts +43 -0
- package/lib/server/pipeline/impl/redact/index.d.ts +13 -0
- package/lib/server/pipeline/impl/service/index.d.ts +25 -0
- package/lib/server/pipeline/impl/timeout/index.d.ts +8 -0
- package/lib/server/pipeline/interface.d.ts +32 -0
- package/lib/server/servers/dispatch/deps.d.ts +100 -0
- package/lib/server/servers/dispatch/impl/call/index.d.ts +49 -0
- package/lib/server/servers/dispatch/impl/redact/index.d.ts +13 -0
- package/lib/server/servers/dispatch/interface.d.ts +18 -0
- package/lib/server/servers/lifecycle/deps.d.ts +62 -0
- package/lib/server/servers/lifecycle/impl/ledger/index.d.ts +52 -0
- package/lib/server/servers/lifecycle/impl/logs/index.d.ts +48 -0
- package/lib/server/servers/lifecycle/impl/mount/index.d.ts +83 -0
- package/lib/server/servers/lifecycle/impl/service/index.d.ts +26 -0
- package/lib/server/servers/lifecycle/impl/state/index.d.ts +35 -0
- package/lib/server/servers/lifecycle/impl/timeout/index.d.ts +39 -0
- package/lib/server/servers/lifecycle/interface.d.ts +56 -0
- package/lib/server/shared/compose.d.ts +38 -0
- package/lib/server/shared/constants.d.ts +62 -0
- package/lib/server/shared/file-io.d.ts +8 -0
- package/lib/server/shared/host-faces.d.ts +206 -0
- package/lib/server/shared/interface.d.ts +14 -0
- package/lib/server/shared/paths.d.ts +66 -0
- package/lib/server/shared/tool-names.d.ts +11 -0
- package/lib/server/stats/impl/collector.d.ts +68 -0
- package/lib/server/stats/impl/type.d.ts +41 -0
- package/lib/server/stats/interface.d.ts +13 -0
- package/lib/server/store/impl/middleware-state.d.ts +45 -0
- package/lib/server/store/impl/store.d.ts +43 -0
- package/lib/server/store/interface.d.ts +9 -0
- package/lib/server/upgrade/deps.d.ts +25 -0
- package/lib/server/upgrade/impl/chain/index.d.ts +2 -0
- package/lib/server/upgrade/impl/service/index.d.ts +9 -0
- package/lib/server/upgrade/impl/steps/index.d.ts +19 -0
- package/lib/server/upgrade/impl/steps/project-layout.d.ts +24 -0
- package/lib/server/upgrade/impl/steps/storage-layout.d.ts +17 -0
- package/lib/server/upgrade/impl/version/index.d.ts +7 -0
- package/lib/server/upgrade/interface.d.ts +21 -0
- package/lib/server/visibility/impl/mask/index.d.ts +7 -0
- package/lib/server/visibility/interface.d.ts +46 -0
- package/lib/server/workspace/impl/full-name/index.d.ts +24 -0
- package/lib/server/workspace/impl/root-resolution/index.d.ts +18 -0
- package/lib/server/workspace/impl/scope/index.d.ts +14 -0
- package/lib/server/workspace/impl/server-id/index.d.ts +17 -0
- package/lib/server/workspace/interface.d.ts +22 -0
- package/lib/shared/constants.d.ts +22 -0
- package/lib/shared/dto.d.ts +62 -0
- package/lib/shared/frames.d.ts +19 -0
- package/lib/shared/interface.d.ts +22 -0
- package/lib/shared/placement-math.d.ts +81 -0
- package/lib/shared/routes.d.ts +43 -0
- package/lib/shared/service.d.ts +85 -0
- package/lib/shared/status.d.ts +23 -0
- package/lib/vendor/shared/README.md +147 -0
- package/lib/vendor/shared/client/ensure-style.d.ts +23 -0
- package/lib/vendor/shared/client/i18n.d.ts +30 -0
- package/lib/vendor/shared/client/ui/index.d.ts +214 -0
- package/lib/vendor/shared/dsh-home.d.ts +26 -0
- package/lib/vendor/shared/host-utils.d.ts +82 -0
- package/lib/vendor/shared/loopback.d.ts +12 -0
- package/lib/vendor/shared/package.json +12 -0
- package/lib/vendor/shared/paths.d.ts +35 -0
- package/lib/vendor/shared/settings-namespace.d.ts +82 -0
- package/lib/vendor/shared/sse-hub.d.ts +75 -0
- package/lib/vendor/shared/upgrade-chain.d.ts +140 -0
- package/lib/vendor/shared/upgrade-tick.d.ts +17 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +170 -4
package/LICENSE
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MIT License (inherited from wingsky-1/dsh-plugin-hub)
|
package/README.en.md
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
# dsh-mcp-manager
|
|
2
|
+
[](https://www.npmjs.com/package/dsh-mcp-manager)
|
|
3
|
+
[](https://github.com/wingsky-1/dsh-plugin-hub/releases)
|
|
4
|
+
|
|
5
|
+
A **MCP server management plugin** for DSH (DeepSeek Harness): a floating window in the
|
|
6
|
+
top-right of the session UI + a tiered panel + quick onboarding (manual form + paste
|
|
7
|
+
`mcpServers` JSON import, **no servers preconfigured**). Connection and protocol come from
|
|
8
|
+
the official `@deepseek-ai/dsh-mcp-client` (mounted by name through the host cordis loader,
|
|
9
|
+
resolved to the copy inside the DSH installation); this plugin keeps only the configuration
|
|
10
|
+
surface and the model-visible surface. The official client is not redistributed with this
|
|
11
|
+
package, and nothing extra needs to be installed.
|
|
12
|
+
|
|
13
|
+
The model surface carries exactly four atomic tools (`ws_mcp_list` / `ws_mcp_detail` /
|
|
14
|
+
`ws_mcp_search` / `ws_mcp_call`): project-level, global and runtime-injected
|
|
15
|
+
wrapped-definition servers **all go through the middleware** (two-level discovery:
|
|
16
|
+
`ws_mcp_list` for a full inventory → `ws_mcp_detail` to pull the complete schema on
|
|
17
|
+
demand), falling back to the virtual global root `@global` when cwd has no project. The
|
|
18
|
+
host still registers tools as `mcp__<id>__<tool>` (`id` is an opaque short string
|
|
19
|
+
allocated per (workspace, server) for one plugin assembly and cannot be derived from the
|
|
20
|
+
server name), but those names are **removed from the model's tool list** — never call them
|
|
21
|
+
directly.
|
|
22
|
+
The server lists across both config tiers hot-reload without a restart
|
|
23
|
+
(add/remove/toggle/edit).
|
|
24
|
+
(The `middleware` / `middlewarePolicy` config keys were removed in #767 batch 2: writing
|
|
25
|
+
them has no effect, and this plugin never rewrites your config file.)
|
|
26
|
+
|
|
27
|
+
> **A historical session will not open after upgrading DSH to 0.1.5+**
|
|
28
|
+
> (`unclassified message source`)? See
|
|
29
|
+
> [Troubleshooting: a historical session will not open after upgrading (#723)](#723-repair),
|
|
30
|
+
> one command recovers it.
|
|
31
|
+
|
|
32
|
+
## Quick install
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
dsh plugin --profile web add dsh-mcp-manager
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
> After install / uninstall / update, **restart `dsh web` once** (bundle layers are only composed at startup) for changes to take effect.
|
|
39
|
+
|
|
40
|
+
## Core advantages
|
|
41
|
+
|
|
42
|
+
- **Context cost under control**: all MCP goes through the middleware — the model surface
|
|
43
|
+
carries only `ws_mcp_list` / `ws_mcp_detail` / `ws_mcp_search` / `ws_mcp_call`, so no
|
|
44
|
+
matter how many servers or tools you connect the system prompt never balloons
|
|
45
|
+
(two-level discovery: `ws_mcp_list` for a full inventory → `ws_mcp_detail` to pull the
|
|
46
|
+
complete schema on demand)
|
|
47
|
+
- **Per-working-directory maintenance**: project-level config `<project root>/.dsh/dsh-mcp-manager/mcp.json`
|
|
48
|
+
travels with the repo and can be committed to git for team sharing; global config
|
|
49
|
+
`<DSH_HOME>/dsh-mcp-manager/mcp.json` stays always connected; switching sessions auto-loads the
|
|
50
|
+
MCP set of the current directory
|
|
51
|
+
- **Workspace isolation**: the middleware routes by the session's cwd to the matching
|
|
52
|
+
connection pool, with server-full-name consistency checks against cross-workspace
|
|
53
|
+
crosstalk; same-named servers in different directories never clash
|
|
54
|
+
- **Secure by default**: configs store only `${ENV}` references, never key material
|
|
55
|
+
(0600 permissions + atomic writes); stdio subprocess environments are sanitized so
|
|
56
|
+
host credential-shaped variables never leak through; directory summaries and error
|
|
57
|
+
paths go through a redactor
|
|
58
|
+
- **Low-maintenance operations**: tiered status display (running / connecting / failed…);
|
|
59
|
+
bounded exponential-backoff auto-reconnect on disconnects; a per-server timeout override
|
|
60
|
+
(`toolCallTimeoutMs`), while a middleware call settles at the largest in-use server timeout
|
|
61
|
+
plus a 25s internal tail (15s + 25s = 40s by default)
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
Prerequisite: DeepSeek Harness installed and `dsh web` running normally (for running dsh
|
|
66
|
+
without a global install, see "Without a global dsh install" below).
|
|
67
|
+
|
|
68
|
+
### Install plugins (add)
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
dsh plugin --profile web add dsh-mcp-manager
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Uninstall plugins (remove)
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
dsh plugin --profile web remove dsh-mcp-manager
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Update plugins (update)
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
dsh plugin --profile web update dsh-mcp-manager
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> After install / uninstall / update, **restart `dsh web` once** (bundle layers are only
|
|
87
|
+
> composed at startup) for changes to take effect.
|
|
88
|
+
|
|
89
|
+
### Pin a version (@version)
|
|
90
|
+
|
|
91
|
+
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:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
dsh plugin --profile web add dsh-mcp-manager@<version>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Without a global dsh install
|
|
98
|
+
|
|
99
|
+
If there is no global `dsh` command on the machine, use `npx` to run it on the fly (`dsh plugin`
|
|
100
|
+
calls `pnpm` under the hood, so `pnpm` and `Node.js` must still be installed locally):
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
npx @deepseek-ai/dsh plugin --profile web add dsh-mcp-manager
|
|
104
|
+
npx @deepseek-ai/dsh plugin --profile web remove dsh-mcp-manager
|
|
105
|
+
npx @deepseek-ai/dsh plugin --profile web update dsh-mcp-manager
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Capabilities
|
|
109
|
+
|
|
110
|
+
| Capability | Description |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| Top-right floating window | Status dot + count summary (`MCP 2/3`); click to expand the dropdown panel; auto-refreshes on session switch |
|
|
113
|
+
| Project-level MCP | Servers are split into "project-level / global" tiers: project-level stored in `<project root>/.dsh/dsh-mcp-manager/mcp.json` (travels with the project, can be committed to git); global stored in `<DSH_HOME>/dsh-mcp-manager/mcp.json` for persistent connection |
|
|
114
|
+
| Tiered display | Running / Connecting / Reconnecting / Disconnected / Disabled / Failed; each server shows transport, endpoint, and tool count |
|
|
115
|
+
| Server management | CRUD (project-level/global optional), connect / disconnect / reconnect; versioned JSON config, atomic write |
|
|
116
|
+
| Two transports | stdio (local subprocess, env supports `${ENV}` references) and streamable-http (remote, header supports `${ENV}` references, auto-echoes `Mcp-Session-Id`) |
|
|
117
|
+
| JSON import | Paste `mcpServers` JSON text to import (JSON format only; does not scan any application config files) |
|
|
118
|
+
| 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 |
|
|
119
|
+
| 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 |
|
|
120
|
+
| Reconnection | Exponential backoff (starts at 500ms, caps at 30s, gives up after 10 attempts and deregisters the tools) |
|
|
121
|
+
| 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 |
|
|
122
|
+
| 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** |
|
|
123
|
+
| 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); when the page becomes visible again the client rebuilds SSE and POSTs resume for a non-forced availability recovery (carrying the current session cwd, the server pins the root for that call; old body-less requests fall back to the existing binding) — half-open connections silently severed by mobile OS backgrounding heal on their own instead of piling up as zombies. Auto recovery reuses the official management mechanism's existing state projection and in-flight dedup and never force-rebuilds healthy/connecting/reconnecting connections; it does **not** claim to detect real health (a healthy connection with tool registrations is indistinguishable from a half-open one in real time) — half-open connections still recover through explicit user reconnect |
|
|
124
|
+
|
|
125
|
+
## Configuration (floating window position)
|
|
126
|
+
|
|
127
|
+
Configuration page: **Plugin Manager → dsh-mcp-manager → Configure**. The floating button
|
|
128
|
+
(MCP pill) position and offsets (`position` / `offset`) are saved there through the plugin's
|
|
129
|
+
own `Config`; no config-file editing is needed.
|
|
130
|
+
|
|
131
|
+
> 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 from `127.0.0.1:3080` / `127.0.0.1:3081` or an SSH loopback tunnel. Enable dsh-lan-proxy `ownsHostCompat` only on a trusted LAN and only when you accept the shared control-plane risk.
|
|
132
|
+
|
|
133
|
+
| Key | Allowed values | Default |
|
|
134
|
+
| --- | --- | --- |
|
|
135
|
+
| `position` | `top-right` (top-right, default) / `top-left` (top-left) / `bottom-right` (bottom-right) / `bottom-left` (bottom-left) | `top-right` |
|
|
136
|
+
| `offset.x` | Non-negative integer (horizontal offset, px) | `8` |
|
|
137
|
+
| `offset.y` | Non-negative integer (vertical offset, px) | `8` |
|
|
138
|
+
| `offset.blankY` | Non-negative integer (blank-session vertical offset, px) | `40` |
|
|
139
|
+
| `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` |
|
|
140
|
+
|
|
141
|
+
#### Settings namespace
|
|
142
|
+
|
|
143
|
+
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.
|
|
144
|
+
|
|
145
|
+
When `position = bottom-right` or `bottom-left`, the dropdown panel expands **above the
|
|
146
|
+
pill** (bottom anchor, popping upward), does not overflow the viewport, and content stays
|
|
147
|
+
fully visible and clickable; at top anchors it expands downward (historical behavior,
|
|
148
|
+
unchanged default).
|
|
149
|
+
|
|
150
|
+
**Mobile / tablet adaptation** (issue #128): the breakpoint is decided from the
|
|
151
|
+
conversation container's viewport width rather than a window media query — on narrow
|
|
152
|
+
screens (<=480px, portrait phones / very narrow splits) the panel goes near full-width,
|
|
153
|
+
server cards reflow, and action buttons get touch targets of about 44px; the tablet tier
|
|
154
|
+
(<=834px) transitions; desktop is unchanged. Final floating coordinates are clamped to
|
|
155
|
+
the viewport in JS (safe-area semantics: the host has no `viewport-fit=cover`, so
|
|
156
|
+
`env(safe-area-inset-*)` is always 0 and this degrades naturally to a plain clamp);
|
|
157
|
+
the on-screen keyboard is followed via `visualViewport` resize, and orientation changes
|
|
158
|
+
recompute on the next frame.
|
|
159
|
+
|
|
160
|
+
**Cross-package avoidance contract (from issue #116, must not be reverted)**: this
|
|
161
|
+
plugin's pill defaults to `top-right` at 8px from the top and ~26px tall;
|
|
162
|
+
dsh-provider-usage's usage capsule relies on that default position with `offsetY: 48`
|
|
163
|
+
to sit right below it (no overlap by default). Changing this plugin's default anchor /
|
|
164
|
+
vertical offsets breaks that avoidance — treat it as a cross-package behavioral contract
|
|
165
|
+
and adjust provider-usage defaults in lockstep before reverting.
|
|
166
|
+
|
|
167
|
+
Saving in the settings page takes effect immediately, **without restarting dsh web** and
|
|
168
|
+
without manually refreshing the page: the host pushes a frame over the existing SSE events
|
|
169
|
+
channel, and the client automatically re-fetches `/api/dsh-mcp/config` and updates the
|
|
170
|
+
floating position in place.
|
|
171
|
+
|
|
172
|
+
## Configuration (middleware)
|
|
173
|
+
|
|
174
|
+
All MCP goes through the middleware (single pool, **no mode switch**): no server exposes a
|
|
175
|
+
model-visible `mcp__` direct-call tool; the model surface carries four atomic tools
|
|
176
|
+
(two-level discovery, the standard MCP ecosystem shape) —
|
|
177
|
+
`ws_mcp_list` (full inventory of the current workspace's servers and each server's
|
|
178
|
+
complete tool list, not truncated by `ws_mcp_search`'s `limit`; supports `server`
|
|
179
|
+
full-name/bare-name filtering; `perServerLimit` caps tools per server at 50 by default
|
|
180
|
+
/ 500 max, setting `toolsTruncated` when exceeded; empty results carry an explicit
|
|
181
|
+
`message`, and when a `server` filter matches nothing the message attributes the miss to
|
|
182
|
+
the filter and lists the visible project-level servers) / `ws_mcp_detail` (exact single-tool lookup by `@<root>/<server>` + bare tool
|
|
183
|
+
name, returning the complete `inputSchema`; three-way errors: discovery failed with
|
|
184
|
+
reason / server not connected or not found / tool does not exist) / `ws_mcp_search` (keyword search, search first then call; returns a `truncated` flag
|
|
185
|
+
when results hit the `limit`) / `ws_mcp_call` (invoke by `@<root>/<server>`, verify
|
|
186
|
+
argument schema with `ws_mcp_detail`), routed by the calling session's current cwd to
|
|
187
|
+
the matching workspace connection pool, so different workspaces inject different MCPs
|
|
188
|
+
without name clashes, and falling back to the virtual global root `@global` when cwd has no
|
|
189
|
+
project — list/search/detail always merge queries across the "project root unit +
|
|
190
|
+
`@global` unit", and call allows the `@global` root (global config is shared across
|
|
191
|
+
workspaces, so the semantics hold). The host registration name looks like
|
|
192
|
+
`mcp__<id>__<tool>` with an opaque `id` (read it from the tool list); it is internal only
|
|
193
|
+
(the model's tool list never shows it), and a wrapped definition entry
|
|
194
|
+
(`toolDefinitions`) is reached only through `ws_mcp_call` at `@<root>/<server>`.
|
|
195
|
+
Note: global server add/remove/edit refreshes the `@global` unit only after a restart or a
|
|
196
|
+
session touch (existing behavior).
|
|
197
|
+
|
|
198
|
+
### Top-level config keys (Config schema)
|
|
199
|
+
|
|
200
|
+
Top-level keys of `Config` (`packages/dsh-mcp-manager/src/server/config/config-schema.ts`) with defaults and semantics:
|
|
201
|
+
|
|
202
|
+
| Key | Default | Semantics |
|
|
203
|
+
| --- | --- | --- |
|
|
204
|
+
| `enabled` | `true` | Whether the plugin is enabled (plugin-level master switch). |
|
|
205
|
+
| `announceToAgent` | `true` | Whether to announce the plugin to the Agent (capability list carried by `<available_mcp_servers>`). |
|
|
206
|
+
| `storePath` | empty (defaults to `<DSH_HOME>/dsh-mcp-manager/mcp.json`) | Global server config path; empty uses the default path. |
|
|
207
|
+
| `announceCatalog` | `true` | Whether to inject the MCP capability catalog (`<available_mcp_servers>`). |
|
|
208
|
+
| `catalogMaxEntries` | `6` | Cap on catalog injection entries. |
|
|
209
|
+
| `debug.callStats` | `false` | Whether to enable call-stats debugging and persistence (off by default, config-file only; see "Call stats and debug mode" below). |
|
|
210
|
+
| `debug.statsFile` | empty (defaults to `<DSH_HOME>/dsh-mcp-manager/stats.json`) | Stats persistence path; empty uses the default path. |
|
|
211
|
+
| `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)". |
|
|
212
|
+
|
|
213
|
+
**Removed config keys** (#767 batch 2): `middleware` (`off` / `project` / `all`) and
|
|
214
|
+
`middlewarePolicy` (`allowTools` / `denyTools`). The settings-page mode dropdown is gone;
|
|
215
|
+
writing either key **neither errors nor takes effect** (the keys are passed through with no
|
|
216
|
+
consumer), and this plugin never rewrites your config file. Per-tool disable is the only
|
|
217
|
+
admission gate.
|
|
218
|
+
|
|
219
|
+
**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).
|
|
220
|
+
|
|
221
|
+
### Per-tool disable (floating window)
|
|
222
|
+
|
|
223
|
+
- Expanding the "Tools (N)" details of a server card shows a **checkbox list**; toggling
|
|
224
|
+
each tool persists via `PATCH /api/dsh-mcp/tool-disable` (stored under
|
|
225
|
+
`<DSH_HOME>/dsh-mcp-manager/user-state.json` → `disabledTools`, merged write, survives restarts);
|
|
226
|
+
- Semantics: **both project-level and global servers' tools can be disabled** (after the
|
|
227
|
+
single-pool change both go through the middleware; global records are keyed by `@global`
|
|
228
|
+
and shared across workspaces); everything is enabled by default;
|
|
229
|
+
- Per-tool disable is **independent of the server-level `enabled` switch** (re-enabling a
|
|
230
|
+
server does not clear its tool-level state);
|
|
231
|
+
- It **applies to all mcp-manager-managed MCP tools** (`mcp__`-prefixed direct calls and
|
|
232
|
+
middleware `ws_mcp_*` calls consistently; runtime wrapped tools are covered too);
|
|
233
|
+
plugins' own declared discipline bare-name tools are not affected;
|
|
234
|
+
- Overlong tool names (>64 chars, hashed suffix) are irreversible → treated as unknown
|
|
235
|
+
server, neither disabled nor mistakenly denied;
|
|
236
|
+
- **Both** the "project-level" and "global" groups in the floating window render tool
|
|
237
|
+
switches (after the single-pool change both groups go through the middleware, so a global
|
|
238
|
+
switch takes effect just the same);
|
|
239
|
+
- Both the floating window and the management panel group servers by
|
|
240
|
+
"project-level / global" (each group further ordered by connection status).
|
|
241
|
+
|
|
242
|
+
## Routes (all loopback-fenced)
|
|
243
|
+
|
|
244
|
+
| Route | Description |
|
|
245
|
+
| --- | --- |
|
|
246
|
+
| `/api/dsh-mcp/health` | Health check (note: differs from the directory name) |
|
|
247
|
+
| `/api/dsh-mcp/tool-disable` | Per-tool disable toggle (PATCH, loopback-only) |
|
|
248
|
+
| `/api/dsh-mcp/*` | Server management / connection control / tool listing / SSE events, etc. |
|
|
249
|
+
|
|
250
|
+
## Runtime registration (registerServer.toolDefinitions)
|
|
251
|
+
|
|
252
|
+
Other plugins can register MCP servers at runtime via `ctx.mcpManager.registerServer`
|
|
253
|
+
(in-memory only, not persisted; idempotent for same names). The registration input
|
|
254
|
+
supports an optional `toolDefinitions` field (caller-provided wrapped tool definitions,
|
|
255
|
+
`ToolDefinition[]`; tool names are **bare names**):
|
|
256
|
+
|
|
257
|
+
- **With `toolDefinitions`**: all tools of that server are registered **from the wrapped
|
|
258
|
+
definitions** — `execute` comes from the caller (which may preprocess first and then
|
|
259
|
+
forward to the underlying command internally), skipping the
|
|
260
|
+
remote schema projection and the generic `callTool`; the underlying real implementation
|
|
261
|
+
is never exposed;
|
|
262
|
+
- **Without**: current behavior is preserved (remote schema + generic `callTool`), zero
|
|
263
|
+
impact on other servers;
|
|
264
|
+
- **Direct calls are denied by this package's own pre-execute guard, not by convention (#1014)**: `mcp__<id>__<tool>` is
|
|
265
|
+
an internal registration name; the pre-execute guard **denies by default** every `mcp__`
|
|
266
|
+
direct call that is not this package's own forwarding — it no longer relies on the model
|
|
267
|
+
obeying a prompt, nor on declaration-surface masking (which necessarily leaks during connection
|
|
268
|
+
flips). The single allow-path is the host-issued **in-flight** token: the sub-call of
|
|
269
|
+
`ws_mcp_call` → dispatch → `ctx.tools.execute` is admitted by its `parent`, deregistered when
|
|
270
|
+
it settles, and replaying the same token is denied. The denial text points at `ws_mcp_call`
|
|
271
|
+
and says not to retry the same call.
|
|
272
|
+
- **No model-visible `mcp__` direct-call tool: calls only go through `ws_mcp_call` with bare
|
|
273
|
+
names** (`@<root>/<server>` + bare name; a wrapped `execute` is caller JS, so there is
|
|
274
|
+
no remote implementation to call directly). The call name is still derived via
|
|
275
|
+
`publicToolName` (64-char / hash-suffix rules unchanged), but only as the name the
|
|
276
|
+
middleware forwards when calling;
|
|
277
|
+
- **Per-tool disable / visibility / capability catalog still apply to wrapped tools**
|
|
278
|
+
(judged by server + tool name, same as `mcp__`-prefixed tools);
|
|
279
|
+
- Consumed only by the runtime registration surface (runtimeRegistry) — never persisted
|
|
280
|
+
to the store, never passed through mcpServers imports.
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
await ctx.mcpManager.registerServer({
|
|
284
|
+
name: "my-mcp",
|
|
285
|
+
transport: "stdio",
|
|
286
|
+
command: "my-mcp-server",
|
|
287
|
+
args: ["serve", "--mcp"],
|
|
288
|
+
toolDefinitions: [
|
|
289
|
+
{
|
|
290
|
+
name: "my_tool", // bare name
|
|
291
|
+
description: "Caller-provided wrapped tool",
|
|
292
|
+
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
|
|
293
|
+
output: { schema: { ... }, render(args, value) { ... } },
|
|
294
|
+
execute: async (args) => { await prepare(); return forwarded; }, // internal forwarding, never exposed
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Data and Security
|
|
301
|
+
|
|
302
|
+
- Server config: `<DSH_HOME>/dsh-mcp-manager/mcp.json` (stores only `${ENV}` references, **never the
|
|
303
|
+
secrets themselves**); on-disk 0600 permissions + same-directory temporary-file atomic replacement.
|
|
304
|
+
On Windows, `EPERM` / `EBUSY` replacement errors receive bounded asynchronous retries; an external
|
|
305
|
+
change detected during the wait aborts the save and preserves the external contents.
|
|
306
|
+
- All `/api/dsh-mcp/*` routes are restricted to loopback access (non-loopback → 403 / wrong
|
|
307
|
+
method → 405)
|
|
308
|
+
- **stdio subprocess environment sanitization (official dsh-mcp-client semantics)**: sanitization
|
|
309
|
+
applies to the **inherited parent environment** only — credential-shaped names (`KEY` /
|
|
310
|
+
`PASSWORD` / `SECRET` / `TOKEN`) and every `DSH_*` variable are stripped from the parent
|
|
311
|
+
environment so host secrets never leak into the MCP subprocess implicitly; **an `env` entry you
|
|
312
|
+
declare explicitly is passed to the child verbatim** (explicit layers merge after the scrub), so
|
|
313
|
+
`env` is not a redaction boundary — do not put credentials there if you want them isolated
|
|
314
|
+
- **stdio subprocess inherits host privileges**: MCP server commands run under the host
|
|
315
|
+
process's permissions; only configure trusted servers. Trust boundary: in-process plugin
|
|
316
|
+
injection (`ctx.mcpManager.registerServer`) shares this plugin's privileges and is not a
|
|
317
|
+
privilege escalation; **the project-level `mcp.json` that ships inside a repository is the
|
|
318
|
+
side you should scrutinize**
|
|
319
|
+
- **Stats carry metadata only**: debug stats (`debug.callStats`) record call counts / durations /
|
|
320
|
+
outcomes plus the progressive-disclosure funnel; **search terms are persisted only as SHA-256
|
|
321
|
+
hash buckets** (`h:<12 hex>`, empty queries as `<empty>`), and plaintext keys written by older
|
|
322
|
+
versions are dropped on read (the drop happens **at read time**; the next flush stops writing them
|
|
323
|
+
back — until then an inactive stats file still holds them). Hashing is **pseudonymization, not
|
|
324
|
+
anonymization**: search terms have low entropy and remain dictionary-attackable. The funnel's
|
|
325
|
+
other two dimensions are still plaintext: the `ws_mcp_list` server filter and the
|
|
326
|
+
`ws_mcp_detail` server/tool — those are server and tool names, already part of the config and
|
|
327
|
+
catalog surfaces, not free text
|
|
328
|
+
- **MCP tools execute on the real server — confirm before acting**; tool results are returned
|
|
329
|
+
as-is and may contain sensitive information; treat tool descriptions/results as untrusted input
|
|
330
|
+
- **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
|
|
331
|
+
- **Middleware tool read-only boundary**: `ws_mcp_list` / `ws_mcp_detail` / `ws_mcp_search`
|
|
332
|
+
only read the local catalog cache (never touch remote servers or execute tools);
|
|
333
|
+
`ws_mcp_call` is the only entry point that executes remote tools, and it is governed by the
|
|
334
|
+
per-tool disable table; `ws_mcp_call` error messages follow an
|
|
335
|
+
"explicit + next step" style (confirm the server connection / verify the argument schema
|
|
336
|
+
with `ws_mcp_detail` / check the per-tool disable state)
|
|
337
|
+
- **Per-tool disable (three entry points consistent)**: `ws_mcp_call` (callTool checks the
|
|
338
|
+
disable table), the pre-execute guard (`mcp__`-prefixed direct calls),
|
|
339
|
+
and plugins' own declared discipline bare-name tools all go through the single
|
|
340
|
+
`isToolDenied` decision; disabling only affects `mcp__`-prefixed tools, and the denial
|
|
341
|
+
reason carries that semantic note; records live under `<DSH_HOME>/dsh-mcp-manager/user-state.json`
|
|
342
|
+
→ `disabledTools` (the `@global` key is shared across workspaces; merged writes never
|
|
343
|
+
overwrite the whole table)
|
|
344
|
+
- **Call stats and debug mode (Metadata-Only)**: Disabled by default; when configured with `dsh-mcp-manager.debug.callStats: true` in `~/.dsh/settings.yaml`, tool call metrics (call count, success/error, average/max duration) and progressive disclosure funnel stats (`ws_mcp_search` query frequencies, `ws_mcp_list` / `ws_mcp_detail` query distributions) are debounced and atomically written to `<DSH_HOME>/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
|
|
345
|
+
- The capability catalog injection includes source annotations and a "does not represent current
|
|
346
|
+
connection status" note
|
|
347
|
+
- **Message-source shape of the catalog injection**: `source` uses the host-registered generic
|
|
348
|
+
shape `{ kind: "plugin", plugin: "dsh-mcp-manager", form: "snapshot",
|
|
349
|
+
sections: [{ name: "mcp-catalog", text }] }`. A self-invented `source.kind` is refused by
|
|
350
|
+
DSH's session-format v2-to-v3 migration gate (closed whitelist), which makes every session
|
|
351
|
+
persisted before the upgrade unloadable — see the next section
|
|
352
|
+
|
|
353
|
+
<a id="723-repair"></a>
|
|
354
|
+
## Troubleshooting: a historical session will not open after upgrading (#723)
|
|
355
|
+
|
|
356
|
+
**Symptom**: after upgrading DSH to 0.1.5 or later, a historical session reports in the GUI:
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
历史加载失败:failed to observe session "session-…":
|
|
360
|
+
cannot safely transform unclassified message source;
|
|
361
|
+
source v0 artifact remains unchanged (raw log: …/session.jsonl.zstd)(gateway/internal)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
and `session.v3.jsonl.zstd` never appears next to the original log. Cause: 0.2.x and earlier
|
|
365
|
+
wrote the catalog injection message as `source.kind = "mcp-catalog"`, which DSH's v2-to-v3
|
|
366
|
+
migration refuses against its closed `source.kind` whitelist for surface messages (the original
|
|
367
|
+
artifact is preserved by design). This version changes the write side to the generic
|
|
368
|
+
host-registered shape, **but artifacts already on disk need a one-time repair**.
|
|
369
|
+
|
|
370
|
+
**Repair (one-off, repeatable)**: the repository script rewrites the old source in place; it
|
|
371
|
+
touches only source metadata, never the body or the event sequence, so DSH still performs the
|
|
372
|
+
migration itself.
|
|
373
|
+
|
|
374
|
+
```sh
|
|
375
|
+
# 1) Dry run: list affected sessions and counts, change nothing
|
|
376
|
+
node scripts/maintenance/repair-mcp-catalog-sessions.mjs
|
|
377
|
+
|
|
378
|
+
# 2) Apply (a session.jsonl.zstd.bak-<timestamp> backup is created for every rewritten log)
|
|
379
|
+
node scripts/maintenance/repair-mcp-catalog-sessions.mjs --apply
|
|
380
|
+
|
|
381
|
+
# 3) Restart dsh web and open the session
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
- Stop `dsh web` first: a session log being written is not guaranteed safe to rewrite
|
|
385
|
+
- Reads `<DSH_HOME>` by default (`--home <dir>` or `DSH_HOME` overrides it); `--session <id>`
|
|
386
|
+
limits the run to one session
|
|
387
|
+
- Idempotent: repaired artifacts no longer match; every write is self-checked (frame structure,
|
|
388
|
+
per-line JSON, zero leftover legacy kinds)
|
|
389
|
+
- Rollback: overwrite `session.jsonl.zstd` with the matching `.bak-<timestamp>`
|
|
390
|
+
- **v3 artifacts are repaired by default too**: the v3 read path does not validate
|
|
391
|
+
`message.source`, so v3 sessions with the legacy kind load fine today — but a v3 session created
|
|
392
|
+
before the upgrade and written incrementally afterwards carries **both kinds**, and a future
|
|
393
|
+
v3-to-v4 migration with a similar gate would repeat this outage. The repair only swaps source
|
|
394
|
+
metadata, so v3 semantics are unchanged (verified with strict restore + `Session.fromRestore`)
|
|
395
|
+
- `--legacy-only` limits the run to v0/v1/v2; it never writes a v3 file (DSH performs the migration itself)
|
|
396
|
+
- A trailing torn frame (crash during write) is prefix-decoded with the host's recovery semantics; a truncated last line is dropped
|
|
397
|
+
|
|
398
|
+
## Verification
|
|
399
|
+
|
|
400
|
+
```sh
|
|
401
|
+
# Health check (loopback)
|
|
402
|
+
curl -s http://127.0.0.1:3080/api/dsh-mcp/health
|
|
403
|
+
|
|
404
|
+
# Source is in src/; must build after changes
|
|
405
|
+
pnpm --filter dsh-mcp-manager build
|
|
406
|
+
pnpm --filter dsh-mcp-manager test
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## Known Limitations
|
|
410
|
+
|
|
411
|
+
- **The `mcp__` registration name is internal only**: servers are mounted by the official
|
|
412
|
+
dsh-mcp-client, so the host registers tools as `mcp__<id>__<tool>`, where `id` is a
|
|
413
|
+
**random short string** allocated per (workspace, server) — stable within one plugin
|
|
414
|
+
assembly, opaque, and not derivable from the server name; it changes on plugin reload or
|
|
415
|
+
host restart. Those names are removed from the model's tool list, and the model reaches
|
|
416
|
+
them through `ws_mcp_call` — **never hardcode tool names** in scripts or prompts; always
|
|
417
|
+
resolve them through `ws_mcp_list` / `ws_mcp_detail`
|
|
418
|
+
- Does not subscribe to the MCP `tools/list_changed` notification (no long-lived SSE
|
|
419
|
+
connection); tool list changes are re-synced on reconnect / manual refresh
|
|
420
|
+
- The middleware catalog is a "last-good snapshot within collection bounds" (≤512 tools /
|
|
421
|
+
≤256KB total per server); on discovery failure `ws_mcp_list` surfaces the `unavailable`
|
|
422
|
+
reason
|
|
423
|
+
- Only bridges tool capabilities; MCP resources and prompts have no harness consumption
|
|
424
|
+
interface yet
|
|
425
|
+
- **With several tabs bound to different sessions, project-scoped MCP can follow only one**
|
|
426
|
+
(open item from issue #1028): the host keeps a single `projectRoot`, so tabs overwrite
|
|
427
|
+
each other, and the `rebindSession` on every foreground switch amplifies the overwrite.
|
|
428
|
+
This package does not arbitrate which tab wins.
|
|
429
|
+
- **An unresolvable current session keeps the existing binding instead of clearing it**
|
|
430
|
+
(#1028): before the official session snapshot is ready, or while the tab is not held by
|
|
431
|
+
the official `mainView`, the package treats the read as *unknown* and does **not** send
|
|
432
|
+
`cwd:""` — unknown is not "no project", and a wrong clear leaves the panel with global
|
|
433
|
+
entries only and makes project-scoped imports fail with
|
|
434
|
+
`no active project session`. Warning criterion: a first-frame unknown is the race
|
|
435
|
+
where the official snapshot is not ready yet (it happens on every cold start) and stays
|
|
436
|
+
quiet; one console warning is emitted only when a previously resolved session becomes
|
|
437
|
+
unreadable, or when the session stays unreadable across consecutive frames — so a normal
|
|
438
|
+
cold start and a real failure do not show the same yellow warning.
|
|
439
|
+
- **Foreground auto recovery is non-forced (#1120), not an explicit user reconnect**:
|
|
440
|
+
it reuses the official management mechanism's existing state projection and per-root/server
|
|
441
|
+
in-flight dedup instead of disposing/restarting on every visibilitychange;
|
|
442
|
+
connected/connecting/reconnecting connections keep their generation and official backoff,
|
|
443
|
+
missing entries and real failures recover through the normal path, and userDisabled entries
|
|
444
|
+
are never revived. The official mount layer only exposes ready/disposed/tool-registration
|
|
445
|
+
faces, so **a healthy connection with tool registrations is indistinguishable from a
|
|
446
|
+
half-open one in real time** — auto recovery makes no real-health claim and sends no
|
|
447
|
+
home-grown ping; half-open connections still recover through explicit user reconnect.
|
|
448
|
+
Resume carries the current session cwd, and the server resolves and pins the root within
|
|
449
|
+
that call (old body-less requests fall back to the existing binding; a new request that
|
|
450
|
+
explicitly has no workspace, i.e. `cwd:""`, pins `@global` instead of falling back to
|
|
451
|
+
someone else's projectRoot); the client recovery throttle covers resume keyed by cwd, so
|
|
452
|
+
recoveries for different cwds never swallow each other.
|
|
453
|
+
- Requires Node ≥ 20
|
|
454
|
+
|
|
455
|
+
## Type dependencies
|
|
456
|
+
|
|
457
|
+
Host-side and client-side types both come from the official `@deepseek-ai/*` packages
|
|
458
|
+
(`cordis`, `dsh-host-webserver`, `dsh-agent`, `dsh-tools`, `dsh-system-prompt`,
|
|
459
|
+
`dsh-llm`, `dsh-client-ui-slots`, `dsh-api-session-controller`,
|
|
460
|
+
`dsh-client-ui-session`; versions are pinned in the repository's `pnpm-workspace.yaml`
|
|
461
|
+
catalog and upgraded with DSH releases): **`import type` only, compile-time usage** —
|
|
462
|
+
build artifacts contain zero official runtime imports. The package declares this host
|
|
463
|
+
coupling as optional peerDependencies; consumers running type checks against the plugin
|
|
464
|
+
must be able to resolve these official packages (skipping type checking is unaffected).
|
|
465
|
+
|
|
466
|
+
The client's "current session" read goes through the single seam
|
|
467
|
+
`src/client/core/current-session.ts`, using the official criterion
|
|
468
|
+
`retainedBy.mainView > 0` and anchored to the official `SessionListState` /
|
|
469
|
+
`SessionSummary` types (**no self-declared mirror types**): since DSH 0.1.7-rc.2 the
|
|
470
|
+
session list snapshot no longer has a `current` field and the official `ISessions`
|
|
471
|
+
exposes no current-session accessor, so the package stopped hand-rolling a
|
|
472
|
+
`{current, byId}` shape.
|
|
473
|
+
|
|
474
|
+
## License
|
|
475
|
+
|
|
476
|
+
MIT
|
|
477
|
+
|
|
478
|
+
### Session loading and workspace switches
|
|
479
|
+
|
|
480
|
+
After application startup, global MCPs and projects in the official workspace registry are prepared in the background. Configuration saves and source-file changes refresh affected connections. Switching sessions reads a workspace snapshot without waiting for connection, discovery, or retry; newly added workspaces are prepared once in the background.
|
|
481
|
+
|
|
482
|
+
Global connections are shared, while enable switches persist per workspace and apply to the UI, catalog injection, discovery, and execution. Late responses from a previous workspace cannot replace the current workspace snapshot.
|