dsh-mcp-panel 0.2.0 → 0.3.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.
- package/CHANGELOG.md +95 -0
- package/README.es.md +17 -5
- package/README.hi.md +17 -5
- package/README.md +17 -5
- package/README.pt.md +17 -5
- package/README.zh.md +17 -5
- package/THIRD_PARTY_NOTICES.md +11 -0
- package/docs/optimization-plan-v2.zh.md +325 -0
- package/docs/optimization-plan.zh.md +157 -0
- package/docs/research-notes.zh.md +114 -0
- package/docs/upstream-proposal.md +150 -0
- package/lib/client.js +283 -130
- package/lib/client.js.map +1 -1
- package/lib/index.js +87 -19
- package/lib/typert.host.js +2 -1
- package/lib/types/client/McpPanelTab.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +12 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/present.d.ts +29 -1
- package/lib/types/client/present.d.ts.map +1 -1
- package/lib/types/client/remote.d.ts +9 -9
- package/lib/types/command.d.ts +6 -0
- package/lib/types/command.d.ts.map +1 -1
- package/lib/types/probe.d.ts.map +1 -1
- package/lib/types/service.d.ts +11 -2
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/typert.host.d.ts +9 -9
- package/lib/types/wire.d.ts +21 -21
- package/lib/types/wire.d.ts.map +1 -1
- package/package.json +18 -8
- package/src/client/McpPanelTab.tsx +68 -14
- package/src/client/locales.ts +12 -0
- package/src/client/present.ts +49 -1
- package/src/client/styles.ts +32 -0
- package/src/command.ts +39 -4
- package/src/probe.ts +1 -1
- package/src/service.ts +62 -10
- package/src/wire.ts +3 -3
package/lib/types/wire.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../src/wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,4DAA4D;AAC5D,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,iBAAiB,GAAG,SAAS,CAAA;AAElE,6EAA6E;AAC7E,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,IAAI,CAAA;AAE5F,qFAAqF;AACrF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAA;AAE9G,kFAAkF;AAClF,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,SAAS,CAAA;AAE1D,6EAA6E;AAC7E,MAAM,WAAW,WAAW;IAC1B,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAA;IACZ,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAA;IACf,2FAA2F;IAC3F,SAAS,EAAE,YAAY,CAAA;IACvB,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAA;IACd,sFAAsF;IACtF,OAAO,EAAE,OAAO,CAAA;IAChB,kEAAkE;IAClE,UAAU,EAAE,aAAa,CAAA;IACzB,mGAAmG;IACnG,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,KAAK,EAAE,SAAS,WAAW,EAAE,CAAA;IAC7B,wEAAwE;IACxE,KAAK,EAAE,kBAAkB,CAAA;IACzB,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAA;IACf,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAA;IACnB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAA;IACtB,6EAA6E;IAC7E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,uFAAuF;IACvF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,6FAA6F;IAC7F,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,2EAA2E;IAC3E,UAAU,EAAE,WAAW,GAAG,aAAa,GAAG,IAAI,CAAA;IAC9C,2EAA2E;IAC3E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,6CAA6C;IAC7C,YAAY,EAAE,eAAe,CAAA;CAC9B;AAED,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAA;IACV,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,
|
|
1
|
+
{"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../src/wire.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-mcp-panel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Read-only runtime management panel for the official DeepSeek Harness MCP client: /mcp command, a Settings page MCP tab with connection status, recent errors, reconnect counts and tool inventory (sanitized for display), controlled enable/disable patch suggestions, and an optional one-shot Streamable HTTP connectivity probe.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/PerryLink/dsh-mcp-panel.git"
|
|
8
8
|
},
|
|
9
|
+
"homepage": "https://github.com/PerryLink/dsh-mcp-panel#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/PerryLink/dsh-mcp-panel/issues"
|
|
12
|
+
},
|
|
13
|
+
"author": "PerryLink",
|
|
9
14
|
"private": false,
|
|
10
15
|
"type": "module",
|
|
11
16
|
"main": "./lib/index.js",
|
|
@@ -28,9 +33,15 @@
|
|
|
28
33
|
"files": [
|
|
29
34
|
"lib",
|
|
30
35
|
"src",
|
|
36
|
+
"docs",
|
|
31
37
|
"cordis.patch.yml",
|
|
38
|
+
"CHANGELOG.md",
|
|
39
|
+
"THIRD_PARTY_NOTICES.md",
|
|
32
40
|
"README.md",
|
|
33
41
|
"README.zh.md",
|
|
42
|
+
"README.es.md",
|
|
43
|
+
"README.pt.md",
|
|
44
|
+
"README.hi.md",
|
|
34
45
|
"LICENSE"
|
|
35
46
|
],
|
|
36
47
|
"dsh": {
|
|
@@ -72,7 +83,7 @@
|
|
|
72
83
|
},
|
|
73
84
|
"dependencies": {
|
|
74
85
|
"tsdown": "^0.22.14",
|
|
75
|
-
"typescript": "^
|
|
86
|
+
"typescript": "^7.0.0",
|
|
76
87
|
"zod": "^4.4.3"
|
|
77
88
|
},
|
|
78
89
|
"devDependencies": {
|
|
@@ -92,20 +103,19 @@
|
|
|
92
103
|
"@deepseek-ai/dsh-typert-protocol": "0.1.0-rc.6",
|
|
93
104
|
"@types/node": "^22.19.0",
|
|
94
105
|
"@types/react": "18.3.31",
|
|
95
|
-
"jsdom": "^
|
|
106
|
+
"jsdom": "^30.0.1",
|
|
96
107
|
"react": "18.3.1",
|
|
97
108
|
"react-dom": "18.3.1",
|
|
98
|
-
"vitest": "^
|
|
109
|
+
"vitest": "^4.1.10"
|
|
99
110
|
},
|
|
111
|
+
"license": "Apache-2.0",
|
|
100
112
|
"scripts": {
|
|
101
113
|
"build": "node scripts/prepare.mjs",
|
|
102
114
|
"typecheck": "tsc --noEmit",
|
|
103
115
|
"typecheck:ci": "tsc -p tsconfig.ci.json --noEmit",
|
|
104
116
|
"test": "vitest run",
|
|
105
117
|
"test:watch": "vitest",
|
|
106
|
-
"prepare": "node scripts/prepare.mjs",
|
|
107
118
|
"verify:self-contained": "node scripts/verify-self-contained.mjs",
|
|
108
119
|
"verify:artifacts": "node scripts/verify-artifacts.mjs"
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useId, useState, type ReactNode } from 'react'
|
|
4
4
|
import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
|
|
5
|
-
import { presentMcpPanel, probeBadge, type BadgeTone, type PresentedServerRow } from './present.ts'
|
|
5
|
+
import { filterServers, presentMcpPanel, probeBadge, summarizePanel, type BadgeTone, type PresentedServerRow } from './present.ts'
|
|
6
6
|
import type { McpPanelSnapshot, McpProbeView, ProbeStarted } from '../wire.ts'
|
|
7
7
|
|
|
8
8
|
/** Registration-side injected face: the unwrapped snapshot read + probe start. */
|
|
@@ -21,7 +21,7 @@ export type McpPanelTabProps =
|
|
|
21
21
|
|
|
22
22
|
type ViewState =
|
|
23
23
|
| { readonly status: 'loading' }
|
|
24
|
-
| { readonly status: 'error' }
|
|
24
|
+
| { readonly status: 'error'; readonly message: string }
|
|
25
25
|
| { readonly status: 'ready'; readonly snapshot: McpPanelSnapshot }
|
|
26
26
|
|
|
27
27
|
/** Localized label for one server badge code. */
|
|
@@ -46,6 +46,7 @@ function probeLabel(badge: ReturnType<typeof probeBadge>['badge'], t: McpPanelTa
|
|
|
46
46
|
case 'failed': return t('probeFailed')
|
|
47
47
|
case 'killed': return t('probeKilled')
|
|
48
48
|
case 'stopping': return t('probeStopping')
|
|
49
|
+
default: return t('probeUnknown')
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
|
|
@@ -60,12 +61,16 @@ function formatProbeTime(view: McpProbeView): string {
|
|
|
60
61
|
export function McpPanelTab({ status, probe, t }: McpPanelTabProps): ReactNode {
|
|
61
62
|
const listId = useId()
|
|
62
63
|
const [request, setRequest] = useState(0)
|
|
63
|
-
|
|
64
|
+
// Expanded card set: multiple cards may be open at once, so "expand all"
|
|
65
|
+
// and "collapse all" can act on the whole (filtered) list.
|
|
66
|
+
const [expanded, setExpanded] = useState<Record<string, true>>({})
|
|
64
67
|
const [probeError, setProbeError] = useState<string | null>(null)
|
|
65
68
|
const [state, setState] = useState<ViewState>({ status: 'loading' })
|
|
66
69
|
// Per-card tool filter: one query per server so expanding two cards at once
|
|
67
70
|
// never filters one card by the other card's search text.
|
|
68
71
|
const [toolQueries, setToolQueries] = useState<Record<string, string>>({})
|
|
72
|
+
// Server search across names and display targets; filters the card list only.
|
|
73
|
+
const [serverQuery, setServerQuery] = useState('')
|
|
69
74
|
|
|
70
75
|
const reload = (): void => {
|
|
71
76
|
setRequest(value => value + 1)
|
|
@@ -75,7 +80,11 @@ export function McpPanelTab({ status, probe, t }: McpPanelTabProps): ReactNode {
|
|
|
75
80
|
let current = true
|
|
76
81
|
void Promise.resolve().then(() => status()).then(
|
|
77
82
|
(snapshot) => { if (current) setState({ status: 'ready', snapshot }) },
|
|
78
|
-
() => {
|
|
83
|
+
(error: unknown) => {
|
|
84
|
+
if (current) {
|
|
85
|
+
setState({ status: 'error', message: error instanceof Error ? error.message : String(error) })
|
|
86
|
+
}
|
|
87
|
+
},
|
|
79
88
|
)
|
|
80
89
|
return () => { current = false }
|
|
81
90
|
}, [status, request])
|
|
@@ -97,19 +106,34 @@ export function McpPanelTab({ status, probe, t }: McpPanelTabProps): ReactNode {
|
|
|
97
106
|
}
|
|
98
107
|
}, [intervalMs])
|
|
99
108
|
|
|
109
|
+
const model = state.status === 'ready' ? presentMcpPanel(state.snapshot) : undefined
|
|
110
|
+
const visibleServers = model !== undefined ? filterServers(model.servers, serverQuery) : []
|
|
111
|
+
const summary = model !== undefined ? summarizePanel(visibleServers) : null
|
|
112
|
+
const summaryText = summary === null ? '' : t('summary')
|
|
113
|
+
.replace('{total}', String(summary.total))
|
|
114
|
+
.replace('{connected}', String(summary.connected))
|
|
115
|
+
.replace('{errored}', String(summary.errored))
|
|
116
|
+
const probeRunning = model !== undefined && model.probes.some(probe => probe.view.status === 'running')
|
|
117
|
+
// While a probe runs, poll on a short fixed cadence so the probe row (and
|
|
118
|
+
// the disabled probe button) settles even when refreshIntervalMs is 0.
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (!probeRunning) return undefined
|
|
121
|
+
const timer = setInterval(() => { if (!document.hidden) reload() }, 1500)
|
|
122
|
+
return () => { clearInterval(timer) }
|
|
123
|
+
}, [probeRunning])
|
|
124
|
+
|
|
100
125
|
const retry = (): void => {
|
|
101
126
|
setState({ status: 'loading' })
|
|
102
127
|
reload()
|
|
103
128
|
}
|
|
104
129
|
|
|
105
|
-
const model = state.status === 'ready' ? presentMcpPanel(state.snapshot) : undefined
|
|
106
|
-
|
|
107
130
|
return (
|
|
108
131
|
<div className="dmcp-section" data-dsh-mcp-panel="" aria-busy={state.status === 'loading'}>
|
|
109
132
|
{state.status === 'loading' ? <p className="dmcp-status">{t('loading')}</p> : null}
|
|
110
133
|
{state.status === 'error' ? (
|
|
111
134
|
<div className="dmcp-failure">
|
|
112
135
|
<p role="alert">{t('error')}</p>
|
|
136
|
+
<p className="dmcp-failure-detail">{state.message}</p>
|
|
113
137
|
<button type="button" onClick={retry}>{t('retry')}</button>
|
|
114
138
|
</div>
|
|
115
139
|
) : null}
|
|
@@ -118,12 +142,34 @@ export function McpPanelTab({ status, probe, t }: McpPanelTabProps): ReactNode {
|
|
|
118
142
|
{model.empty ? <p className="dmcp-status">{t('empty')}</p> : (
|
|
119
143
|
<>
|
|
120
144
|
<h3 className="dmcp-heading">{t('servers')}</h3>
|
|
145
|
+
<p className="dmcp-summary">{summaryText}</p>
|
|
146
|
+
<div className="dmcp-toolbar">
|
|
147
|
+
<input
|
|
148
|
+
type="search"
|
|
149
|
+
className="dmcp-tool-filter dmcp-server-filter"
|
|
150
|
+
value={serverQuery}
|
|
151
|
+
placeholder={t('filterServers')}
|
|
152
|
+
aria-label={t('filterServers')}
|
|
153
|
+
onChange={(event) => { setServerQuery(event.currentTarget.value) }}
|
|
154
|
+
/>
|
|
155
|
+
<button
|
|
156
|
+
type="button"
|
|
157
|
+
className="dmcp-action"
|
|
158
|
+
onClick={() => {
|
|
159
|
+
setExpanded(Object.fromEntries(visibleServers.map(row => [row.view.serverName, true] as const)))
|
|
160
|
+
}}
|
|
161
|
+
>
|
|
162
|
+
{t('expandAll')}
|
|
163
|
+
</button>
|
|
164
|
+
<button type="button" className="dmcp-action" onClick={() => { setExpanded({}) }}>{t('collapseAll')}</button>
|
|
165
|
+
</div>
|
|
166
|
+
{visibleServers.length === 0 ? <p className="dmcp-status">{t('noMatch')}</p> : null}
|
|
121
167
|
<ul className="dmcp-cards">
|
|
122
|
-
{
|
|
123
|
-
const open = expanded
|
|
168
|
+
{visibleServers.map((row) => {
|
|
169
|
+
const open = expanded[row.view.serverName] === true
|
|
124
170
|
const detailId = `${listId}-${encodeURIComponent(row.view.serverName)}`
|
|
125
171
|
const toolQuery = toolQueries[row.view.serverName] ?? ''
|
|
126
|
-
const
|
|
172
|
+
const rowProbeRunning = model.probes.some(
|
|
127
173
|
probe => probe.view.status === 'running' && probe.view.serverName === row.view.serverName,
|
|
128
174
|
)
|
|
129
175
|
return (
|
|
@@ -133,7 +179,14 @@ export function McpPanelTab({ status, probe, t }: McpPanelTabProps): ReactNode {
|
|
|
133
179
|
className="dmcp-card-content"
|
|
134
180
|
aria-expanded={open}
|
|
135
181
|
aria-controls={detailId}
|
|
136
|
-
onClick={() => {
|
|
182
|
+
onClick={() => {
|
|
183
|
+
setExpanded((current) => {
|
|
184
|
+
const next = { ...current }
|
|
185
|
+
if (next[row.view.serverName] === true) delete next[row.view.serverName]
|
|
186
|
+
else next[row.view.serverName] = true
|
|
187
|
+
return next
|
|
188
|
+
})
|
|
189
|
+
}}
|
|
137
190
|
>
|
|
138
191
|
<strong className="dmcp-card-title">{row.view.serverName}</strong>
|
|
139
192
|
<span className="dmcp-card-trailing">
|
|
@@ -171,7 +224,7 @@ export function McpPanelTab({ status, probe, t }: McpPanelTabProps): ReactNode {
|
|
|
171
224
|
<button
|
|
172
225
|
type="button"
|
|
173
226
|
className="dmcp-probe-now"
|
|
174
|
-
disabled={
|
|
227
|
+
disabled={rowProbeRunning}
|
|
175
228
|
onClick={() => {
|
|
176
229
|
setProbeError(null)
|
|
177
230
|
void Promise.resolve().then(() => probe(row.view.serverName)).then(
|
|
@@ -180,7 +233,7 @@ export function McpPanelTab({ status, probe, t }: McpPanelTabProps): ReactNode {
|
|
|
180
233
|
)
|
|
181
234
|
}}
|
|
182
235
|
>
|
|
183
|
-
{
|
|
236
|
+
{rowProbeRunning ? t('probeRunning') : t('probeNow')}
|
|
184
237
|
</button>
|
|
185
238
|
) : null}
|
|
186
239
|
{row.view.tools.length === 0 ? (
|
|
@@ -246,10 +299,11 @@ export function McpPanelTab({ status, probe, t }: McpPanelTabProps): ReactNode {
|
|
|
246
299
|
)
|
|
247
300
|
}
|
|
248
301
|
|
|
249
|
-
/** One tone-colored badge chip.
|
|
302
|
+
/** One tone-colored badge chip. The label is visible text, so no `role="img"`
|
|
303
|
+
* or `aria-label`: screen readers announce it exactly once. */
|
|
250
304
|
function Badge({ tone, label }: { readonly tone: BadgeTone; readonly label: string }): ReactNode {
|
|
251
305
|
return (
|
|
252
|
-
<span className="dmcp-badge" data-tone={tone}
|
|
306
|
+
<span className="dmcp-badge" data-tone={tone} title={label}>
|
|
253
307
|
<span className="dmcp-dot" aria-hidden="true" />
|
|
254
308
|
{label}
|
|
255
309
|
</span>
|
package/src/client/locales.ts
CHANGED
|
@@ -8,6 +8,11 @@ export const zh = {
|
|
|
8
8
|
retry: '重试',
|
|
9
9
|
empty: '此 profile 未配置官方 MCP 服务器(@deepseek-ai/dsh-mcp-client 行)。',
|
|
10
10
|
servers: '服务器',
|
|
11
|
+
summary: '服务器 {total} 台:已连接 {connected},错误 {errored}',
|
|
12
|
+
filterServers: '过滤服务器',
|
|
13
|
+
noMatch: '没有匹配的服务器。',
|
|
14
|
+
expandAll: '全部展开',
|
|
15
|
+
collapseAll: '全部折叠',
|
|
11
16
|
tools: '工具',
|
|
12
17
|
noTools: '未注册工具',
|
|
13
18
|
status: '状态',
|
|
@@ -37,6 +42,7 @@ export const zh = {
|
|
|
37
42
|
probeFailed: '失败',
|
|
38
43
|
probeKilled: '已取消',
|
|
39
44
|
probeStopping: '取消中',
|
|
45
|
+
probeUnknown: '未知',
|
|
40
46
|
probeNow: '探测',
|
|
41
47
|
probeReachable: '可达',
|
|
42
48
|
probeUnreachable: '不可达',
|
|
@@ -55,6 +61,11 @@ export const en = {
|
|
|
55
61
|
retry: 'Retry',
|
|
56
62
|
empty: 'This profile configures no official MCP servers (@deepseek-ai/dsh-mcp-client rows).',
|
|
57
63
|
servers: 'Servers',
|
|
64
|
+
summary: '{total} servers: {connected} connected, {errored} with errors',
|
|
65
|
+
filterServers: 'Filter servers',
|
|
66
|
+
noMatch: 'No servers match the filter.',
|
|
67
|
+
expandAll: 'Expand all',
|
|
68
|
+
collapseAll: 'Collapse all',
|
|
58
69
|
tools: 'Tools',
|
|
59
70
|
noTools: 'No tools registered',
|
|
60
71
|
status: 'Status',
|
|
@@ -84,6 +95,7 @@ export const en = {
|
|
|
84
95
|
probeFailed: 'Failed',
|
|
85
96
|
probeKilled: 'Killed',
|
|
86
97
|
probeStopping: 'Stopping',
|
|
98
|
+
probeUnknown: 'Unknown',
|
|
87
99
|
probeNow: 'Probe',
|
|
88
100
|
probeReachable: 'Reachable',
|
|
89
101
|
probeUnreachable: 'Unreachable',
|
package/src/client/present.ts
CHANGED
|
@@ -38,7 +38,17 @@ export interface PresentedProbeRow {
|
|
|
38
38
|
/** Badge tone for the probe state. */
|
|
39
39
|
readonly tone: BadgeTone
|
|
40
40
|
/** Badge code for the probe state. */
|
|
41
|
-
readonly badge: 'running' | 'completed' | 'failed' | 'killed' | 'stopping'
|
|
41
|
+
readonly badge: 'running' | 'completed' | 'failed' | 'killed' | 'stopping' | 'unknown'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Counts for the panel summary line. */
|
|
45
|
+
export interface PanelSummary {
|
|
46
|
+
/** Servers shown in the tab. */
|
|
47
|
+
readonly total: number
|
|
48
|
+
/** Servers whose connection badge reads `connected`. */
|
|
49
|
+
readonly connected: number
|
|
50
|
+
/** Servers whose connection badge reads `failed` or `exhausted`. */
|
|
51
|
+
readonly errored: number
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
/** The complete render-ready tab model. */
|
|
@@ -89,6 +99,8 @@ export function probeBadge(status: McpProbeView['status']): { badge: PresentedPr
|
|
|
89
99
|
case 'stopping': return { badge: 'stopping', tone: 'warn' }
|
|
90
100
|
case 'failed': return { badge: 'failed', tone: 'error' }
|
|
91
101
|
case 'killed': return { badge: 'killed', tone: 'muted' }
|
|
102
|
+
// Registry states outside the panel vocabulary: never throw on render.
|
|
103
|
+
default: return { badge: 'unknown', tone: 'muted' }
|
|
92
104
|
}
|
|
93
105
|
}
|
|
94
106
|
|
|
@@ -125,3 +137,39 @@ export function presentMcpPanel(snapshot: McpPanelSnapshot, now = Date.now()): P
|
|
|
125
137
|
refreshIntervalMs: snapshot.refreshIntervalMs,
|
|
126
138
|
}
|
|
127
139
|
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Count the summary facts for the tab header line. Counting is derived from
|
|
143
|
+
* the same badge codes the cards show, so the line can never disagree with
|
|
144
|
+
* the rows beneath it.
|
|
145
|
+
*
|
|
146
|
+
* @param servers - the presented server rows (typically the filtered list).
|
|
147
|
+
* @returns the summary counts.
|
|
148
|
+
*/
|
|
149
|
+
export function summarizePanel(servers: readonly PresentedServerRow[]): PanelSummary {
|
|
150
|
+
let connected = 0
|
|
151
|
+
let errored = 0
|
|
152
|
+
for (const row of servers) {
|
|
153
|
+
if (row.badge === 'connected') connected += 1
|
|
154
|
+
else if (row.badge === 'failed' || row.badge === 'exhausted') errored += 1
|
|
155
|
+
}
|
|
156
|
+
return { total: servers.length, connected, errored }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Filter server rows by a case-insensitive substring match against the
|
|
161
|
+
* server name or its display target. An empty query returns the rows
|
|
162
|
+
* unchanged (stable identity, no copies).
|
|
163
|
+
*
|
|
164
|
+
* @param servers - the presented server rows.
|
|
165
|
+
* @param query - the raw filter text.
|
|
166
|
+
* @returns the matching rows.
|
|
167
|
+
*/
|
|
168
|
+
export function filterServers(servers: readonly PresentedServerRow[], query: string): readonly PresentedServerRow[] {
|
|
169
|
+
const needle = query.trim().toLocaleLowerCase()
|
|
170
|
+
if (needle === '') return servers
|
|
171
|
+
return servers.filter(row =>
|
|
172
|
+
row.view.serverName.toLocaleLowerCase().includes(needle)
|
|
173
|
+
|| row.view.target.toLocaleLowerCase().includes(needle),
|
|
174
|
+
)
|
|
175
|
+
}
|
package/src/client/styles.ts
CHANGED
|
@@ -41,6 +41,11 @@ const PANEL_CSS = `
|
|
|
41
41
|
font: inherit;
|
|
42
42
|
cursor: pointer;
|
|
43
43
|
}
|
|
44
|
+
[data-dsh-mcp-panel] .dmcp-failure-detail {
|
|
45
|
+
margin: 0;
|
|
46
|
+
color: var(--dsw-alias-label-secondary);
|
|
47
|
+
overflow-wrap: anywhere;
|
|
48
|
+
}
|
|
44
49
|
[data-dsh-mcp-panel] .dmcp-panel {
|
|
45
50
|
display: flex;
|
|
46
51
|
flex-direction: column;
|
|
@@ -52,6 +57,33 @@ const PANEL_CSS = `
|
|
|
52
57
|
font-size: 1em;
|
|
53
58
|
color: var(--dsw-alias-label-primary);
|
|
54
59
|
}
|
|
60
|
+
[data-dsh-mcp-panel] .dmcp-summary {
|
|
61
|
+
margin: 0;
|
|
62
|
+
color: var(--dsw-alias-label-secondary);
|
|
63
|
+
}
|
|
64
|
+
[data-dsh-mcp-panel] .dmcp-toolbar {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: 8px;
|
|
68
|
+
flex-wrap: wrap;
|
|
69
|
+
}
|
|
70
|
+
[data-dsh-mcp-panel] .dmcp-server-filter {
|
|
71
|
+
flex: 1 1 180px;
|
|
72
|
+
min-width: 0;
|
|
73
|
+
}
|
|
74
|
+
[data-dsh-mcp-panel] .dmcp-action {
|
|
75
|
+
font: inherit;
|
|
76
|
+
cursor: pointer;
|
|
77
|
+
color: var(--dsw-alias-label-primary);
|
|
78
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
79
|
+
border: 1px solid var(--dsw-alias-border-l3);
|
|
80
|
+
border-radius: 4px;
|
|
81
|
+
padding: 4px 10px;
|
|
82
|
+
}
|
|
83
|
+
[data-dsh-mcp-panel] .dmcp-action:focus-visible {
|
|
84
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
85
|
+
outline-offset: -2px;
|
|
86
|
+
}
|
|
55
87
|
[data-dsh-mcp-panel] .dmcp-cards {
|
|
56
88
|
list-style: none;
|
|
57
89
|
margin: 0;
|
package/src/command.ts
CHANGED
|
@@ -34,6 +34,8 @@ export type CommandLanguage = 'en' | 'zh' | 'es' | 'pt' | 'hi'
|
|
|
34
34
|
export interface CommandMessages {
|
|
35
35
|
enabled: string
|
|
36
36
|
disabled: string
|
|
37
|
+
/** State marker for leftover `mcp__` namespaces with no configured row. */
|
|
38
|
+
unconfigured: string
|
|
37
39
|
status: string
|
|
38
40
|
reconnects: string
|
|
39
41
|
lastError: string
|
|
@@ -50,7 +52,11 @@ export interface CommandMessages {
|
|
|
50
52
|
patchIntro: (action: string, server: string, entryId: string, patchFile: string | null) => string
|
|
51
53
|
patchNoRuntimeToggle: string
|
|
52
54
|
patchReloadPath: string
|
|
55
|
+
/** Rejection for disable/enable on an unconfigured leftover namespace. */
|
|
56
|
+
noPatchForLeftover: (server: string) => string
|
|
53
57
|
usage: string
|
|
58
|
+
/** Command input hint shown in the command UI. */
|
|
59
|
+
hint: string
|
|
54
60
|
probeStarted: (server: string, jobId: string) => string
|
|
55
61
|
unknownServer: (server: string, known: string) => string
|
|
56
62
|
}
|
|
@@ -59,6 +65,7 @@ export interface CommandMessages {
|
|
|
59
65
|
export const EN_MESSAGES: CommandMessages = {
|
|
60
66
|
enabled: 'enabled',
|
|
61
67
|
disabled: 'disabled',
|
|
68
|
+
unconfigured: 'unconfigured',
|
|
62
69
|
status: 'status',
|
|
63
70
|
reconnects: 'reconnects',
|
|
64
71
|
lastError: 'last error',
|
|
@@ -76,7 +83,10 @@ export const EN_MESSAGES: CommandMessages = {
|
|
|
76
83
|
`To ${action} "${server}" (entry ${entryId}), add this line to the profile patch layer${patchFile === null ? '' : ` (${patchFile})`}:`,
|
|
77
84
|
patchNoRuntimeToggle: '@deepseek-ai/dsh-mcp-client has no runtime toggle; the Loader applies the patch on reload.',
|
|
78
85
|
patchReloadPath: 'The web surface hot-reloads cordis.patch.yml edits; other surfaces restart. This command never edits your config.',
|
|
86
|
+
noPatchForLeftover: server =>
|
|
87
|
+
`"${server}" is not a configured server — its tools come from another plugin's mcp__ namespace, so there is no row to disable or enable.`,
|
|
79
88
|
usage: 'Usage: /mcp | /mcp <server> | /mcp <server> tools | /mcp <server> disable | /mcp <server> enable | /mcp <server> probe',
|
|
89
|
+
hint: '[server] [tools|disable|enable|probe]',
|
|
80
90
|
probeStarted: (server, jobId) =>
|
|
81
91
|
`Probe started for "${server}" (background job ${jobId}). Read the result in the MCP panel: Settings → Plugins → MCP.`,
|
|
82
92
|
unknownServer: (server, known) =>
|
|
@@ -87,6 +97,7 @@ export const EN_MESSAGES: CommandMessages = {
|
|
|
87
97
|
export const ZH_MESSAGES: CommandMessages = {
|
|
88
98
|
enabled: '已启用',
|
|
89
99
|
disabled: '已停用',
|
|
100
|
+
unconfigured: '未配置',
|
|
90
101
|
status: '状态',
|
|
91
102
|
reconnects: '重连',
|
|
92
103
|
lastError: '最近错误',
|
|
@@ -106,7 +117,10 @@ export const ZH_MESSAGES: CommandMessages = {
|
|
|
106
117
|
},
|
|
107
118
|
patchNoRuntimeToggle: '@deepseek-ai/dsh-mcp-client 没有运行时开关;Loader 在重载时应用该 patch。',
|
|
108
119
|
patchReloadPath: 'web 面板会热重载 cordis.patch.yml 的修改;其他面板重启生效。本命令绝不修改你的配置。',
|
|
120
|
+
noPatchForLeftover: server =>
|
|
121
|
+
`"${server}" 不是已配置的服务器——其工具来自其他插件的 mcp__ 命名空间,没有可停用/启用的条目。`,
|
|
109
122
|
usage: '用法:/mcp | /mcp <server> | /mcp <server> tools | /mcp <server> disable | /mcp <server> enable | /mcp <server> probe',
|
|
123
|
+
hint: '[server] [tools|disable|enable|probe]',
|
|
110
124
|
probeStarted: (server, jobId) =>
|
|
111
125
|
`已对 "${server}" 启动探测(后台任务 ${jobId})。结果仅面板可见:设置 → 插件 → MCP。`,
|
|
112
126
|
unknownServer: (server, known) =>
|
|
@@ -117,6 +131,7 @@ export const ZH_MESSAGES: CommandMessages = {
|
|
|
117
131
|
export const ES_MESSAGES: CommandMessages = {
|
|
118
132
|
enabled: 'habilitado',
|
|
119
133
|
disabled: 'deshabilitado',
|
|
134
|
+
unconfigured: 'sin configurar',
|
|
120
135
|
status: 'estado',
|
|
121
136
|
reconnects: 'reconexiones',
|
|
122
137
|
lastError: 'último error',
|
|
@@ -136,7 +151,10 @@ export const ES_MESSAGES: CommandMessages = {
|
|
|
136
151
|
},
|
|
137
152
|
patchNoRuntimeToggle: '@deepseek-ai/dsh-mcp-client no tiene conmutador en tiempo de ejecución; el Loader aplica el parche al recargar.',
|
|
138
153
|
patchReloadPath: 'La superficie web recarga en caliente los cambios de cordis.patch.yml; otras superficies se reinician. Este comando nunca edita tu configuración.',
|
|
154
|
+
noPatchForLeftover: server =>
|
|
155
|
+
`"${server}" no es un servidor configurado — sus herramientas provienen del espacio mcp__ de otro plugin, así que no hay fila que deshabilitar o habilitar.`,
|
|
139
156
|
usage: 'Uso: /mcp | /mcp <server> | /mcp <server> tools | /mcp <server> disable | /mcp <server> enable | /mcp <server> probe',
|
|
157
|
+
hint: '[server] [tools|disable|enable|probe]',
|
|
140
158
|
probeStarted: (server, jobId) =>
|
|
141
159
|
`Sonda iniciada para "${server}" (tarea en segundo plano ${jobId}). Lee el resultado en el panel MCP: Ajustes → Plugins → MCP.`,
|
|
142
160
|
unknownServer: (server, known) =>
|
|
@@ -147,6 +165,7 @@ export const ES_MESSAGES: CommandMessages = {
|
|
|
147
165
|
export const PT_MESSAGES: CommandMessages = {
|
|
148
166
|
enabled: 'habilitado',
|
|
149
167
|
disabled: 'desabilitado',
|
|
168
|
+
unconfigured: 'não configurado',
|
|
150
169
|
status: 'status',
|
|
151
170
|
reconnects: 'reconexões',
|
|
152
171
|
lastError: 'último erro',
|
|
@@ -166,7 +185,10 @@ export const PT_MESSAGES: CommandMessages = {
|
|
|
166
185
|
},
|
|
167
186
|
patchNoRuntimeToggle: '@deepseek-ai/dsh-mcp-client não tem alternância em tempo de execução; o Loader aplica o patch ao recarregar.',
|
|
168
187
|
patchReloadPath: 'A superfície web recarrega em quente as edições de cordis.patch.yml; outras superfícies reiniciam. Este comando nunca edita sua configuração.',
|
|
188
|
+
noPatchForLeftover: server =>
|
|
189
|
+
`"${server}" não é um servidor configurado — suas ferramentas vêm do namespace mcp__ de outro plugin, então não há linha para desabilitar ou habilitar.`,
|
|
169
190
|
usage: 'Uso: /mcp | /mcp <server> | /mcp <server> tools | /mcp <server> disable | /mcp <server> enable | /mcp <server> probe',
|
|
191
|
+
hint: '[server] [tools|disable|enable|probe]',
|
|
170
192
|
probeStarted: (server, jobId) =>
|
|
171
193
|
`Sonda iniciada para "${server}" (tarefa em segundo plano ${jobId}). Leia o resultado no painel MCP: Configurações → Plugins → MCP.`,
|
|
172
194
|
unknownServer: (server, known) =>
|
|
@@ -177,6 +199,7 @@ export const PT_MESSAGES: CommandMessages = {
|
|
|
177
199
|
export const HI_MESSAGES: CommandMessages = {
|
|
178
200
|
enabled: 'सक्षम',
|
|
179
201
|
disabled: 'अक्षम',
|
|
202
|
+
unconfigured: 'अकॉन्फ़िगर',
|
|
180
203
|
status: 'स्थिति',
|
|
181
204
|
reconnects: 'रीकनेक्ट',
|
|
182
205
|
lastError: 'अंतिम त्रुटि',
|
|
@@ -196,7 +219,10 @@ export const HI_MESSAGES: CommandMessages = {
|
|
|
196
219
|
},
|
|
197
220
|
patchNoRuntimeToggle: '@deepseek-ai/dsh-mcp-client के पास रनटाइम टॉगल नहीं है; Loader रीलोड पर पैच लागू करता है।',
|
|
198
221
|
patchReloadPath: 'वेब सतह cordis.patch.yml के बदलाव हॉट-रीलोड करती है; अन्य सतहें रीस्टार्ट करें। यह कमांड आपका कॉन्फ़िगरेशन कभी नहीं बदलती।',
|
|
222
|
+
noPatchForLeftover: server =>
|
|
223
|
+
`"${server}" कॉन्फ़िगर किया गया सर्वर नहीं है — इसके टूल दूसरे प्लगइन के mcp__ नेमस्पेस से आते हैं, इसलिए अक्षम/सक्षम करने के लिए कोई पंक्ति नहीं है।`,
|
|
199
224
|
usage: 'उपयोग: /mcp | /mcp <server> | /mcp <server> tools | /mcp <server> disable | /mcp <server> enable | /mcp <server> probe',
|
|
225
|
+
hint: '[server] [tools|disable|enable|probe]',
|
|
200
226
|
probeStarted: (server, jobId) =>
|
|
201
227
|
`"${server}" के लिए प्रोब शुरू (बैकग्राउंड जॉब ${jobId})। परिणाम MCP पैनल में पढ़ें: सेटिंग्स → प्लगइन्स → MCP।`,
|
|
202
228
|
unknownServer: (server, known) =>
|
|
@@ -236,7 +262,10 @@ function statusText(view: McpServerView): string {
|
|
|
236
262
|
* @returns the single display line.
|
|
237
263
|
*/
|
|
238
264
|
export function renderServer(view: McpServerView, messages: CommandMessages = EN_MESSAGES): string {
|
|
239
|
-
|
|
265
|
+
// A leftover namespace (foreign mcp__ tools, no loader row) is unconfigured,
|
|
266
|
+
// not disabled — its config facts do not exist. Keep this in sync with the
|
|
267
|
+
// tab's `connectionBadge`.
|
|
268
|
+
const state = view.entryId === '' ? messages.unconfigured : view.enabled ? messages.enabled : messages.disabled
|
|
240
269
|
const details = [
|
|
241
270
|
`${messages.status}: ${statusText(view)}`,
|
|
242
271
|
`${messages.reconnects}: ${reconnectText(view)}`,
|
|
@@ -352,7 +381,7 @@ export function mcpCommand(service: McpPanelService, language: CommandLanguage =
|
|
|
352
381
|
return {
|
|
353
382
|
name: 'mcp',
|
|
354
383
|
description: 'Show MCP server status, tools, and enable/disable patch suggestions (read-only)',
|
|
355
|
-
input: { hint:
|
|
384
|
+
input: { hint: messages.hint },
|
|
356
385
|
handler: ({ rawInput }) => {
|
|
357
386
|
const parsed = parseMcpArgs(rawInput)
|
|
358
387
|
if (parsed.kind === 'usage') return { kind: 'error', text: messages.usage }
|
|
@@ -368,8 +397,14 @@ export function mcpCommand(service: McpPanelService, language: CommandLanguage =
|
|
|
368
397
|
}
|
|
369
398
|
switch (parsed.action) {
|
|
370
399
|
case 'tools': return { kind: 'success', text: renderTools(view, messages) }
|
|
371
|
-
case 'disable':
|
|
372
|
-
case 'enable':
|
|
400
|
+
case 'disable':
|
|
401
|
+
case 'enable': {
|
|
402
|
+
// Leftover namespaces have no loader row: a patch suggestion with an
|
|
403
|
+
// empty entry id would be malformed, so refuse instead of emitting
|
|
404
|
+
// `- set: { id: , … }`.
|
|
405
|
+
if (view.entryId === '') return { kind: 'error', text: messages.noPatchForLeftover(parsed.server) }
|
|
406
|
+
return { kind: 'success', text: renderPatchSuggestion(view, parsed.action, snapshot.patchFile, messages) }
|
|
407
|
+
}
|
|
373
408
|
case 'probe': {
|
|
374
409
|
// The service throws for stdio rows and for a missing job registry;
|
|
375
410
|
// the command reports those as errors without touching any config.
|
package/src/probe.ts
CHANGED
|
@@ -31,7 +31,7 @@ const INITIALIZE_PROTOCOL_VERSION = '2024-11-05'
|
|
|
31
31
|
/** MCP clientInfo facts; protocol constants, not configuration. Exported so the
|
|
32
32
|
* version-consistency tripwire (`tests/version.spec.ts`) can assert the
|
|
33
33
|
* advertised version tracks the package version. */
|
|
34
|
-
export const PROBE_CLIENT_INFO = { name: 'dsh-mcp-panel', version: '0.
|
|
34
|
+
export const PROBE_CLIENT_INFO = { name: 'dsh-mcp-panel', version: '0.3.0' }
|
|
35
35
|
|
|
36
36
|
/** One settled probe: outcome status plus a sanitized one-line detail. */
|
|
37
37
|
export interface ProbeOutcome {
|