@hirohsu/user-web-feedback 2.6.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/LICENSE +21 -0
- package/README.md +953 -0
- package/dist/cli.cjs +95778 -0
- package/dist/index.cjs +92818 -0
- package/dist/static/app.js +385 -0
- package/dist/static/components/navbar.css +406 -0
- package/dist/static/components/navbar.html +49 -0
- package/dist/static/components/navbar.js +211 -0
- package/dist/static/dashboard.css +495 -0
- package/dist/static/dashboard.html +95 -0
- package/dist/static/dashboard.js +540 -0
- package/dist/static/favicon.svg +27 -0
- package/dist/static/index.html +541 -0
- package/dist/static/logs.html +376 -0
- package/dist/static/logs.js +442 -0
- package/dist/static/mcp-settings.html +797 -0
- package/dist/static/mcp-settings.js +884 -0
- package/dist/static/modules/app-core.js +124 -0
- package/dist/static/modules/conversation-panel.js +247 -0
- package/dist/static/modules/feedback-handler.js +1420 -0
- package/dist/static/modules/image-handler.js +155 -0
- package/dist/static/modules/log-viewer.js +296 -0
- package/dist/static/modules/mcp-manager.js +474 -0
- package/dist/static/modules/prompt-manager.js +364 -0
- package/dist/static/modules/settings-manager.js +299 -0
- package/dist/static/modules/socket-manager.js +170 -0
- package/dist/static/modules/state-manager.js +352 -0
- package/dist/static/modules/timer-controller.js +243 -0
- package/dist/static/modules/ui-helpers.js +246 -0
- package/dist/static/settings.html +355 -0
- package/dist/static/settings.js +425 -0
- package/dist/static/socket.io.min.js +7 -0
- package/dist/static/style.css +2157 -0
- package/dist/static/terminals.html +357 -0
- package/dist/static/terminals.js +321 -0
- package/package.json +91 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcp-manager.js
|
|
3
|
+
* MCP Servers 管理模組
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
getMcpServers,
|
|
8
|
+
setMcpServers,
|
|
9
|
+
getEditingMcpServerId,
|
|
10
|
+
setEditingMcpServerId,
|
|
11
|
+
findMcpServerById,
|
|
12
|
+
} from "./state-manager.js";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
showToast,
|
|
16
|
+
showLoadingOverlay,
|
|
17
|
+
hideLoadingOverlay,
|
|
18
|
+
escapeHtml,
|
|
19
|
+
} from "./ui-helpers.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 載入 MCP Servers
|
|
23
|
+
*/
|
|
24
|
+
export async function loadMCPServers() {
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetch("/api/mcp-servers");
|
|
27
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
28
|
+
const data = await response.json();
|
|
29
|
+
if (data.success) {
|
|
30
|
+
setMcpServers(data.servers || []);
|
|
31
|
+
renderMCPServerList();
|
|
32
|
+
}
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error("載入 MCP Servers 失敗:", error);
|
|
35
|
+
showToast("error", "錯誤", "載入 MCP Servers 失敗");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 渲染 MCP Server 列表
|
|
41
|
+
*/
|
|
42
|
+
export function renderMCPServerList() {
|
|
43
|
+
const container = document.getElementById("mcpServerList");
|
|
44
|
+
const mcpServers = getMcpServers();
|
|
45
|
+
|
|
46
|
+
if (!mcpServers || mcpServers.length === 0) {
|
|
47
|
+
container.innerHTML = `
|
|
48
|
+
<div class="placeholder">
|
|
49
|
+
<span class="icon">🔌</span>
|
|
50
|
+
<p>尚無 MCP Server</p>
|
|
51
|
+
</div>
|
|
52
|
+
`;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
container.innerHTML = mcpServers
|
|
57
|
+
.map((server) => {
|
|
58
|
+
const state = server.state || { status: "disconnected", tools: [] };
|
|
59
|
+
const toolsCount = state.tools?.length || 0;
|
|
60
|
+
const statusText = getStatusText(state.status);
|
|
61
|
+
|
|
62
|
+
return `
|
|
63
|
+
<div class="mcp-server-item" data-id="${server.id}">
|
|
64
|
+
<div class="mcp-server-status ${
|
|
65
|
+
state.status
|
|
66
|
+
}" title="${statusText}"></div>
|
|
67
|
+
<div class="mcp-server-info">
|
|
68
|
+
<div class="mcp-server-name">${escapeHtml(server.name)}</div>
|
|
69
|
+
<div class="mcp-server-details">
|
|
70
|
+
<span class="mcp-server-transport">${server.transport}</span>
|
|
71
|
+
${
|
|
72
|
+
state.status === "connected"
|
|
73
|
+
? `<span class="mcp-server-tools-count">${toolsCount} 工具</span>`
|
|
74
|
+
: ""
|
|
75
|
+
}
|
|
76
|
+
${
|
|
77
|
+
!server.enabled
|
|
78
|
+
? '<span style="color: var(--text-muted)">已停用</span>'
|
|
79
|
+
: ""
|
|
80
|
+
}
|
|
81
|
+
</div>
|
|
82
|
+
${
|
|
83
|
+
state.error
|
|
84
|
+
? `<div class="mcp-server-error">錯誤: ${escapeHtml(
|
|
85
|
+
state.error
|
|
86
|
+
)}</div>`
|
|
87
|
+
: ""
|
|
88
|
+
}
|
|
89
|
+
${
|
|
90
|
+
state.status === "connected" && toolsCount > 0
|
|
91
|
+
? renderToolsList(state.tools)
|
|
92
|
+
: ""
|
|
93
|
+
}
|
|
94
|
+
</div>
|
|
95
|
+
<div class="mcp-server-actions">
|
|
96
|
+
${
|
|
97
|
+
state.status === "connected"
|
|
98
|
+
? `<button class="btn btn-ghost btn-disconnect" onclick="disconnectMCPServer(${server.id})" title="斷開">🔌</button>`
|
|
99
|
+
: `<button class="btn btn-ghost btn-connect" onclick="connectMCPServer(${
|
|
100
|
+
server.id
|
|
101
|
+
})" title="連接" ${
|
|
102
|
+
!server.enabled ? "disabled" : ""
|
|
103
|
+
}>🔗</button>`
|
|
104
|
+
}
|
|
105
|
+
<button class="btn btn-ghost btn-edit" onclick="editMCPServer(${
|
|
106
|
+
server.id
|
|
107
|
+
})" title="編輯">✏️</button>
|
|
108
|
+
<button class="btn btn-ghost btn-delete" onclick="deleteMCPServerConfirm(${
|
|
109
|
+
server.id
|
|
110
|
+
})" title="刪除">🗑️</button>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
`;
|
|
114
|
+
})
|
|
115
|
+
.join("");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 渲染工具列表
|
|
120
|
+
*/
|
|
121
|
+
function renderToolsList(tools) {
|
|
122
|
+
if (!tools || tools.length === 0) return "";
|
|
123
|
+
|
|
124
|
+
const displayTools = tools.slice(0, 5);
|
|
125
|
+
const remaining = tools.length - 5;
|
|
126
|
+
|
|
127
|
+
return `
|
|
128
|
+
<div class="mcp-tools-list">
|
|
129
|
+
${displayTools
|
|
130
|
+
.map(
|
|
131
|
+
(tool) => `
|
|
132
|
+
<div class="mcp-tool-item">
|
|
133
|
+
<span class="mcp-tool-name">${escapeHtml(tool.name)}</span>
|
|
134
|
+
<span class="mcp-tool-desc">${escapeHtml(
|
|
135
|
+
tool.description || ""
|
|
136
|
+
)}</span>
|
|
137
|
+
</div>
|
|
138
|
+
`
|
|
139
|
+
)
|
|
140
|
+
.join("")}
|
|
141
|
+
${
|
|
142
|
+
remaining > 0
|
|
143
|
+
? `<div class="mcp-tool-item" style="color: var(--text-muted)">...還有 ${remaining} 個工具</div>`
|
|
144
|
+
: ""
|
|
145
|
+
}
|
|
146
|
+
</div>
|
|
147
|
+
`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 取得狀態文字
|
|
152
|
+
*/
|
|
153
|
+
function getStatusText(status) {
|
|
154
|
+
const texts = {
|
|
155
|
+
disconnected: "未連接",
|
|
156
|
+
connecting: "連接中...",
|
|
157
|
+
connected: "已連接",
|
|
158
|
+
error: "連接錯誤",
|
|
159
|
+
};
|
|
160
|
+
return texts[status] || status;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* 開啟 MCP Servers 彈窗
|
|
165
|
+
*/
|
|
166
|
+
export function openMCPServersModal() {
|
|
167
|
+
document.getElementById("mcpServersModal").classList.add("show");
|
|
168
|
+
loadMCPServers();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* 關閉 MCP Servers 彈窗
|
|
173
|
+
*/
|
|
174
|
+
export function closeMCPServersModal() {
|
|
175
|
+
document.getElementById("mcpServersModal").classList.remove("show");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 開啟 MCP Server 編輯彈窗
|
|
180
|
+
*/
|
|
181
|
+
export function openMCPServerEditModal(server = null) {
|
|
182
|
+
setEditingMcpServerId(server?.id || null);
|
|
183
|
+
|
|
184
|
+
document.getElementById("mcpServerEditTitle").textContent = server
|
|
185
|
+
? "編輯 MCP Server"
|
|
186
|
+
: "新增 MCP Server";
|
|
187
|
+
document.getElementById("mcpServerId").value = server?.id || "";
|
|
188
|
+
document.getElementById("mcpServerName").value = server?.name || "";
|
|
189
|
+
document.getElementById("mcpServerTransport").value =
|
|
190
|
+
server?.transport || "stdio";
|
|
191
|
+
document.getElementById("mcpServerCommand").value = server?.command || "";
|
|
192
|
+
document.getElementById("mcpServerArgs").value = (server?.args || []).join(
|
|
193
|
+
"\n"
|
|
194
|
+
);
|
|
195
|
+
document.getElementById("mcpServerEnv").value = server?.env
|
|
196
|
+
? Object.entries(server.env)
|
|
197
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
198
|
+
.join("\n")
|
|
199
|
+
: "";
|
|
200
|
+
document.getElementById("mcpServerUrl").value = server?.url || "";
|
|
201
|
+
document.getElementById("mcpServerEnabled").checked =
|
|
202
|
+
server?.enabled !== false;
|
|
203
|
+
|
|
204
|
+
onTransportChange();
|
|
205
|
+
document.getElementById("mcpServerEditModal").classList.add("show");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* 關閉 MCP Server 編輯彈窗
|
|
210
|
+
*/
|
|
211
|
+
export function closeMCPServerEditModal() {
|
|
212
|
+
document.getElementById("mcpServerEditModal").classList.remove("show");
|
|
213
|
+
setEditingMcpServerId(null);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* 傳輸方式變更處理
|
|
218
|
+
*/
|
|
219
|
+
export function onTransportChange() {
|
|
220
|
+
const transport = document.getElementById("mcpServerTransport").value;
|
|
221
|
+
const stdioSettings = document.getElementById("stdioSettings");
|
|
222
|
+
const httpSettings = document.getElementById("httpSettings");
|
|
223
|
+
|
|
224
|
+
if (transport === "stdio") {
|
|
225
|
+
stdioSettings.style.display = "block";
|
|
226
|
+
httpSettings.style.display = "none";
|
|
227
|
+
} else {
|
|
228
|
+
stdioSettings.style.display = "none";
|
|
229
|
+
httpSettings.style.display = "block";
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* 儲存 MCP Server
|
|
235
|
+
*/
|
|
236
|
+
export async function saveMCPServer() {
|
|
237
|
+
const id = document.getElementById("mcpServerId").value;
|
|
238
|
+
const name = document.getElementById("mcpServerName").value.trim();
|
|
239
|
+
const transport = document.getElementById("mcpServerTransport").value;
|
|
240
|
+
const command = document.getElementById("mcpServerCommand").value.trim();
|
|
241
|
+
const argsText = document.getElementById("mcpServerArgs").value.trim();
|
|
242
|
+
const envText = document.getElementById("mcpServerEnv").value.trim();
|
|
243
|
+
const url = document.getElementById("mcpServerUrl").value.trim();
|
|
244
|
+
const enabled = document.getElementById("mcpServerEnabled").checked;
|
|
245
|
+
|
|
246
|
+
if (!name) {
|
|
247
|
+
showToast("error", "錯誤", "請輸入名稱");
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (transport === "stdio" && !command) {
|
|
252
|
+
showToast("error", "錯誤", "stdio 傳輸方式需要指定命令");
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if ((transport === "sse" || transport === "streamable-http") && !url) {
|
|
257
|
+
showToast("error", "錯誤", `${transport} 傳輸方式需要指定 URL`);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const args = argsText
|
|
262
|
+
? argsText.split("\n").filter((a) => a.trim())
|
|
263
|
+
: undefined;
|
|
264
|
+
const env = envText
|
|
265
|
+
? Object.fromEntries(
|
|
266
|
+
envText
|
|
267
|
+
.split("\n")
|
|
268
|
+
.filter((line) => line.includes("="))
|
|
269
|
+
.map((line) => {
|
|
270
|
+
const idx = line.indexOf("=");
|
|
271
|
+
return [
|
|
272
|
+
line.substring(0, idx).trim(),
|
|
273
|
+
line.substring(idx + 1).trim(),
|
|
274
|
+
];
|
|
275
|
+
})
|
|
276
|
+
)
|
|
277
|
+
: undefined;
|
|
278
|
+
|
|
279
|
+
const data = {
|
|
280
|
+
name,
|
|
281
|
+
transport,
|
|
282
|
+
command: transport === "stdio" ? command : undefined,
|
|
283
|
+
args: transport === "stdio" ? args : undefined,
|
|
284
|
+
env: transport === "stdio" ? env : undefined,
|
|
285
|
+
url: transport !== "stdio" ? url : undefined,
|
|
286
|
+
enabled,
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
try {
|
|
290
|
+
showLoadingOverlay("儲存中...");
|
|
291
|
+
|
|
292
|
+
const response = await fetch(
|
|
293
|
+
id ? `/api/mcp-servers/${id}` : "/api/mcp-servers",
|
|
294
|
+
{
|
|
295
|
+
method: id ? "PUT" : "POST",
|
|
296
|
+
headers: { "Content-Type": "application/json" },
|
|
297
|
+
body: JSON.stringify(data),
|
|
298
|
+
}
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
302
|
+
|
|
303
|
+
const result = await response.json();
|
|
304
|
+
if (result.success) {
|
|
305
|
+
showToast(
|
|
306
|
+
"success",
|
|
307
|
+
"成功",
|
|
308
|
+
id ? "MCP Server 已更新" : "MCP Server 已建立"
|
|
309
|
+
);
|
|
310
|
+
closeMCPServerEditModal();
|
|
311
|
+
await loadMCPServers();
|
|
312
|
+
} else {
|
|
313
|
+
throw new Error(result.error || "儲存失敗");
|
|
314
|
+
}
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error("儲存 MCP Server 失敗:", error);
|
|
317
|
+
showToast("error", "錯誤", error.message);
|
|
318
|
+
} finally {
|
|
319
|
+
hideLoadingOverlay();
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* 連接 MCP Server
|
|
325
|
+
*/
|
|
326
|
+
export async function connectMCPServer(id) {
|
|
327
|
+
try {
|
|
328
|
+
showLoadingOverlay("連接中...");
|
|
329
|
+
const response = await fetch(`/api/mcp-servers/${id}/connect`, {
|
|
330
|
+
method: "POST",
|
|
331
|
+
});
|
|
332
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
333
|
+
|
|
334
|
+
const result = await response.json();
|
|
335
|
+
if (result.success) {
|
|
336
|
+
showToast("success", "成功", "MCP Server 已連接");
|
|
337
|
+
} else {
|
|
338
|
+
showToast("warning", "連接失敗", result.state?.error || "未知錯誤");
|
|
339
|
+
}
|
|
340
|
+
await loadMCPServers();
|
|
341
|
+
} catch (error) {
|
|
342
|
+
console.error("連接 MCP Server 失敗:", error);
|
|
343
|
+
showToast("error", "錯誤", error.message);
|
|
344
|
+
} finally {
|
|
345
|
+
hideLoadingOverlay();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* 斷開 MCP Server
|
|
351
|
+
*/
|
|
352
|
+
export async function disconnectMCPServer(id) {
|
|
353
|
+
try {
|
|
354
|
+
showLoadingOverlay("斷開中...");
|
|
355
|
+
const response = await fetch(`/api/mcp-servers/${id}/disconnect`, {
|
|
356
|
+
method: "POST",
|
|
357
|
+
});
|
|
358
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
359
|
+
|
|
360
|
+
showToast("success", "成功", "MCP Server 已斷開");
|
|
361
|
+
await loadMCPServers();
|
|
362
|
+
} catch (error) {
|
|
363
|
+
console.error("斷開 MCP Server 失敗:", error);
|
|
364
|
+
showToast("error", "錯誤", error.message);
|
|
365
|
+
} finally {
|
|
366
|
+
hideLoadingOverlay();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* 編輯 MCP Server
|
|
372
|
+
*/
|
|
373
|
+
export function editMCPServer(id) {
|
|
374
|
+
const server = findMcpServerById(id);
|
|
375
|
+
if (server) {
|
|
376
|
+
openMCPServerEditModal(server);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* 刪除 MCP Server 確認
|
|
382
|
+
*/
|
|
383
|
+
export async function deleteMCPServerConfirm(id) {
|
|
384
|
+
const server = findMcpServerById(id);
|
|
385
|
+
if (!server) return;
|
|
386
|
+
|
|
387
|
+
if (!confirm(`確定要刪除 MCP Server "${server.name}" 嗎?此操作無法復原。`)) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
try {
|
|
392
|
+
showLoadingOverlay("刪除中...");
|
|
393
|
+
const response = await fetch(`/api/mcp-servers/${id}`, {
|
|
394
|
+
method: "DELETE",
|
|
395
|
+
});
|
|
396
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
397
|
+
|
|
398
|
+
showToast("success", "成功", "MCP Server 已刪除");
|
|
399
|
+
await loadMCPServers();
|
|
400
|
+
} catch (error) {
|
|
401
|
+
console.error("刪除 MCP Server 失敗:", error);
|
|
402
|
+
showToast("error", "錯誤", error.message);
|
|
403
|
+
} finally {
|
|
404
|
+
hideLoadingOverlay();
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* 連接所有 MCP Servers
|
|
410
|
+
*/
|
|
411
|
+
export async function connectAllMCPServers() {
|
|
412
|
+
try {
|
|
413
|
+
showLoadingOverlay("連接所有 MCP Servers...");
|
|
414
|
+
const response = await fetch("/api/mcp-servers/connect-all", {
|
|
415
|
+
method: "POST",
|
|
416
|
+
});
|
|
417
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
418
|
+
|
|
419
|
+
const result = await response.json();
|
|
420
|
+
if (result.success) {
|
|
421
|
+
const succeeded = result.results.filter((r) => r.success).length;
|
|
422
|
+
const total = result.results.length;
|
|
423
|
+
showToast(
|
|
424
|
+
"success",
|
|
425
|
+
"完成",
|
|
426
|
+
`已連接 ${succeeded}/${total} 個 MCP Servers`
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
await loadMCPServers();
|
|
430
|
+
} catch (error) {
|
|
431
|
+
console.error("連接所有 MCP Servers 失敗:", error);
|
|
432
|
+
showToast("error", "錯誤", error.message);
|
|
433
|
+
} finally {
|
|
434
|
+
hideLoadingOverlay();
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* 斷開所有 MCP Servers
|
|
440
|
+
*/
|
|
441
|
+
export async function disconnectAllMCPServers() {
|
|
442
|
+
try {
|
|
443
|
+
showLoadingOverlay("斷開所有 MCP Servers...");
|
|
444
|
+
const response = await fetch("/api/mcp-servers/disconnect-all", {
|
|
445
|
+
method: "POST",
|
|
446
|
+
});
|
|
447
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
448
|
+
|
|
449
|
+
showToast("success", "成功", "已斷開所有 MCP Servers");
|
|
450
|
+
await loadMCPServers();
|
|
451
|
+
} catch (error) {
|
|
452
|
+
console.error("斷開所有 MCP Servers 失敗:", error);
|
|
453
|
+
showToast("error", "錯誤", error.message);
|
|
454
|
+
} finally {
|
|
455
|
+
hideLoadingOverlay();
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export default {
|
|
460
|
+
loadMCPServers,
|
|
461
|
+
renderMCPServerList,
|
|
462
|
+
openMCPServersModal,
|
|
463
|
+
closeMCPServersModal,
|
|
464
|
+
openMCPServerEditModal,
|
|
465
|
+
closeMCPServerEditModal,
|
|
466
|
+
onTransportChange,
|
|
467
|
+
saveMCPServer,
|
|
468
|
+
connectMCPServer,
|
|
469
|
+
disconnectMCPServer,
|
|
470
|
+
editMCPServer,
|
|
471
|
+
deleteMCPServerConfirm,
|
|
472
|
+
connectAllMCPServers,
|
|
473
|
+
disconnectAllMCPServers,
|
|
474
|
+
};
|