@kwonye/mcpx 0.1.93 → 0.1.94
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/dist/adapters/cline.d.ts.map +1 -1
- package/dist/adapters/codex.d.ts.map +1 -1
- package/dist/adapters/kiro.d.ts.map +1 -1
- package/dist/adapters/opencode.d.ts.map +1 -1
- package/dist/adapters/utils/index.d.ts +11 -3
- package/dist/adapters/utils/index.d.ts.map +1 -1
- package/dist/{cli-y7ba5qvr.js → cli-154shqmt.js} +126 -68
- package/dist/{cli-qvkpwy9w.js → cli-9fmn9y72.js} +36 -17
- package/dist/{cli-np0wwh6m.js → cli-csfsg1yf.js} +78 -4
- package/dist/{cli-m2645syd.js → cli-mxmgxdm2.js} +127 -69
- package/dist/{cli-kwyp9ywh.js → cli-n8vt375e.js} +306 -172
- package/dist/{cli-8vxva0cb.js → cli-tk8bggg5.js} +81 -8
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +45 -21
- package/dist/{config-2s5nsm2g.js → config-dtc3c79c.js} +6 -2
- package/dist/core/config-repair.d.ts.map +1 -1
- package/dist/core/config-store.d.ts +3 -0
- package/dist/core/config-store.d.ts.map +1 -0
- package/dist/core/config.d.ts +13 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/daemon.d.ts +1 -1
- package/dist/core/daemon.d.ts.map +1 -1
- package/dist/core/errors.d.ts +18 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/index.d.ts +5 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +81 -6
- package/dist/core/oauth.d.ts.map +1 -1
- package/dist/core/plugin-manager.d.ts.map +1 -1
- package/dist/core/plugin-projections.d.ts +6 -2
- package/dist/core/plugin-projections.d.ts.map +1 -1
- package/dist/core/registry.d.ts +4 -1
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/secrets.d.ts.map +1 -1
- package/dist/core/server-auth.d.ts.map +1 -1
- package/dist/core/status.d.ts +1 -0
- package/dist/core/status.d.ts.map +1 -1
- package/dist/core/sync.d.ts +19 -2
- package/dist/core/sync.d.ts.map +1 -1
- package/dist/gateway/server.d.ts +4 -1
- package/dist/gateway/server.d.ts.map +1 -1
- package/dist/{plugin-manager-1sc4b6am.js → plugin-manager-1sjwfnah.js} +4 -4
- package/dist/{registry-mztfy0cz.js → registry-n12thgf2.js} +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
saveConfig
|
|
3
|
-
} from "./cli-np0wwh6m.js";
|
|
4
1
|
import {
|
|
5
2
|
ensureGatewayToken
|
|
6
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-tk8bggg5.js";
|
|
7
4
|
import {
|
|
8
5
|
ensureDir,
|
|
9
6
|
getManagedIndexPath,
|
|
@@ -75,10 +72,10 @@ function loadOwnership(targetDir) {
|
|
|
75
72
|
}
|
|
76
73
|
}
|
|
77
74
|
function saveOwnership(targetDir, manifest) {
|
|
75
|
+
ensureDir(targetDir);
|
|
78
76
|
fs2.writeFileSync(path2.join(targetDir, OWNERSHIP_MANIFEST), JSON.stringify(manifest, null, 2));
|
|
79
77
|
}
|
|
80
78
|
function recordOwned(targetDir, pluginId, paths) {
|
|
81
|
-
ensureDir(targetDir);
|
|
82
79
|
const manifest = loadOwnership(targetDir);
|
|
83
80
|
manifest.plugins[pluginId] = {
|
|
84
81
|
pluginId,
|
|
@@ -114,16 +111,42 @@ function pruneAllPluginProjections(targetDir) {
|
|
|
114
111
|
prunePluginProjections(targetDir, pluginId);
|
|
115
112
|
}
|
|
116
113
|
}
|
|
114
|
+
function pruneUnlistedPlugins(targetDir, keepPluginIds) {
|
|
115
|
+
const manifest = loadOwnership(targetDir);
|
|
116
|
+
const keep = new Set(keepPluginIds);
|
|
117
|
+
for (const [pluginId] of Object.entries(manifest.plugins)) {
|
|
118
|
+
if (!keep.has(pluginId)) {
|
|
119
|
+
prunePluginProjections(targetDir, pluginId);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
117
123
|
function nsName(pluginName, id) {
|
|
118
124
|
return `${pluginName}__${id}`;
|
|
119
125
|
}
|
|
126
|
+
function isComponentApproved(plugin, component) {
|
|
127
|
+
const approval = plugin.approvals?.[component];
|
|
128
|
+
if (approval === false)
|
|
129
|
+
return false;
|
|
130
|
+
if (approval === true)
|
|
131
|
+
return true;
|
|
132
|
+
if (component === "hooks")
|
|
133
|
+
return false;
|
|
134
|
+
if (component === "mcpServers")
|
|
135
|
+
return plugin.components.mcpServers;
|
|
136
|
+
return plugin.components[component] ?? false;
|
|
137
|
+
}
|
|
120
138
|
function syncClaude(plugins) {
|
|
121
139
|
const targetBase = path2.join(homeDir(), ".claude", "skills");
|
|
122
140
|
const projectedDirs = [];
|
|
123
141
|
const unsupported = [];
|
|
142
|
+
const skippedUnapproved = [];
|
|
124
143
|
for (const plugin of plugins) {
|
|
125
144
|
if (!plugin.enabled)
|
|
126
145
|
continue;
|
|
146
|
+
if (!isComponentApproved(plugin, "skills")) {
|
|
147
|
+
skippedUnapproved.push(`${plugin.pluginName}:skills`);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
127
150
|
const targetDir = path2.join(targetBase, plugin.pluginName);
|
|
128
151
|
ensureDir(targetDir);
|
|
129
152
|
const mcpJsonSrc = path2.join(plugin.pluginRoot, ".mcp.json");
|
|
@@ -156,18 +179,20 @@ function syncCodex(plugins) {
|
|
|
156
179
|
const projectedDirs = [];
|
|
157
180
|
const unsupported = ["hooks", "agents"];
|
|
158
181
|
for (const plugin of plugins) {
|
|
159
|
-
if (!plugin.enabled
|
|
182
|
+
if (!plugin.enabled)
|
|
160
183
|
continue;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
184
|
+
if (plugin.components.skills && isComponentApproved(plugin, "skills")) {
|
|
185
|
+
ensureDir(targetBase);
|
|
186
|
+
const owned = [];
|
|
187
|
+
for (const skill of plugin.skills) {
|
|
188
|
+
const targetDir = path2.join(targetBase, nsName(plugin.pluginName, skill.id));
|
|
189
|
+
ensureDir(targetDir);
|
|
190
|
+
copyFileOrDir(skill.path, path2.join(targetDir, "SKILL.md"));
|
|
191
|
+
owned.push(nsName(plugin.pluginName, skill.id));
|
|
192
|
+
projectedDirs.push(targetDir);
|
|
193
|
+
}
|
|
194
|
+
recordOwned(targetBase, plugin.pluginId, owned);
|
|
169
195
|
}
|
|
170
|
-
recordOwned(targetBase, plugin.pluginId, owned);
|
|
171
196
|
}
|
|
172
197
|
return {
|
|
173
198
|
clientId: "codex",
|
|
@@ -186,7 +211,7 @@ function syncCursor(plugins) {
|
|
|
186
211
|
for (const plugin of plugins) {
|
|
187
212
|
if (!plugin.enabled)
|
|
188
213
|
continue;
|
|
189
|
-
if (plugin.components.skills) {
|
|
214
|
+
if (plugin.components.skills && isComponentApproved(plugin, "skills")) {
|
|
190
215
|
ensureDir(skillsBase);
|
|
191
216
|
for (const skill of plugin.skills) {
|
|
192
217
|
const targetDir = path2.join(skillsBase, nsName(plugin.pluginName, skill.id));
|
|
@@ -196,7 +221,7 @@ function syncCursor(plugins) {
|
|
|
196
221
|
projectedDirs.push(targetDir);
|
|
197
222
|
}
|
|
198
223
|
}
|
|
199
|
-
if (plugin.components.commands) {
|
|
224
|
+
if (plugin.components.commands && isComponentApproved(plugin, "commands")) {
|
|
200
225
|
ensureDir(commandsBase);
|
|
201
226
|
for (const cmd of plugin.commands) {
|
|
202
227
|
const targetPath = path2.join(commandsBase, `${nsName(plugin.pluginName, cmd.id)}.md`);
|
|
@@ -222,18 +247,20 @@ function syncVsCode(plugins) {
|
|
|
222
247
|
const projectedDirs = [];
|
|
223
248
|
const unsupported = ["hooks", "agents"];
|
|
224
249
|
for (const plugin of plugins) {
|
|
225
|
-
if (!plugin.enabled
|
|
250
|
+
if (!plugin.enabled)
|
|
226
251
|
continue;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
252
|
+
if (plugin.components.skills && isComponentApproved(plugin, "skills")) {
|
|
253
|
+
ensureDir(skillsBase);
|
|
254
|
+
const owned = [];
|
|
255
|
+
for (const skill of plugin.skills) {
|
|
256
|
+
const targetDir = path2.join(skillsBase, nsName(plugin.pluginName, skill.id));
|
|
257
|
+
ensureDir(targetDir);
|
|
258
|
+
copyFileOrDir(skill.path, path2.join(targetDir, "SKILL.md"));
|
|
259
|
+
owned.push(nsName(plugin.pluginName, skill.id));
|
|
260
|
+
projectedDirs.push(targetDir);
|
|
261
|
+
}
|
|
262
|
+
recordOwned(skillsBase, plugin.pluginId, owned);
|
|
235
263
|
}
|
|
236
|
-
recordOwned(skillsBase, plugin.pluginId, owned);
|
|
237
264
|
}
|
|
238
265
|
return {
|
|
239
266
|
clientId: "vscode",
|
|
@@ -242,117 +269,146 @@ function syncVsCode(plugins) {
|
|
|
242
269
|
unsupported
|
|
243
270
|
};
|
|
244
271
|
}
|
|
245
|
-
function
|
|
246
|
-
const
|
|
272
|
+
function syncQwen(plugins) {
|
|
273
|
+
const targetBase = path2.join(homeDir(), ".qwen", "skills");
|
|
247
274
|
const projectedDirs = [];
|
|
248
275
|
const unsupported = ["hooks", "agents", "commands"];
|
|
249
276
|
for (const plugin of plugins) {
|
|
250
|
-
if (!plugin.enabled
|
|
277
|
+
if (!plugin.enabled)
|
|
251
278
|
continue;
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
279
|
+
if (plugin.components.skills && isComponentApproved(plugin, "skills")) {
|
|
280
|
+
ensureDir(targetBase);
|
|
281
|
+
const owned = [];
|
|
282
|
+
for (const skill of plugin.skills) {
|
|
283
|
+
const targetDir = path2.join(targetBase, nsName(plugin.pluginName, skill.id));
|
|
284
|
+
ensureDir(targetDir);
|
|
285
|
+
copyFileOrDir(skill.path, path2.join(targetDir, "SKILL.md"));
|
|
286
|
+
owned.push(nsName(plugin.pluginName, skill.id));
|
|
287
|
+
projectedDirs.push(targetDir);
|
|
288
|
+
}
|
|
289
|
+
recordOwned(targetBase, plugin.pluginId, owned);
|
|
259
290
|
}
|
|
260
|
-
recordOwned(skillsBase, plugin.pluginId, owned);
|
|
261
291
|
}
|
|
262
292
|
return {
|
|
263
|
-
clientId: "
|
|
293
|
+
clientId: "qwen",
|
|
264
294
|
status: "SYNCED",
|
|
265
295
|
projectedDirs,
|
|
266
296
|
unsupported
|
|
267
297
|
};
|
|
268
298
|
}
|
|
269
|
-
function
|
|
270
|
-
const
|
|
271
|
-
const commandsBase = path2.join(homeDir(), ".qwen", "commands");
|
|
299
|
+
function syncCline(plugins) {
|
|
300
|
+
const targetBase = path2.join(homeDir(), ".config", "cline", "skills");
|
|
272
301
|
const projectedDirs = [];
|
|
273
|
-
const unsupported = ["hooks", "agents"];
|
|
274
|
-
const ownedSkills = [];
|
|
275
|
-
const ownedCommands = [];
|
|
302
|
+
const unsupported = ["hooks", "agents", "commands"];
|
|
276
303
|
for (const plugin of plugins) {
|
|
277
304
|
if (!plugin.enabled)
|
|
278
305
|
continue;
|
|
279
|
-
if (plugin.components.skills) {
|
|
280
|
-
ensureDir(
|
|
306
|
+
if (plugin.components.skills && isComponentApproved(plugin, "skills")) {
|
|
307
|
+
ensureDir(targetBase);
|
|
308
|
+
const owned = [];
|
|
281
309
|
for (const skill of plugin.skills) {
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
310
|
+
const targetDir = path2.join(targetBase, nsName(plugin.pluginName, skill.id));
|
|
311
|
+
ensureDir(targetDir);
|
|
312
|
+
copyFileOrDir(skill.path, path2.join(targetDir, "SKILL.md"));
|
|
313
|
+
owned.push(nsName(plugin.pluginName, skill.id));
|
|
314
|
+
projectedDirs.push(targetDir);
|
|
286
315
|
}
|
|
316
|
+
recordOwned(targetBase, plugin.pluginId, owned);
|
|
287
317
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
clientId: "cline",
|
|
321
|
+
status: "SYNCED",
|
|
322
|
+
projectedDirs,
|
|
323
|
+
unsupported
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function syncKiro(plugins) {
|
|
327
|
+
const targetBase = path2.join(homeDir(), ".kiro", "skills");
|
|
328
|
+
const projectedDirs = [];
|
|
329
|
+
const unsupported = ["hooks", "agents", "commands"];
|
|
330
|
+
for (const plugin of plugins) {
|
|
331
|
+
if (!plugin.enabled)
|
|
332
|
+
continue;
|
|
333
|
+
if (plugin.components.skills && isComponentApproved(plugin, "skills")) {
|
|
334
|
+
ensureDir(targetBase);
|
|
335
|
+
const owned = [];
|
|
336
|
+
for (const skill of plugin.skills) {
|
|
337
|
+
const targetDir = path2.join(targetBase, nsName(plugin.pluginName, skill.id));
|
|
338
|
+
ensureDir(targetDir);
|
|
339
|
+
copyFileOrDir(skill.path, path2.join(targetDir, "SKILL.md"));
|
|
340
|
+
owned.push(nsName(plugin.pluginName, skill.id));
|
|
341
|
+
projectedDirs.push(targetDir);
|
|
295
342
|
}
|
|
343
|
+
recordOwned(targetBase, plugin.pluginId, owned);
|
|
296
344
|
}
|
|
297
|
-
if (ownedSkills.length > 0)
|
|
298
|
-
recordOwned(skillsBase, plugin.pluginId, ownedSkills);
|
|
299
|
-
if (ownedCommands.length > 0)
|
|
300
|
-
recordOwned(commandsBase, plugin.pluginId, ownedCommands);
|
|
301
345
|
}
|
|
302
346
|
return {
|
|
303
|
-
clientId: "
|
|
347
|
+
clientId: "kiro",
|
|
304
348
|
status: "SYNCED",
|
|
305
349
|
projectedDirs,
|
|
306
350
|
unsupported
|
|
307
351
|
};
|
|
308
352
|
}
|
|
309
|
-
var CLIENT_SYNCERS = {
|
|
310
|
-
claude: syncClaude,
|
|
311
|
-
"claude-desktop": syncClaudeDesktop,
|
|
312
|
-
codex: syncCodex,
|
|
313
|
-
cursor: syncCursor,
|
|
314
|
-
vscode: syncVsCode,
|
|
315
|
-
kiro: syncKiro,
|
|
316
|
-
qwen: syncQwen
|
|
317
|
-
};
|
|
318
353
|
function syncPluginsToClient(clientId, plugins) {
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
354
|
+
const syncMap = {
|
|
355
|
+
claude: syncClaude,
|
|
356
|
+
"claude-desktop": syncClaudeDesktop,
|
|
357
|
+
codex: syncCodex,
|
|
358
|
+
cursor: syncCursor,
|
|
359
|
+
vscode: syncVsCode,
|
|
360
|
+
qwen: syncQwen,
|
|
361
|
+
cline: syncCline,
|
|
362
|
+
kiro: syncKiro
|
|
363
|
+
};
|
|
364
|
+
const syncFn = syncMap[clientId];
|
|
365
|
+
if (!syncFn) {
|
|
366
|
+
return { clientId, status: "SKIPPED", projectedDirs: [], unsupported: [] };
|
|
367
|
+
}
|
|
368
|
+
const targetBaseMap = {
|
|
369
|
+
claude: path2.join(homeDir(), ".claude", "skills"),
|
|
370
|
+
"claude-desktop": "",
|
|
371
|
+
codex: path2.join(homeDir(), ".codex", "skills"),
|
|
372
|
+
cursor: path2.join(homeDir(), ".cursor"),
|
|
373
|
+
vscode: path2.join(homeDir(), ".copilot", "skills"),
|
|
374
|
+
qwen: path2.join(homeDir(), ".qwen", "skills"),
|
|
375
|
+
cline: path2.join(homeDir(), ".config", "cline", "skills"),
|
|
376
|
+
kiro: path2.join(homeDir(), ".kiro", "skills")
|
|
377
|
+
};
|
|
378
|
+
const target = targetBaseMap[clientId];
|
|
379
|
+
if (target) {
|
|
380
|
+
const enabledIds = plugins.filter((p) => p.enabled).map((p) => p.pluginId);
|
|
381
|
+
pruneUnlistedPlugins(target, enabledIds);
|
|
328
382
|
}
|
|
329
|
-
return
|
|
383
|
+
return syncFn(plugins);
|
|
330
384
|
}
|
|
331
385
|
function copyPluginDir(src, dest, exclude = []) {
|
|
386
|
+
const excludeSet = new Set(exclude);
|
|
332
387
|
ensureDir(dest);
|
|
333
388
|
const entries = fs2.readdirSync(src, { withFileTypes: true });
|
|
334
389
|
for (const entry of entries) {
|
|
335
|
-
if (
|
|
336
|
-
continue;
|
|
337
|
-
if (entry.name.startsWith(".") && entry.name !== ".claude-plugin")
|
|
390
|
+
if (excludeSet.has(entry.name))
|
|
338
391
|
continue;
|
|
339
392
|
const srcPath = path2.join(src, entry.name);
|
|
340
393
|
const destPath = path2.join(dest, entry.name);
|
|
341
394
|
if (entry.isDirectory()) {
|
|
342
395
|
copyPluginDir(srcPath, destPath, exclude);
|
|
343
|
-
} else {
|
|
344
|
-
|
|
345
|
-
|
|
396
|
+
} else if (entry.isFile()) {
|
|
397
|
+
try {
|
|
398
|
+
fs2.copyFileSync(srcPath, destPath);
|
|
399
|
+
} catch {}
|
|
346
400
|
}
|
|
347
401
|
}
|
|
348
402
|
}
|
|
349
403
|
function copyFileOrDir(src, dest) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
404
|
+
try {
|
|
405
|
+
ensureDir(path2.dirname(dest));
|
|
406
|
+
if (fs2.statSync(src).isDirectory()) {
|
|
407
|
+
copyPluginDir(src, dest);
|
|
408
|
+
} else {
|
|
409
|
+
fs2.copyFileSync(src, dest);
|
|
410
|
+
}
|
|
411
|
+
} catch {}
|
|
356
412
|
}
|
|
357
413
|
|
|
358
414
|
// src/adapters/claude.ts
|
|
@@ -475,17 +531,21 @@ function removeSourceEntries(entries, names) {
|
|
|
475
531
|
delete entries[name];
|
|
476
532
|
}
|
|
477
533
|
}
|
|
478
|
-
function
|
|
479
|
-
const existingDisabled =
|
|
480
|
-
|
|
481
|
-
raw.disabledMcpServers
|
|
534
|
+
function purgeManagedFromDisabledArray(raw, managedNames) {
|
|
535
|
+
const existingDisabled = raw.disabledMcpServers ?? [];
|
|
536
|
+
raw.disabledMcpServers = existingDisabled.filter((name) => !managedNames.includes(name));
|
|
537
|
+
if (Array.isArray(raw.disabledMcpServers) && raw.disabledMcpServers.length === 0) {
|
|
538
|
+
delete raw.disabledMcpServers;
|
|
539
|
+
}
|
|
482
540
|
}
|
|
483
|
-
function
|
|
541
|
+
function purgeManagedFromExcludedArray(raw, managedNames) {
|
|
484
542
|
const mcp = raw.mcp ?? {};
|
|
485
|
-
const existingExcluded =
|
|
486
|
-
|
|
487
|
-
mcp.excluded
|
|
488
|
-
|
|
543
|
+
const existingExcluded = mcp.excluded ?? [];
|
|
544
|
+
mcp.excluded = existingExcluded.filter((name) => !managedNames.includes(name));
|
|
545
|
+
if (Array.isArray(mcp.excluded) && mcp.excluded.length === 0) {
|
|
546
|
+
delete mcp.excluded;
|
|
547
|
+
}
|
|
548
|
+
raw.mcp = Object.keys(mcp).length > 0 ? mcp : undefined;
|
|
489
549
|
}
|
|
490
550
|
|
|
491
551
|
// src/adapters/claude.ts
|
|
@@ -619,7 +679,7 @@ class ClaudeAdapter {
|
|
|
619
679
|
topLevelServers[name] = entry;
|
|
620
680
|
}
|
|
621
681
|
raw.mcpServers = topLevelServers;
|
|
622
|
-
|
|
682
|
+
purgeManagedFromDisabledArray(raw, managedNames);
|
|
623
683
|
const scopeByNormalizedPath = new Map;
|
|
624
684
|
for (const scope of options.projectScopes ?? []) {
|
|
625
685
|
scopeByNormalizedPath.set(normalizeProjectKey(scope.path), scope.disabledServerNames);
|
|
@@ -883,8 +943,7 @@ class CodexAdapter {
|
|
|
883
943
|
const mcpServers = doc.mcp_servers ?? {};
|
|
884
944
|
removeSourceEntries(mcpServers, options.sourceEntriesToRemove);
|
|
885
945
|
const managedNames = options.managedEntries.map((entry) => entry.name);
|
|
886
|
-
const serverEntries = Object.fromEntries(options.managedEntries.map((entry) => [entry.name, {
|
|
887
|
-
enabled: entry.enabled,
|
|
946
|
+
const serverEntries = Object.fromEntries(options.managedEntries.filter((entry) => entry.enabled).map((entry) => [entry.name, {
|
|
888
947
|
url: entry.url,
|
|
889
948
|
http_headers: entry.headers
|
|
890
949
|
}]));
|
|
@@ -1162,11 +1221,10 @@ class ClineAdapter {
|
|
|
1162
1221
|
};
|
|
1163
1222
|
removeSourceEntries(servers, options.sourceEntriesToRemove);
|
|
1164
1223
|
const managedNames = options.managedEntries.map((entry) => entry.name);
|
|
1165
|
-
const serverEntries = Object.fromEntries(options.managedEntries.map((entry) => [entry.name, {
|
|
1224
|
+
const serverEntries = Object.fromEntries(options.managedEntries.filter((entry) => entry.enabled).map((entry) => [entry.name, {
|
|
1166
1225
|
type: "streamableHttp",
|
|
1167
1226
|
url: entry.url,
|
|
1168
|
-
headers: entry.headers
|
|
1169
|
-
disabled: !entry.enabled
|
|
1227
|
+
headers: entry.headers
|
|
1170
1228
|
}]));
|
|
1171
1229
|
for (const name of managedNames) {
|
|
1172
1230
|
const conflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, servers[name]);
|
|
@@ -1286,10 +1344,9 @@ class KiroAdapter {
|
|
|
1286
1344
|
};
|
|
1287
1345
|
removeSourceEntries(servers, options.sourceEntriesToRemove);
|
|
1288
1346
|
const managedNames = options.managedEntries.map((entry) => entry.name);
|
|
1289
|
-
const serverEntries = Object.fromEntries(options.managedEntries.map((entry) => [entry.name, {
|
|
1347
|
+
const serverEntries = Object.fromEntries(options.managedEntries.filter((entry) => entry.enabled).map((entry) => [entry.name, {
|
|
1290
1348
|
url: entry.url,
|
|
1291
|
-
headers: entry.headers
|
|
1292
|
-
disabled: !entry.enabled
|
|
1349
|
+
headers: entry.headers
|
|
1293
1350
|
}]));
|
|
1294
1351
|
for (const name of managedNames) {
|
|
1295
1352
|
const conflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, servers[name]);
|
|
@@ -1431,11 +1488,10 @@ class OpenCodeAdapter {
|
|
|
1431
1488
|
};
|
|
1432
1489
|
removeSourceEntries(mcp, options.sourceEntriesToRemove);
|
|
1433
1490
|
const managedNames = options.managedEntries.map((entry) => entry.name);
|
|
1434
|
-
const serverEntries = Object.fromEntries(options.managedEntries.map((entry) => [entry.name, {
|
|
1491
|
+
const serverEntries = Object.fromEntries(options.managedEntries.filter((entry) => entry.enabled).map((entry) => [entry.name, {
|
|
1435
1492
|
type: "remote",
|
|
1436
1493
|
url: entry.url,
|
|
1437
|
-
headers: entry.headers
|
|
1438
|
-
enabled: entry.enabled
|
|
1494
|
+
headers: entry.headers
|
|
1439
1495
|
}]));
|
|
1440
1496
|
for (const name of managedNames) {
|
|
1441
1497
|
const conflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, mcp[name]);
|
|
@@ -1581,9 +1637,9 @@ class VsCodeAdapter {
|
|
|
1581
1637
|
servers
|
|
1582
1638
|
};
|
|
1583
1639
|
writeJsonAtomic(configPath, next);
|
|
1584
|
-
setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(
|
|
1640
|
+
setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(enabledEntries.map((entry) => [
|
|
1585
1641
|
entry.name,
|
|
1586
|
-
JSON.stringify({ type: "http", url: entry.url, headers: entry.headers
|
|
1642
|
+
JSON.stringify({ type: "http", url: entry.url, headers: entry.headers })
|
|
1587
1643
|
])));
|
|
1588
1644
|
return okResult(this.id, configPath);
|
|
1589
1645
|
} catch (error) {
|
|
@@ -1714,7 +1770,7 @@ class QwenAdapter {
|
|
|
1714
1770
|
topLevelServers[name] = entry;
|
|
1715
1771
|
}
|
|
1716
1772
|
raw.mcpServers = topLevelServers;
|
|
1717
|
-
|
|
1773
|
+
purgeManagedFromExcludedArray(raw, managedNames);
|
|
1718
1774
|
writeJsonAtomic(configPath, raw);
|
|
1719
1775
|
setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(options.managedEntries.map((entry) => [
|
|
1720
1776
|
entry.name,
|
|
@@ -1795,33 +1851,28 @@ function buildProjectScopes(config) {
|
|
|
1795
1851
|
});
|
|
1796
1852
|
}
|
|
1797
1853
|
function buildManagedEntries(config, gatewayUrl, localToken) {
|
|
1798
|
-
|
|
1799
|
-
return entries.map(([name, spec]) => ({
|
|
1854
|
+
return Object.entries(config.servers).map(([name, spec]) => ({
|
|
1800
1855
|
name: `${name} (mcpx)`,
|
|
1801
1856
|
url: `${gatewayUrl}?upstream=${encodeURIComponent(name)}`,
|
|
1802
|
-
headers: {
|
|
1803
|
-
Authorization: `Bearer ${localToken}`
|
|
1804
|
-
},
|
|
1857
|
+
headers: { Authorization: `Bearer ${localToken}` },
|
|
1805
1858
|
enabled: isServerEnabled(spec)
|
|
1806
1859
|
}));
|
|
1807
1860
|
}
|
|
1808
1861
|
function isClientInternalServerCommand(candidate) {
|
|
1809
1862
|
return candidate.spec.transport === "stdio" && /\.app\/Contents\//.test(candidate.spec.command ?? "");
|
|
1810
1863
|
}
|
|
1811
|
-
function
|
|
1864
|
+
function getFilteredAdapters(targetClients) {
|
|
1812
1865
|
const adapters = getAdapters();
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
conflicts: [],
|
|
1821
|
-
errors: []
|
|
1822
|
-
};
|
|
1866
|
+
if (targetClients && targetClients.length > 0) {
|
|
1867
|
+
return adapters.filter((a) => targetClients.includes(a.id));
|
|
1868
|
+
}
|
|
1869
|
+
return adapters;
|
|
1870
|
+
}
|
|
1871
|
+
function runImportPhase(adapters, config, managedIndex) {
|
|
1872
|
+
const imports = { imported: [], duplicates: [], skipped: [], conflicts: [], errors: [] };
|
|
1823
1873
|
const sourceEntriesToRemove = new Map;
|
|
1824
|
-
|
|
1874
|
+
const phaseErrors = [];
|
|
1875
|
+
for (const adapter of adapters) {
|
|
1825
1876
|
try {
|
|
1826
1877
|
const scan = adapter.scanForImports(config, managedIndex);
|
|
1827
1878
|
imports.skipped.push(...scan.skipped);
|
|
@@ -1848,7 +1899,7 @@ function syncAllClients(config, secrets, targetClients) {
|
|
|
1848
1899
|
if (!sourceEntriesToRemove.has(candidate.clientId)) {
|
|
1849
1900
|
sourceEntriesToRemove.set(candidate.clientId, new Set);
|
|
1850
1901
|
}
|
|
1851
|
-
sourceEntriesToRemove.get(candidate.clientId)
|
|
1902
|
+
sourceEntriesToRemove.get(candidate.clientId).add(candidate.sourceEntryName);
|
|
1852
1903
|
continue;
|
|
1853
1904
|
}
|
|
1854
1905
|
if (serverSpecsEqual(existing, candidate.spec)) {
|
|
@@ -1861,7 +1912,7 @@ function syncAllClients(config, secrets, targetClients) {
|
|
|
1861
1912
|
if (!sourceEntriesToRemove.has(candidate.clientId)) {
|
|
1862
1913
|
sourceEntriesToRemove.set(candidate.clientId, new Set);
|
|
1863
1914
|
}
|
|
1864
|
-
sourceEntriesToRemove.get(candidate.clientId)
|
|
1915
|
+
sourceEntriesToRemove.get(candidate.clientId).add(candidate.sourceEntryName);
|
|
1865
1916
|
continue;
|
|
1866
1917
|
}
|
|
1867
1918
|
imports.conflicts.push({
|
|
@@ -1878,13 +1929,111 @@ function syncAllClients(config, secrets, targetClients) {
|
|
|
1878
1929
|
configPath: adapter.detectConfigPath() ?? undefined,
|
|
1879
1930
|
message: error instanceof Error ? error.message : String(error)
|
|
1880
1931
|
});
|
|
1932
|
+
phaseErrors.push({
|
|
1933
|
+
clientId: adapter.id,
|
|
1934
|
+
phase: "import",
|
|
1935
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
return { imports, sourceEntriesToRemove, phaseErrors };
|
|
1940
|
+
}
|
|
1941
|
+
function runSkillsPhase(adapters, skills) {
|
|
1942
|
+
const phaseErrors = [];
|
|
1943
|
+
for (const adapter of adapters) {
|
|
1944
|
+
if (adapter.syncSkills) {
|
|
1945
|
+
try {
|
|
1946
|
+
adapter.syncSkills(skills);
|
|
1947
|
+
} catch (error) {
|
|
1948
|
+
phaseErrors.push({
|
|
1949
|
+
clientId: adapter.id,
|
|
1950
|
+
phase: "skills",
|
|
1951
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1952
|
+
});
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
return phaseErrors;
|
|
1957
|
+
}
|
|
1958
|
+
function runPluginsPhase(adapters, pluginInputs) {
|
|
1959
|
+
const pluginResults = [];
|
|
1960
|
+
const phaseErrors = [];
|
|
1961
|
+
for (const adapter of adapters) {
|
|
1962
|
+
if (adapter.syncPlugins) {
|
|
1963
|
+
try {
|
|
1964
|
+
const result = adapter.syncPlugins(pluginInputs);
|
|
1965
|
+
if (result)
|
|
1966
|
+
pluginResults.push(result);
|
|
1967
|
+
} catch (error) {
|
|
1968
|
+
phaseErrors.push({
|
|
1969
|
+
clientId: adapter.id,
|
|
1970
|
+
phase: "plugins",
|
|
1971
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1972
|
+
});
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
return { pluginResults, phaseErrors };
|
|
1977
|
+
}
|
|
1978
|
+
function runGatewayPhase(adapters, config, managedEntries, managedIndex, managedIndexPath, sourceEntriesToRemove, projectScopes) {
|
|
1979
|
+
const results = [];
|
|
1980
|
+
const phaseErrors = [];
|
|
1981
|
+
for (const adapter of adapters) {
|
|
1982
|
+
if (!adapter.supportsHttp()) {
|
|
1983
|
+
results.push({
|
|
1984
|
+
clientId: adapter.id,
|
|
1985
|
+
status: "UNSUPPORTED_HTTP",
|
|
1986
|
+
message: "Client adapter does not support MCP over HTTP."
|
|
1987
|
+
});
|
|
1988
|
+
continue;
|
|
1989
|
+
}
|
|
1990
|
+
try {
|
|
1991
|
+
const result = adapter.syncGateway(config, {
|
|
1992
|
+
managedEntries,
|
|
1993
|
+
managedIndex,
|
|
1994
|
+
managedIndexPath,
|
|
1995
|
+
sourceEntriesToRemove: Array.from(sourceEntriesToRemove.get(adapter.id) ?? []),
|
|
1996
|
+
projectScopes
|
|
1997
|
+
});
|
|
1998
|
+
results.push(result);
|
|
1999
|
+
} catch (error) {
|
|
2000
|
+
results.push({
|
|
2001
|
+
clientId: adapter.id,
|
|
2002
|
+
status: "ERROR",
|
|
2003
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2004
|
+
});
|
|
2005
|
+
phaseErrors.push({
|
|
2006
|
+
clientId: adapter.id,
|
|
2007
|
+
phase: "gateway",
|
|
2008
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2009
|
+
});
|
|
1881
2010
|
}
|
|
1882
2011
|
}
|
|
2012
|
+
return { results, phaseErrors };
|
|
2013
|
+
}
|
|
2014
|
+
function syncAllClients(config, secrets, options) {
|
|
2015
|
+
const opts = Array.isArray(options) ? { targetClients: options, importScan: false } : { importScan: false, ...options };
|
|
2016
|
+
const managedIndexPath = getManagedIndexPath();
|
|
2017
|
+
const managedIndex = loadManagedIndex(managedIndexPath);
|
|
2018
|
+
const adapters = getFilteredAdapters(opts.targetClients);
|
|
2019
|
+
const allPhaseErrors = [];
|
|
2020
|
+
let imports = { imported: [], duplicates: [], skipped: [], conflicts: [], errors: [] };
|
|
2021
|
+
let sourceEntriesToRemove = new Map;
|
|
2022
|
+
if (opts.importScan) {
|
|
2023
|
+
const importResult = runImportPhase(adapters, config, managedIndex);
|
|
2024
|
+
imports = importResult.imports;
|
|
2025
|
+
sourceEntriesToRemove = importResult.sourceEntriesToRemove;
|
|
2026
|
+
allPhaseErrors.push(...importResult.phaseErrors ?? []);
|
|
2027
|
+
}
|
|
1883
2028
|
const localToken = ensureGatewayToken(config, secrets);
|
|
1884
2029
|
const gatewayUrl = getGatewayUrl(config);
|
|
1885
2030
|
const managedEntries = buildManagedEntries(config, gatewayUrl, localToken);
|
|
2031
|
+
const gatewayResult = runGatewayPhase(adapters, config, managedEntries, managedIndex, managedIndexPath, sourceEntriesToRemove, buildProjectScopes(config));
|
|
2032
|
+
const results = gatewayResult.results;
|
|
2033
|
+
allPhaseErrors.push(...gatewayResult.phaseErrors ?? []);
|
|
1886
2034
|
const skills = listSkills();
|
|
1887
|
-
const
|
|
2035
|
+
const skillsErrors = runSkillsPhase(adapters, skills);
|
|
2036
|
+
allPhaseErrors.push(...skillsErrors ?? []);
|
|
1888
2037
|
const pluginInputs = Object.values(config.plugins ?? {}).map((p) => ({
|
|
1889
2038
|
pluginId: p.id,
|
|
1890
2039
|
pluginName: p.name,
|
|
@@ -1898,51 +2047,36 @@ function syncAllClients(config, secrets, targetClients) {
|
|
|
1898
2047
|
agents: p.discovered.agents,
|
|
1899
2048
|
hooks: p.discovered.hooks
|
|
1900
2049
|
}));
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
}
|
|
1907
|
-
if (adapter.syncPlugins && pluginInputs.length > 0) {
|
|
1908
|
-
try {
|
|
1909
|
-
adapter.syncPlugins(pluginInputs);
|
|
1910
|
-
} catch (error) {}
|
|
1911
|
-
}
|
|
1912
|
-
if (!adapter.supportsHttp()) {
|
|
1913
|
-
results.push({
|
|
1914
|
-
clientId: adapter.id,
|
|
1915
|
-
status: "UNSUPPORTED_HTTP",
|
|
1916
|
-
message: "Client adapter does not support MCP over HTTP."
|
|
1917
|
-
});
|
|
1918
|
-
continue;
|
|
1919
|
-
}
|
|
1920
|
-
const result = adapter.syncGateway(config, {
|
|
1921
|
-
managedEntries,
|
|
1922
|
-
managedIndex,
|
|
1923
|
-
managedIndexPath,
|
|
1924
|
-
sourceEntriesToRemove: Array.from(sourceEntriesToRemove.get(adapter.id) ?? []),
|
|
1925
|
-
projectScopes: buildProjectScopes(config)
|
|
1926
|
-
});
|
|
1927
|
-
results.push(result);
|
|
1928
|
-
}
|
|
2050
|
+
const pluginResult = runPluginsPhase(adapters, pluginInputs);
|
|
2051
|
+
const pluginResults = pluginResult.pluginResults;
|
|
2052
|
+
allPhaseErrors.push(...pluginResult.phaseErrors ?? []);
|
|
2053
|
+
saveManagedIndex(managedIndex, managedIndexPath);
|
|
2054
|
+
const clientStates = {};
|
|
1929
2055
|
for (const result of results) {
|
|
1930
|
-
|
|
2056
|
+
clientStates[result.clientId] = {
|
|
1931
2057
|
status: result.status,
|
|
1932
2058
|
configPath: result.configPath,
|
|
1933
2059
|
message: result.message,
|
|
1934
2060
|
lastSyncAt: new Date().toISOString()
|
|
1935
2061
|
};
|
|
1936
2062
|
}
|
|
1937
|
-
|
|
1938
|
-
saveConfig(config);
|
|
1939
|
-
const hasErrors = results.some((result) => result.status === "ERROR") || imports.conflicts.length > 0 || imports.errors.length > 0;
|
|
2063
|
+
const hasErrors = results.some((r) => r.status === "ERROR") || imports.conflicts.length > 0 || imports.errors.length > 0;
|
|
1940
2064
|
return {
|
|
1941
2065
|
gatewayUrl,
|
|
1942
2066
|
imports,
|
|
1943
2067
|
results,
|
|
1944
|
-
hasErrors
|
|
2068
|
+
hasErrors,
|
|
2069
|
+
clientStates,
|
|
2070
|
+
phaseErrors: allPhaseErrors.length > 0 ? allPhaseErrors : undefined,
|
|
2071
|
+
pluginResults: pluginResults.length > 0 ? pluginResults : undefined
|
|
1945
2072
|
};
|
|
1946
2073
|
}
|
|
2074
|
+
function persistSyncState(summary, config) {
|
|
2075
|
+
if (!summary.clientStates)
|
|
2076
|
+
return;
|
|
2077
|
+
for (const [clientId, state] of Object.entries(summary.clientStates)) {
|
|
2078
|
+
config.clients[clientId] = state;
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
1947
2081
|
|
|
1948
|
-
export { listSkills, getSkill, saveSkill, deleteSkill, prunePluginProjections, pruneAllPluginProjections, syncPluginsToClient, getAdapters, loadManagedIndex, getGatewayUrl, syncAllClients };
|
|
2082
|
+
export { listSkills, getSkill, saveSkill, deleteSkill, prunePluginProjections, pruneAllPluginProjections, syncPluginsToClient, getAdapters, loadManagedIndex, getGatewayUrl, syncAllClients, persistSyncState };
|