@kwonye/mcpx 0.1.90 → 0.1.93

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/adapters/claude-desktop.d.ts +2 -1
  2. package/dist/adapters/claude-desktop.d.ts.map +1 -1
  3. package/dist/adapters/claude.d.ts +2 -1
  4. package/dist/adapters/claude.d.ts.map +1 -1
  5. package/dist/adapters/cline.d.ts.map +1 -1
  6. package/dist/adapters/codex.d.ts +2 -1
  7. package/dist/adapters/codex.d.ts.map +1 -1
  8. package/dist/adapters/cursor.d.ts +2 -1
  9. package/dist/adapters/cursor.d.ts.map +1 -1
  10. package/dist/adapters/kiro.d.ts +2 -1
  11. package/dist/adapters/kiro.d.ts.map +1 -1
  12. package/dist/adapters/opencode.d.ts.map +1 -1
  13. package/dist/adapters/qwen.d.ts +2 -1
  14. package/dist/adapters/qwen.d.ts.map +1 -1
  15. package/dist/adapters/vscode.d.ts +2 -1
  16. package/dist/adapters/vscode.d.ts.map +1 -1
  17. package/dist/{cli-qfvawh8e.js → cli-8vxva0cb.js} +1 -1
  18. package/dist/cli-kwyp9ywh.js +1948 -0
  19. package/dist/{cli-mzgjjdjt.js → cli-m2645syd.js} +58 -1630
  20. package/dist/{cli-btx8jwra.js → cli-np0wwh6m.js} +58 -4
  21. package/dist/cli-qvkpwy9w.js +904 -0
  22. package/dist/{cli-cvve840g.js → cli-y7ba5qvr.js} +57 -1629
  23. package/dist/{cli-zbbeadz8.js → cli-zjepj3sj.js} +7 -1
  24. package/dist/cli.d.ts.map +1 -1
  25. package/dist/cli.js +143 -15
  26. package/dist/{config-nkgc4c4n.js → config-2s5nsm2g.js} +2 -2
  27. package/dist/core/config.d.ts.map +1 -1
  28. package/dist/core/index.d.ts +9 -1
  29. package/dist/core/index.d.ts.map +1 -1
  30. package/dist/core/index.js +58 -12
  31. package/dist/core/paths.d.ts +4 -0
  32. package/dist/core/paths.d.ts.map +1 -1
  33. package/dist/core/plugin-cache.d.ts +21 -0
  34. package/dist/core/plugin-cache.d.ts.map +1 -0
  35. package/dist/core/plugin-data.d.ts +29 -0
  36. package/dist/core/plugin-data.d.ts.map +1 -0
  37. package/dist/core/plugin-lifecycle.d.ts +8 -0
  38. package/dist/core/plugin-lifecycle.d.ts.map +1 -0
  39. package/dist/core/plugin-manager.d.ts +52 -0
  40. package/dist/core/plugin-manager.d.ts.map +1 -0
  41. package/dist/core/plugin-parse.d.ts +6 -0
  42. package/dist/core/plugin-parse.d.ts.map +1 -0
  43. package/dist/core/plugin-projections.d.ts +5 -0
  44. package/dist/core/plugin-projections.d.ts.map +1 -0
  45. package/dist/core/plugin-source.d.ts +5 -0
  46. package/dist/core/plugin-source.d.ts.map +1 -0
  47. package/dist/core/sync.d.ts.map +1 -1
  48. package/dist/plugin-manager-1sc4b6am.js +31 -0
  49. package/dist/{registry-vykv33et.js → registry-mztfy0cz.js} +2 -2
  50. package/dist/types.d.ts +83 -0
  51. package/dist/types.d.ts.map +1 -1
  52. package/dist/version.d.ts +1 -1
  53. package/package.json +3 -2
@@ -1,73 +1,29 @@
1
+ import {
2
+ getGatewayUrl,
3
+ syncAllClients
4
+ } from "./cli-kwyp9ywh.js";
1
5
  import {
2
6
  loadConfig,
3
7
  loadMergedConfig,
4
8
  saveConfig
5
- } from "./cli-btx8jwra.js";
9
+ } from "./cli-np0wwh6m.js";
6
10
  import {
7
11
  SecretsManager,
8
12
  ensureGatewayToken
9
- } from "./cli-qfvawh8e.js";
13
+ } from "./cli-8vxva0cb.js";
10
14
  import {
11
15
  ensureDir,
12
16
  ensureParentDir,
13
17
  getLogPath,
14
- getManagedIndexPath,
15
18
  getPidPath,
16
- getSkillsDir,
17
19
  getStagedVersionPath,
18
20
  getUpdateLockPath,
19
- getUpdatesDir,
20
- homeDir,
21
- readJsonFile,
22
- sha256,
23
- writeJsonAtomic
24
- } from "./cli-zbbeadz8.js";
21
+ getUpdatesDir
22
+ } from "./cli-zjepj3sj.js";
25
23
  import {
26
24
  isServerEnabled
27
25
  } from "./cli-s4gspqdf.js";
28
26
 
29
- // src/core/skills.ts
30
- import fs from "node:fs";
31
- import path from "node:path";
32
- function listSkills() {
33
- const skillsDir = getSkillsDir();
34
- if (!fs.existsSync(skillsDir)) {
35
- return [];
36
- }
37
- const files = fs.readdirSync(skillsDir);
38
- const skills = [];
39
- for (const file of files) {
40
- if (file.endsWith(".md")) {
41
- const id = path.basename(file, ".md");
42
- const content = fs.readFileSync(path.join(skillsDir, file), "utf-8");
43
- skills.push({ id, content });
44
- }
45
- }
46
- return skills;
47
- }
48
- function getSkill(id) {
49
- const skillsDir = getSkillsDir();
50
- const filePath = path.join(skillsDir, `${id}.md`);
51
- if (!fs.existsSync(filePath)) {
52
- return null;
53
- }
54
- const content = fs.readFileSync(filePath, "utf-8");
55
- return { id, content };
56
- }
57
- function saveSkill(id, content) {
58
- const skillsDir = getSkillsDir();
59
- ensureDir(skillsDir);
60
- const filePath = path.join(skillsDir, `${id}.md`);
61
- fs.writeFileSync(filePath, content, "utf-8");
62
- }
63
- function deleteSkill(id) {
64
- const skillsDir = getSkillsDir();
65
- const filePath = path.join(skillsDir, `${id}.md`);
66
- if (fs.existsSync(filePath)) {
67
- fs.unlinkSync(filePath);
68
- }
69
- }
70
-
71
27
  // src/core/auth-probe.ts
72
28
  var JSON_RPC_VERSION = "2.0";
73
29
  var DEFAULT_AUTH_PROBE_TIMEOUT_MS = 8000;
@@ -289,1534 +245,6 @@ function mapRegistryToSpec(_name, option, resolvedValues) {
289
245
  };
290
246
  }
291
247
 
292
- // src/adapters/claude.ts
293
- import fs2 from "node:fs";
294
- import path2 from "node:path";
295
- import { z } from "zod";
296
-
297
- // src/adapters/utils/index.ts
298
- function getManagedEntryNames(managedIndex, clientId) {
299
- return Object.keys(managedIndex.managed[clientId]?.entries ?? {});
300
- }
301
- function isManagedEntry(managedIndex, clientId, entryName) {
302
- return Boolean(managedIndex.managed[clientId]?.entries?.[entryName]);
303
- }
304
- function pruneStaleManagedEntries(managedIndex, clientId, servers, keepEntryNames) {
305
- const keep = new Set(keepEntryNames);
306
- const managedNames = getManagedEntryNames(managedIndex, clientId);
307
- for (const name of managedNames) {
308
- if (!keep.has(name)) {
309
- delete servers[name];
310
- }
311
- }
312
- for (const name of Object.keys(servers)) {
313
- if (!keep.has(name) && name.endsWith(" (mcpx)")) {
314
- delete servers[name];
315
- }
316
- }
317
- }
318
- function ensureManagedEntryWritable(managedIndex, clientId, entryName, existingValue) {
319
- if (existingValue === undefined || existingValue === null) {
320
- return null;
321
- }
322
- if (isManagedEntry(managedIndex, clientId, entryName)) {
323
- return null;
324
- }
325
- return `Cannot sync managed entry "${entryName}" because an unmanaged entry already exists.`;
326
- }
327
- function setManagedEntries(managedIndex, clientId, configPath, entries) {
328
- if (!managedIndex.managed[clientId]) {
329
- managedIndex.managed[clientId] = {
330
- configPath,
331
- entries: {}
332
- };
333
- }
334
- managedIndex.managed[clientId].configPath = configPath;
335
- managedIndex.managed[clientId].entries = Object.fromEntries(Object.entries(entries).map(([entryName, serializedEntry]) => [entryName, {
336
- fingerprint: sha256(serializedEntry),
337
- lastSyncedAt: new Date().toISOString()
338
- }]));
339
- }
340
- function okResult(clientId, configPath, message) {
341
- return {
342
- clientId,
343
- status: "SYNCED",
344
- configPath,
345
- message
346
- };
347
- }
348
- function errorResult(clientId, configPath, message) {
349
- return {
350
- clientId,
351
- status: "ERROR",
352
- configPath,
353
- message
354
- };
355
- }
356
- function managedGatewayEntryName(serverName) {
357
- return `${serverName} (mcpx)`;
358
- }
359
- function isManagedGatewayProjection(entryName) {
360
- return entryName.endsWith(" (mcpx)");
361
- }
362
- function sortRecord(record) {
363
- if (!record || Object.keys(record).length === 0) {
364
- return;
365
- }
366
- return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
367
- }
368
- function normalizeServerSpec(spec) {
369
- if (spec.transport === "http") {
370
- return {
371
- transport: "http",
372
- url: spec.url,
373
- headers: sortRecord(spec.headers)
374
- };
375
- }
376
- return {
377
- transport: "stdio",
378
- command: spec.command,
379
- args: spec.args && spec.args.length > 0 ? [...spec.args] : undefined,
380
- env: sortRecord(spec.env),
381
- cwd: spec.cwd
382
- };
383
- }
384
- function serializeServerSpec(spec) {
385
- return JSON.stringify(normalizeServerSpec(spec));
386
- }
387
- function serverSpecsEqual(left, right) {
388
- return serializeServerSpec(left) === serializeServerSpec(right);
389
- }
390
- function emptyImportScan(clientId, configPath) {
391
- return {
392
- clientId,
393
- configPath,
394
- candidates: [],
395
- skipped: []
396
- };
397
- }
398
- function buildImportSkip(clientId, sourceEntryName, reason, configPath, serverName = sourceEntryName) {
399
- return {
400
- clientId,
401
- configPath,
402
- sourceEntryName,
403
- serverName,
404
- reason
405
- };
406
- }
407
- function removeSourceEntries(entries, names) {
408
- for (const name of names ?? []) {
409
- delete entries[name];
410
- }
411
- }
412
- function syncDisabledMcpServersArray(raw, managedNames, managedEntries) {
413
- const existingDisabled = (raw.disabledMcpServers ?? []).filter((name) => !managedNames.includes(name));
414
- const disabledManaged = managedEntries.filter((entry) => !entry.enabled).map((entry) => entry.name);
415
- raw.disabledMcpServers = [...existingDisabled, ...disabledManaged];
416
- }
417
- function syncMcpExcludedArray(raw, managedNames, managedEntries) {
418
- const mcp = raw.mcp ?? {};
419
- const existingExcluded = (mcp.excluded ?? []).filter((name) => !managedNames.includes(name));
420
- const disabledManaged = managedEntries.filter((entry) => !entry.enabled).map((entry) => entry.name);
421
- mcp.excluded = [...existingExcluded, ...disabledManaged];
422
- raw.mcp = mcp;
423
- }
424
-
425
- // src/adapters/claude.ts
426
- function normalizeProjectKey(p) {
427
- try {
428
- return fs2.realpathSync(path2.resolve(p));
429
- } catch {
430
- return path2.resolve(p);
431
- }
432
- }
433
- function syncProjectDisabledArray(project, managedNames, disabledForThisProject) {
434
- const existingNonManaged = (project.disabledMcpServers ?? []).filter((name) => !managedNames.includes(name));
435
- const combined = [...existingNonManaged, ...disabledForThisProject];
436
- if (combined.length > 0) {
437
- project.disabledMcpServers = combined;
438
- } else {
439
- delete project.disabledMcpServers;
440
- }
441
- }
442
- var stringMapSchema = z.record(z.string(), z.string());
443
- var claudeEntrySchema = z.object({
444
- type: z.string().optional(),
445
- url: z.string().min(1).optional(),
446
- headers: stringMapSchema.optional(),
447
- command: z.string().min(1).optional(),
448
- args: z.array(z.string()).optional(),
449
- env: stringMapSchema.optional(),
450
- cwd: z.string().min(1).optional(),
451
- disabled: z.boolean().optional()
452
- }).passthrough();
453
-
454
- class ClaudeAdapter {
455
- id = "claude";
456
- detectConfigPath() {
457
- return path2.join(homeDir(), ".claude.json");
458
- }
459
- supportsHttp() {
460
- return true;
461
- }
462
- scanForImports(_config, managedIndex) {
463
- const configPath = this.detectConfigPath();
464
- const result = emptyImportScan(this.id, configPath ?? undefined);
465
- if (!configPath) {
466
- return result;
467
- }
468
- const raw = readJsonFile(configPath, {});
469
- const topLevelServers = raw.mcpServers ?? {};
470
- const disabledMcpServers = new Set(raw.disabledMcpServers ?? []);
471
- const projects = raw.projects ?? {};
472
- for (const project of Object.values(projects)) {
473
- const projectDisabled = project?.disabledMcpServers ?? [];
474
- for (const name of projectDisabled) {
475
- disabledMcpServers.add(name);
476
- }
477
- }
478
- for (const [name, rawEntry] of Object.entries(topLevelServers)) {
479
- if (isManagedGatewayProjection(name) || managedIndex.managed[this.id]?.entries?.[name]) {
480
- continue;
481
- }
482
- const parsed = claudeEntrySchema.safeParse(rawEntry);
483
- if (!parsed.success) {
484
- result.skipped.push(buildImportSkip(this.id, name, "Entry could not be mapped to an mcpx server.", configPath));
485
- continue;
486
- }
487
- const entry = parsed.data;
488
- const isDisabled = entry.disabled === true || disabledMcpServers.has(name);
489
- if ((entry.type === undefined || entry.type === "http") && entry.url && !entry.command) {
490
- result.candidates.push({
491
- clientId: this.id,
492
- configPath,
493
- sourceEntryName: name,
494
- serverName: name,
495
- spec: {
496
- transport: "http",
497
- url: entry.url,
498
- headers: entry.headers,
499
- enabled: !isDisabled
500
- }
501
- });
502
- continue;
503
- }
504
- if ((entry.type === undefined || entry.type === "stdio") && entry.command && !entry.url) {
505
- result.candidates.push({
506
- clientId: this.id,
507
- configPath,
508
- sourceEntryName: name,
509
- serverName: name,
510
- spec: {
511
- transport: "stdio",
512
- command: entry.command,
513
- args: entry.args,
514
- env: entry.env,
515
- cwd: entry.cwd,
516
- enabled: !isDisabled
517
- }
518
- });
519
- continue;
520
- }
521
- result.skipped.push(buildImportSkip(this.id, name, "Entry must define exactly one transport that mcpx supports.", configPath));
522
- }
523
- return result;
524
- }
525
- syncGateway(_config, options) {
526
- const configPath = this.detectConfigPath();
527
- if (!configPath) {
528
- return errorResult(this.id, undefined, "Unable to resolve Claude config path.");
529
- }
530
- try {
531
- const raw = readJsonFile(configPath, {});
532
- const managedNames = options.managedEntries.map((entry) => entry.name);
533
- const enabledEntries = options.managedEntries.filter((entry) => entry.enabled);
534
- const serverEntries = Object.fromEntries(enabledEntries.map((entry) => [entry.name, {
535
- type: "http",
536
- url: entry.url,
537
- headers: entry.headers
538
- }]));
539
- const enabledManagedNames = enabledEntries.map((entry) => entry.name);
540
- const topLevelServers = raw.mcpServers ?? {};
541
- removeSourceEntries(topLevelServers, options.sourceEntriesToRemove);
542
- for (const name of enabledManagedNames) {
543
- const topLevelConflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, topLevelServers[name]);
544
- if (topLevelConflict) {
545
- return errorResult(this.id, configPath, topLevelConflict);
546
- }
547
- }
548
- pruneStaleManagedEntries(options.managedIndex, this.id, topLevelServers, enabledManagedNames);
549
- for (const [name, entry] of Object.entries(serverEntries)) {
550
- topLevelServers[name] = entry;
551
- }
552
- raw.mcpServers = topLevelServers;
553
- syncDisabledMcpServersArray(raw, managedNames, options.managedEntries);
554
- const scopeByNormalizedPath = new Map;
555
- for (const scope of options.projectScopes ?? []) {
556
- scopeByNormalizedPath.set(normalizeProjectKey(scope.path), scope.disabledServerNames);
557
- }
558
- const projects = raw.projects ?? {};
559
- for (const projectPath of Object.keys(projects)) {
560
- const project = projects[projectPath] ?? {};
561
- const disabledForThis = scopeByNormalizedPath.get(normalizeProjectKey(projectPath)) ?? [];
562
- syncProjectDisabledArray(project, managedNames, disabledForThis);
563
- projects[projectPath] = project;
564
- }
565
- for (const scope of options.projectScopes ?? []) {
566
- if (scope.disabledServerNames.length === 0)
567
- continue;
568
- const normalizedKey = normalizeProjectKey(scope.path);
569
- const alreadyExists = Object.keys(projects).some((p) => normalizeProjectKey(p) === normalizedKey);
570
- if (!alreadyExists) {
571
- projects[scope.path] = { disabledMcpServers: [...scope.disabledServerNames] };
572
- }
573
- }
574
- raw.projects = projects;
575
- writeJsonAtomic(configPath, raw);
576
- setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(Object.entries(serverEntries).map(([name, entry]) => [name, JSON.stringify(entry)])));
577
- return okResult(this.id, configPath);
578
- } catch (error) {
579
- return errorResult(this.id, configPath, error.message);
580
- }
581
- }
582
- }
583
-
584
- // src/adapters/claude-desktop.ts
585
- import { execFileSync } from "node:child_process";
586
- import path3 from "node:path";
587
- import { z as z2 } from "zod";
588
- var stringMapSchema2 = z2.record(z2.string(), z2.string());
589
- var claudeDesktopEntrySchema = z2.object({
590
- type: z2.string().optional(),
591
- url: z2.string().min(1).optional(),
592
- headers: stringMapSchema2.optional(),
593
- command: z2.string().min(1).optional(),
594
- args: z2.array(z2.string()).optional(),
595
- env: stringMapSchema2.optional(),
596
- cwd: z2.string().min(1).optional(),
597
- disabled: z2.boolean().optional()
598
- }).passthrough();
599
- function buildProxyEntry(entry) {
600
- const upstreamName = entry.name.replace(/ \(mcpx\)$/, "");
601
- try {
602
- const mcpxPath = execFileSync("which", ["mcpx"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
603
- if (mcpxPath)
604
- return { command: mcpxPath, args: ["proxy", upstreamName] };
605
- } catch {}
606
- return { command: "npx", args: ["-y", "@kwonye/mcpx@latest", "proxy", upstreamName] };
607
- }
608
-
609
- class ClaudeDesktopAdapter {
610
- id = "claude-desktop";
611
- detectConfigPath() {
612
- if (process.platform === "linux") {
613
- return path3.join(homeDir(), ".config", "Claude", "claude_desktop_config.json");
614
- }
615
- if (process.platform === "win32") {
616
- return path3.join(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json");
617
- }
618
- return path3.join(homeDir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
619
- }
620
- supportsHttp() {
621
- return true;
622
- }
623
- scanForImports(_config, managedIndex) {
624
- const configPath = this.detectConfigPath();
625
- const result = emptyImportScan(this.id, configPath ?? undefined);
626
- if (!configPath) {
627
- return result;
628
- }
629
- const raw = readJsonFile(configPath, {});
630
- const topLevelServers = raw.mcpServers ?? {};
631
- for (const [name, rawEntry] of Object.entries(topLevelServers)) {
632
- if (isManagedGatewayProjection(name) || managedIndex.managed[this.id]?.entries?.[name]) {
633
- continue;
634
- }
635
- const parsed = claudeDesktopEntrySchema.safeParse(rawEntry);
636
- if (!parsed.success) {
637
- result.skipped.push(buildImportSkip(this.id, name, "Entry could not be mapped to an mcpx server.", configPath));
638
- continue;
639
- }
640
- const entry = parsed.data;
641
- if ((entry.type === undefined || entry.type === "http" || entry.type === "streamable_http") && entry.url && !entry.command) {
642
- result.candidates.push({
643
- clientId: this.id,
644
- configPath,
645
- sourceEntryName: name,
646
- serverName: name,
647
- spec: {
648
- transport: "http",
649
- url: entry.url,
650
- headers: entry.headers,
651
- enabled: entry.disabled !== true
652
- }
653
- });
654
- continue;
655
- }
656
- if ((entry.type === undefined || entry.type === "stdio") && entry.command && !entry.url) {
657
- result.candidates.push({
658
- clientId: this.id,
659
- configPath,
660
- sourceEntryName: name,
661
- serverName: name,
662
- spec: {
663
- transport: "stdio",
664
- command: entry.command,
665
- args: entry.args,
666
- env: entry.env,
667
- cwd: entry.cwd,
668
- enabled: entry.disabled !== true
669
- }
670
- });
671
- continue;
672
- }
673
- result.skipped.push(buildImportSkip(this.id, name, "Entry must define exactly one transport that mcpx supports.", configPath));
674
- }
675
- return result;
676
- }
677
- syncGateway(_config, options) {
678
- const configPath = this.detectConfigPath();
679
- if (!configPath) {
680
- return errorResult(this.id, undefined, "Unable to resolve Claude Desktop config path.");
681
- }
682
- try {
683
- const raw = readJsonFile(configPath, {});
684
- const enabledEntries = options.managedEntries.filter((entry) => entry.enabled);
685
- const serverEntries = Object.fromEntries(enabledEntries.map((entry) => {
686
- const { command, args } = buildProxyEntry(entry);
687
- return [entry.name, { command, args }];
688
- }));
689
- const enabledManagedNames = enabledEntries.map((entry) => entry.name);
690
- const topLevelServers = raw.mcpServers ?? {};
691
- removeSourceEntries(topLevelServers, options.sourceEntriesToRemove);
692
- for (const name of enabledManagedNames) {
693
- const topLevelConflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, topLevelServers[name]);
694
- if (topLevelConflict) {
695
- return errorResult(this.id, configPath, topLevelConflict);
696
- }
697
- }
698
- pruneStaleManagedEntries(options.managedIndex, this.id, topLevelServers, enabledManagedNames);
699
- for (const [name, entry] of Object.entries(serverEntries)) {
700
- topLevelServers[name] = entry;
701
- }
702
- raw.mcpServers = topLevelServers;
703
- writeJsonAtomic(configPath, raw);
704
- setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(enabledEntries.map((entry) => {
705
- const { command, args } = buildProxyEntry(entry);
706
- return [entry.name, JSON.stringify({ command, args })];
707
- })));
708
- return okResult(this.id, configPath);
709
- } catch (error) {
710
- return errorResult(this.id, configPath, error.message);
711
- }
712
- }
713
- }
714
-
715
- // src/adapters/codex.ts
716
- import path4 from "node:path";
717
- import fs3 from "node:fs";
718
- import { parse, stringify } from "@iarna/toml";
719
- import { z as z3 } from "zod";
720
- var stringMapSchema3 = z3.preprocess((value) => {
721
- if (!value || typeof value !== "object" || Array.isArray(value)) {
722
- return value;
723
- }
724
- return Object.fromEntries(Object.entries(value));
725
- }, z3.record(z3.string(), z3.string()));
726
- var codexEntrySchema = z3.object({
727
- enabled: z3.boolean().optional(),
728
- url: z3.string().min(1).optional(),
729
- headers: stringMapSchema3.optional(),
730
- http_headers: stringMapSchema3.optional(),
731
- command: z3.string().min(1).optional(),
732
- args: z3.array(z3.string()).optional(),
733
- env: stringMapSchema3.optional(),
734
- cwd: z3.string().min(1).optional()
735
- }).passthrough();
736
-
737
- class CodexAdapter {
738
- id = "codex";
739
- detectConfigPath() {
740
- return path4.join(homeDir(), ".codex", "config.toml");
741
- }
742
- supportsHttp() {
743
- return true;
744
- }
745
- scanForImports(_config, managedIndex) {
746
- const configPath = this.detectConfigPath();
747
- const result = emptyImportScan(this.id, configPath ?? undefined);
748
- if (!configPath || !fs3.existsSync(configPath)) {
749
- return result;
750
- }
751
- const existing = fs3.readFileSync(configPath, "utf8");
752
- const doc = existing.trim().length > 0 ? parse(existing) : {};
753
- const mcpServers = doc.mcp_servers ?? {};
754
- for (const [name, rawEntry] of Object.entries(mcpServers)) {
755
- if (isManagedGatewayProjection(name) || managedIndex.managed[this.id]?.entries?.[name]) {
756
- continue;
757
- }
758
- const parsed = codexEntrySchema.safeParse(rawEntry);
759
- if (!parsed.success) {
760
- result.skipped.push(buildImportSkip(this.id, name, "Entry could not be mapped to an mcpx server.", configPath));
761
- continue;
762
- }
763
- const entry = parsed.data;
764
- if (entry.url && !entry.command) {
765
- result.candidates.push({
766
- clientId: this.id,
767
- configPath,
768
- sourceEntryName: name,
769
- serverName: name,
770
- spec: {
771
- transport: "http",
772
- url: entry.url,
773
- headers: entry.http_headers ?? entry.headers,
774
- enabled: entry.enabled !== false
775
- }
776
- });
777
- continue;
778
- }
779
- if (entry.command && !entry.url) {
780
- result.candidates.push({
781
- clientId: this.id,
782
- configPath,
783
- sourceEntryName: name,
784
- serverName: name,
785
- spec: {
786
- transport: "stdio",
787
- command: entry.command,
788
- args: entry.args,
789
- env: entry.env,
790
- cwd: entry.cwd,
791
- enabled: entry.enabled !== false
792
- }
793
- });
794
- continue;
795
- }
796
- result.skipped.push(buildImportSkip(this.id, name, "Entry must define exactly one transport that mcpx supports.", configPath));
797
- }
798
- return result;
799
- }
800
- syncGateway(_config, options) {
801
- const configPath = this.detectConfigPath();
802
- if (!configPath) {
803
- return errorResult(this.id, undefined, "Unable to resolve Codex config.toml path.");
804
- }
805
- try {
806
- const existing = fs3.existsSync(configPath) ? fs3.readFileSync(configPath, "utf8") : "";
807
- const doc = existing.trim().length > 0 ? parse(existing) : {};
808
- const mcpServers = doc.mcp_servers ?? {};
809
- removeSourceEntries(mcpServers, options.sourceEntriesToRemove);
810
- const managedNames = options.managedEntries.map((entry) => entry.name);
811
- const serverEntries = Object.fromEntries(options.managedEntries.map((entry) => [entry.name, {
812
- enabled: entry.enabled,
813
- url: entry.url,
814
- http_headers: entry.headers
815
- }]));
816
- for (const name of managedNames) {
817
- const conflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, mcpServers[name]);
818
- if (conflict) {
819
- return errorResult(this.id, configPath, conflict);
820
- }
821
- }
822
- pruneStaleManagedEntries(options.managedIndex, this.id, mcpServers, managedNames);
823
- for (const [name, entry] of Object.entries(serverEntries)) {
824
- mcpServers[name] = entry;
825
- }
826
- doc.mcp_servers = mcpServers;
827
- fs3.mkdirSync(path4.dirname(configPath), { recursive: true });
828
- const tmpPath = `${configPath}.tmp-${process.pid}-${Date.now()}`;
829
- fs3.writeFileSync(tmpPath, stringify(doc), { mode: 384 });
830
- fs3.renameSync(tmpPath, configPath);
831
- setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(Object.entries(serverEntries).map(([name, entry]) => [name, JSON.stringify(entry)])));
832
- return okResult(this.id, configPath);
833
- } catch (error) {
834
- return errorResult(this.id, configPath, error.message);
835
- }
836
- }
837
- }
838
-
839
- // src/adapters/cursor.ts
840
- import path5 from "node:path";
841
- import { z as z4 } from "zod";
842
- var stringMapSchema4 = z4.record(z4.string(), z4.string());
843
- var cursorEntrySchema = z4.object({
844
- type: z4.string().optional(),
845
- url: z4.string().min(1).optional(),
846
- headers: stringMapSchema4.optional(),
847
- command: z4.string().min(1).optional(),
848
- args: z4.array(z4.string()).optional(),
849
- env: stringMapSchema4.optional(),
850
- cwd: z4.string().min(1).optional(),
851
- disabled: z4.boolean().optional()
852
- }).passthrough();
853
-
854
- class CursorAdapter {
855
- id = "cursor";
856
- detectConfigPath() {
857
- if (process.platform === "linux") {
858
- return path5.join(homeDir(), ".config", "Cursor", "User", "mcp.json");
859
- }
860
- if (process.platform === "win32") {
861
- return path5.join(process.env.APPDATA ?? "", "Cursor", "User", "mcp.json");
862
- }
863
- return path5.join(homeDir(), "Library", "Application Support", "Cursor", "User", "mcp.json");
864
- }
865
- supportsHttp() {
866
- return true;
867
- }
868
- scanForImports(_config, managedIndex) {
869
- const configPath = this.detectConfigPath();
870
- const result = emptyImportScan(this.id, configPath ?? undefined);
871
- if (!configPath) {
872
- return result;
873
- }
874
- const raw = readJsonFile(configPath, {});
875
- const servers = {
876
- ...raw.servers ?? {}
877
- };
878
- for (const [name, rawEntry] of Object.entries(servers)) {
879
- if (isManagedGatewayProjection(name) || managedIndex.managed[this.id]?.entries?.[name]) {
880
- continue;
881
- }
882
- const parsed = cursorEntrySchema.safeParse(rawEntry);
883
- if (!parsed.success) {
884
- result.skipped.push(buildImportSkip(this.id, name, "Entry could not be mapped to an mcpx server.", configPath));
885
- continue;
886
- }
887
- const entry = parsed.data;
888
- if ((entry.type === undefined || entry.type === "http") && entry.url && !entry.command) {
889
- result.candidates.push({
890
- clientId: this.id,
891
- configPath,
892
- sourceEntryName: name,
893
- serverName: name,
894
- spec: {
895
- transport: "http",
896
- url: entry.url,
897
- headers: entry.headers,
898
- enabled: entry.disabled !== true
899
- }
900
- });
901
- continue;
902
- }
903
- if ((entry.type === undefined || entry.type === "stdio") && entry.command && !entry.url) {
904
- result.candidates.push({
905
- clientId: this.id,
906
- configPath,
907
- sourceEntryName: name,
908
- serverName: name,
909
- spec: {
910
- transport: "stdio",
911
- command: entry.command,
912
- args: entry.args,
913
- env: entry.env,
914
- cwd: entry.cwd,
915
- enabled: entry.disabled !== true
916
- }
917
- });
918
- continue;
919
- }
920
- result.skipped.push(buildImportSkip(this.id, name, "Entry must define exactly one transport that mcpx supports.", configPath));
921
- }
922
- return result;
923
- }
924
- syncGateway(_config, options) {
925
- const configPath = this.detectConfigPath();
926
- if (!configPath) {
927
- return errorResult(this.id, undefined, "Unable to resolve Cursor MCP config path.");
928
- }
929
- try {
930
- const raw = readJsonFile(configPath, {});
931
- const servers = {
932
- ...raw.servers ?? {}
933
- };
934
- removeSourceEntries(servers, options.sourceEntriesToRemove);
935
- const enabledEntries = options.managedEntries.filter((entry) => entry.enabled);
936
- const serverEntries = Object.fromEntries(enabledEntries.map((entry) => [entry.name, {
937
- type: "http",
938
- url: entry.url,
939
- headers: entry.headers
940
- }]));
941
- const enabledManagedNames = enabledEntries.map((entry) => entry.name);
942
- for (const name of enabledManagedNames) {
943
- const conflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, servers[name]);
944
- if (conflict) {
945
- return errorResult(this.id, configPath, conflict);
946
- }
947
- }
948
- pruneStaleManagedEntries(options.managedIndex, this.id, servers, enabledManagedNames);
949
- for (const [name, entry] of Object.entries(serverEntries)) {
950
- servers[name] = entry;
951
- }
952
- const next = {
953
- ...raw,
954
- servers
955
- };
956
- writeJsonAtomic(configPath, next);
957
- setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(options.managedEntries.map((entry) => [
958
- entry.name,
959
- JSON.stringify({ type: "http", url: entry.url, headers: entry.headers, enabled: entry.enabled })
960
- ])));
961
- return okResult(this.id, configPath);
962
- } catch (error) {
963
- return errorResult(this.id, configPath, error.message);
964
- }
965
- }
966
- }
967
-
968
- // src/adapters/cline.ts
969
- import path6 from "node:path";
970
- import fs4 from "node:fs";
971
- import { z as z5 } from "zod";
972
- var stringMapSchema5 = z5.record(z5.string(), z5.string());
973
- var clineEntrySchema = z5.object({
974
- transportType: z5.string().optional(),
975
- url: z5.string().min(1).optional(),
976
- headers: stringMapSchema5.optional(),
977
- command: z5.string().min(1).optional(),
978
- args: z5.array(z5.string()).optional(),
979
- env: stringMapSchema5.optional(),
980
- cwd: z5.string().min(1).optional(),
981
- disabled: z5.boolean().optional()
982
- }).passthrough();
983
- function getCandidatePaths() {
984
- if (process.platform === "linux") {
985
- return [
986
- path6.join(homeDir(), ".config", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
987
- path6.join(homeDir(), ".config", "Cursor", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json")
988
- ];
989
- }
990
- if (process.platform === "win32") {
991
- return [
992
- path6.join(process.env.APPDATA ?? "", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
993
- path6.join(process.env.APPDATA ?? "", "Cursor", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json")
994
- ];
995
- }
996
- return [
997
- path6.join(homeDir(), "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json"),
998
- path6.join(homeDir(), "Library", "Application Support", "Cursor", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json")
999
- ];
1000
- }
1001
-
1002
- class ClineAdapter {
1003
- id = "cline";
1004
- detectConfigPath() {
1005
- const candidates = getCandidatePaths();
1006
- for (const candidate of candidates) {
1007
- if (fs4.existsSync(candidate)) {
1008
- return candidate;
1009
- }
1010
- }
1011
- return candidates[0] ?? null;
1012
- }
1013
- supportsHttp() {
1014
- return true;
1015
- }
1016
- scanForImports(_config, managedIndex) {
1017
- const configPath = this.detectConfigPath();
1018
- const result = emptyImportScan(this.id, configPath ?? undefined);
1019
- if (!configPath || !fs4.existsSync(configPath)) {
1020
- return result;
1021
- }
1022
- const raw = readJsonFile(configPath, {});
1023
- const servers = {
1024
- ...raw.mcpServers ?? {}
1025
- };
1026
- for (const [name, rawEntry] of Object.entries(servers)) {
1027
- if (isManagedGatewayProjection(name) || managedIndex.managed[this.id]?.entries?.[name]) {
1028
- continue;
1029
- }
1030
- const parsed = clineEntrySchema.safeParse(rawEntry);
1031
- if (!parsed.success) {
1032
- result.skipped.push(buildImportSkip(this.id, name, "Entry could not be mapped to an mcpx server.", configPath));
1033
- continue;
1034
- }
1035
- const entry = parsed.data;
1036
- if ((entry.transportType === undefined || entry.transportType === "http") && entry.url && !entry.command) {
1037
- result.candidates.push({
1038
- clientId: this.id,
1039
- configPath,
1040
- sourceEntryName: name,
1041
- serverName: name,
1042
- spec: {
1043
- transport: "http",
1044
- url: entry.url,
1045
- headers: entry.headers,
1046
- enabled: entry.disabled !== true
1047
- }
1048
- });
1049
- continue;
1050
- }
1051
- if ((entry.transportType === undefined || entry.transportType === "stdio") && entry.command && !entry.url) {
1052
- result.candidates.push({
1053
- clientId: this.id,
1054
- configPath,
1055
- sourceEntryName: name,
1056
- serverName: name,
1057
- spec: {
1058
- transport: "stdio",
1059
- command: entry.command,
1060
- args: entry.args,
1061
- env: entry.env,
1062
- cwd: entry.cwd,
1063
- enabled: entry.disabled !== true
1064
- }
1065
- });
1066
- continue;
1067
- }
1068
- result.skipped.push(buildImportSkip(this.id, name, "Entry must define exactly one transport that mcpx supports.", configPath));
1069
- }
1070
- return result;
1071
- }
1072
- syncGateway(_config, options) {
1073
- const configPath = this.detectConfigPath();
1074
- if (!configPath) {
1075
- return errorResult(this.id, undefined, "Unable to resolve Cline MCP config path.");
1076
- }
1077
- if (!fs4.existsSync(configPath)) {
1078
- return okResult(this.id, configPath, "Cline config not found; skipping sync.");
1079
- }
1080
- try {
1081
- const raw = readJsonFile(configPath, {});
1082
- const servers = {
1083
- ...raw.mcpServers ?? {}
1084
- };
1085
- removeSourceEntries(servers, options.sourceEntriesToRemove);
1086
- const managedNames = options.managedEntries.map((entry) => entry.name);
1087
- const serverEntries = Object.fromEntries(options.managedEntries.map((entry) => [entry.name, {
1088
- transportType: "http",
1089
- url: entry.url,
1090
- headers: entry.headers,
1091
- disabled: !entry.enabled
1092
- }]));
1093
- for (const name of managedNames) {
1094
- const conflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, servers[name]);
1095
- if (conflict) {
1096
- return errorResult(this.id, configPath, conflict);
1097
- }
1098
- }
1099
- pruneStaleManagedEntries(options.managedIndex, this.id, servers, managedNames);
1100
- for (const [name, entry] of Object.entries(serverEntries)) {
1101
- servers[name] = entry;
1102
- }
1103
- const next = {
1104
- ...raw,
1105
- mcpServers: servers
1106
- };
1107
- writeJsonAtomic(configPath, next);
1108
- setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(Object.entries(serverEntries).map(([name, entry]) => [name, JSON.stringify(entry)])));
1109
- return okResult(this.id, configPath);
1110
- } catch (error) {
1111
- return errorResult(this.id, configPath, error.message);
1112
- }
1113
- }
1114
- }
1115
-
1116
- // src/adapters/kiro.ts
1117
- import fs5 from "node:fs";
1118
- import path7 from "node:path";
1119
- import { z as z6 } from "zod";
1120
- var stringMapSchema6 = z6.record(z6.string(), z6.string());
1121
- var kiroEntrySchema = z6.object({
1122
- url: z6.string().min(1).optional(),
1123
- headers: stringMapSchema6.optional(),
1124
- command: z6.string().min(1).optional(),
1125
- args: z6.array(z6.string()).optional(),
1126
- env: stringMapSchema6.optional(),
1127
- cwd: z6.string().min(1).optional(),
1128
- disabled: z6.boolean().optional()
1129
- }).passthrough();
1130
-
1131
- class KiroAdapter {
1132
- id = "kiro";
1133
- detectConfigPath() {
1134
- return path7.join(homeDir(), ".kiro", "settings", "mcp.json");
1135
- }
1136
- supportsHttp() {
1137
- return true;
1138
- }
1139
- scanForImports(_config, managedIndex) {
1140
- const configPath = this.detectConfigPath();
1141
- const result = emptyImportScan(this.id, configPath ?? undefined);
1142
- if (!configPath) {
1143
- return result;
1144
- }
1145
- const raw = readJsonFile(configPath, {});
1146
- const servers = {
1147
- ...raw.mcpServers ?? {}
1148
- };
1149
- for (const [name, rawEntry] of Object.entries(servers)) {
1150
- if (isManagedGatewayProjection(name) || managedIndex.managed[this.id]?.entries?.[name]) {
1151
- continue;
1152
- }
1153
- const parsed = kiroEntrySchema.safeParse(rawEntry);
1154
- if (!parsed.success) {
1155
- result.skipped.push(buildImportSkip(this.id, name, "Entry could not be mapped to an mcpx server.", configPath));
1156
- continue;
1157
- }
1158
- const entry = parsed.data;
1159
- if (entry.url && !entry.command) {
1160
- result.candidates.push({
1161
- clientId: this.id,
1162
- configPath,
1163
- sourceEntryName: name,
1164
- serverName: name,
1165
- spec: {
1166
- transport: "http",
1167
- url: entry.url,
1168
- headers: entry.headers,
1169
- enabled: entry.disabled !== true
1170
- }
1171
- });
1172
- continue;
1173
- }
1174
- if (entry.command && !entry.url) {
1175
- result.candidates.push({
1176
- clientId: this.id,
1177
- configPath,
1178
- sourceEntryName: name,
1179
- serverName: name,
1180
- spec: {
1181
- transport: "stdio",
1182
- command: entry.command,
1183
- args: entry.args,
1184
- env: entry.env,
1185
- cwd: entry.cwd,
1186
- enabled: entry.disabled !== true
1187
- }
1188
- });
1189
- continue;
1190
- }
1191
- result.skipped.push(buildImportSkip(this.id, name, "Entry must define exactly one transport that mcpx supports.", configPath));
1192
- }
1193
- return result;
1194
- }
1195
- syncGateway(_config, options) {
1196
- const configPath = this.detectConfigPath();
1197
- if (!configPath) {
1198
- return errorResult(this.id, undefined, "Unable to resolve Kiro MCP config path.");
1199
- }
1200
- try {
1201
- const raw = readJsonFile(configPath, {});
1202
- const servers = {
1203
- ...raw.mcpServers ?? {}
1204
- };
1205
- removeSourceEntries(servers, options.sourceEntriesToRemove);
1206
- const managedNames = options.managedEntries.map((entry) => entry.name);
1207
- const serverEntries = Object.fromEntries(options.managedEntries.map((entry) => [entry.name, {
1208
- url: entry.url,
1209
- headers: entry.headers,
1210
- disabled: !entry.enabled
1211
- }]));
1212
- for (const name of managedNames) {
1213
- const conflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, servers[name]);
1214
- if (conflict) {
1215
- return errorResult(this.id, configPath, conflict);
1216
- }
1217
- }
1218
- pruneStaleManagedEntries(options.managedIndex, this.id, servers, managedNames);
1219
- for (const [name, entry] of Object.entries(serverEntries)) {
1220
- servers[name] = entry;
1221
- }
1222
- const next = {
1223
- ...raw,
1224
- mcpServers: servers
1225
- };
1226
- writeJsonAtomic(configPath, next);
1227
- setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(Object.entries(serverEntries).map(([name, entry]) => [name, JSON.stringify(entry)])));
1228
- return okResult(this.id, configPath);
1229
- } catch (error) {
1230
- return errorResult(this.id, configPath, error.message);
1231
- }
1232
- }
1233
- syncSkills(skills) {
1234
- const skillsDir = path7.join(homeDir(), ".kiro", "skills");
1235
- if (!fs5.existsSync(skillsDir)) {
1236
- fs5.mkdirSync(skillsDir, { recursive: true });
1237
- }
1238
- const existingFiles = fs5.readdirSync(skillsDir);
1239
- const managedIds = new Set(skills.map((s) => s.id));
1240
- for (const file of existingFiles) {
1241
- if (file.endsWith(".md")) {
1242
- const id = path7.basename(file, ".md");
1243
- if (!managedIds.has(id)) {
1244
- fs5.unlinkSync(path7.join(skillsDir, file));
1245
- }
1246
- }
1247
- }
1248
- for (const skill of skills) {
1249
- const targetPath = path7.join(skillsDir, `${skill.id}.md`);
1250
- fs5.writeFileSync(targetPath, skill.content, "utf-8");
1251
- }
1252
- }
1253
- }
1254
-
1255
- // src/adapters/opencode.ts
1256
- import path8 from "node:path";
1257
- import { z as z7 } from "zod";
1258
- var stringMapSchema7 = z7.record(z7.string(), z7.string());
1259
- var openCodeEntrySchema = z7.object({
1260
- type: z7.string().optional(),
1261
- url: z7.string().min(1).optional(),
1262
- headers: stringMapSchema7.optional(),
1263
- command: z7.string().min(1).optional(),
1264
- args: z7.array(z7.string()).optional(),
1265
- env: stringMapSchema7.optional(),
1266
- cwd: z7.string().min(1).optional(),
1267
- enabled: z7.boolean().optional()
1268
- }).passthrough();
1269
-
1270
- class OpenCodeAdapter {
1271
- id = "opencode";
1272
- detectConfigPath() {
1273
- return path8.join(homeDir(), ".config", "opencode", "opencode.json");
1274
- }
1275
- supportsHttp() {
1276
- return true;
1277
- }
1278
- scanForImports(_config, managedIndex) {
1279
- const configPath = this.detectConfigPath();
1280
- const result = emptyImportScan(this.id, configPath ?? undefined);
1281
- if (!configPath) {
1282
- return result;
1283
- }
1284
- const raw = readJsonFile(configPath, {});
1285
- const mcp = {
1286
- ...raw.mcp ?? {}
1287
- };
1288
- for (const [name, rawEntry] of Object.entries(mcp)) {
1289
- if (isManagedGatewayProjection(name) || managedIndex.managed[this.id]?.entries?.[name]) {
1290
- continue;
1291
- }
1292
- const parsed = openCodeEntrySchema.safeParse(rawEntry);
1293
- if (!parsed.success) {
1294
- result.skipped.push(buildImportSkip(this.id, name, "Entry could not be mapped to an mcpx server.", configPath));
1295
- continue;
1296
- }
1297
- const entry = parsed.data;
1298
- if ((entry.type === undefined || entry.type === "remote" || entry.type === "http") && entry.url && !entry.command) {
1299
- result.candidates.push({
1300
- clientId: this.id,
1301
- configPath,
1302
- sourceEntryName: name,
1303
- serverName: name,
1304
- spec: {
1305
- transport: "http",
1306
- url: entry.url,
1307
- headers: entry.headers,
1308
- enabled: entry.enabled !== false
1309
- }
1310
- });
1311
- continue;
1312
- }
1313
- if ((entry.type === undefined || entry.type === "stdio") && entry.command && !entry.url) {
1314
- result.candidates.push({
1315
- clientId: this.id,
1316
- configPath,
1317
- sourceEntryName: name,
1318
- serverName: name,
1319
- spec: {
1320
- transport: "stdio",
1321
- command: entry.command,
1322
- args: entry.args,
1323
- env: entry.env,
1324
- cwd: entry.cwd,
1325
- enabled: entry.enabled !== false
1326
- }
1327
- });
1328
- continue;
1329
- }
1330
- result.skipped.push(buildImportSkip(this.id, name, "Entry must define exactly one transport that mcpx supports.", configPath));
1331
- }
1332
- return result;
1333
- }
1334
- syncGateway(_config, options) {
1335
- const configPath = this.detectConfigPath();
1336
- if (!configPath) {
1337
- return errorResult(this.id, undefined, "Unable to resolve OpenCode config path.");
1338
- }
1339
- try {
1340
- const raw = readJsonFile(configPath, {});
1341
- const mcp = {
1342
- ...raw.mcp ?? {}
1343
- };
1344
- removeSourceEntries(mcp, options.sourceEntriesToRemove);
1345
- const managedNames = options.managedEntries.map((entry) => entry.name);
1346
- const serverEntries = Object.fromEntries(options.managedEntries.map((entry) => [entry.name, {
1347
- type: "remote",
1348
- url: entry.url,
1349
- headers: entry.headers,
1350
- enabled: entry.enabled
1351
- }]));
1352
- for (const name of managedNames) {
1353
- const conflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, mcp[name]);
1354
- if (conflict) {
1355
- return errorResult(this.id, configPath, conflict);
1356
- }
1357
- }
1358
- pruneStaleManagedEntries(options.managedIndex, this.id, mcp, managedNames);
1359
- for (const [name, entry] of Object.entries(serverEntries)) {
1360
- mcp[name] = entry;
1361
- }
1362
- const next = {
1363
- ...raw,
1364
- mcp
1365
- };
1366
- writeJsonAtomic(configPath, next);
1367
- setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(Object.entries(serverEntries).map(([name, entry]) => [name, JSON.stringify(entry)])));
1368
- return okResult(this.id, configPath);
1369
- } catch (error) {
1370
- return errorResult(this.id, configPath, error.message);
1371
- }
1372
- }
1373
- }
1374
-
1375
- // src/adapters/vscode.ts
1376
- import path9 from "node:path";
1377
- import { z as z8 } from "zod";
1378
- var stringMapSchema8 = z8.record(z8.string(), z8.string());
1379
- var vscodeEntrySchema = z8.object({
1380
- type: z8.string().optional(),
1381
- url: z8.string().min(1).optional(),
1382
- headers: stringMapSchema8.optional(),
1383
- command: z8.string().min(1).optional(),
1384
- args: z8.array(z8.string()).optional(),
1385
- env: stringMapSchema8.optional(),
1386
- cwd: z8.string().min(1).optional(),
1387
- disabled: z8.boolean().optional()
1388
- }).passthrough();
1389
-
1390
- class VsCodeAdapter {
1391
- id = "vscode";
1392
- detectConfigPath() {
1393
- if (process.platform === "linux") {
1394
- return path9.join(homeDir(), ".config", "Code", "User", "mcp.json");
1395
- }
1396
- if (process.platform === "win32") {
1397
- return path9.join(process.env.APPDATA ?? "", "Code", "User", "mcp.json");
1398
- }
1399
- return path9.join(homeDir(), "Library", "Application Support", "Code", "User", "mcp.json");
1400
- }
1401
- supportsHttp() {
1402
- return true;
1403
- }
1404
- scanForImports(_config, managedIndex) {
1405
- const configPath = this.detectConfigPath();
1406
- const result = emptyImportScan(this.id, configPath ?? undefined);
1407
- if (!configPath) {
1408
- return result;
1409
- }
1410
- const raw = readJsonFile(configPath, {});
1411
- const servers = {
1412
- ...raw.servers ?? {}
1413
- };
1414
- for (const [name, rawEntry] of Object.entries(servers)) {
1415
- if (isManagedGatewayProjection(name) || managedIndex.managed[this.id]?.entries?.[name]) {
1416
- continue;
1417
- }
1418
- const parsed = vscodeEntrySchema.safeParse(rawEntry);
1419
- if (!parsed.success) {
1420
- result.skipped.push(buildImportSkip(this.id, name, "Entry could not be mapped to an mcpx server.", configPath));
1421
- continue;
1422
- }
1423
- const entry = parsed.data;
1424
- if ((entry.type === undefined || entry.type === "http") && entry.url && !entry.command) {
1425
- result.candidates.push({
1426
- clientId: this.id,
1427
- configPath,
1428
- sourceEntryName: name,
1429
- serverName: name,
1430
- spec: {
1431
- transport: "http",
1432
- url: entry.url,
1433
- headers: entry.headers,
1434
- enabled: entry.disabled !== true
1435
- }
1436
- });
1437
- continue;
1438
- }
1439
- if ((entry.type === undefined || entry.type === "stdio") && entry.command && !entry.url) {
1440
- result.candidates.push({
1441
- clientId: this.id,
1442
- configPath,
1443
- sourceEntryName: name,
1444
- serverName: name,
1445
- spec: {
1446
- transport: "stdio",
1447
- command: entry.command,
1448
- args: entry.args,
1449
- env: entry.env,
1450
- cwd: entry.cwd,
1451
- enabled: entry.disabled !== true
1452
- }
1453
- });
1454
- continue;
1455
- }
1456
- result.skipped.push(buildImportSkip(this.id, name, "Entry must define exactly one transport that mcpx supports.", configPath));
1457
- }
1458
- return result;
1459
- }
1460
- syncGateway(_config, options) {
1461
- const configPath = this.detectConfigPath();
1462
- if (!configPath) {
1463
- return errorResult(this.id, undefined, "Unable to resolve VS Code MCP config path.");
1464
- }
1465
- try {
1466
- const raw = readJsonFile(configPath, {});
1467
- const servers = {
1468
- ...raw.servers ?? {}
1469
- };
1470
- removeSourceEntries(servers, options.sourceEntriesToRemove);
1471
- const enabledEntries = options.managedEntries.filter((entry) => entry.enabled);
1472
- const serverEntries = Object.fromEntries(enabledEntries.map((entry) => [entry.name, {
1473
- type: "http",
1474
- url: entry.url,
1475
- headers: entry.headers
1476
- }]));
1477
- const enabledManagedNames = enabledEntries.map((entry) => entry.name);
1478
- for (const name of enabledManagedNames) {
1479
- const conflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, servers[name]);
1480
- if (conflict) {
1481
- return errorResult(this.id, configPath, conflict);
1482
- }
1483
- }
1484
- pruneStaleManagedEntries(options.managedIndex, this.id, servers, enabledManagedNames);
1485
- for (const [name, entry] of Object.entries(serverEntries)) {
1486
- servers[name] = entry;
1487
- }
1488
- const next = {
1489
- ...raw,
1490
- servers
1491
- };
1492
- writeJsonAtomic(configPath, next);
1493
- setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(options.managedEntries.map((entry) => [
1494
- entry.name,
1495
- JSON.stringify({ type: "http", url: entry.url, headers: entry.headers, enabled: entry.enabled })
1496
- ])));
1497
- return okResult(this.id, configPath);
1498
- } catch (error) {
1499
- return errorResult(this.id, configPath, error.message);
1500
- }
1501
- }
1502
- }
1503
-
1504
- // src/adapters/qwen.ts
1505
- import fs6 from "node:fs";
1506
- import path10 from "node:path";
1507
- import { z as z9 } from "zod";
1508
- var stringMapSchema9 = z9.record(z9.string(), z9.string());
1509
- var qwenEntrySchema = z9.object({
1510
- httpUrl: z9.string().min(1).optional(),
1511
- headers: stringMapSchema9.optional(),
1512
- command: z9.string().min(1).optional(),
1513
- args: z9.array(z9.string()).optional(),
1514
- env: stringMapSchema9.optional(),
1515
- cwd: z9.string().min(1).optional(),
1516
- disabled: z9.boolean().optional()
1517
- }).passthrough();
1518
-
1519
- class QwenAdapter {
1520
- id = "qwen";
1521
- detectConfigPath() {
1522
- return path10.join(homeDir(), ".qwen", "settings.json");
1523
- }
1524
- supportsHttp() {
1525
- return true;
1526
- }
1527
- scanForImports(_config, managedIndex) {
1528
- const configPath = this.detectConfigPath();
1529
- const result = emptyImportScan(this.id, configPath ?? undefined);
1530
- if (!configPath) {
1531
- return result;
1532
- }
1533
- const raw = readJsonFile(configPath, {});
1534
- const excludedSet = new Set(raw.mcp?.excluded ?? []);
1535
- const topLevelServers = raw.mcpServers ?? {};
1536
- for (const [name, rawEntry] of Object.entries(topLevelServers)) {
1537
- if (isManagedGatewayProjection(name) || managedIndex.managed[this.id]?.entries?.[name]) {
1538
- continue;
1539
- }
1540
- const parsed = qwenEntrySchema.safeParse(rawEntry);
1541
- if (!parsed.success) {
1542
- result.skipped.push(buildImportSkip(this.id, name, "Entry could not be mapped to an mcpx server.", configPath));
1543
- continue;
1544
- }
1545
- const entry = parsed.data;
1546
- if (entry.httpUrl && !entry.command) {
1547
- result.candidates.push({
1548
- clientId: this.id,
1549
- configPath,
1550
- sourceEntryName: name,
1551
- serverName: name,
1552
- spec: {
1553
- transport: "http",
1554
- url: entry.httpUrl,
1555
- headers: entry.headers,
1556
- enabled: !(entry.disabled === true || excludedSet.has(name))
1557
- }
1558
- });
1559
- continue;
1560
- }
1561
- if (entry.command && !entry.httpUrl) {
1562
- result.candidates.push({
1563
- clientId: this.id,
1564
- configPath,
1565
- sourceEntryName: name,
1566
- serverName: name,
1567
- spec: {
1568
- transport: "stdio",
1569
- command: entry.command,
1570
- args: entry.args,
1571
- env: entry.env,
1572
- cwd: entry.cwd,
1573
- enabled: !(entry.disabled === true || excludedSet.has(name))
1574
- }
1575
- });
1576
- continue;
1577
- }
1578
- result.skipped.push(buildImportSkip(this.id, name, "Entry must define exactly one transport that mcpx supports.", configPath));
1579
- }
1580
- return result;
1581
- }
1582
- syncGateway(_config, options) {
1583
- const configPath = this.detectConfigPath();
1584
- if (!configPath) {
1585
- return errorResult(this.id, undefined, "Unable to resolve Qwen config path.");
1586
- }
1587
- try {
1588
- const raw = readJsonFile(configPath, {});
1589
- const managedNames = options.managedEntries.map((entry) => entry.name);
1590
- const serverEntries = Object.fromEntries(options.managedEntries.map((entry) => [entry.name, {
1591
- httpUrl: entry.url,
1592
- headers: entry.headers
1593
- }]));
1594
- const topLevelServers = raw.mcpServers ?? {};
1595
- removeSourceEntries(topLevelServers, options.sourceEntriesToRemove);
1596
- for (const name of managedNames) {
1597
- const topLevelConflict = ensureManagedEntryWritable(options.managedIndex, this.id, name, topLevelServers[name]);
1598
- if (topLevelConflict) {
1599
- return errorResult(this.id, configPath, topLevelConflict);
1600
- }
1601
- }
1602
- pruneStaleManagedEntries(options.managedIndex, this.id, topLevelServers, managedNames);
1603
- for (const [name, entry] of Object.entries(serverEntries)) {
1604
- topLevelServers[name] = entry;
1605
- }
1606
- raw.mcpServers = topLevelServers;
1607
- syncMcpExcludedArray(raw, managedNames, options.managedEntries);
1608
- writeJsonAtomic(configPath, raw);
1609
- setManagedEntries(options.managedIndex, this.id, configPath, Object.fromEntries(options.managedEntries.map((entry) => [
1610
- entry.name,
1611
- JSON.stringify({ httpUrl: entry.url, headers: entry.headers, enabled: entry.enabled })
1612
- ])));
1613
- return okResult(this.id, configPath);
1614
- } catch (error) {
1615
- return errorResult(this.id, configPath, error.message);
1616
- }
1617
- }
1618
- syncSkills(skills) {
1619
- const skillsDir = path10.join(homeDir(), ".qwen", "skills");
1620
- if (!fs6.existsSync(skillsDir)) {
1621
- fs6.mkdirSync(skillsDir, { recursive: true });
1622
- }
1623
- const existingFiles = fs6.readdirSync(skillsDir);
1624
- const managedIds = new Set(skills.map((s) => s.id));
1625
- for (const file of existingFiles) {
1626
- if (file.endsWith(".md")) {
1627
- const id = path10.basename(file, ".md");
1628
- if (!managedIds.has(id)) {
1629
- fs6.unlinkSync(path10.join(skillsDir, file));
1630
- }
1631
- }
1632
- }
1633
- for (const skill of skills) {
1634
- const targetPath = path10.join(skillsDir, `${skill.id}.md`);
1635
- fs6.writeFileSync(targetPath, skill.content, "utf-8");
1636
- }
1637
- }
1638
- }
1639
-
1640
- // src/adapters/index.ts
1641
- function getAdapters() {
1642
- return [
1643
- new ClaudeAdapter,
1644
- new ClaudeDesktopAdapter,
1645
- new CodexAdapter,
1646
- new CursorAdapter,
1647
- new ClineAdapter,
1648
- new OpenCodeAdapter,
1649
- new KiroAdapter,
1650
- new VsCodeAdapter,
1651
- new QwenAdapter
1652
- ];
1653
- }
1654
-
1655
- // src/core/managed-index.ts
1656
- function defaultManagedIndex() {
1657
- return {
1658
- schemaVersion: 1,
1659
- managed: {}
1660
- };
1661
- }
1662
- function loadManagedIndex(filePath = getManagedIndexPath()) {
1663
- const raw = readJsonFile(filePath, defaultManagedIndex());
1664
- if (!raw || typeof raw !== "object") {
1665
- return defaultManagedIndex();
1666
- }
1667
- if (raw.schemaVersion !== 1) {
1668
- return defaultManagedIndex();
1669
- }
1670
- return raw;
1671
- }
1672
- function saveManagedIndex(index, filePath = getManagedIndexPath()) {
1673
- writeJsonAtomic(filePath, index);
1674
- }
1675
-
1676
- // src/core/sync.ts
1677
- function getGatewayUrl(config) {
1678
- return `http://127.0.0.1:${config.gateway.port}/mcp`;
1679
- }
1680
- function buildProjectScopes(config) {
1681
- const globallyEnabled = new Set(Object.entries(config.servers).filter(([, spec]) => isServerEnabled(spec)).map(([name]) => name));
1682
- return Object.values(config.projects ?? {}).map((project) => {
1683
- const disabledServerNames = (project.disabledServers ?? []).filter((name) => globallyEnabled.has(name)).map((name) => managedGatewayEntryName(name));
1684
- return { path: project.path, disabledServerNames };
1685
- });
1686
- }
1687
- function buildManagedEntries(config, gatewayUrl, localToken) {
1688
- const entries = Object.entries(config.servers);
1689
- return entries.map(([name, spec]) => ({
1690
- name: `${name} (mcpx)`,
1691
- url: `${gatewayUrl}?upstream=${encodeURIComponent(name)}`,
1692
- headers: {
1693
- Authorization: `Bearer ${localToken}`
1694
- },
1695
- enabled: isServerEnabled(spec)
1696
- }));
1697
- }
1698
- function isClientInternalServerCommand(candidate) {
1699
- return candidate.spec.transport === "stdio" && /\.app\/Contents\//.test(candidate.spec.command ?? "");
1700
- }
1701
- function syncAllClients(config, secrets, targetClients) {
1702
- const adapters = getAdapters();
1703
- const managedIndexPath = getManagedIndexPath();
1704
- const managedIndex = loadManagedIndex(managedIndexPath);
1705
- const filteredAdapters = targetClients && targetClients.length > 0 ? adapters.filter((adapter) => targetClients.includes(adapter.id)) : adapters;
1706
- const imports = {
1707
- imported: [],
1708
- duplicates: [],
1709
- skipped: [],
1710
- conflicts: [],
1711
- errors: []
1712
- };
1713
- const sourceEntriesToRemove = new Map;
1714
- for (const adapter of filteredAdapters) {
1715
- try {
1716
- const scan = adapter.scanForImports(config, managedIndex);
1717
- imports.skipped.push(...scan.skipped);
1718
- for (const candidate of scan.candidates) {
1719
- if (isClientInternalServerCommand(candidate)) {
1720
- imports.skipped.push({
1721
- clientId: candidate.clientId,
1722
- configPath: candidate.configPath,
1723
- sourceEntryName: candidate.sourceEntryName,
1724
- serverName: candidate.serverName,
1725
- reason: "client-internal server"
1726
- });
1727
- continue;
1728
- }
1729
- const existing = config.servers[candidate.serverName];
1730
- if (!existing) {
1731
- config.servers[candidate.serverName] = candidate.spec;
1732
- imports.imported.push({
1733
- clientId: candidate.clientId,
1734
- configPath: candidate.configPath,
1735
- sourceEntryName: candidate.sourceEntryName,
1736
- serverName: candidate.serverName
1737
- });
1738
- if (!sourceEntriesToRemove.has(candidate.clientId)) {
1739
- sourceEntriesToRemove.set(candidate.clientId, new Set);
1740
- }
1741
- sourceEntriesToRemove.get(candidate.clientId)?.add(candidate.sourceEntryName);
1742
- continue;
1743
- }
1744
- if (serverSpecsEqual(existing, candidate.spec)) {
1745
- imports.duplicates.push({
1746
- clientId: candidate.clientId,
1747
- configPath: candidate.configPath,
1748
- sourceEntryName: candidate.sourceEntryName,
1749
- serverName: candidate.serverName
1750
- });
1751
- if (!sourceEntriesToRemove.has(candidate.clientId)) {
1752
- sourceEntriesToRemove.set(candidate.clientId, new Set);
1753
- }
1754
- sourceEntriesToRemove.get(candidate.clientId)?.add(candidate.sourceEntryName);
1755
- continue;
1756
- }
1757
- imports.conflicts.push({
1758
- clientId: candidate.clientId,
1759
- configPath: candidate.configPath,
1760
- sourceEntryName: candidate.sourceEntryName,
1761
- serverName: candidate.serverName,
1762
- message: `Server "${candidate.serverName}" already exists in mcpx with a different configuration.`
1763
- });
1764
- }
1765
- } catch (error) {
1766
- imports.errors.push({
1767
- clientId: adapter.id,
1768
- configPath: adapter.detectConfigPath() ?? undefined,
1769
- message: error instanceof Error ? error.message : String(error)
1770
- });
1771
- }
1772
- }
1773
- const localToken = ensureGatewayToken(config, secrets);
1774
- const gatewayUrl = getGatewayUrl(config);
1775
- const managedEntries = buildManagedEntries(config, gatewayUrl, localToken);
1776
- const skills = listSkills();
1777
- const results = [];
1778
- for (const adapter of filteredAdapters) {
1779
- if (adapter.syncSkills) {
1780
- try {
1781
- adapter.syncSkills(skills);
1782
- } catch (error) {}
1783
- }
1784
- if (!adapter.supportsHttp()) {
1785
- results.push({
1786
- clientId: adapter.id,
1787
- status: "UNSUPPORTED_HTTP",
1788
- message: "Client adapter does not support MCP over HTTP."
1789
- });
1790
- continue;
1791
- }
1792
- const result = adapter.syncGateway(config, {
1793
- managedEntries,
1794
- managedIndex,
1795
- managedIndexPath,
1796
- sourceEntriesToRemove: Array.from(sourceEntriesToRemove.get(adapter.id) ?? []),
1797
- projectScopes: buildProjectScopes(config)
1798
- });
1799
- results.push(result);
1800
- }
1801
- for (const result of results) {
1802
- config.clients[result.clientId] = {
1803
- status: result.status,
1804
- configPath: result.configPath,
1805
- message: result.message,
1806
- lastSyncAt: new Date().toISOString()
1807
- };
1808
- }
1809
- saveManagedIndex(managedIndex, managedIndexPath);
1810
- saveConfig(config);
1811
- const hasErrors = results.some((result) => result.status === "ERROR") || imports.conflicts.length > 0 || imports.errors.length > 0;
1812
- return {
1813
- gatewayUrl,
1814
- imports,
1815
- results,
1816
- hasErrors
1817
- };
1818
- }
1819
-
1820
248
  // src/core/server-auth.ts
1821
249
  function normalizeNamePart(value) {
1822
250
  return value.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "_").replace(/^_+|_+$/g, "") || "value";
@@ -1928,20 +356,20 @@ function maybePrefixBearer(target, value, raw = false) {
1928
356
 
1929
357
  // src/core/spawn-env.ts
1930
358
  import os from "node:os";
1931
- import path11 from "node:path";
1932
- import fs7 from "node:fs";
359
+ import path from "node:path";
360
+ import fs from "node:fs";
1933
361
  function existingNvmCurrentBin() {
1934
- const nvmDir = process.env.NVM_DIR ?? path11.join(os.homedir(), ".nvm");
1935
- const current = path11.join(nvmDir, "current", "bin");
1936
- return fs7.existsSync(current) ? current : null;
362
+ const nvmDir = process.env.NVM_DIR ?? path.join(os.homedir(), ".nvm");
363
+ const current = path.join(nvmDir, "current", "bin");
364
+ return fs.existsSync(current) ? current : null;
1937
365
  }
1938
366
  function buildEnrichedPath(current = process.env.PATH ?? "") {
1939
367
  const candidates = [
1940
368
  ...current.split(":"),
1941
369
  "/opt/homebrew/bin",
1942
370
  "/usr/local/bin",
1943
- path11.join(os.homedir(), ".bun", "bin"),
1944
- path11.join(os.homedir(), ".local", "bin"),
371
+ path.join(os.homedir(), ".bun", "bin"),
372
+ path.join(os.homedir(), ".local", "bin"),
1945
373
  existingNvmCurrentBin()
1946
374
  ].filter((entry) => Boolean(entry));
1947
375
  const seen = new Set;
@@ -2250,12 +678,12 @@ async function getOAuthAccessToken(serverName, spec, secrets, options = {}) {
2250
678
  }
2251
679
 
2252
680
  // src/version.ts
2253
- var APP_VERSION = "0.1.90";
681
+ var APP_VERSION = "0.1.93";
2254
682
 
2255
683
  // src/core/update.ts
2256
- import fs8 from "node:fs";
2257
- import path12 from "node:path";
2258
- import { execFileSync as execFileSync2 } from "node:child_process";
684
+ import fs2 from "node:fs";
685
+ import path2 from "node:path";
686
+ import { execFileSync } from "node:child_process";
2259
687
  function compareVersions(a, b) {
2260
688
  const partsA = a.split(".").map(Number);
2261
689
  const partsB = b.split(".").map(Number);
@@ -2271,7 +699,7 @@ function compareVersions(a, b) {
2271
699
  }
2272
700
  async function checkForUpdates() {
2273
701
  try {
2274
- const output = execFileSync2("npm", ["view", "@kwonye/mcpx", "version"], {
702
+ const output = execFileSync("npm", ["view", "@kwonye/mcpx", "version"], {
2275
703
  encoding: "utf8",
2276
704
  stdio: ["pipe", "pipe", "pipe"]
2277
705
  }).trim();
@@ -2293,17 +721,17 @@ async function checkForUpdates() {
2293
721
  }
2294
722
  function getStagedUpdate() {
2295
723
  const stagedPath = getStagedVersionPath();
2296
- if (!fs8.existsSync(stagedPath)) {
724
+ if (!fs2.existsSync(stagedPath)) {
2297
725
  return null;
2298
726
  }
2299
727
  try {
2300
- const raw = fs8.readFileSync(stagedPath, "utf8");
728
+ const raw = fs2.readFileSync(stagedPath, "utf8");
2301
729
  const info = JSON.parse(raw);
2302
730
  if (!info.version || !info.cliPath) {
2303
731
  return null;
2304
732
  }
2305
- const absoluteCliPath = path12.isAbsolute(info.cliPath) ? info.cliPath : path12.join(getUpdatesDir(), info.cliPath);
2306
- if (!fs8.existsSync(absoluteCliPath)) {
733
+ const absoluteCliPath = path2.isAbsolute(info.cliPath) ? info.cliPath : path2.join(getUpdatesDir(), info.cliPath);
734
+ if (!fs2.existsSync(absoluteCliPath)) {
2307
735
  return null;
2308
736
  }
2309
737
  return {
@@ -2319,18 +747,18 @@ function stageUpdate(version, cliPath) {
2319
747
  ensureDir(updatesDir);
2320
748
  const stagedInfo = {
2321
749
  version,
2322
- cliPath: path12.isAbsolute(cliPath) ? path12.relative(updatesDir, cliPath) : cliPath,
750
+ cliPath: path2.isAbsolute(cliPath) ? path2.relative(updatesDir, cliPath) : cliPath,
2323
751
  stagedAt: new Date().toISOString()
2324
752
  };
2325
- fs8.writeFileSync(getStagedVersionPath(), JSON.stringify(stagedInfo, null, 2), "utf8");
753
+ fs2.writeFileSync(getStagedVersionPath(), JSON.stringify(stagedInfo, null, 2), "utf8");
2326
754
  }
2327
755
  function shouldUseStagedCli(stagedVersion, currentVersion) {
2328
756
  return compareVersions(stagedVersion, currentVersion) > 0;
2329
757
  }
2330
758
  function clearStagedUpdate() {
2331
759
  const stagedPath = getStagedVersionPath();
2332
- if (fs8.existsSync(stagedPath)) {
2333
- fs8.unlinkSync(stagedPath);
760
+ if (fs2.existsSync(stagedPath)) {
761
+ fs2.unlinkSync(stagedPath);
2334
762
  }
2335
763
  }
2336
764
  function getStagedCliPath() {
@@ -2339,31 +767,31 @@ function getStagedCliPath() {
2339
767
  }
2340
768
  function removeOldVersions(keepCount = 2) {
2341
769
  const updatesDir = getUpdatesDir();
2342
- if (!fs8.existsSync(updatesDir)) {
770
+ if (!fs2.existsSync(updatesDir)) {
2343
771
  return;
2344
772
  }
2345
- const entries = fs8.readdirSync(updatesDir, { withFileTypes: true });
773
+ const entries = fs2.readdirSync(updatesDir, { withFileTypes: true });
2346
774
  const versionDirs = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith("v")).map((entry) => entry.name).sort((a, b) => compareVersions(b.slice(1), a.slice(1)));
2347
775
  if (versionDirs.length <= keepCount) {
2348
776
  return;
2349
777
  }
2350
778
  for (const oldVersion of versionDirs.slice(keepCount)) {
2351
- const oldPath = path12.join(updatesDir, oldVersion);
779
+ const oldPath = path2.join(updatesDir, oldVersion);
2352
780
  try {
2353
- fs8.rmSync(oldPath, { recursive: true, force: true });
781
+ fs2.rmSync(oldPath, { recursive: true, force: true });
2354
782
  } catch {}
2355
783
  }
2356
784
  }
2357
785
 
2358
786
  // src/core/update-manager.ts
2359
- import fs9 from "node:fs";
2360
- import path13 from "node:path";
787
+ import fs3 from "node:fs";
788
+ import path3 from "node:path";
2361
789
  import { execSync, spawn } from "node:child_process";
2362
790
  function acquireLock() {
2363
791
  const lockPath = getUpdateLockPath();
2364
792
  try {
2365
- ensureDir(path13.dirname(lockPath));
2366
- fs9.writeFileSync(lockPath, `${process.pid}
793
+ ensureDir(path3.dirname(lockPath));
794
+ fs3.writeFileSync(lockPath, `${process.pid}
2367
795
  `, { flag: "wx" });
2368
796
  return true;
2369
797
  } catch {
@@ -2373,25 +801,25 @@ function acquireLock() {
2373
801
  function releaseLock() {
2374
802
  const lockPath = getUpdateLockPath();
2375
803
  try {
2376
- fs9.unlinkSync(lockPath);
804
+ fs3.unlinkSync(lockPath);
2377
805
  } catch {}
2378
806
  }
2379
807
  function isUpdateInProgress() {
2380
808
  const lockPath = getUpdateLockPath();
2381
- if (!fs9.existsSync(lockPath)) {
809
+ if (!fs3.existsSync(lockPath)) {
2382
810
  return false;
2383
811
  }
2384
812
  try {
2385
- const raw = fs9.readFileSync(lockPath, "utf8").trim();
813
+ const raw = fs3.readFileSync(lockPath, "utf8").trim();
2386
814
  const pid = Number(raw);
2387
815
  if (!Number.isFinite(pid) || pid <= 0) {
2388
- fs9.unlinkSync(lockPath);
816
+ fs3.unlinkSync(lockPath);
2389
817
  return false;
2390
818
  }
2391
819
  process.kill(pid, 0);
2392
820
  return true;
2393
821
  } catch {
2394
- fs9.unlinkSync(lockPath);
822
+ fs3.unlinkSync(lockPath);
2395
823
  return false;
2396
824
  }
2397
825
  }
@@ -2402,8 +830,8 @@ async function downloadAndStageUpdate() {
2402
830
  }
2403
831
  const targetVersion = updateStatus.latestVersion;
2404
832
  const updatesDir = getUpdatesDir();
2405
- const versionDir = path13.join(updatesDir, `v${targetVersion}`);
2406
- if (fs9.existsSync(versionDir)) {
833
+ const versionDir = path3.join(updatesDir, `v${targetVersion}`);
834
+ if (fs3.existsSync(versionDir)) {
2407
835
  const existingStaged = getStagedUpdate();
2408
836
  if (existingStaged?.version === targetVersion) {
2409
837
  return { success: false, error: `Version ${targetVersion} already staged` };
@@ -2415,8 +843,8 @@ async function downloadAndStageUpdate() {
2415
843
  cwd: versionDir,
2416
844
  stdio: ["pipe", "pipe", "pipe"]
2417
845
  });
2418
- const tarballPath = path13.join(versionDir, `kwonye-mcpx-${targetVersion}.tgz`);
2419
- if (!fs9.existsSync(tarballPath)) {
846
+ const tarballPath = path3.join(versionDir, `kwonye-mcpx-${targetVersion}.tgz`);
847
+ if (!fs3.existsSync(tarballPath)) {
2420
848
  throw new Error("Downloaded tarball not found");
2421
849
  }
2422
850
  execSync(`tar -xzf ${tarballPath} --strip-components=1`, {
@@ -2427,8 +855,8 @@ async function downloadAndStageUpdate() {
2427
855
  cwd: versionDir,
2428
856
  stdio: ["pipe", "pipe", "pipe"]
2429
857
  });
2430
- const cliPath = path13.join(versionDir, "dist", "cli.js");
2431
- if (!fs9.existsSync(cliPath)) {
858
+ const cliPath = path3.join(versionDir, "dist", "cli.js");
859
+ if (!fs3.existsSync(cliPath)) {
2432
860
  throw new Error("CLI entry point not found in downloaded package");
2433
861
  }
2434
862
  stageUpdate(targetVersion, cliPath);
@@ -2436,7 +864,7 @@ async function downloadAndStageUpdate() {
2436
864
  return { success: true, version: targetVersion };
2437
865
  } catch (error) {
2438
866
  try {
2439
- fs9.rmSync(versionDir, { recursive: true, force: true });
867
+ fs3.rmSync(versionDir, { recursive: true, force: true });
2440
868
  } catch {}
2441
869
  return {
2442
870
  success: false,
@@ -2514,7 +942,7 @@ function performRollback() {
2514
942
  }
2515
943
 
2516
944
  // src/core/daemon.ts
2517
- import fs10 from "node:fs";
945
+ import fs4 from "node:fs";
2518
946
  import net from "node:net";
2519
947
  import { spawn as spawn2 } from "node:child_process";
2520
948
 
@@ -3466,10 +1894,10 @@ function createGatewayServer(options) {
3466
1894
 
3467
1895
  // src/core/daemon.ts
3468
1896
  function readPidFromFile(pidPath = getPidPath()) {
3469
- if (!fs10.existsSync(pidPath)) {
1897
+ if (!fs4.existsSync(pidPath)) {
3470
1898
  return null;
3471
1899
  }
3472
- const raw = fs10.readFileSync(pidPath, "utf8").trim();
1900
+ const raw = fs4.readFileSync(pidPath, "utf8").trim();
3473
1901
  if (!raw) {
3474
1902
  return null;
3475
1903
  }
@@ -3571,7 +1999,7 @@ async function startDaemon(config, cliPath, secrets) {
3571
1999
  };
3572
2000
  }
3573
2001
  try {
3574
- fs10.unlinkSync(getPidPath());
2002
+ fs4.unlinkSync(getPidPath());
3575
2003
  } catch {}
3576
2004
  }
3577
2005
  const port = await resolveGatewayPort(config);
@@ -3580,7 +2008,7 @@ async function startDaemon(config, cliPath, secrets) {
3580
2008
  const logPath = getLogPath();
3581
2009
  ensureParentDir(pidPath);
3582
2010
  ensureParentDir(logPath);
3583
- const logFd = fs10.openSync(logPath, "a", 384);
2011
+ const logFd = fs4.openSync(logPath, "a", 384);
3584
2012
  const child = spawn2(process.execPath, [cliPath, "daemon", "run", "--port", String(port)], {
3585
2013
  detached: true,
3586
2014
  stdio: ["ignore", logFd, logFd],
@@ -3590,7 +2018,7 @@ async function startDaemon(config, cliPath, secrets) {
3590
2018
  }
3591
2019
  });
3592
2020
  child.unref();
3593
- fs10.writeFileSync(pidPath, `${child.pid}
2021
+ fs4.writeFileSync(pidPath, `${child.pid}
3594
2022
  `, { mode: 384 });
3595
2023
  startBackgroundUpdateCheck();
3596
2024
  await waitForGatewayReady(port, token);
@@ -3614,7 +2042,7 @@ function stopDaemon() {
3614
2042
  process.kill(pid, "SIGTERM");
3615
2043
  } catch {}
3616
2044
  try {
3617
- fs10.unlinkSync(pidPath);
2045
+ fs4.unlinkSync(pidPath);
3618
2046
  } catch {}
3619
2047
  return {
3620
2048
  stopped: true,
@@ -3627,10 +2055,10 @@ async function restartDaemon(config, cliPath, secrets) {
3627
2055
  }
3628
2056
  function readDaemonLogs(maxLines = 200) {
3629
2057
  const logPath = getLogPath();
3630
- if (!fs10.existsSync(logPath)) {
2058
+ if (!fs4.existsSync(logPath)) {
3631
2059
  return "";
3632
2060
  }
3633
- const lines = fs10.readFileSync(logPath, "utf8").split(`
2061
+ const lines = fs4.readFileSync(logPath, "utf8").split(`
3634
2062
  `);
3635
2063
  return lines.slice(Math.max(lines.length - maxLines, 0)).join(`
3636
2064
  `);
@@ -3768,4 +2196,4 @@ async function buildStatusReport(config, managedIndex, daemon = getDaemonStatus(
3768
2196
  };
3769
2197
  }
3770
2198
 
3771
- export { listSkills, getSkill, saveSkill, deleteSkill, probeHttpAuthRequirement, fetchRegistryServerDetail, selectBestPackage, extractRequiredInputs, mapRegistryToSpec, getAdapters, loadManagedIndex, getGatewayUrl, syncAllClients, toSecretRef, secretRefName, defaultAuthSecretName, resolveAuthTarget, applyAuthReference, removeAuthReference, listAuthBindings, maybePrefixBearer, buildEnrichedPath, isOAuthReference, oauthReferenceServerName, runOAuthLogin, getOAuthAccessToken, APP_VERSION, compareVersions, checkForUpdates, getStagedUpdate, shouldUseStagedCli, clearStagedUpdate, getStagedCliPath, startBackgroundUpdateCheck, runBackgroundUpdate, performUpdate, performRollback, getDaemonStatus, startDaemon, stopDaemon, restartDaemon, readDaemonLogs, runDaemonForeground, STATUS_CLIENTS, buildStatusReport };
2199
+ export { probeHttpAuthRequirement, fetchRegistryServerDetail, selectBestPackage, extractRequiredInputs, mapRegistryToSpec, toSecretRef, secretRefName, defaultAuthSecretName, resolveAuthTarget, applyAuthReference, removeAuthReference, listAuthBindings, maybePrefixBearer, buildEnrichedPath, isOAuthReference, oauthReferenceServerName, runOAuthLogin, getOAuthAccessToken, APP_VERSION, compareVersions, checkForUpdates, getStagedUpdate, shouldUseStagedCli, clearStagedUpdate, getStagedCliPath, startBackgroundUpdateCheck, runBackgroundUpdate, performUpdate, performRollback, getDaemonStatus, startDaemon, stopDaemon, restartDaemon, readDaemonLogs, runDaemonForeground, STATUS_CLIENTS, buildStatusReport };