@railgun52/dsh-mcp-servers 0.1.0

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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +64 -0
  3. package/README.zh.md +64 -0
  4. package/cordis.patch.yml +3 -0
  5. package/icon.svg +5 -0
  6. package/lib/client.js +357 -0
  7. package/lib/client.js.map +1 -0
  8. package/lib/index.js +150 -0
  9. package/lib/invariant.js +8 -0
  10. package/lib/types/client/McpSection.d.ts +9 -0
  11. package/lib/types/client/McpSection.d.ts.map +1 -0
  12. package/lib/types/client/McpSection.js +140 -0
  13. package/lib/types/client/McpSection.js.map +1 -0
  14. package/lib/types/client/index.d.ts +10 -0
  15. package/lib/types/client/index.d.ts.map +1 -0
  16. package/lib/types/client/index.js +21 -0
  17. package/lib/types/client/index.js.map +1 -0
  18. package/lib/types/client/locales.d.ts +22 -0
  19. package/lib/types/client/locales.d.ts.map +1 -0
  20. package/lib/types/client/locales.js +35 -0
  21. package/lib/types/client/locales.js.map +1 -0
  22. package/lib/types/index.d.ts +59 -0
  23. package/lib/types/index.d.ts.map +1 -0
  24. package/lib/types/index.js +36 -0
  25. package/lib/types/index.js.map +1 -0
  26. package/lib/types/invariant.d.ts +5 -0
  27. package/lib/types/invariant.d.ts.map +1 -0
  28. package/lib/types/invariant.js +6 -0
  29. package/lib/types/invariant.js.map +1 -0
  30. package/lib/types/mcp-bridge.d.ts +20 -0
  31. package/lib/types/mcp-bridge.d.ts.map +1 -0
  32. package/lib/types/mcp-bridge.js +100 -0
  33. package/lib/types/mcp-bridge.js.map +1 -0
  34. package/lib/types/mcp-servers-schema.d.ts +66 -0
  35. package/lib/types/mcp-servers-schema.d.ts.map +1 -0
  36. package/lib/types/mcp-servers-schema.js +22 -0
  37. package/lib/types/mcp-servers-schema.js.map +1 -0
  38. package/package.json +96 -0
  39. package/src/client/McpSection.module.css +143 -0
  40. package/src/client/McpSection.tsx +248 -0
  41. package/src/client/index.ts +38 -0
  42. package/src/client/locales.ts +35 -0
  43. package/src/css-modules.d.ts +4 -0
  44. package/src/index.ts +45 -0
  45. package/src/invariant.ts +8 -0
  46. package/src/mcp-bridge.ts +111 -0
  47. package/src/mcp-servers-schema.ts +45 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 railgun52
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # dsh-mcp-servers — MCP servers settings page
2
+
3
+ English | [中文](README.zh.md)
4
+
5
+ > A profile-config settings page for DeepSeek Harness that lets you manage MCP servers from the Web UI and mounts live `mcp-client` instances from the saved list.
6
+
7
+ Each server you add becomes a running MCP client whose tools are registered on the agent tool registry, so the model can call them the moment you save — no restart, no hand-edited YAML. The page is a JSON editor over the `mcp-servers` profile-config namespace; the Host half owns the schema and the live bridge, the browser half owns the editor card.
8
+
9
+ ## Features
10
+
11
+ | Feature | Description |
12
+ |---|---|
13
+ | Settings page | A first-level Settings section `MCP 服务器` with an add/edit/remove card list |
14
+ | JSON editor | Edit the whole `servers` array in one textarea; add a server with one click |
15
+ | Live bridge | The Host mounts one `mcp-client` instance per enabled server and re-syncs on every settings edit (`loader/volatile-update`) without remounting the plugin |
16
+ | stdio + streamable-http | Each server carries `name`, `command`, `args`, `env`, `transport`, `url`, `enabled` |
17
+ | Profile-config backed | Values persist to the active profile's plugin config; the page reads/writes through the shared `configForms` namespace |
18
+
19
+ ## Architecture
20
+
21
+ ```text
22
+ dsh-mcp-servers/
23
+ |-- src/
24
+ | |-- index.ts # host half: Config schema (volatile servers) + mcp-client bridge
25
+ | |-- mcp-servers-schema.ts # McpServersSchema + McpServerConfig
26
+ | |-- mcp-bridge.ts # applyMcpBridge: create/dispose mcp-client instances from the live value
27
+ | |-- invariant.ts
28
+ | `-- client/
29
+ | |-- index.ts # browser half: configForms.whileServed + settings.section card
30
+ | |-- McpSection.tsx # JSON editor card (load/save through configForms)
31
+ | |-- McpSection.module.css
32
+ | `-- locales.ts # zh/en nav + page copy
33
+ `-- cordis.patch.yml # bundle patch: inserts the mcp-servers plugin row
34
+ ```
35
+
36
+ - **Namespace**: `mcp-servers`. The owning profile entry id must equal this string; the plugin's Config schema IS the namespace under the profile-config settings model.
37
+ - **Live edits**: `servers` is declared `.volatile()`, so the settings model exposes the namespace and edits do not remount the plugin. The Host reads the live value through `Volatile.get()` and re-syncs the bridge on `loader/volatile-update`.
38
+ - **Browser bundle**: rides the `window.__ModuleLoader__.load` contract; React and `@deepseek-ai/dsh-client-ui-primitives` resolve from the loader's module table (external); CSS Modules are inlined by lightningcss as `<style data-plugin>`.
39
+
40
+ ## Install
41
+
42
+ ```sh
43
+ ### From a local directory (development)
44
+ dsh plugin --profile web add link:/absolute/path/to/dsh-mcp-servers
45
+
46
+ ### From npm (once published)
47
+ dsh plugin --profile web add @railgun52/dsh-mcp-servers@latest
48
+ ```
49
+
50
+ After installing, **restart `dsh web`**. Open Settings → MCP 服务器 to manage servers. In link mode, run `pnpm build` and refresh the page after a code change; no reinstall needed.
51
+
52
+ ## Development
53
+
54
+ ```sh
55
+ pnpm install
56
+ pnpm build # tsc -b (types+declarations) && tsdown (node half + browser bundle)
57
+ pnpm typecheck # type check only
58
+ ```
59
+
60
+ The browser bundle is produced with the harness `clientBundle` helper; building from a fresh clone requires the DeepSeek Harness repository available (the `tsdown.config.ts` imports its `clientBundle`). The shipped `lib/` is pre-built, so consumers never build.
61
+
62
+ ## License
63
+
64
+ [MIT](LICENSE)
package/README.zh.md ADDED
@@ -0,0 +1,64 @@
1
+ # dsh-mcp-servers — MCP 服务器设置页
2
+
3
+ [English](README.md) | 中文
4
+
5
+ > DeepSeek Harness 的 profile-config 设置页,在 Web UI 里管理 MCP 服务器,并把保存的服务器列表挂成实时运行的 `mcp-client` 实例。
6
+
7
+ 你添加的每个服务器都会成为一个运行中的 MCP 客户端,其工具会注册到智能体工具表上——保存即生效,模型马上能调用,无需重启、无需手改 YAML。页面是对 `mcp-servers` profile-config 命名空间的 JSON 编辑器;Host 端负责 schema 与实时桥,浏览器端负责编辑卡片。
8
+
9
+ ## 功能
10
+
11
+ | 功能 | 说明 |
12
+ |---|---|
13
+ | 设置页 | 一级设置 section `MCP 服务器`,提供增/改/删卡片列表 |
14
+ | JSON 编辑器 | 用一个文本框编辑整段 `servers` 数组;一键添加服务器 |
15
+ | 实时桥 | Host 为每个启用的服务器挂一个 `mcp-client` 实例,并在每次设置改动时(`loader/volatile-update`)重同步,不重载插件 |
16
+ | stdio + streamable-http | 每个服务器含 `name`、`command`、`args`、`env`、`transport`、`url`、`enabled` |
17
+ | profile-config 存储 | 值持久化到当前 profile 的插件配置;页面通过共享 `configForms` 命名空间读写 |
18
+
19
+ ## 架构
20
+
21
+ ```text
22
+ dsh-mcp-servers/
23
+ |-- src/
24
+ | |-- index.ts # host 端:Config schema(volatile servers)+ mcp-client 桥
25
+ | |-- mcp-servers-schema.ts # McpServersSchema + McpServerConfig
26
+ | |-- mcp-bridge.ts # applyMcpBridge:按实时值创建/销毁 mcp-client 实例
27
+ | |-- invariant.ts
28
+ | `-- client/
29
+ | |-- index.ts # 浏览器端:configForms.whileServed + settings.section 卡片
30
+ | |-- McpSection.tsx # JSON 编辑卡片(经 configForms load/save)
31
+ | |-- McpSection.module.css
32
+ | `-- locales.ts # zh/en 导航与页面文案
33
+ `-- cordis.patch.yml # bundle patch:插入 mcp-servers 插件行
34
+ ```
35
+
36
+ - **命名空间**:`mcp-servers`。所属 profile 条目 id 必须等于该字符串;在 profile-config 设置模型下,插件的 Config schema 即命名空间。
37
+ - **实时编辑**:`servers` 声明为 `.volatile()`,设置模型据此暴露命名空间,且编辑不重载插件;Host 通过 `Volatile.get()` 读实时值,并在 `loader/volatile-update` 时重同步桥。
38
+ - **浏览器 bundle**:走 `window.__ModuleLoader__.load` 契约;React 与 `@deepseek-ai/dsh-client-ui-primitives` 从加载器模块表解析(external);CSS Modules 由 lightningcss 内联为 `<style data-plugin>`。
39
+
40
+ ## 安装
41
+
42
+ ```sh
43
+ ### 从本地目录(开发)
44
+ dsh plugin --profile web add link:/absolute/path/to/dsh-mcp-servers
45
+
46
+ ### 从 npm(发布后)
47
+ dsh plugin --profile web add @railgun52/dsh-mcp-servers@latest
48
+ ```
49
+
50
+ 安装后**重启 `dsh web`**。打开 设置 → MCP 服务器 管理服务器。link 模式下改代码后跑 `pnpm build` 再刷新页面即可,无需重新安装。
51
+
52
+ ## 开发
53
+
54
+ ```sh
55
+ pnpm install
56
+ pnpm build # tsc -b(类型+声明)&& tsdown(node 半 + 浏览器 bundle)
57
+ pnpm typecheck # 仅类型检查
58
+ ```
59
+
60
+ 浏览器 bundle 用 harness 的 `clientBundle` helper 产出;从全新克隆构建需要 DeepSeek Harness 仓库在场(`tsdown.config.ts` 引入其 `clientBundle`)。发布的 `lib/` 已预构建,使用者无需构建。
61
+
62
+ ## 许可证
63
+
64
+ [MIT](LICENSE)
@@ -0,0 +1,3 @@
1
+ - insert:
2
+ - id: mcp-servers
3
+ name: '@railgun52/dsh-mcp-servers'
package/icon.svg ADDED
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" fill="none">
2
+ <rect width="64" height="64" rx="14" fill="#0EA5E9"/>
3
+ <path d="M26 14h12v8a8 8 0 0 1-3 6.2V34h6a4 4 0 0 1 4 4v12H19V38a4 4 0 0 1 4-4h6v-5.8A8 8 0 0 1 26 22v-8z" fill="#fff"/>
4
+ <rect x="24" y="44" width="16" height="4" rx="2" fill="#0EA5E9"/>
5
+ </svg>
package/lib/client.js ADDED
@@ -0,0 +1,357 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@railgun52/dsh-mcp-servers",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react = require("react");
8
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
+ //#region \0dsh-css:G:\DSH2026\deepseek-harness-master\packages\client\ui-settings-mcp\src\client\McpSection.module.css.mjs
11
+ const css = ".gZZtfG_section{max-width:800px;padding:24px}.gZZtfG_header{margin-bottom:24px}.gZZtfG_title{margin:0 0 8px;font-size:20px;font-weight:600}.gZZtfG_intro{color:var(--text-secondary);margin:0;font-size:14px}.gZZtfG_toolbar{margin-bottom:16px}.gZZtfG_list{flex-direction:column;gap:8px;display:flex}.gZZtfG_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;justify-content:space-between;align-items:center;padding:12px 16px;transition:box-shadow .15s;display:flex}.gZZtfG_card:hover{box-shadow:0 1px 4px #0000000f}.gZZtfG_cardBody{flex:1;min-width:0}.gZZtfG_cardName{align-items:center;gap:8px;font-weight:500;display:flex}.gZZtfG_cardMeta{color:var(--text-secondary);text-overflow:ellipsis;white-space:nowrap;margin-top:4px;font-size:12px;overflow:hidden}.gZZtfG_cardMeta code{font-size:12px}.gZZtfG_cardActions{flex-shrink:0;align-items:center;gap:4px;display:flex}.gZZtfG_statusOn{background:#22c55e;border-radius:50%;width:8px;height:8px;display:inline-block}.gZZtfG_statusOff{background:#888;border-radius:50%;width:8px;height:8px;display:inline-block}.gZZtfG_deleteBtn{cursor:pointer;color:var(--text-secondary);background:0 0;border:none;border-radius:4px;align-items:center;padding:4px;display:flex}.gZZtfG_deleteBtn:hover{background:var(--bg-hover);color:var(--text-error)}.gZZtfG_empty{text-align:center;color:var(--text-secondary);padding:40px}.gZZtfG_error{background:var(--bg-error);color:var(--text-error);border-radius:6px;margin-bottom:16px;padding:8px 12px;font-size:13px}.gZZtfG_loading{text-align:center;color:var(--text-secondary);padding:40px}.gZZtfG_modalBody{padding:0}.gZZtfG_modalBody p{padding:0 16px}.gZZtfG_modalActions{justify-content:flex-end;gap:8px;padding:16px;display:flex}.gZZtfG_jsonEditor{resize:vertical;background:var(--bg-input);width:100%;color:var(--text-primary);box-sizing:border-box;border:none;outline:none;min-height:300px;padding:12px;font-family:monospace;font-size:13px;line-height:1.5}.gZZtfG_jsonEditor:focus{background:var(--bg-input-focus)}.gZZtfG_dialogMcp{width:min(720px,100%)}";
12
+ const tagId = "@railgun52/dsh-mcp-servers/McpSection.module.css";
13
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
14
+ const tag = document.createElement("style");
15
+ tag.dataset.plugin = "@railgun52/dsh-mcp-servers";
16
+ tag.dataset.pluginCss = tagId;
17
+ tag.textContent = css;
18
+ document.head.appendChild(tag);
19
+ }
20
+ var McpSection_module_css_default = {
21
+ "card": "gZZtfG_card",
22
+ "cardActions": "gZZtfG_cardActions",
23
+ "cardBody": "gZZtfG_cardBody",
24
+ "cardMeta": "gZZtfG_cardMeta",
25
+ "cardName": "gZZtfG_cardName",
26
+ "deleteBtn": "gZZtfG_deleteBtn",
27
+ "dialogMcp": "gZZtfG_dialogMcp",
28
+ "empty": "gZZtfG_empty",
29
+ "error": "gZZtfG_error",
30
+ "header": "gZZtfG_header",
31
+ "intro": "gZZtfG_intro",
32
+ "jsonEditor": "gZZtfG_jsonEditor",
33
+ "list": "gZZtfG_list",
34
+ "loading": "gZZtfG_loading",
35
+ "modalActions": "gZZtfG_modalActions",
36
+ "modalBody": "gZZtfG_modalBody",
37
+ "section": "gZZtfG_section",
38
+ "statusOff": "gZZtfG_statusOff",
39
+ "statusOn": "gZZtfG_statusOn",
40
+ "title": "gZZtfG_title",
41
+ "toolbar": "gZZtfG_toolbar"
42
+ };
43
+ //#endregion
44
+ //#region src/client/McpSection.tsx
45
+ function serversToJson(servers) {
46
+ const mcpServers = {};
47
+ for (const s of servers) {
48
+ const entry = { command: s.command };
49
+ if (s.args.length > 0) entry.args = s.args;
50
+ if (Object.keys(s.env).length > 0) entry.env = s.env;
51
+ if (s.transport === "streamable-http") entry.transport = "streamable-http";
52
+ if (s.url) entry.url = s.url;
53
+ mcpServers[s.name] = entry;
54
+ }
55
+ return JSON.stringify({ mcpServers }, null, 2);
56
+ }
57
+ function jsonToServers(text) {
58
+ const map = JSON.parse(text).mcpServers;
59
+ if (!map || typeof map !== "object") throw new Error("Missing \"mcpServers\" key");
60
+ return Object.entries(map).map(([name, config]) => {
61
+ const c = config;
62
+ const args = Array.isArray(c.args) ? c.args.map(String) : [];
63
+ const env = c.env && typeof c.env === "object" ? Object.fromEntries(Object.entries(c.env).map(([k, v]) => [k, String(v)])) : {};
64
+ return {
65
+ name,
66
+ command: String(c.command ?? ""),
67
+ args,
68
+ env,
69
+ transport: c.transport === "streamable-http" ? "streamable-http" : "stdio",
70
+ url: String(c.url ?? ""),
71
+ enabled: c.enabled !== false
72
+ };
73
+ });
74
+ }
75
+ const EMPTY_TEMPLATE = JSON.stringify({ mcpServers: { "my-server": {
76
+ command: "npx",
77
+ args: [
78
+ "-y",
79
+ "@modelcontextprotocol/server-filesystem",
80
+ "/path"
81
+ ]
82
+ } } }, null, 2);
83
+ function McpSection({ load, save, t: t_ }) {
84
+ const t = t_ ?? ((key) => key);
85
+ const [servers, setServers] = (0, react.useState)([]);
86
+ const [loading, setLoading] = (0, react.useState)(true);
87
+ const [saving, setSaving] = (0, react.useState)(false);
88
+ const [error, setError] = (0, react.useState)(null);
89
+ const [editJson, setEditJson] = (0, react.useState)("");
90
+ const [editIndex, setEditIndex] = (0, react.useState)(null);
91
+ const [showEditModal, setShowEditModal] = (0, react.useState)(false);
92
+ const [editError, setEditError] = (0, react.useState)(null);
93
+ const [deleteTarget, setDeleteTarget] = (0, react.useState)(null);
94
+ const loadConfig = (0, react.useCallback)(() => {
95
+ setLoading(true);
96
+ setError(null);
97
+ try {
98
+ setServers(load?.() ?? []);
99
+ } catch (e) {
100
+ setError(t("loadFailed"));
101
+ } finally {
102
+ setLoading(false);
103
+ }
104
+ }, [load, t]);
105
+ (0, react.useEffect)(() => {
106
+ loadConfig();
107
+ }, [loadConfig]);
108
+ const saveConfig = async (newServers) => {
109
+ setSaving(true);
110
+ setError(null);
111
+ try {
112
+ await save?.(newServers);
113
+ setServers(newServers);
114
+ } catch (e) {
115
+ setError(t("saveFailed"));
116
+ } finally {
117
+ setSaving(false);
118
+ }
119
+ };
120
+ const handleAdd = () => {
121
+ setEditJson(EMPTY_TEMPLATE);
122
+ setEditIndex(null);
123
+ setEditError(null);
124
+ setShowEditModal(true);
125
+ };
126
+ const handleEdit = (index) => {
127
+ const server = servers[index];
128
+ if (!server) return;
129
+ setEditJson(serversToJson([server]));
130
+ setEditIndex(index);
131
+ setEditError(null);
132
+ setShowEditModal(true);
133
+ };
134
+ const handleSaveJson = async () => {
135
+ try {
136
+ const parsed = jsonToServers(editJson);
137
+ if (parsed.length === 0) {
138
+ setEditError("No servers found in JSON");
139
+ return;
140
+ }
141
+ if (editIndex !== null) {
142
+ const newServers = [...servers];
143
+ newServers[editIndex] = parsed[0];
144
+ await saveConfig(newServers);
145
+ } else {
146
+ const merged = new Map(servers.map((s) => [s.name, s]));
147
+ for (const s of parsed) merged.set(s.name, s);
148
+ await saveConfig(Array.from(merged.values()).filter((s) => s !== void 0));
149
+ }
150
+ setShowEditModal(false);
151
+ } catch (e) {
152
+ setEditError(e instanceof Error ? e.message : String(e));
153
+ }
154
+ };
155
+ const handleDelete = async (index) => {
156
+ await saveConfig(servers.filter((_, i) => i !== index));
157
+ setDeleteTarget(null);
158
+ };
159
+ if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
160
+ className: McpSection_module_css_default.section,
161
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
162
+ className: McpSection_module_css_default.loading,
163
+ children: "Loading..."
164
+ })
165
+ });
166
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
167
+ className: McpSection_module_css_default.section,
168
+ children: [
169
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
170
+ className: McpSection_module_css_default.header,
171
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
172
+ className: McpSection_module_css_default.title,
173
+ children: t("title")
174
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
175
+ className: McpSection_module_css_default.intro,
176
+ children: t("intro")
177
+ })]
178
+ }),
179
+ error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
180
+ className: McpSection_module_css_default.error,
181
+ children: error
182
+ }),
183
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
184
+ className: McpSection_module_css_default.toolbar,
185
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Button, {
186
+ onClick: handleAdd,
187
+ disabled: saving,
188
+ children: [
189
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, {}),
190
+ " ",
191
+ t("add")
192
+ ]
193
+ })
194
+ }),
195
+ servers.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
196
+ className: McpSection_module_css_default.empty,
197
+ children: t("noServers")
198
+ }),
199
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
200
+ className: McpSection_module_css_default.list,
201
+ children: servers.map((server, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
202
+ className: McpSection_module_css_default.card,
203
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
204
+ className: McpSection_module_css_default.cardBody,
205
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
206
+ className: McpSection_module_css_default.cardName,
207
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: server.enabled ? McpSection_module_css_default.statusOn : McpSection_module_css_default.statusOff }), server.name]
208
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
209
+ className: McpSection_module_css_default.cardMeta,
210
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("code", { children: [
211
+ server.command,
212
+ " ",
213
+ server.args.join(" ")
214
+ ] })
215
+ })]
216
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
217
+ className: McpSection_module_css_default.cardActions,
218
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
219
+ onClick: () => handleEdit(i),
220
+ children: t("edit")
221
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
222
+ className: McpSection_module_css_default.deleteBtn,
223
+ onClick: () => setDeleteTarget({
224
+ name: server.name,
225
+ index: i
226
+ }),
227
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, {})
228
+ })]
229
+ })]
230
+ }, i))
231
+ }),
232
+ showEditModal && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
233
+ open: true,
234
+ onClose: () => setShowEditModal(false),
235
+ title: editIndex !== null ? t("edit") : t("add"),
236
+ closeLabel: t("close"),
237
+ className: McpSection_module_css_default.dialogMcp ?? "",
238
+ footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
239
+ onClick: handleSaveJson,
240
+ disabled: saving,
241
+ children: t("save")
242
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
243
+ onClick: () => setShowEditModal(false),
244
+ children: t("cancel")
245
+ })] }),
246
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
247
+ className: McpSection_module_css_default.modalBody,
248
+ children: [editError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
249
+ className: McpSection_module_css_default.error,
250
+ children: editError
251
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
252
+ className: McpSection_module_css_default.jsonEditor,
253
+ value: editJson,
254
+ onChange: (e) => setEditJson(e.target.value),
255
+ rows: 16,
256
+ spellCheck: false
257
+ })]
258
+ })
259
+ }),
260
+ deleteTarget && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
261
+ open: true,
262
+ onClose: () => setDeleteTarget(null),
263
+ title: t("remove"),
264
+ closeLabel: t("close"),
265
+ className: McpSection_module_css_default.dialogMcp ?? "",
266
+ footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
267
+ onClick: () => handleDelete(deleteTarget.index),
268
+ children: t("remove")
269
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
270
+ onClick: () => setDeleteTarget(null),
271
+ children: t("cancel")
272
+ })] }),
273
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
274
+ className: McpSection_module_css_default.modalBody,
275
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("deleteConfirm").replace("{server}", deleteTarget.name) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("deleteDescription") })]
276
+ })
277
+ })
278
+ ]
279
+ });
280
+ }
281
+ //#endregion
282
+ //#region src/client/locales.ts
283
+ const en = {
284
+ nav: "MCP Servers",
285
+ title: "MCP Configuration",
286
+ intro: "Manage your MCP servers by editing the JSON configuration below.",
287
+ add: "Add server",
288
+ edit: "Edit MCP config",
289
+ remove: "Delete",
290
+ deleteConfirm: "Delete {server}?",
291
+ deleteDescription: "This will remove the MCP server configuration.",
292
+ save: "Save",
293
+ cancel: "Cancel",
294
+ close: "Close",
295
+ noServers: "No MCP servers configured. Click \"Add server\" to get started.",
296
+ loadFailed: "Failed to load MCP configuration.",
297
+ saveFailed: "Failed to save MCP configuration.",
298
+ saved: "Configuration saved."
299
+ };
300
+ const zh = {
301
+ nav: "MCP 服务器",
302
+ title: "MCP 配置",
303
+ intro: "通过编辑下方的 JSON 配置来管理 MCP 服务器。",
304
+ add: "添加服务器",
305
+ edit: "编辑 MCP 配置",
306
+ remove: "删除",
307
+ deleteConfirm: "删除 {server}?",
308
+ deleteDescription: "这将移除 MCP 服务器配置。",
309
+ save: "保存",
310
+ cancel: "取消",
311
+ close: "关闭",
312
+ noServers: "还没有配置 MCP 服务器,点击\"添加服务器\"开始配置。",
313
+ loadFailed: "加载 MCP 配置失败。",
314
+ saveFailed: "保存 MCP 配置失败。",
315
+ saved: "配置已保存。"
316
+ };
317
+ //#endregion
318
+ //#region src/client/index.ts
319
+ const NS = "settings.mcp";
320
+ const NAMESPACE = "mcp-servers";
321
+ const inject = [
322
+ "slots",
323
+ "locale",
324
+ "configForms"
325
+ ];
326
+ function apply(ctx) {
327
+ ctx.effect(() => ctx.locale.register(NS, {
328
+ zh,
329
+ en
330
+ }), "ui-settings-mcp: copy dictionaries");
331
+ const form = ctx.configForms.get(NAMESPACE);
332
+ const t = ctx.locale.bind(NS);
333
+ const load = () => form.getSnapshot().value?.servers ?? [];
334
+ const save = async (servers) => {
335
+ await form.set("servers", servers);
336
+ };
337
+ ctx.effect(() => ctx.configForms.whileServed([NAMESPACE], () => ctx.slots.inject("settings.section", () => ctx.slots.register({
338
+ name: "settings.section",
339
+ id: "mcp",
340
+ order: 25,
341
+ label: () => t("nav"),
342
+ locale: NS,
343
+ inject: () => ({
344
+ load,
345
+ save,
346
+ t
347
+ })
348
+ }, McpSection))), "ui-settings-mcp: page");
349
+ }
350
+ //#endregion
351
+ exports.apply = apply;
352
+ exports.inject = inject;
353
+ return module.exports;
354
+ }
355
+ });
356
+
357
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":["styles","Button","IconPlusOutlineRegular","IconTrashOutlineRegular","Modal"],"sources":["../../../packages/client/ui-settings-mcp/src/client/McpSection.tsx","../../../packages/client/ui-settings-mcp/src/client/locales.ts","../../../packages/client/ui-settings-mcp/src/client/index.ts"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react'\nimport { Button, IconPlusOutlineRegular, IconTrashOutlineRegular, Modal } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { McpKey } from './locales.ts'\nimport styles from './McpSection.module.css'\n\ninterface McpServer {\n name: string\n command: string\n args: string[]\n env: Record<string, string>\n transport: 'stdio' | 'streamable-http'\n url: string\n enabled: boolean\n}\n\nexport interface McpSectionInjected {\n load: () => unknown[]\n save: (servers: unknown[]) => Promise<void>\n t: (key: McpKey) => string\n}\n\nexport type McpSectionProps = Partial<McpSectionInjected>\n\nfunction serversToJson(servers: McpServer[]): string {\n const mcpServers: Record<string, Record<string, unknown>> = {}\n for (const s of servers) {\n const entry: Record<string, unknown> = { command: s.command }\n if (s.args.length > 0) entry.args = s.args\n if (Object.keys(s.env).length > 0) entry.env = s.env\n if (s.transport === 'streamable-http') entry.transport = 'streamable-http'\n if (s.url) entry.url = s.url\n mcpServers[s.name] = entry\n }\n return JSON.stringify({ mcpServers }, null, 2)\n}\n\nfunction jsonToServers(text: string): McpServer[] {\n const parsed = JSON.parse(text)\n const map = parsed.mcpServers\n if (!map || typeof map !== 'object') throw new Error('Missing \"mcpServers\" key')\n return Object.entries(map).map(([name, config]) => {\n const c = config as Record<string, unknown>\n const args = Array.isArray(c.args) ? c.args.map(String) : []\n const env = c.env && typeof c.env === 'object'\n ? Object.fromEntries(Object.entries(c.env).map(([k, v]) => [k, String(v)]))\n : {}\n return {\n name,\n command: String(c.command ?? ''),\n args,\n env,\n transport: c.transport === 'streamable-http' ? 'streamable-http' as const : 'stdio' as const,\n url: String(c.url ?? ''),\n enabled: c.enabled !== false,\n }\n })\n}\n\nconst EMPTY_TEMPLATE = JSON.stringify({\n mcpServers: {\n 'my-server': {\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-filesystem', '/path'],\n },\n },\n}, null, 2)\n\nexport function McpSection({ load, save, t: t_ }: McpSectionProps) {\n const t = t_ ?? ((key: string) => key)\n const [servers, setServers] = useState<McpServer[]>([])\n const [loading, setLoading] = useState(true)\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [editJson, setEditJson] = useState('')\n const [editIndex, setEditIndex] = useState<number | null>(null)\n const [showEditModal, setShowEditModal] = useState(false)\n const [editError, setEditError] = useState<string | null>(null)\n const [deleteTarget, setDeleteTarget] = useState<{ name: string; index: number } | null>(null)\n\n const loadConfig = useCallback(() => {\n setLoading(true)\n setError(null)\n try {\n const loaded = load?.() ?? []\n setServers(loaded as McpServer[])\n } catch (e) {\n setError(t('loadFailed'))\n } finally {\n setLoading(false)\n }\n }, [load, t])\n\n useEffect(() => { loadConfig() }, [loadConfig])\n\n const saveConfig = async (newServers: McpServer[]) => {\n setSaving(true)\n setError(null)\n try {\n await save?.(newServers)\n setServers(newServers)\n } catch (e) {\n setError(t('saveFailed'))\n } finally {\n setSaving(false)\n }\n }\n\n const handleAdd = () => {\n setEditJson(EMPTY_TEMPLATE)\n setEditIndex(null)\n setEditError(null)\n setShowEditModal(true)\n }\n\n const handleEdit = (index: number) => {\n const server = servers[index]\n if (!server) return\n setEditJson(serversToJson([server]))\n setEditIndex(index)\n setEditError(null)\n setShowEditModal(true)\n }\n\n const handleSaveJson = async () => {\n try {\n const parsed = jsonToServers(editJson)\n if (parsed.length === 0) {\n setEditError('No servers found in JSON')\n return\n }\n if (editIndex !== null) {\n const newServers = [...servers]\n newServers[editIndex] = parsed[0]!\n await saveConfig(newServers)\n } else {\n const merged = new Map(servers.map(s => [s.name, s]))\n for (const s of parsed) merged.set(s.name, s)\n await saveConfig(Array.from(merged.values()).filter((s): s is McpServer => s !== undefined))\n }\n setShowEditModal(false)\n } catch (e) {\n setEditError(e instanceof Error ? e.message : String(e))\n }\n }\n\n const handleDelete = async (index: number) => {\n const newServers = servers.filter((_, i) => i !== index)\n await saveConfig(newServers)\n setDeleteTarget(null)\n }\n\n if (loading) {\n return <div className={styles.section}><div className={styles.loading}>Loading...</div></div>\n }\n\n return (\n <div className={styles.section}>\n <div className={styles.header}>\n <h2 className={styles.title}>{t('title')}</h2>\n <p className={styles.intro}>{t('intro')}</p>\n </div>\n\n {error && <div className={styles.error}>{error}</div>}\n\n <div className={styles.toolbar}>\n <Button onClick={handleAdd} disabled={saving}>\n <IconPlusOutlineRegular /> {t('add')}\n </Button>\n </div>\n\n {servers.length === 0 && (\n <div className={styles.empty}>{t('noServers')}</div>\n )}\n\n <div className={styles.list}>\n {servers.map((server, i) => (\n <div key={i} className={styles.card}>\n <div className={styles.cardBody}>\n <div className={styles.cardName}>\n <span className={server.enabled ? styles.statusOn : styles.statusOff} />\n {server.name}\n </div>\n <div className={styles.cardMeta}>\n <code>{server.command} {server.args.join(' ')}</code>\n </div>\n </div>\n <div className={styles.cardActions}>\n <Button onClick={() => handleEdit(i)}>{t('edit')}</Button>\n <button className={styles.deleteBtn} onClick={() => setDeleteTarget({ name: server.name, index: i })}>\n <IconTrashOutlineRegular />\n </button>\n </div>\n </div>\n ))}\n </div>\n\n {showEditModal && (\n <Modal\n open\n onClose={() => setShowEditModal(false)}\n title={editIndex !== null ? t('edit') : t('add')}\n closeLabel={t('close')}\n className={styles.dialogMcp ?? ''}\n footer={(\n <>\n <Button onClick={handleSaveJson} disabled={saving}>{t('save')}</Button>\n <Button onClick={() => setShowEditModal(false)}>{t('cancel')}</Button>\n </>\n )}\n >\n <div className={styles.modalBody}>\n {editError && <div className={styles.error}>{editError}</div>}\n <textarea\n className={styles.jsonEditor}\n value={editJson}\n onChange={e => setEditJson(e.target.value)}\n rows={16}\n spellCheck={false}\n />\n </div>\n </Modal>\n )}\n\n {deleteTarget && (\n <Modal\n open\n onClose={() => setDeleteTarget(null)}\n title={t('remove')}\n closeLabel={t('close')}\n className={styles.dialogMcp ?? ''}\n footer={(\n <>\n <Button onClick={() => handleDelete(deleteTarget.index)}>{t('remove')}</Button>\n <Button onClick={() => setDeleteTarget(null)}>{t('cancel')}</Button>\n </>\n )}\n >\n <div className={styles.modalBody}>\n <p>{t('deleteConfirm').replace('{server}', deleteTarget.name)}</p>\n <p>{t('deleteDescription')}</p>\n </div>\n </Modal>\n )}\n </div>\n )\n}\n\n\n","export const en = {\n nav: 'MCP Servers',\n title: 'MCP Configuration',\n intro: 'Manage your MCP servers by editing the JSON configuration below.',\n add: 'Add server',\n edit: 'Edit MCP config',\n remove: 'Delete',\n deleteConfirm: 'Delete {server}?',\n deleteDescription: 'This will remove the MCP server configuration.',\n save: 'Save',\n cancel: 'Cancel',\n close: 'Close',\n noServers: 'No MCP servers configured. Click \"Add server\" to get started.',\n loadFailed: 'Failed to load MCP configuration.',\n saveFailed: 'Failed to save MCP configuration.',\n saved: 'Configuration saved.',\n}\nexport type McpKey = keyof typeof en\nexport const zh: { [Key in keyof typeof en]: string } = {\n nav: 'MCP 服务器',\n title: 'MCP 配置',\n intro: '通过编辑下方的 JSON 配置来管理 MCP 服务器。',\n add: '添加服务器',\n edit: '编辑 MCP 配置',\n remove: '删除',\n deleteConfirm: '删除 {server}?',\n deleteDescription: '这将移除 MCP 服务器配置。',\n save: '保存',\n cancel: '取消',\n close: '关闭',\n noServers: '还没有配置 MCP 服务器,点击\"添加服务器\"开始配置。',\n loadFailed: '加载 MCP 配置失败。',\n saveFailed: '保存 MCP 配置失败。',\n saved: '配置已保存。',\n}\n","import type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport { McpSection } from './McpSection.tsx'\nimport type { McpSectionInjected } from './McpSection.tsx'\nimport { en, zh, type McpKey } from './locales.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n 'settings.mcp': McpKey\n }\n}\nconst NS = 'settings.mcp'\nconst NAMESPACE = 'mcp-servers'\n\ninterface McpServersConfig {\n servers: unknown[]\n}\n\nexport const inject = ['slots', 'locale', 'configForms']\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'ui-settings-mcp: copy dictionaries')\n const form = ctx.configForms.get<McpServersConfig>(NAMESPACE)\n const t = ctx.locale.bind(NS) as McpSectionInjected['t']\n const load = (): unknown[] => form.getSnapshot().value?.servers ?? []\n const save = async (servers: unknown[]): Promise<void> => { await form.set('servers', servers) }\n ctx.effect(() => ctx.configForms.whileServed([NAMESPACE], () => ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'mcp',\n order: 25,\n label: () => t('nav'),\n locale: NS,\n inject: (): McpSectionInjected => ({ load, save, t }),\n }, McpSection))), 'ui-settings-mcp: page')\n}\n"],"mappings":"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"}