@max-null/dsh-skill-mcp-center 0.6.2 → 0.6.4
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/README.md +6 -0
- package/client.js +7 -1
- package/dist/service.d.ts +10 -1
- package/dist/service.js +17 -6
- package/docs/shots/mcp-switch-session-only.png +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,12 @@ Skill 与 MCP 管理中心:在设置里管理 skills 与 MCP 服务器,右
|
|
|
23
23
|
|
|
24
24
|

|
|
25
25
|
|
|
26
|
+
### 设置页:MCP 开关的效力边界
|
|
27
|
+
|
|
28
|
+
DSH 的 `Loader.write()` 是空实现,面板上的启停只改内存树——所以 MCP 标签页顶部写明「开关只对本次运行生效,重启后恢复」;要长期禁用,给 `cordis.patch.yml` 的对应条目加 `disabled: true`。被面板关掉的条目会在卡片里标「本次运行已停用 · 重启恢复」,而 patch 里持久禁用的条目不标——两种「关」必须能区分:
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
26
32
|
### 侧栏:Skill 一览
|
|
27
33
|
|
|
28
34
|
搜索 + 命名空间筛选(全部 / 全局 / 工作区),每条带开关与 `MD`(查看 SKILL.md)。**插件包内自带的 skill 同样列出**,并标出来源插件——下图里 8 个 `ssid-*` 来自 `dsh-skills`,而用户级的 `ssid-release` 没有来源标签,这正是两者的区别:
|
package/client.js
CHANGED
|
@@ -223,6 +223,8 @@ var zhDict = {
|
|
|
223
223
|
provider: "provider \xB7 {name}",
|
|
224
224
|
addServer: "\uFF0B \u6DFB\u52A0 server",
|
|
225
225
|
hotApplied: "\u589E\u5220\u6539\u70ED\u751F\u6548\uFF0C\u514D\u91CD\u542F",
|
|
226
|
+
switchSessionOnly: "\u5F00\u5173\u53EA\u5BF9\u672C\u6B21\u8FD0\u884C\u751F\u6548\uFF0C\u91CD\u542F\u540E\u6062\u590D\uFF08\u8981\u957F\u671F\u7981\u7528\uFF0C\u7ED9\u8BE5\u6761\u76EE\u52A0 disabled: true\uFF09",
|
|
227
|
+
switchReverted: "\u672C\u6B21\u8FD0\u884C\u5DF2\u505C\u7528 \xB7 \u91CD\u542F\u6062\u590D",
|
|
226
228
|
edit: "\u7F16\u8F91",
|
|
227
229
|
remove: "\u5220\u9664",
|
|
228
230
|
disableServer: "\u505C\u7528\uFF08\u65AD\u5F00\u5E76\u91CA\u653E context\uFF09",
|
|
@@ -288,6 +290,8 @@ var enDict = {
|
|
|
288
290
|
provider: "provider \xB7 {name}",
|
|
289
291
|
addServer: "\uFF0B Add server",
|
|
290
292
|
hotApplied: "hot-applied, no restart",
|
|
293
|
+
switchSessionOnly: "switch applies to this run only, reverted after restart (to disable for good, add disabled: true to the entry)",
|
|
294
|
+
switchReverted: "disabled for this run \xB7 restored on restart",
|
|
291
295
|
edit: "Edit",
|
|
292
296
|
remove: "Remove",
|
|
293
297
|
disableServer: "Disable (disconnect & free context)",
|
|
@@ -659,6 +663,7 @@ function McpView() {
|
|
|
659
663
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "smc-spacer" }),
|
|
660
664
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "smc-sub", children: t("hotApplied") })
|
|
661
665
|
] }),
|
|
666
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-sub", style: { marginBottom: 8 }, children: t("switchSessionOnly") }),
|
|
662
667
|
editing !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ServerForm, { server: editing === "new" ? null : editing, onClose: () => {
|
|
663
668
|
setEditing(null);
|
|
664
669
|
}, onSaved: () => {
|
|
@@ -690,7 +695,8 @@ function McpView() {
|
|
|
690
695
|
}
|
|
691
696
|
)
|
|
692
697
|
] }),
|
|
693
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-desc", children: s.transport === "stdio" ? `${s.command ?? ""} ${(s.args ?? []).join(" ")}` : s.url })
|
|
698
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-desc", children: s.transport === "stdio" ? `${s.command ?? ""} ${(s.args ?? []).join(" ")}` : s.url }),
|
|
699
|
+
s.disabled && s.sessionToggled === true && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "smc-desc", children: t("switchReverted") })
|
|
694
700
|
] }, s.id))
|
|
695
701
|
] });
|
|
696
702
|
}
|
package/dist/service.d.ts
CHANGED
|
@@ -42,6 +42,13 @@ export interface McpServer {
|
|
|
42
42
|
url?: string;
|
|
43
43
|
headers?: Record<string, string>;
|
|
44
44
|
disabled: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* True when the switch was changed during this run. Lets the panel say
|
|
47
|
+
* "reverted on restart" only where that is true — an entry disabled in
|
|
48
|
+
* `cordis.patch.yml` stays disabled across restarts and must not be
|
|
49
|
+
* labelled as session-only.
|
|
50
|
+
*/
|
|
51
|
+
sessionToggled: boolean;
|
|
45
52
|
fiberPhase: string | null;
|
|
46
53
|
}
|
|
47
54
|
/** One tool a server contributes, as the management surface lists it. */
|
|
@@ -146,6 +153,8 @@ export declare function deleteTargetOf(path: string, roots: readonly string[]):
|
|
|
146
153
|
export declare class SkillMcpService extends Service {
|
|
147
154
|
static inject: string[];
|
|
148
155
|
private readonly officialSkillDirs;
|
|
156
|
+
/** Ids toggled by the panel during this run (in-memory only, by design: the host does not persist it). */
|
|
157
|
+
private readonly sessionToggled;
|
|
149
158
|
constructor(ctx: Context, config?: SkillConfig);
|
|
150
159
|
/**
|
|
151
160
|
* Skill roots that live **inside loaded plugin packages**.
|
|
@@ -207,7 +216,7 @@ export declare class SkillMcpService extends Service {
|
|
|
207
216
|
updateMcpServer(id: string, config: McpConfig): Promise<void>;
|
|
208
217
|
/** Remove one server — disconnects and unregisters its tools. */
|
|
209
218
|
removeMcpServer(id: string): Promise<void>;
|
|
210
|
-
/** Enable/disable one server without deleting its config. */
|
|
219
|
+
/** Enable/disable one server without deleting its config. The host does not persist this. */
|
|
211
220
|
setMcpServerEnabled(id: string, enabled: boolean): Promise<void>;
|
|
212
221
|
/** Runtime status per server: upstream `mcpStatus` seam when present, else derived. */
|
|
213
222
|
mcpStatus(): Promise<McpServerStatus[]>;
|
package/dist/service.js
CHANGED
|
@@ -232,6 +232,8 @@ export function deleteTargetOf(path, roots) {
|
|
|
232
232
|
export class SkillMcpService extends Service {
|
|
233
233
|
static inject = ['loader', 'tools'];
|
|
234
234
|
officialSkillDirs;
|
|
235
|
+
/** Ids toggled by the panel during this run (in-memory only, by design: the host does not persist it). */
|
|
236
|
+
sessionToggled = new Set();
|
|
235
237
|
constructor(ctx, config = {}) {
|
|
236
238
|
super(ctx, 'skillMcp');
|
|
237
239
|
this.officialSkillDirs = config.officialSkillDirs ?? [];
|
|
@@ -404,17 +406,23 @@ export class SkillMcpService extends Service {
|
|
|
404
406
|
// plugin `name` ('mcp-client'); one entry = one MCP server.
|
|
405
407
|
if (entry.options.name !== '@deepseek-ai/dsh-mcp-client')
|
|
406
408
|
continue;
|
|
407
|
-
|
|
409
|
+
// `!!js` 表达式在 options.config 里保留为 { __jsExpr } 节点,求值结果在 fiber.config 上
|
|
410
|
+
// (与本仓库 pluginSkillRoots 同一个坑)。照 options 读会把表达式当值:
|
|
411
|
+
// command 渲染成 [object Object]、args 变成一串 JSON 转义。fiber 缺失时退回 options。
|
|
412
|
+
const evaluated = entry.fiber?.config;
|
|
413
|
+
const cfg = evaluated ?? entry.options.config;
|
|
414
|
+
const text = (value) => typeof value === 'string' ? value : value === undefined ? undefined : JSON.stringify(value);
|
|
408
415
|
servers.push({
|
|
409
416
|
id: entry.id,
|
|
410
417
|
serverName: cfg?.serverName ?? entry.id,
|
|
411
418
|
transport: cfg?.transport === 'streamable-http' ? 'streamable-http' : 'stdio',
|
|
412
|
-
command: cfg?.command,
|
|
413
|
-
args: cfg?.args,
|
|
414
|
-
cwd: cfg?.cwd,
|
|
415
|
-
url: cfg?.url,
|
|
419
|
+
command: text(cfg?.command),
|
|
420
|
+
args: cfg?.args?.map(arg => text(arg) ?? ''),
|
|
421
|
+
cwd: text(cfg?.cwd),
|
|
422
|
+
url: text(cfg?.url),
|
|
416
423
|
headers: cfg?.headers,
|
|
417
424
|
disabled: entry.disabled,
|
|
425
|
+
sessionToggled: this.sessionToggled.has(entry.id),
|
|
418
426
|
fiberPhase: entry.fiber === undefined ? null : FIBER_PHASE[entry.fiber.state],
|
|
419
427
|
});
|
|
420
428
|
}
|
|
@@ -436,9 +444,12 @@ export class SkillMcpService extends Service {
|
|
|
436
444
|
async removeMcpServer(id) {
|
|
437
445
|
await this.ctx.loader.remove(id);
|
|
438
446
|
}
|
|
439
|
-
/** Enable/disable one server without deleting its config. */
|
|
447
|
+
/** Enable/disable one server without deleting its config. The host does not persist this. */
|
|
440
448
|
async setMcpServerEnabled(id, enabled) {
|
|
441
449
|
await this.ctx.loader.update(id, { disabled: enabled ? null : true });
|
|
450
|
+
// 记「本次运行改过」:Loader 根树的 write 是 no-op(loader lib/index.js 的 `write() {}`),
|
|
451
|
+
// 所以这里改的只是内存态;面板据此显示“重启后恢复”,而不是假装它是持久设置。
|
|
452
|
+
this.sessionToggled.add(id);
|
|
442
453
|
}
|
|
443
454
|
/** Runtime status per server: upstream `mcpStatus` seam when present, else derived. */
|
|
444
455
|
async mcpStatus() {
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@max-null/dsh-skill-mcp-center",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "Skill & MCP management center for DeepSeek Harness — manage skills and MCP servers in Settings, live MCP status in the sidebar",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|