mcpman 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -0
- package/dist/chunk-YZNTMR6O.js +88 -0
- package/dist/index.cjs +1828 -419
- package/dist/index.js +1698 -410
- package/dist/lockfile-RBA7HB24.js +25 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -37,6 +37,100 @@ var init_cjs_shims = __esm({
|
|
|
37
37
|
}
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
+
// src/core/lockfile.ts
|
|
41
|
+
var lockfile_exports = {};
|
|
42
|
+
__export(lockfile_exports, {
|
|
43
|
+
LOCKFILE_NAME: () => LOCKFILE_NAME,
|
|
44
|
+
addEntry: () => addEntry,
|
|
45
|
+
createEmptyLockfile: () => createEmptyLockfile,
|
|
46
|
+
findLockfile: () => findLockfile,
|
|
47
|
+
getGlobalLockfilePath: () => getGlobalLockfilePath,
|
|
48
|
+
getLockedVersion: () => getLockedVersion,
|
|
49
|
+
readLockfile: () => readLockfile,
|
|
50
|
+
removeEntry: () => removeEntry,
|
|
51
|
+
resolveLockfilePath: () => resolveLockfilePath,
|
|
52
|
+
writeLockfile: () => writeLockfile
|
|
53
|
+
});
|
|
54
|
+
function findLockfile() {
|
|
55
|
+
let dir = process.cwd();
|
|
56
|
+
while (true) {
|
|
57
|
+
const candidate = import_node_path.default.join(dir, LOCKFILE_NAME);
|
|
58
|
+
if (import_node_fs.default.existsSync(candidate)) return candidate;
|
|
59
|
+
const parent = import_node_path.default.dirname(dir);
|
|
60
|
+
if (parent === dir) break;
|
|
61
|
+
dir = parent;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function getGlobalLockfilePath() {
|
|
66
|
+
return import_node_path.default.join(import_node_os.default.homedir(), ".mcpman", LOCKFILE_NAME);
|
|
67
|
+
}
|
|
68
|
+
function resolveLockfilePath() {
|
|
69
|
+
return findLockfile() ?? getGlobalLockfilePath();
|
|
70
|
+
}
|
|
71
|
+
function readLockfile(filePath) {
|
|
72
|
+
const target = filePath ?? resolveLockfilePath();
|
|
73
|
+
if (!import_node_fs.default.existsSync(target)) {
|
|
74
|
+
return { lockfileVersion: 1, servers: {} };
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const raw = import_node_fs.default.readFileSync(target, "utf-8");
|
|
78
|
+
return JSON.parse(raw);
|
|
79
|
+
} catch {
|
|
80
|
+
return { lockfileVersion: 1, servers: {} };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function serialize(data) {
|
|
84
|
+
const sorted = {
|
|
85
|
+
lockfileVersion: data.lockfileVersion,
|
|
86
|
+
servers: Object.fromEntries(
|
|
87
|
+
Object.entries(data.servers).sort(([a], [b]) => a.localeCompare(b))
|
|
88
|
+
)
|
|
89
|
+
};
|
|
90
|
+
return `${JSON.stringify(sorted, null, 2)}
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
function writeLockfile(data, filePath) {
|
|
94
|
+
const target = filePath ?? resolveLockfilePath();
|
|
95
|
+
const dir = import_node_path.default.dirname(target);
|
|
96
|
+
if (!import_node_fs.default.existsSync(dir)) {
|
|
97
|
+
import_node_fs.default.mkdirSync(dir, { recursive: true });
|
|
98
|
+
}
|
|
99
|
+
const tmp = `${target}.tmp`;
|
|
100
|
+
import_node_fs.default.writeFileSync(tmp, serialize(data), "utf-8");
|
|
101
|
+
import_node_fs.default.renameSync(tmp, target);
|
|
102
|
+
}
|
|
103
|
+
function addEntry(name, entry, filePath) {
|
|
104
|
+
const data = readLockfile(filePath);
|
|
105
|
+
data.servers[name] = entry;
|
|
106
|
+
writeLockfile(data, filePath);
|
|
107
|
+
}
|
|
108
|
+
function removeEntry(name, filePath) {
|
|
109
|
+
const data = readLockfile(filePath);
|
|
110
|
+
if (name in data.servers) {
|
|
111
|
+
delete data.servers[name];
|
|
112
|
+
writeLockfile(data, filePath);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function getLockedVersion(name, filePath) {
|
|
116
|
+
const data = readLockfile(filePath);
|
|
117
|
+
return data.servers[name]?.version;
|
|
118
|
+
}
|
|
119
|
+
function createEmptyLockfile(filePath) {
|
|
120
|
+
writeLockfile({ lockfileVersion: 1, servers: {} }, filePath);
|
|
121
|
+
}
|
|
122
|
+
var import_node_fs, import_node_os, import_node_path, LOCKFILE_NAME;
|
|
123
|
+
var init_lockfile = __esm({
|
|
124
|
+
"src/core/lockfile.ts"() {
|
|
125
|
+
"use strict";
|
|
126
|
+
init_cjs_shims();
|
|
127
|
+
import_node_fs = __toESM(require("fs"), 1);
|
|
128
|
+
import_node_os = __toESM(require("os"), 1);
|
|
129
|
+
import_node_path = __toESM(require("path"), 1);
|
|
130
|
+
LOCKFILE_NAME = "mcpman.lock";
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
40
134
|
// src/core/trust-scorer.ts
|
|
41
135
|
var trust_scorer_exports = {};
|
|
42
136
|
__export(trust_scorer_exports, {
|
|
@@ -437,12 +531,12 @@ __export(vault_service_exports, {
|
|
|
437
531
|
writeVault: () => writeVault
|
|
438
532
|
});
|
|
439
533
|
function getVaultPath() {
|
|
440
|
-
return
|
|
534
|
+
return import_node_path10.default.join(import_node_os5.default.homedir(), ".mcpman", "vault.enc");
|
|
441
535
|
}
|
|
442
536
|
function readVault(vaultPath = getVaultPath()) {
|
|
443
537
|
const empty = { version: 1, servers: {} };
|
|
444
538
|
try {
|
|
445
|
-
const raw =
|
|
539
|
+
const raw = import_node_fs8.default.readFileSync(vaultPath, "utf-8");
|
|
446
540
|
const parsed = JSON.parse(raw);
|
|
447
541
|
if (parsed.version !== 1 || typeof parsed.servers !== "object") return empty;
|
|
448
542
|
return parsed;
|
|
@@ -451,16 +545,16 @@ function readVault(vaultPath = getVaultPath()) {
|
|
|
451
545
|
}
|
|
452
546
|
}
|
|
453
547
|
function writeVault(data, vaultPath = getVaultPath()) {
|
|
454
|
-
const dir =
|
|
455
|
-
|
|
548
|
+
const dir = import_node_path10.default.dirname(vaultPath);
|
|
549
|
+
import_node_fs8.default.mkdirSync(dir, { recursive: true });
|
|
456
550
|
const tmp = `${vaultPath}.tmp`;
|
|
457
|
-
|
|
551
|
+
import_node_fs8.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
458
552
|
if (process.platform !== "win32") {
|
|
459
|
-
|
|
553
|
+
import_node_fs8.default.chmodSync(tmp, 384);
|
|
460
554
|
}
|
|
461
|
-
|
|
555
|
+
import_node_fs8.default.renameSync(tmp, vaultPath);
|
|
462
556
|
if (process.platform !== "win32") {
|
|
463
|
-
|
|
557
|
+
import_node_fs8.default.chmodSync(vaultPath, 384);
|
|
464
558
|
}
|
|
465
559
|
}
|
|
466
560
|
function encrypt(value, password2) {
|
|
@@ -550,15 +644,15 @@ function listSecrets(server, vaultPath = getVaultPath()) {
|
|
|
550
644
|
keys: Object.keys(keys)
|
|
551
645
|
}));
|
|
552
646
|
}
|
|
553
|
-
var import_node_crypto2,
|
|
647
|
+
var import_node_crypto2, import_node_fs8, import_node_os5, import_node_path10, p3, _cachedPassword;
|
|
554
648
|
var init_vault_service = __esm({
|
|
555
649
|
"src/core/vault-service.ts"() {
|
|
556
650
|
"use strict";
|
|
557
651
|
init_cjs_shims();
|
|
558
652
|
import_node_crypto2 = __toESM(require("crypto"), 1);
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
653
|
+
import_node_fs8 = __toESM(require("fs"), 1);
|
|
654
|
+
import_node_os5 = __toESM(require("os"), 1);
|
|
655
|
+
import_node_path10 = __toESM(require("path"), 1);
|
|
562
656
|
p3 = __toESM(require("@clack/prompts"), 1);
|
|
563
657
|
_cachedPassword = null;
|
|
564
658
|
process.on("exit", () => {
|
|
@@ -569,7 +663,7 @@ var init_vault_service = __esm({
|
|
|
569
663
|
|
|
570
664
|
// src/index.ts
|
|
571
665
|
init_cjs_shims();
|
|
572
|
-
var
|
|
666
|
+
var import_citty27 = require("citty");
|
|
573
667
|
|
|
574
668
|
// src/commands/audit.ts
|
|
575
669
|
init_cjs_shims();
|
|
@@ -577,70 +671,7 @@ var p = __toESM(require("@clack/prompts"), 1);
|
|
|
577
671
|
var import_citty = require("citty");
|
|
578
672
|
var import_nanospinner = require("nanospinner");
|
|
579
673
|
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
580
|
-
|
|
581
|
-
// src/core/lockfile.ts
|
|
582
|
-
init_cjs_shims();
|
|
583
|
-
var import_node_fs = __toESM(require("fs"), 1);
|
|
584
|
-
var import_node_os = __toESM(require("os"), 1);
|
|
585
|
-
var import_node_path = __toESM(require("path"), 1);
|
|
586
|
-
var LOCKFILE_NAME = "mcpman.lock";
|
|
587
|
-
function findLockfile() {
|
|
588
|
-
let dir = process.cwd();
|
|
589
|
-
while (true) {
|
|
590
|
-
const candidate = import_node_path.default.join(dir, LOCKFILE_NAME);
|
|
591
|
-
if (import_node_fs.default.existsSync(candidate)) return candidate;
|
|
592
|
-
const parent = import_node_path.default.dirname(dir);
|
|
593
|
-
if (parent === dir) break;
|
|
594
|
-
dir = parent;
|
|
595
|
-
}
|
|
596
|
-
return null;
|
|
597
|
-
}
|
|
598
|
-
function getGlobalLockfilePath() {
|
|
599
|
-
return import_node_path.default.join(import_node_os.default.homedir(), ".mcpman", LOCKFILE_NAME);
|
|
600
|
-
}
|
|
601
|
-
function resolveLockfilePath() {
|
|
602
|
-
return findLockfile() ?? getGlobalLockfilePath();
|
|
603
|
-
}
|
|
604
|
-
function readLockfile(filePath) {
|
|
605
|
-
const target = filePath ?? resolveLockfilePath();
|
|
606
|
-
if (!import_node_fs.default.existsSync(target)) {
|
|
607
|
-
return { lockfileVersion: 1, servers: {} };
|
|
608
|
-
}
|
|
609
|
-
try {
|
|
610
|
-
const raw = import_node_fs.default.readFileSync(target, "utf-8");
|
|
611
|
-
return JSON.parse(raw);
|
|
612
|
-
} catch {
|
|
613
|
-
return { lockfileVersion: 1, servers: {} };
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
function serialize(data) {
|
|
617
|
-
const sorted = {
|
|
618
|
-
lockfileVersion: data.lockfileVersion,
|
|
619
|
-
servers: Object.fromEntries(
|
|
620
|
-
Object.entries(data.servers).sort(([a], [b]) => a.localeCompare(b))
|
|
621
|
-
)
|
|
622
|
-
};
|
|
623
|
-
return `${JSON.stringify(sorted, null, 2)}
|
|
624
|
-
`;
|
|
625
|
-
}
|
|
626
|
-
function writeLockfile(data, filePath) {
|
|
627
|
-
const target = filePath ?? resolveLockfilePath();
|
|
628
|
-
const dir = import_node_path.default.dirname(target);
|
|
629
|
-
if (!import_node_fs.default.existsSync(dir)) {
|
|
630
|
-
import_node_fs.default.mkdirSync(dir, { recursive: true });
|
|
631
|
-
}
|
|
632
|
-
const tmp = `${target}.tmp`;
|
|
633
|
-
import_node_fs.default.writeFileSync(tmp, serialize(data), "utf-8");
|
|
634
|
-
import_node_fs.default.renameSync(tmp, target);
|
|
635
|
-
}
|
|
636
|
-
function addEntry(name, entry, filePath) {
|
|
637
|
-
const data = readLockfile(filePath);
|
|
638
|
-
data.servers[name] = entry;
|
|
639
|
-
writeLockfile(data, filePath);
|
|
640
|
-
}
|
|
641
|
-
function createEmptyLockfile(filePath) {
|
|
642
|
-
writeLockfile({ lockfileVersion: 1, servers: {} }, filePath);
|
|
643
|
-
}
|
|
674
|
+
init_lockfile();
|
|
644
675
|
|
|
645
676
|
// src/core/security-scanner.ts
|
|
646
677
|
init_cjs_shims();
|
|
@@ -786,6 +817,7 @@ async function scanAllServers(servers, concurrency = 3) {
|
|
|
786
817
|
|
|
787
818
|
// src/core/server-updater.ts
|
|
788
819
|
init_cjs_shims();
|
|
820
|
+
init_lockfile();
|
|
789
821
|
|
|
790
822
|
// src/core/registry.ts
|
|
791
823
|
init_cjs_shims();
|
|
@@ -1471,11 +1503,290 @@ async function runAuditFix(reports, servers, skipConfirm) {
|
|
|
1471
1503
|
`);
|
|
1472
1504
|
}
|
|
1473
1505
|
|
|
1474
|
-
// src/commands/
|
|
1506
|
+
// src/commands/completions.ts
|
|
1475
1507
|
init_cjs_shims();
|
|
1476
|
-
var
|
|
1508
|
+
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
1509
|
+
var import_node_os4 = __toESM(require("os"), 1);
|
|
1510
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
1477
1511
|
var import_citty2 = require("citty");
|
|
1478
1512
|
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
1513
|
+
|
|
1514
|
+
// src/core/completion-generator.ts
|
|
1515
|
+
init_cjs_shims();
|
|
1516
|
+
init_lockfile();
|
|
1517
|
+
function getCommandList() {
|
|
1518
|
+
return [
|
|
1519
|
+
"install",
|
|
1520
|
+
"list",
|
|
1521
|
+
"remove",
|
|
1522
|
+
"doctor",
|
|
1523
|
+
"init",
|
|
1524
|
+
"secrets",
|
|
1525
|
+
"sync",
|
|
1526
|
+
"audit",
|
|
1527
|
+
"update",
|
|
1528
|
+
"upgrade",
|
|
1529
|
+
"config",
|
|
1530
|
+
"search",
|
|
1531
|
+
"info",
|
|
1532
|
+
"run",
|
|
1533
|
+
"logs",
|
|
1534
|
+
"test",
|
|
1535
|
+
"profiles",
|
|
1536
|
+
"plugin",
|
|
1537
|
+
"export",
|
|
1538
|
+
"import",
|
|
1539
|
+
"create",
|
|
1540
|
+
"link",
|
|
1541
|
+
"watch",
|
|
1542
|
+
"registry",
|
|
1543
|
+
"completions",
|
|
1544
|
+
"why"
|
|
1545
|
+
];
|
|
1546
|
+
}
|
|
1547
|
+
var SERVER_ARG_COMMANDS = [
|
|
1548
|
+
"run",
|
|
1549
|
+
"test",
|
|
1550
|
+
"logs",
|
|
1551
|
+
"watch",
|
|
1552
|
+
"remove",
|
|
1553
|
+
"update",
|
|
1554
|
+
"info",
|
|
1555
|
+
"audit",
|
|
1556
|
+
"link",
|
|
1557
|
+
"why"
|
|
1558
|
+
];
|
|
1559
|
+
function getServerNames(lockfilePath) {
|
|
1560
|
+
try {
|
|
1561
|
+
const data = readLockfile(lockfilePath);
|
|
1562
|
+
return Object.keys(data.servers);
|
|
1563
|
+
} catch {
|
|
1564
|
+
return [];
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
function generateBashCompletion() {
|
|
1568
|
+
const serverCmds = SERVER_ARG_COMMANDS.join("|");
|
|
1569
|
+
return `# mcpman bash completion
|
|
1570
|
+
# Add to ~/.bashrc or ~/.bash_profile:
|
|
1571
|
+
# source <(mcpman completions bash)
|
|
1572
|
+
# Or append permanently:
|
|
1573
|
+
# mcpman completions bash >> ~/.bashrc
|
|
1574
|
+
|
|
1575
|
+
_mcpman_completions() {
|
|
1576
|
+
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
1577
|
+
local prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
1578
|
+
|
|
1579
|
+
if [ "$COMP_CWORD" -eq 1 ]; then
|
|
1580
|
+
COMPREPLY=($(compgen -W "$(mcpman completions --list-commands 2>/dev/null)" -- "$cur"))
|
|
1581
|
+
return
|
|
1582
|
+
fi
|
|
1583
|
+
|
|
1584
|
+
case "$prev" in
|
|
1585
|
+
${serverCmds})
|
|
1586
|
+
COMPREPLY=($(compgen -W "$(mcpman completions --list-servers 2>/dev/null)" -- "$cur"))
|
|
1587
|
+
;;
|
|
1588
|
+
--client|-c)
|
|
1589
|
+
COMPREPLY=($(compgen -W "claude-desktop cursor vscode windsurf" -- "$cur"))
|
|
1590
|
+
;;
|
|
1591
|
+
--runtime|-r)
|
|
1592
|
+
COMPREPLY=($(compgen -W "node python" -- "$cur"))
|
|
1593
|
+
;;
|
|
1594
|
+
esac
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
complete -F _mcpman_completions mcpman
|
|
1598
|
+
`;
|
|
1599
|
+
}
|
|
1600
|
+
function generateZshCompletion() {
|
|
1601
|
+
const serverCmds = SERVER_ARG_COMMANDS.map((c) => `'${c}'`).join(" ");
|
|
1602
|
+
return `#compdef mcpman
|
|
1603
|
+
# mcpman zsh completion
|
|
1604
|
+
# Add to ~/.zshrc:
|
|
1605
|
+
# source <(mcpman completions zsh)
|
|
1606
|
+
# Or use compinit:
|
|
1607
|
+
# mcpman completions zsh > "\${fpath[1]}/_mcpman"
|
|
1608
|
+
|
|
1609
|
+
_mcpman() {
|
|
1610
|
+
local state
|
|
1611
|
+
|
|
1612
|
+
_arguments \\
|
|
1613
|
+
'1: :->command' \\
|
|
1614
|
+
'*: :->args'
|
|
1615
|
+
|
|
1616
|
+
case $state in
|
|
1617
|
+
command)
|
|
1618
|
+
local commands
|
|
1619
|
+
commands=($(mcpman completions --list-commands 2>/dev/null))
|
|
1620
|
+
_describe 'command' commands
|
|
1621
|
+
;;
|
|
1622
|
+
args)
|
|
1623
|
+
local cmd="\${words[2]}"
|
|
1624
|
+
local server_cmds=(${serverCmds})
|
|
1625
|
+
if (( server_cmds[(I)$cmd] )); then
|
|
1626
|
+
local servers
|
|
1627
|
+
servers=($(mcpman completions --list-servers 2>/dev/null))
|
|
1628
|
+
_describe 'server' servers
|
|
1629
|
+
fi
|
|
1630
|
+
;;
|
|
1631
|
+
esac
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
compdef _mcpman mcpman
|
|
1635
|
+
`;
|
|
1636
|
+
}
|
|
1637
|
+
function generateFishCompletion() {
|
|
1638
|
+
const serverCmds = SERVER_ARG_COMMANDS.join(" ");
|
|
1639
|
+
return `# mcpman fish completion
|
|
1640
|
+
# Add to ~/.config/fish/completions/mcpman.fish:
|
|
1641
|
+
# mcpman completions fish > ~/.config/fish/completions/mcpman.fish
|
|
1642
|
+
|
|
1643
|
+
# Disable file completion for mcpman
|
|
1644
|
+
complete -c mcpman -f
|
|
1645
|
+
|
|
1646
|
+
# Subcommand completions (dynamic)
|
|
1647
|
+
complete -c mcpman -n '__fish_use_subcommand' \\
|
|
1648
|
+
-a "(mcpman completions --list-commands 2>/dev/null)"
|
|
1649
|
+
|
|
1650
|
+
# Server name completions for commands that take a server arg
|
|
1651
|
+
for cmd in ${serverCmds}
|
|
1652
|
+
complete -c mcpman -n "__fish_seen_subcommand_from $cmd" \\
|
|
1653
|
+
-a "(mcpman completions --list-servers 2>/dev/null)"
|
|
1654
|
+
end
|
|
1655
|
+
|
|
1656
|
+
# --client flag completions
|
|
1657
|
+
complete -c mcpman -l client -s c \\
|
|
1658
|
+
-a "claude-desktop cursor vscode windsurf" \\
|
|
1659
|
+
-d "Target client"
|
|
1660
|
+
|
|
1661
|
+
# --runtime flag completions
|
|
1662
|
+
complete -c mcpman -l runtime -s r \\
|
|
1663
|
+
-a "node python" \\
|
|
1664
|
+
-d "Runtime"
|
|
1665
|
+
`;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
// src/commands/completions.ts
|
|
1669
|
+
var completions_default = (0, import_citty2.defineCommand)({
|
|
1670
|
+
meta: {
|
|
1671
|
+
name: "completions",
|
|
1672
|
+
description: "Generate shell completion scripts (bash, zsh, fish)"
|
|
1673
|
+
},
|
|
1674
|
+
args: {
|
|
1675
|
+
shell: {
|
|
1676
|
+
type: "positional",
|
|
1677
|
+
description: "Shell: bash, zsh, fish, or install",
|
|
1678
|
+
required: false
|
|
1679
|
+
},
|
|
1680
|
+
"list-commands": {
|
|
1681
|
+
type: "boolean",
|
|
1682
|
+
description: "Output all command names (used by completion scripts)",
|
|
1683
|
+
default: false
|
|
1684
|
+
},
|
|
1685
|
+
"list-servers": {
|
|
1686
|
+
type: "boolean",
|
|
1687
|
+
description: "Output server names from lockfile (used by completion scripts)",
|
|
1688
|
+
default: false
|
|
1689
|
+
}
|
|
1690
|
+
},
|
|
1691
|
+
async run({ args }) {
|
|
1692
|
+
if (args["list-commands"]) {
|
|
1693
|
+
console.log(getCommandList().join("\n"));
|
|
1694
|
+
return;
|
|
1695
|
+
}
|
|
1696
|
+
if (args["list-servers"]) {
|
|
1697
|
+
console.log(getServerNames().join("\n"));
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
const shell = args.shell;
|
|
1701
|
+
if (!shell) {
|
|
1702
|
+
printUsage();
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
switch (shell.toLowerCase()) {
|
|
1706
|
+
case "bash":
|
|
1707
|
+
process.stdout.write(generateBashCompletion());
|
|
1708
|
+
break;
|
|
1709
|
+
case "zsh":
|
|
1710
|
+
process.stdout.write(generateZshCompletion());
|
|
1711
|
+
break;
|
|
1712
|
+
case "fish":
|
|
1713
|
+
process.stdout.write(generateFishCompletion());
|
|
1714
|
+
break;
|
|
1715
|
+
case "install":
|
|
1716
|
+
await installCompletion();
|
|
1717
|
+
break;
|
|
1718
|
+
default:
|
|
1719
|
+
console.error(import_picocolors2.default.red(` Error: Unknown shell '${shell}'. Use: bash, zsh, or fish.`));
|
|
1720
|
+
process.exit(1);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
});
|
|
1724
|
+
function printUsage() {
|
|
1725
|
+
console.log(import_picocolors2.default.bold("\n mcpman completions \u2014 Shell completion setup\n"));
|
|
1726
|
+
console.log(" Usage:");
|
|
1727
|
+
console.log(` ${import_picocolors2.default.cyan("mcpman completions bash")} Output bash completion script`);
|
|
1728
|
+
console.log(` ${import_picocolors2.default.cyan("mcpman completions zsh")} Output zsh completion script`);
|
|
1729
|
+
console.log(` ${import_picocolors2.default.cyan("mcpman completions fish")} Output fish completion script`);
|
|
1730
|
+
console.log(` ${import_picocolors2.default.cyan("mcpman completions install")} Auto-detect shell and install
|
|
1731
|
+
`);
|
|
1732
|
+
console.log(" Quick setup:");
|
|
1733
|
+
console.log(` ${import_picocolors2.default.dim("# bash")}`);
|
|
1734
|
+
console.log(` ${import_picocolors2.default.cyan("source <(mcpman completions bash)")}`);
|
|
1735
|
+
console.log(` ${import_picocolors2.default.dim("# zsh")}`);
|
|
1736
|
+
console.log(` ${import_picocolors2.default.cyan("source <(mcpman completions zsh)")}
|
|
1737
|
+
`);
|
|
1738
|
+
}
|
|
1739
|
+
async function installCompletion() {
|
|
1740
|
+
const shellBin = process.env.SHELL ?? "";
|
|
1741
|
+
let detectedShell = "";
|
|
1742
|
+
if (shellBin.includes("zsh")) detectedShell = "zsh";
|
|
1743
|
+
else if (shellBin.includes("fish")) detectedShell = "fish";
|
|
1744
|
+
else if (shellBin.includes("bash")) detectedShell = "bash";
|
|
1745
|
+
if (!detectedShell) {
|
|
1746
|
+
console.error(import_picocolors2.default.red(" Could not detect shell from $SHELL. Run manually:"));
|
|
1747
|
+
console.error(import_picocolors2.default.dim(" source <(mcpman completions bash|zsh|fish)"));
|
|
1748
|
+
process.exit(1);
|
|
1749
|
+
}
|
|
1750
|
+
const home = import_node_os4.default.homedir();
|
|
1751
|
+
let rcFile;
|
|
1752
|
+
let script;
|
|
1753
|
+
if (detectedShell === "zsh") {
|
|
1754
|
+
rcFile = import_node_path7.default.join(home, ".zshrc");
|
|
1755
|
+
script = generateZshCompletion();
|
|
1756
|
+
} else if (detectedShell === "fish") {
|
|
1757
|
+
const fishDir = import_node_path7.default.join(home, ".config", "fish", "completions");
|
|
1758
|
+
import_node_fs6.default.mkdirSync(fishDir, { recursive: true });
|
|
1759
|
+
rcFile = import_node_path7.default.join(fishDir, "mcpman.fish");
|
|
1760
|
+
import_node_fs6.default.writeFileSync(rcFile, generateFishCompletion(), "utf-8");
|
|
1761
|
+
console.log(import_picocolors2.default.green(` Installed fish completions to ${rcFile}`));
|
|
1762
|
+
return;
|
|
1763
|
+
} else {
|
|
1764
|
+
rcFile = import_node_path7.default.join(home, ".bashrc");
|
|
1765
|
+
script = generateBashCompletion();
|
|
1766
|
+
}
|
|
1767
|
+
const marker = "# mcpman completions";
|
|
1768
|
+
let existing = "";
|
|
1769
|
+
try {
|
|
1770
|
+
existing = import_node_fs6.default.readFileSync(rcFile, "utf-8");
|
|
1771
|
+
} catch {
|
|
1772
|
+
}
|
|
1773
|
+
if (existing.includes(marker)) {
|
|
1774
|
+
console.log(import_picocolors2.default.yellow(` Completions already installed in ${rcFile}. Skipping.`));
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
import_node_fs6.default.appendFileSync(rcFile, `
|
|
1778
|
+
${marker}
|
|
1779
|
+
source <(mcpman completions ${detectedShell})
|
|
1780
|
+
`);
|
|
1781
|
+
console.log(import_picocolors2.default.green(` Installed ${detectedShell} completions in ${rcFile}`));
|
|
1782
|
+
console.log(import_picocolors2.default.dim(` Restart your shell or run: source ${rcFile}`));
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
// src/commands/config.ts
|
|
1786
|
+
init_cjs_shims();
|
|
1787
|
+
var p2 = __toESM(require("@clack/prompts"), 1);
|
|
1788
|
+
var import_citty3 = require("citty");
|
|
1789
|
+
var import_picocolors3 = __toESM(require("picocolors"), 1);
|
|
1479
1790
|
function coerceValue(raw) {
|
|
1480
1791
|
if (raw === "true") return true;
|
|
1481
1792
|
if (raw === "false") return false;
|
|
@@ -1483,7 +1794,7 @@ function coerceValue(raw) {
|
|
|
1483
1794
|
if (!Number.isNaN(num) && raw.trim() !== "") return num;
|
|
1484
1795
|
return raw;
|
|
1485
1796
|
}
|
|
1486
|
-
var setCommand = (0,
|
|
1797
|
+
var setCommand = (0, import_citty3.defineCommand)({
|
|
1487
1798
|
meta: { name: "set", description: "Set a config value" },
|
|
1488
1799
|
args: {
|
|
1489
1800
|
key: {
|
|
@@ -1501,14 +1812,14 @@ var setCommand = (0, import_citty2.defineCommand)({
|
|
|
1501
1812
|
try {
|
|
1502
1813
|
const coerced = coerceValue(args.value);
|
|
1503
1814
|
setConfigValue(args.key, coerced);
|
|
1504
|
-
console.log(`${
|
|
1815
|
+
console.log(`${import_picocolors3.default.green("\u2713")} Set ${import_picocolors3.default.bold(args.key)} = ${import_picocolors3.default.cyan(String(coerced))}`);
|
|
1505
1816
|
} catch (err) {
|
|
1506
|
-
console.error(`${
|
|
1817
|
+
console.error(`${import_picocolors3.default.red("\u2717")} ${String(err)}`);
|
|
1507
1818
|
process.exit(1);
|
|
1508
1819
|
}
|
|
1509
1820
|
}
|
|
1510
1821
|
});
|
|
1511
|
-
var getCommand = (0,
|
|
1822
|
+
var getCommand = (0, import_citty3.defineCommand)({
|
|
1512
1823
|
meta: { name: "get", description: "Get a config value" },
|
|
1513
1824
|
args: {
|
|
1514
1825
|
key: {
|
|
@@ -1520,32 +1831,32 @@ var getCommand = (0, import_citty2.defineCommand)({
|
|
|
1520
1831
|
run({ args }) {
|
|
1521
1832
|
const val = getConfigValue(args.key);
|
|
1522
1833
|
if (val === void 0) {
|
|
1523
|
-
console.log(
|
|
1834
|
+
console.log(import_picocolors3.default.dim(`${args.key}: (not set)`));
|
|
1524
1835
|
} else {
|
|
1525
|
-
console.log(`${
|
|
1836
|
+
console.log(`${import_picocolors3.default.bold(args.key)}: ${import_picocolors3.default.cyan(String(val))}`);
|
|
1526
1837
|
}
|
|
1527
1838
|
}
|
|
1528
1839
|
});
|
|
1529
|
-
var listCommand = (0,
|
|
1840
|
+
var listCommand = (0, import_citty3.defineCommand)({
|
|
1530
1841
|
meta: { name: "list", description: "List all config values" },
|
|
1531
1842
|
run() {
|
|
1532
1843
|
const data = readConfig();
|
|
1533
1844
|
const entries = Object.entries(data);
|
|
1534
1845
|
if (entries.length === 0) {
|
|
1535
|
-
console.log(
|
|
1846
|
+
console.log(import_picocolors3.default.dim("No config values set. Use `mcpman config set <key> <value>`."));
|
|
1536
1847
|
return;
|
|
1537
1848
|
}
|
|
1538
1849
|
console.log("");
|
|
1539
|
-
console.log(
|
|
1850
|
+
console.log(import_picocolors3.default.bold("mcpman config:"));
|
|
1540
1851
|
console.log("");
|
|
1541
1852
|
for (const [key, val] of entries) {
|
|
1542
|
-
console.log(` ${
|
|
1853
|
+
console.log(` ${import_picocolors3.default.green("\u25CF")} ${import_picocolors3.default.bold(key)} ${import_picocolors3.default.cyan(String(val))}`);
|
|
1543
1854
|
}
|
|
1544
1855
|
console.log("");
|
|
1545
|
-
console.log(
|
|
1856
|
+
console.log(import_picocolors3.default.dim(` ${entries.length} key${entries.length !== 1 ? "s" : ""} configured`));
|
|
1546
1857
|
}
|
|
1547
1858
|
});
|
|
1548
|
-
var resetCommand = (0,
|
|
1859
|
+
var resetCommand = (0, import_citty3.defineCommand)({
|
|
1549
1860
|
meta: { name: "reset", description: "Reset config to defaults (removes config file)" },
|
|
1550
1861
|
async run() {
|
|
1551
1862
|
const confirmed = await p2.confirm({
|
|
@@ -1557,10 +1868,10 @@ var resetCommand = (0, import_citty2.defineCommand)({
|
|
|
1557
1868
|
return;
|
|
1558
1869
|
}
|
|
1559
1870
|
writeConfig({});
|
|
1560
|
-
console.log(`${
|
|
1871
|
+
console.log(`${import_picocolors3.default.green("\u2713")} Config reset to defaults.`);
|
|
1561
1872
|
}
|
|
1562
1873
|
});
|
|
1563
|
-
var config_default = (0,
|
|
1874
|
+
var config_default = (0, import_citty3.defineCommand)({
|
|
1564
1875
|
meta: {
|
|
1565
1876
|
name: "config",
|
|
1566
1877
|
description: "Manage mcpman CLI configuration"
|
|
@@ -1573,46 +1884,336 @@ var config_default = (0, import_citty2.defineCommand)({
|
|
|
1573
1884
|
}
|
|
1574
1885
|
});
|
|
1575
1886
|
|
|
1576
|
-
// src/commands/
|
|
1887
|
+
// src/commands/create.ts
|
|
1577
1888
|
init_cjs_shims();
|
|
1578
|
-
var
|
|
1579
|
-
var
|
|
1889
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
1890
|
+
var import_citty4 = require("citty");
|
|
1891
|
+
var import_picocolors4 = __toESM(require("picocolors"), 1);
|
|
1580
1892
|
|
|
1581
|
-
// src/core/
|
|
1893
|
+
// src/core/scaffold-service.ts
|
|
1582
1894
|
init_cjs_shims();
|
|
1895
|
+
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
1896
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
1897
|
+
function sanitizeName(name) {
|
|
1898
|
+
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
1899
|
+
}
|
|
1900
|
+
function generateNodeProject(options) {
|
|
1901
|
+
const { name, description } = options;
|
|
1902
|
+
const packageJson = JSON.stringify(
|
|
1903
|
+
{
|
|
1904
|
+
name,
|
|
1905
|
+
version: "0.1.0",
|
|
1906
|
+
description,
|
|
1907
|
+
type: "module",
|
|
1908
|
+
bin: { [name]: "./dist/index.js" },
|
|
1909
|
+
main: "./dist/index.js",
|
|
1910
|
+
scripts: {
|
|
1911
|
+
build: "tsc",
|
|
1912
|
+
start: "node dist/index.js",
|
|
1913
|
+
dev: "tsx src/index.ts"
|
|
1914
|
+
},
|
|
1915
|
+
mcp: {
|
|
1916
|
+
name,
|
|
1917
|
+
description,
|
|
1918
|
+
transport: "stdio",
|
|
1919
|
+
env: []
|
|
1920
|
+
},
|
|
1921
|
+
dependencies: {
|
|
1922
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
1923
|
+
},
|
|
1924
|
+
devDependencies: {
|
|
1925
|
+
typescript: "^5.0.0",
|
|
1926
|
+
tsx: "^4.0.0",
|
|
1927
|
+
"@types/node": "^20.0.0"
|
|
1928
|
+
}
|
|
1929
|
+
},
|
|
1930
|
+
null,
|
|
1931
|
+
2
|
|
1932
|
+
);
|
|
1933
|
+
const tsconfig = JSON.stringify(
|
|
1934
|
+
{
|
|
1935
|
+
compilerOptions: {
|
|
1936
|
+
target: "ES2022",
|
|
1937
|
+
module: "NodeNext",
|
|
1938
|
+
moduleResolution: "NodeNext",
|
|
1939
|
+
outDir: "./dist",
|
|
1940
|
+
rootDir: "./src",
|
|
1941
|
+
strict: true,
|
|
1942
|
+
esModuleInterop: true,
|
|
1943
|
+
skipLibCheck: true
|
|
1944
|
+
},
|
|
1945
|
+
include: ["src"]
|
|
1946
|
+
},
|
|
1947
|
+
null,
|
|
1948
|
+
2
|
|
1949
|
+
);
|
|
1950
|
+
const indexTs = `#!/usr/bin/env node
|
|
1951
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
1952
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1583
1953
|
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1954
|
+
const server = new Server(
|
|
1955
|
+
{ name: "${name}", version: "0.1.0" },
|
|
1956
|
+
{ capabilities: { tools: {} } }
|
|
1957
|
+
);
|
|
1588
1958
|
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1959
|
+
server.setRequestHandler("tools/list", async () => ({
|
|
1960
|
+
tools: [
|
|
1961
|
+
{
|
|
1962
|
+
name: "hello",
|
|
1963
|
+
description: "Say hello",
|
|
1964
|
+
inputSchema: { type: "object", properties: { name: { type: "string" } } },
|
|
1965
|
+
},
|
|
1966
|
+
],
|
|
1967
|
+
}));
|
|
1968
|
+
|
|
1969
|
+
server.setRequestHandler("tools/call", async (request) => {
|
|
1970
|
+
if (request.params.name === "hello") {
|
|
1971
|
+
const who = request.params.arguments?.name ?? "world";
|
|
1972
|
+
return { content: [{ type: "text", text: \`Hello, \${who}!\` }] };
|
|
1973
|
+
}
|
|
1974
|
+
throw new Error(\`Unknown tool: \${request.params.name}\`);
|
|
1975
|
+
});
|
|
1976
|
+
|
|
1977
|
+
const transport = new StdioServerTransport();
|
|
1978
|
+
await server.connect(transport);
|
|
1979
|
+
`;
|
|
1980
|
+
return {
|
|
1981
|
+
"package.json": packageJson,
|
|
1982
|
+
"tsconfig.json": tsconfig,
|
|
1983
|
+
"src/index.ts": indexTs
|
|
1984
|
+
};
|
|
1985
|
+
}
|
|
1986
|
+
function generatePythonProject(options) {
|
|
1987
|
+
const { name, description } = options;
|
|
1988
|
+
const pyprojectToml = `[build-system]
|
|
1989
|
+
requires = ["setuptools>=68"]
|
|
1990
|
+
build-backend = "setuptools.backends.legacy:build"
|
|
1991
|
+
|
|
1992
|
+
[project]
|
|
1993
|
+
name = "${name}"
|
|
1994
|
+
version = "0.1.0"
|
|
1995
|
+
description = "${description}"
|
|
1996
|
+
requires-python = ">=3.10"
|
|
1997
|
+
dependencies = ["mcp>=1.0.0"]
|
|
1998
|
+
|
|
1999
|
+
[project.scripts]
|
|
2000
|
+
${name} = "${name.replace(/-/g, "_")}:main"
|
|
2001
|
+
|
|
2002
|
+
[tool.mcp]
|
|
2003
|
+
name = "${name}"
|
|
2004
|
+
description = "${description}"
|
|
2005
|
+
transport = "stdio"
|
|
2006
|
+
`;
|
|
2007
|
+
const mainPy = `#!/usr/bin/env python3
|
|
2008
|
+
"""${description}"""
|
|
2009
|
+
from mcp.server import Server
|
|
2010
|
+
from mcp.server.stdio import stdio_server
|
|
2011
|
+
|
|
2012
|
+
app = Server("${name}")
|
|
2013
|
+
|
|
2014
|
+
@app.list_tools()
|
|
2015
|
+
async def list_tools():
|
|
2016
|
+
return [
|
|
2017
|
+
{
|
|
2018
|
+
"name": "hello",
|
|
2019
|
+
"description": "Say hello",
|
|
2020
|
+
"inputSchema": {
|
|
2021
|
+
"type": "object",
|
|
2022
|
+
"properties": {"name": {"type": "string"}},
|
|
2023
|
+
},
|
|
2024
|
+
}
|
|
2025
|
+
]
|
|
2026
|
+
|
|
2027
|
+
@app.call_tool()
|
|
2028
|
+
async def call_tool(name: str, arguments: dict):
|
|
2029
|
+
if name == "hello":
|
|
2030
|
+
who = arguments.get("name", "world")
|
|
2031
|
+
return [{"type": "text", "text": f"Hello, {who}!"}]
|
|
2032
|
+
raise ValueError(f"Unknown tool: {name}")
|
|
2033
|
+
|
|
2034
|
+
async def main():
|
|
2035
|
+
async with stdio_server() as (read, write):
|
|
2036
|
+
await app.run(read, write)
|
|
2037
|
+
|
|
2038
|
+
if __name__ == "__main__":
|
|
2039
|
+
import asyncio
|
|
2040
|
+
asyncio.run(main())
|
|
2041
|
+
`;
|
|
2042
|
+
return {
|
|
2043
|
+
"pyproject.toml": pyprojectToml,
|
|
2044
|
+
"main.py": mainPy
|
|
2045
|
+
};
|
|
2046
|
+
}
|
|
2047
|
+
function writeScaffold(dir, files) {
|
|
2048
|
+
if (import_node_fs7.default.existsSync(dir)) {
|
|
2049
|
+
const existing = import_node_fs7.default.readdirSync(dir);
|
|
2050
|
+
if (existing.length > 0) {
|
|
2051
|
+
throw new Error(`Directory '${dir}' already exists and is not empty.`);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
for (const [relativePath, content] of Object.entries(files)) {
|
|
2055
|
+
const fullPath = import_node_path8.default.join(dir, relativePath);
|
|
2056
|
+
const parentDir = import_node_path8.default.dirname(fullPath);
|
|
2057
|
+
import_node_fs7.default.mkdirSync(parentDir, { recursive: true });
|
|
2058
|
+
import_node_fs7.default.writeFileSync(fullPath, content, "utf-8");
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
// src/commands/create.ts
|
|
2063
|
+
var create_default = (0, import_citty4.defineCommand)({
|
|
2064
|
+
meta: {
|
|
2065
|
+
name: "create",
|
|
2066
|
+
description: "Scaffold a new MCP server project"
|
|
2067
|
+
},
|
|
2068
|
+
args: {
|
|
2069
|
+
name: {
|
|
2070
|
+
type: "positional",
|
|
2071
|
+
description: "Project name",
|
|
2072
|
+
required: false
|
|
2073
|
+
},
|
|
2074
|
+
runtime: {
|
|
2075
|
+
type: "string",
|
|
2076
|
+
description: "Runtime: node or python (default: node)",
|
|
2077
|
+
alias: "r"
|
|
2078
|
+
},
|
|
2079
|
+
description: {
|
|
2080
|
+
type: "string",
|
|
2081
|
+
description: "Project description",
|
|
2082
|
+
alias: "d"
|
|
2083
|
+
},
|
|
2084
|
+
yes: {
|
|
2085
|
+
type: "boolean",
|
|
2086
|
+
description: "Accept all defaults, skip prompts",
|
|
2087
|
+
alias: "y",
|
|
2088
|
+
default: false
|
|
2089
|
+
}
|
|
2090
|
+
},
|
|
2091
|
+
async run({ args }) {
|
|
2092
|
+
let projectName = args.name ?? "";
|
|
2093
|
+
let projectDescription = args.description ?? "";
|
|
2094
|
+
let runtime = args.runtime ?? "node";
|
|
2095
|
+
const acceptDefaults = args.yes;
|
|
2096
|
+
if (!acceptDefaults) {
|
|
2097
|
+
if (!projectName) {
|
|
2098
|
+
const readline = await import("readline");
|
|
2099
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
2100
|
+
projectName = await new Promise((resolve) => {
|
|
2101
|
+
rl.question(import_picocolors4.default.cyan(" Project name: "), (answer) => {
|
|
2102
|
+
rl.close();
|
|
2103
|
+
resolve(answer.trim());
|
|
2104
|
+
});
|
|
2105
|
+
});
|
|
2106
|
+
}
|
|
2107
|
+
if (!projectDescription) {
|
|
2108
|
+
const readline = await import("readline");
|
|
2109
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
2110
|
+
projectDescription = await new Promise((resolve) => {
|
|
2111
|
+
rl.question(import_picocolors4.default.cyan(" Description (optional): "), (answer) => {
|
|
2112
|
+
rl.close();
|
|
2113
|
+
resolve(answer.trim());
|
|
2114
|
+
});
|
|
2115
|
+
});
|
|
2116
|
+
}
|
|
2117
|
+
if (!args.runtime) {
|
|
2118
|
+
const readline = await import("readline");
|
|
2119
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
2120
|
+
const answer = await new Promise((resolve) => {
|
|
2121
|
+
rl.question(import_picocolors4.default.cyan(" Runtime [node/python] (default: node): "), (a) => {
|
|
2122
|
+
rl.close();
|
|
2123
|
+
resolve(a.trim() || "node");
|
|
2124
|
+
});
|
|
2125
|
+
});
|
|
2126
|
+
runtime = answer;
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
if (!projectName) {
|
|
2130
|
+
console.error(import_picocolors4.default.red(" Error: Project name is required."));
|
|
2131
|
+
process.exit(1);
|
|
2132
|
+
}
|
|
2133
|
+
const sanitized = sanitizeName(projectName);
|
|
2134
|
+
if (!sanitized) {
|
|
2135
|
+
console.error(import_picocolors4.default.red(` Error: Invalid project name '${projectName}'.`));
|
|
2136
|
+
process.exit(1);
|
|
2137
|
+
}
|
|
2138
|
+
if (runtime !== "node" && runtime !== "python") {
|
|
2139
|
+
console.error(import_picocolors4.default.red(` Error: Unknown runtime '${runtime}'. Use node or python.`));
|
|
2140
|
+
process.exit(1);
|
|
2141
|
+
}
|
|
2142
|
+
const options = {
|
|
2143
|
+
name: sanitized,
|
|
2144
|
+
description: projectDescription || `${sanitized} MCP server`,
|
|
2145
|
+
runtime,
|
|
2146
|
+
transport: "stdio"
|
|
2147
|
+
};
|
|
2148
|
+
const files = runtime === "python" ? generatePythonProject(options) : generateNodeProject(options);
|
|
2149
|
+
const targetDir = import_node_path9.default.resolve(sanitized);
|
|
2150
|
+
try {
|
|
2151
|
+
writeScaffold(targetDir, files);
|
|
2152
|
+
} catch (err) {
|
|
2153
|
+
console.error(import_picocolors4.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
2154
|
+
process.exit(1);
|
|
2155
|
+
}
|
|
2156
|
+
console.log(import_picocolors4.default.green(`
|
|
2157
|
+
Created ${import_picocolors4.default.bold(sanitized)}/
|
|
2158
|
+
`));
|
|
2159
|
+
console.log(import_picocolors4.default.dim(" Files generated:"));
|
|
2160
|
+
for (const file of Object.keys(files)) {
|
|
2161
|
+
console.log(` ${import_picocolors4.default.cyan(file)}`);
|
|
2162
|
+
}
|
|
2163
|
+
console.log("\n Next steps:");
|
|
2164
|
+
if (runtime === "node") {
|
|
2165
|
+
console.log(` ${import_picocolors4.default.bold(`cd ${sanitized}`)}`);
|
|
2166
|
+
console.log(` ${import_picocolors4.default.bold("npm install")}`);
|
|
2167
|
+
console.log(` ${import_picocolors4.default.bold("mcpman link .")}`);
|
|
2168
|
+
} else {
|
|
2169
|
+
console.log(` ${import_picocolors4.default.bold(`cd ${sanitized}`)}`);
|
|
2170
|
+
console.log(` ${import_picocolors4.default.bold("pip install -e .")}`);
|
|
2171
|
+
console.log(` ${import_picocolors4.default.bold("mcpman link .")}`);
|
|
2172
|
+
}
|
|
2173
|
+
console.log();
|
|
2174
|
+
}
|
|
2175
|
+
});
|
|
2176
|
+
|
|
2177
|
+
// src/commands/doctor.ts
|
|
2178
|
+
init_cjs_shims();
|
|
2179
|
+
var import_citty5 = require("citty");
|
|
2180
|
+
var import_picocolors5 = __toESM(require("picocolors"), 1);
|
|
2181
|
+
|
|
2182
|
+
// src/core/health-checker.ts
|
|
2183
|
+
init_cjs_shims();
|
|
2184
|
+
|
|
2185
|
+
// src/core/diagnostics.ts
|
|
2186
|
+
init_cjs_shims();
|
|
2187
|
+
var import_node_child_process3 = require("child_process");
|
|
2188
|
+
var import_node_util = require("util");
|
|
2189
|
+
|
|
2190
|
+
// src/core/mcp-process-checks.ts
|
|
2191
|
+
init_cjs_shims();
|
|
2192
|
+
var import_node_child_process2 = require("child_process");
|
|
2193
|
+
async function checkProcessSpawn(command, args, env, timeoutMs = 3e3) {
|
|
2194
|
+
return new Promise((resolve) => {
|
|
2195
|
+
let settled = false;
|
|
2196
|
+
const child = (0, import_node_child_process2.spawn)(command, args, {
|
|
2197
|
+
env: { ...process.env, ...env },
|
|
2198
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
2199
|
+
});
|
|
2200
|
+
const timer = setTimeout(() => {
|
|
2201
|
+
if (!settled) {
|
|
2202
|
+
settled = true;
|
|
2203
|
+
child.kill("SIGTERM");
|
|
2204
|
+
resolve({ name: "Process", passed: true, message: "starts successfully (still running)" });
|
|
2205
|
+
}
|
|
2206
|
+
}, timeoutMs);
|
|
2207
|
+
child.on("error", (err) => {
|
|
2208
|
+
if (!settled) {
|
|
2209
|
+
settled = true;
|
|
2210
|
+
clearTimeout(timer);
|
|
2211
|
+
resolve({ name: "Process", passed: false, message: `spawn error: ${err.message}` });
|
|
2212
|
+
}
|
|
2213
|
+
});
|
|
2214
|
+
child.on("exit", (code) => {
|
|
2215
|
+
if (!settled) {
|
|
2216
|
+
settled = true;
|
|
1616
2217
|
clearTimeout(timer);
|
|
1617
2218
|
if (code === 0 || code === null) {
|
|
1618
2219
|
resolve({ name: "Process", passed: true, message: "exits cleanly" });
|
|
@@ -1929,12 +2530,12 @@ async function getInstalledServers(clientFilter) {
|
|
|
1929
2530
|
|
|
1930
2531
|
// src/commands/doctor.ts
|
|
1931
2532
|
var CHECK_ICON = {
|
|
1932
|
-
pass:
|
|
1933
|
-
fail:
|
|
1934
|
-
skip:
|
|
1935
|
-
warn:
|
|
2533
|
+
pass: import_picocolors5.default.green("\u2713"),
|
|
2534
|
+
fail: import_picocolors5.default.red("\u2717"),
|
|
2535
|
+
skip: import_picocolors5.default.dim("-"),
|
|
2536
|
+
warn: import_picocolors5.default.yellow("\u26A0")
|
|
1936
2537
|
};
|
|
1937
|
-
var doctor_default = (0,
|
|
2538
|
+
var doctor_default = (0, import_citty5.defineCommand)({
|
|
1938
2539
|
meta: {
|
|
1939
2540
|
name: "doctor",
|
|
1940
2541
|
description: "Check MCP server health and configuration"
|
|
@@ -1947,11 +2548,11 @@ var doctor_default = (0, import_citty3.defineCommand)({
|
|
|
1947
2548
|
}
|
|
1948
2549
|
},
|
|
1949
2550
|
async run({ args }) {
|
|
1950
|
-
console.log(
|
|
2551
|
+
console.log(import_picocolors5.default.bold("\n mcpman doctor\n"));
|
|
1951
2552
|
const servers = await getInstalledServers();
|
|
1952
2553
|
if (servers.length === 0) {
|
|
1953
2554
|
console.log(
|
|
1954
|
-
|
|
2555
|
+
import_picocolors5.default.dim(" No MCP servers installed. Run mcpman install <server> to get started.")
|
|
1955
2556
|
);
|
|
1956
2557
|
return;
|
|
1957
2558
|
}
|
|
@@ -1968,20 +2569,20 @@ var doctor_default = (0, import_citty3.defineCommand)({
|
|
|
1968
2569
|
if (pluginSummary.total > 0) {
|
|
1969
2570
|
printPluginSection(pluginSummary);
|
|
1970
2571
|
}
|
|
1971
|
-
console.log(
|
|
2572
|
+
console.log(import_picocolors5.default.dim(` ${"\u2500".repeat(50)}`));
|
|
1972
2573
|
const parts = [];
|
|
1973
|
-
if (passed > 0) parts.push(
|
|
1974
|
-
if (failed > 0) parts.push(
|
|
2574
|
+
if (passed > 0) parts.push(import_picocolors5.default.green(`${passed} healthy`));
|
|
2575
|
+
if (failed > 0) parts.push(import_picocolors5.default.red(`${failed} unhealthy`));
|
|
1975
2576
|
console.log(` Summary: ${parts.join(", ")}`);
|
|
1976
2577
|
if (pluginSummary.total > 0) {
|
|
1977
2578
|
const pParts = [];
|
|
1978
|
-
if (pluginSummary.healthy > 0) pParts.push(
|
|
1979
|
-
if (pluginSummary.unhealthy > 0) pParts.push(
|
|
2579
|
+
if (pluginSummary.healthy > 0) pParts.push(import_picocolors5.default.green(`${pluginSummary.healthy} ok`));
|
|
2580
|
+
if (pluginSummary.unhealthy > 0) pParts.push(import_picocolors5.default.red(`${pluginSummary.unhealthy} broken`));
|
|
1980
2581
|
console.log(` Plugins: ${pParts.join(", ")}`);
|
|
1981
2582
|
}
|
|
1982
2583
|
if (failed > 0 || pluginSummary.unhealthy > 0) {
|
|
1983
2584
|
if (!args.fix) {
|
|
1984
|
-
console.log(
|
|
2585
|
+
console.log(import_picocolors5.default.dim(` Run ${import_picocolors5.default.cyan("mcpman doctor --fix")} for fix suggestions.
|
|
1985
2586
|
`));
|
|
1986
2587
|
}
|
|
1987
2588
|
process.exit(1);
|
|
@@ -1990,26 +2591,26 @@ var doctor_default = (0, import_citty3.defineCommand)({
|
|
|
1990
2591
|
}
|
|
1991
2592
|
});
|
|
1992
2593
|
function printPluginSection(summary) {
|
|
1993
|
-
console.log(
|
|
2594
|
+
console.log(import_picocolors5.default.bold(` Plugins (${summary.total})`));
|
|
1994
2595
|
for (const r of summary.results) {
|
|
1995
|
-
const icon = r.loadable && r.prefixUnique && r.resolvable ?
|
|
2596
|
+
const icon = r.loadable && r.prefixUnique && r.resolvable ? import_picocolors5.default.green("\u2713") : import_picocolors5.default.red("\u2717");
|
|
1996
2597
|
const label = r.pluginName ? `${r.packageName} (${r.pluginName})` : r.packageName;
|
|
1997
|
-
const prefix = r.prefix ?
|
|
2598
|
+
const prefix = r.prefix ? import_picocolors5.default.dim(` [${r.prefix}]`) : "";
|
|
1998
2599
|
console.log(` ${icon} ${label}${prefix}`);
|
|
1999
2600
|
if (r.error) {
|
|
2000
|
-
console.log(` ${
|
|
2601
|
+
console.log(` ${import_picocolors5.default.yellow("\u2192")} ${r.error}`);
|
|
2001
2602
|
}
|
|
2002
2603
|
}
|
|
2003
2604
|
console.log();
|
|
2004
2605
|
}
|
|
2005
2606
|
function printServerResult(result, showFix) {
|
|
2006
|
-
const icon = result.status === "healthy" ?
|
|
2007
|
-
console.log(` ${icon} ${
|
|
2607
|
+
const icon = result.status === "healthy" ? import_picocolors5.default.green("\u25CF") : import_picocolors5.default.red("\u25CF");
|
|
2608
|
+
console.log(` ${icon} ${import_picocolors5.default.bold(result.serverName)}`);
|
|
2008
2609
|
for (const check of result.checks) {
|
|
2009
2610
|
const checkIcon = check.skipped ? CHECK_ICON.skip : check.passed ? CHECK_ICON.pass : CHECK_ICON.fail;
|
|
2010
2611
|
console.log(` ${checkIcon} ${check.name}: ${check.message}`);
|
|
2011
2612
|
if (showFix && !check.passed && !check.skipped && check.fix) {
|
|
2012
|
-
console.log(` ${
|
|
2613
|
+
console.log(` ${import_picocolors5.default.yellow("\u2192")} Fix: ${import_picocolors5.default.cyan(check.fix)}`);
|
|
2013
2614
|
}
|
|
2014
2615
|
}
|
|
2015
2616
|
console.log();
|
|
@@ -2033,22 +2634,23 @@ async function runParallel(tasks, concurrency) {
|
|
|
2033
2634
|
|
|
2034
2635
|
// src/commands/export-command.ts
|
|
2035
2636
|
init_cjs_shims();
|
|
2036
|
-
var
|
|
2037
|
-
var
|
|
2038
|
-
var
|
|
2039
|
-
var
|
|
2637
|
+
var import_node_fs10 = __toESM(require("fs"), 1);
|
|
2638
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
2639
|
+
var import_citty6 = require("citty");
|
|
2640
|
+
var import_picocolors6 = __toESM(require("picocolors"), 1);
|
|
2040
2641
|
|
|
2041
2642
|
// src/core/export-import-service.ts
|
|
2042
2643
|
init_cjs_shims();
|
|
2043
|
-
var
|
|
2644
|
+
var import_node_fs9 = __toESM(require("fs"), 1);
|
|
2044
2645
|
|
|
2045
2646
|
// src/utils/constants.ts
|
|
2046
2647
|
init_cjs_shims();
|
|
2047
2648
|
var APP_NAME = "mcpman";
|
|
2048
|
-
var APP_VERSION = "0.
|
|
2649
|
+
var APP_VERSION = "0.7.0";
|
|
2049
2650
|
var APP_DESCRIPTION = "The package manager for MCP servers";
|
|
2050
2651
|
|
|
2051
2652
|
// src/core/export-import-service.ts
|
|
2653
|
+
init_lockfile();
|
|
2052
2654
|
init_vault_service();
|
|
2053
2655
|
function createExportBundle(opts = {}) {
|
|
2054
2656
|
const { includeVault = true, includePlugins = true } = opts;
|
|
@@ -2062,7 +2664,7 @@ function createExportBundle(opts = {}) {
|
|
|
2062
2664
|
};
|
|
2063
2665
|
if (includeVault) {
|
|
2064
2666
|
const vaultPath = getVaultPath();
|
|
2065
|
-
if (
|
|
2667
|
+
if (import_node_fs9.default.existsSync(vaultPath)) {
|
|
2066
2668
|
bundle.vault = readVault();
|
|
2067
2669
|
}
|
|
2068
2670
|
}
|
|
@@ -2128,7 +2730,7 @@ function importBundle(bundle, opts = {}) {
|
|
|
2128
2730
|
|
|
2129
2731
|
// src/commands/export-command.ts
|
|
2130
2732
|
var DEFAULT_OUTPUT = "mcpman-export.json";
|
|
2131
|
-
var export_command_default = (0,
|
|
2733
|
+
var export_command_default = (0, import_citty6.defineCommand)({
|
|
2132
2734
|
meta: {
|
|
2133
2735
|
name: "export",
|
|
2134
2736
|
description: "Export mcpman config, lockfile, vault, and plugins to a portable JSON file"
|
|
@@ -2152,30 +2754,30 @@ var export_command_default = (0, import_citty4.defineCommand)({
|
|
|
2152
2754
|
},
|
|
2153
2755
|
run({ args }) {
|
|
2154
2756
|
const outputFile = args.output || DEFAULT_OUTPUT;
|
|
2155
|
-
const outputPath =
|
|
2757
|
+
const outputPath = import_node_path11.default.resolve(outputFile);
|
|
2156
2758
|
const bundle = createExportBundle({
|
|
2157
2759
|
includeVault: !args["no-vault"],
|
|
2158
2760
|
includePlugins: !args["no-plugins"]
|
|
2159
2761
|
});
|
|
2160
2762
|
const serverCount = Object.keys(bundle.lockfile.servers).length;
|
|
2161
2763
|
const configKeys = Object.keys(bundle.config).length;
|
|
2162
|
-
|
|
2163
|
-
console.log(`${
|
|
2164
|
-
console.log(
|
|
2165
|
-
console.log(
|
|
2166
|
-
console.log(
|
|
2167
|
-
console.log(
|
|
2764
|
+
import_node_fs10.default.writeFileSync(outputPath, JSON.stringify(bundle, null, 2), "utf-8");
|
|
2765
|
+
console.log(`${import_picocolors6.default.green("\u2713")} Exported to ${import_picocolors6.default.bold(outputFile)}`);
|
|
2766
|
+
console.log(import_picocolors6.default.dim(` Config keys: ${configKeys}`));
|
|
2767
|
+
console.log(import_picocolors6.default.dim(` Servers: ${serverCount}`));
|
|
2768
|
+
console.log(import_picocolors6.default.dim(` Vault: ${bundle.vault ? "included" : "excluded"}`));
|
|
2769
|
+
console.log(import_picocolors6.default.dim(` Plugins: ${bundle.plugins?.length ?? 0}`));
|
|
2168
2770
|
}
|
|
2169
2771
|
});
|
|
2170
2772
|
|
|
2171
2773
|
// src/commands/import-command.ts
|
|
2172
2774
|
init_cjs_shims();
|
|
2173
|
-
var
|
|
2174
|
-
var
|
|
2775
|
+
var import_node_fs11 = __toESM(require("fs"), 1);
|
|
2776
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
2175
2777
|
var p4 = __toESM(require("@clack/prompts"), 1);
|
|
2176
|
-
var
|
|
2177
|
-
var
|
|
2178
|
-
var import_command_default = (0,
|
|
2778
|
+
var import_citty7 = require("citty");
|
|
2779
|
+
var import_picocolors7 = __toESM(require("picocolors"), 1);
|
|
2780
|
+
var import_command_default = (0, import_citty7.defineCommand)({
|
|
2179
2781
|
meta: {
|
|
2180
2782
|
name: "import",
|
|
2181
2783
|
description: "Import mcpman config, lockfile, vault, and plugins from an export file"
|
|
@@ -2198,21 +2800,21 @@ var import_command_default = (0, import_citty5.defineCommand)({
|
|
|
2198
2800
|
}
|
|
2199
2801
|
},
|
|
2200
2802
|
async run({ args }) {
|
|
2201
|
-
const filePath =
|
|
2202
|
-
if (!
|
|
2203
|
-
console.error(`${
|
|
2803
|
+
const filePath = import_node_path12.default.resolve(args.file);
|
|
2804
|
+
if (!import_node_fs11.default.existsSync(filePath)) {
|
|
2805
|
+
console.error(`${import_picocolors7.default.red("\u2717")} File not found: ${filePath}`);
|
|
2204
2806
|
process.exit(1);
|
|
2205
2807
|
}
|
|
2206
2808
|
let raw;
|
|
2207
2809
|
try {
|
|
2208
|
-
raw = JSON.parse(
|
|
2810
|
+
raw = JSON.parse(import_node_fs11.default.readFileSync(filePath, "utf-8"));
|
|
2209
2811
|
} catch {
|
|
2210
|
-
console.error(`${
|
|
2812
|
+
console.error(`${import_picocolors7.default.red("\u2717")} Invalid JSON in ${filePath}`);
|
|
2211
2813
|
process.exit(1);
|
|
2212
2814
|
}
|
|
2213
2815
|
const error2 = validateBundle(raw);
|
|
2214
2816
|
if (error2) {
|
|
2215
|
-
console.error(`${
|
|
2817
|
+
console.error(`${import_picocolors7.default.red("\u2717")} Invalid export bundle: ${error2}`);
|
|
2216
2818
|
process.exit(1);
|
|
2217
2819
|
}
|
|
2218
2820
|
const bundle = raw;
|
|
@@ -2222,16 +2824,16 @@ var import_command_default = (0, import_citty5.defineCommand)({
|
|
|
2222
2824
|
const hasVault = !!bundle.vault;
|
|
2223
2825
|
const isDryRun = !!args["dry-run"];
|
|
2224
2826
|
console.log("");
|
|
2225
|
-
console.log(
|
|
2226
|
-
console.log(
|
|
2227
|
-
console.log(
|
|
2228
|
-
console.log(` Config keys: ${
|
|
2229
|
-
console.log(` Servers: ${
|
|
2230
|
-
console.log(` Vault: ${hasVault ?
|
|
2231
|
-
console.log(` Plugins: ${
|
|
2827
|
+
console.log(import_picocolors7.default.bold("Import summary:"));
|
|
2828
|
+
console.log(import_picocolors7.default.dim(` Source version: mcpman ${bundle.mcpmanVersion}`));
|
|
2829
|
+
console.log(import_picocolors7.default.dim(` Exported at: ${bundle.exportedAt}`));
|
|
2830
|
+
console.log(` Config keys: ${import_picocolors7.default.cyan(String(configKeys))}`);
|
|
2831
|
+
console.log(` Servers: ${import_picocolors7.default.cyan(String(serverCount))}`);
|
|
2832
|
+
console.log(` Vault: ${hasVault ? import_picocolors7.default.green("included") : import_picocolors7.default.dim("not included")}`);
|
|
2833
|
+
console.log(` Plugins: ${import_picocolors7.default.cyan(String(pluginCount))}`);
|
|
2232
2834
|
console.log("");
|
|
2233
2835
|
if (isDryRun) {
|
|
2234
|
-
console.log(
|
|
2836
|
+
console.log(import_picocolors7.default.yellow(" [dry-run] No changes applied."));
|
|
2235
2837
|
return;
|
|
2236
2838
|
}
|
|
2237
2839
|
if (!args.yes) {
|
|
@@ -2245,22 +2847,23 @@ var import_command_default = (0, import_citty5.defineCommand)({
|
|
|
2245
2847
|
}
|
|
2246
2848
|
}
|
|
2247
2849
|
const summary = importBundle(bundle, { dryRun: false });
|
|
2248
|
-
console.log(`${
|
|
2249
|
-
console.log(
|
|
2250
|
-
console.log(
|
|
2251
|
-
console.log(
|
|
2252
|
-
console.log(
|
|
2850
|
+
console.log(`${import_picocolors7.default.green("\u2713")} Import complete`);
|
|
2851
|
+
console.log(import_picocolors7.default.dim(` Config keys restored: ${summary.configKeys}`));
|
|
2852
|
+
console.log(import_picocolors7.default.dim(` Servers restored: ${summary.servers}`));
|
|
2853
|
+
console.log(import_picocolors7.default.dim(` Vault: ${summary.vaultImported ? "restored" : "skipped"}`));
|
|
2854
|
+
console.log(import_picocolors7.default.dim(` Plugins installed: ${summary.pluginsInstalled}`));
|
|
2253
2855
|
}
|
|
2254
2856
|
});
|
|
2255
2857
|
|
|
2256
2858
|
// src/commands/info.ts
|
|
2257
2859
|
init_cjs_shims();
|
|
2258
|
-
var
|
|
2860
|
+
var import_citty8 = require("citty");
|
|
2259
2861
|
var import_nanospinner2 = require("nanospinner");
|
|
2260
|
-
var
|
|
2862
|
+
var import_picocolors8 = __toESM(require("picocolors"), 1);
|
|
2261
2863
|
|
|
2262
2864
|
// src/core/package-info.ts
|
|
2263
2865
|
init_cjs_shims();
|
|
2866
|
+
init_lockfile();
|
|
2264
2867
|
init_trust_scorer();
|
|
2265
2868
|
async function buildInfo(name, entry, source = "npm") {
|
|
2266
2869
|
const resolvedSource = entry?.source ?? source;
|
|
@@ -2314,11 +2917,11 @@ async function getPackageInfo(serverName) {
|
|
|
2314
2917
|
// src/commands/info.ts
|
|
2315
2918
|
function colorRisk2(score, riskLevel) {
|
|
2316
2919
|
const label = score !== null ? `${score}/100 (${riskLevel})` : riskLevel;
|
|
2317
|
-
if (riskLevel === "LOW") return
|
|
2318
|
-
if (riskLevel === "MEDIUM") return
|
|
2319
|
-
if (riskLevel === "HIGH") return
|
|
2320
|
-
if (riskLevel === "CRITICAL") return
|
|
2321
|
-
return
|
|
2920
|
+
if (riskLevel === "LOW") return import_picocolors8.default.green(label);
|
|
2921
|
+
if (riskLevel === "MEDIUM") return import_picocolors8.default.yellow(label);
|
|
2922
|
+
if (riskLevel === "HIGH") return import_picocolors8.default.red(label);
|
|
2923
|
+
if (riskLevel === "CRITICAL") return import_picocolors8.default.bold(import_picocolors8.default.red(label));
|
|
2924
|
+
return import_picocolors8.default.dim(label);
|
|
2322
2925
|
}
|
|
2323
2926
|
function formatDaysAgo(isoDate) {
|
|
2324
2927
|
if (!isoDate) return "unknown";
|
|
@@ -2328,54 +2931,54 @@ function formatDaysAgo(isoDate) {
|
|
|
2328
2931
|
return `${days} days ago`;
|
|
2329
2932
|
}
|
|
2330
2933
|
function printInfo(info2) {
|
|
2331
|
-
const installedBadge = info2.isInstalled ?
|
|
2934
|
+
const installedBadge = info2.isInstalled ? import_picocolors8.default.green(" [installed]") : import_picocolors8.default.dim(" [not installed]");
|
|
2332
2935
|
console.log();
|
|
2333
|
-
console.log(
|
|
2334
|
-
console.log(
|
|
2335
|
-
console.log(` ${
|
|
2336
|
-
console.log(` ${
|
|
2936
|
+
console.log(import_picocolors8.default.bold(` ${info2.name}@${info2.version}`) + installedBadge);
|
|
2937
|
+
console.log(import_picocolors8.default.dim(` ${"\u2500".repeat(60)}`));
|
|
2938
|
+
console.log(` ${import_picocolors8.default.dim("Source:")} ${info2.source}`);
|
|
2939
|
+
console.log(` ${import_picocolors8.default.dim("Runtime:")} ${info2.runtime}`);
|
|
2337
2940
|
if (info2.description) {
|
|
2338
|
-
console.log(` ${
|
|
2941
|
+
console.log(` ${import_picocolors8.default.dim("Description:")} ${info2.description}`);
|
|
2339
2942
|
}
|
|
2340
2943
|
if (info2.deprecated) {
|
|
2341
|
-
console.log(` ${
|
|
2944
|
+
console.log(` ${import_picocolors8.default.red("[DEPRECATED]")} This package is deprecated`);
|
|
2342
2945
|
}
|
|
2343
2946
|
console.log();
|
|
2344
|
-
console.log(` ${
|
|
2345
|
-
console.log(` ${
|
|
2947
|
+
console.log(` ${import_picocolors8.default.bold("Trust & Security")}`);
|
|
2948
|
+
console.log(` ${import_picocolors8.default.dim("Trust score:")} ${colorRisk2(info2.trustScore, info2.riskLevel)}`);
|
|
2346
2949
|
if (info2.source === "npm") {
|
|
2347
2950
|
console.log(
|
|
2348
|
-
` ${
|
|
2951
|
+
` ${import_picocolors8.default.dim("Downloads:")} ${info2.weeklyDownloads.toLocaleString()}/week ${import_picocolors8.default.dim("|")} ${import_picocolors8.default.dim("Age:")} ${info2.packageAge}d ${import_picocolors8.default.dim("|")} ${import_picocolors8.default.dim("Maintainers:")} ${info2.maintainerCount}`
|
|
2349
2952
|
);
|
|
2350
2953
|
if (info2.lastPublish) {
|
|
2351
|
-
console.log(` ${
|
|
2954
|
+
console.log(` ${import_picocolors8.default.dim("Last publish:")} ${formatDaysAgo(info2.lastPublish)}`);
|
|
2352
2955
|
}
|
|
2353
2956
|
} else {
|
|
2354
|
-
console.log(
|
|
2957
|
+
console.log(import_picocolors8.default.dim(" (Trust data available for npm packages only)"));
|
|
2355
2958
|
}
|
|
2356
2959
|
console.log();
|
|
2357
|
-
console.log(` ${
|
|
2960
|
+
console.log(` ${import_picocolors8.default.bold("Environment Variables")}`);
|
|
2358
2961
|
if (info2.envVars.length > 0) {
|
|
2359
2962
|
for (const env of info2.envVars) {
|
|
2360
|
-
console.log(` ${
|
|
2963
|
+
console.log(` ${import_picocolors8.default.cyan("\u2022")} ${env}`);
|
|
2361
2964
|
}
|
|
2362
2965
|
} else {
|
|
2363
|
-
console.log(
|
|
2966
|
+
console.log(import_picocolors8.default.dim(" none required"));
|
|
2364
2967
|
}
|
|
2365
2968
|
console.log();
|
|
2366
|
-
console.log(` ${
|
|
2969
|
+
console.log(` ${import_picocolors8.default.bold("Installed Clients")}`);
|
|
2367
2970
|
if (info2.installedClients.length > 0) {
|
|
2368
2971
|
for (const client of info2.installedClients) {
|
|
2369
|
-
console.log(` ${
|
|
2972
|
+
console.log(` ${import_picocolors8.default.green("\u2713")} ${client}`);
|
|
2370
2973
|
}
|
|
2371
2974
|
} else {
|
|
2372
|
-
console.log(
|
|
2975
|
+
console.log(import_picocolors8.default.dim(" Not installed in any client"));
|
|
2373
2976
|
}
|
|
2374
2977
|
console.log();
|
|
2375
|
-
console.log(
|
|
2978
|
+
console.log(import_picocolors8.default.dim(` ${"\u2500".repeat(60)}`));
|
|
2376
2979
|
console.log();
|
|
2377
2980
|
}
|
|
2378
|
-
var info_default = (0,
|
|
2981
|
+
var info_default = (0, import_citty8.defineCommand)({
|
|
2379
2982
|
meta: {
|
|
2380
2983
|
name: "info",
|
|
2381
2984
|
description: "Show detailed metadata for an MCP server (installed or from registry)"
|
|
@@ -2399,13 +3002,13 @@ var info_default = (0, import_citty6.defineCommand)({
|
|
|
2399
3002
|
info2 = await getPackageInfo(args.server);
|
|
2400
3003
|
} catch (err) {
|
|
2401
3004
|
spinner5.error({ text: "Failed to fetch package info" });
|
|
2402
|
-
console.error(
|
|
3005
|
+
console.error(import_picocolors8.default.red(String(err)));
|
|
2403
3006
|
process.exit(1);
|
|
2404
3007
|
}
|
|
2405
3008
|
if (!info2) {
|
|
2406
3009
|
spinner5.error({ text: `Package not found: ${args.server}` });
|
|
2407
3010
|
console.log(
|
|
2408
|
-
|
|
3011
|
+
import_picocolors8.default.dim(`
|
|
2409
3012
|
"${args.server}" was not found in the npm registry or your lockfile.
|
|
2410
3013
|
`)
|
|
2411
3014
|
);
|
|
@@ -2422,10 +3025,11 @@ var info_default = (0, import_citty6.defineCommand)({
|
|
|
2422
3025
|
|
|
2423
3026
|
// src/commands/init.ts
|
|
2424
3027
|
init_cjs_shims();
|
|
2425
|
-
var
|
|
3028
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
2426
3029
|
var p5 = __toESM(require("@clack/prompts"), 1);
|
|
2427
|
-
var
|
|
2428
|
-
|
|
3030
|
+
var import_citty9 = require("citty");
|
|
3031
|
+
init_lockfile();
|
|
3032
|
+
var init_default = (0, import_citty9.defineCommand)({
|
|
2429
3033
|
meta: {
|
|
2430
3034
|
name: "init",
|
|
2431
3035
|
description: "Initialize mcpman.lock in the current project"
|
|
@@ -2441,7 +3045,7 @@ var init_default = (0, import_citty7.defineCommand)({
|
|
|
2441
3045
|
async run({ args }) {
|
|
2442
3046
|
const nonInteractive = args.yes || !process.stdout.isTTY;
|
|
2443
3047
|
p5.intro("mcpman init");
|
|
2444
|
-
const targetPath =
|
|
3048
|
+
const targetPath = import_node_path13.default.join(process.cwd(), LOCKFILE_NAME);
|
|
2445
3049
|
const existing = findLockfile();
|
|
2446
3050
|
if (existing) {
|
|
2447
3051
|
if (nonInteractive) {
|
|
@@ -2526,7 +3130,7 @@ var init_default = (0, import_citty7.defineCommand)({
|
|
|
2526
3130
|
// src/commands/install.ts
|
|
2527
3131
|
init_cjs_shims();
|
|
2528
3132
|
var p8 = __toESM(require("@clack/prompts"), 1);
|
|
2529
|
-
var
|
|
3133
|
+
var import_citty10 = require("citty");
|
|
2530
3134
|
|
|
2531
3135
|
// src/core/installer.ts
|
|
2532
3136
|
init_cjs_shims();
|
|
@@ -2567,6 +3171,7 @@ async function offerVaultSave(serverName, newVars, yes) {
|
|
|
2567
3171
|
}
|
|
2568
3172
|
|
|
2569
3173
|
// src/core/installer.ts
|
|
3174
|
+
init_lockfile();
|
|
2570
3175
|
async function loadClients2() {
|
|
2571
3176
|
try {
|
|
2572
3177
|
const mod = await Promise.resolve().then(() => (init_client_detector(), client_detector_exports));
|
|
@@ -2680,9 +3285,12 @@ async function installServer(input, options = {}) {
|
|
|
2680
3285
|
p7.outro(`${metadata.name}@${metadata.version} installed to ${clientTypes.join(", ")}`);
|
|
2681
3286
|
}
|
|
2682
3287
|
|
|
3288
|
+
// src/commands/install.ts
|
|
3289
|
+
init_lockfile();
|
|
3290
|
+
|
|
2683
3291
|
// src/utils/logger.ts
|
|
2684
3292
|
init_cjs_shims();
|
|
2685
|
-
var
|
|
3293
|
+
var import_picocolors9 = __toESM(require("picocolors"), 1);
|
|
2686
3294
|
var noColor = process.env.NO_COLOR !== void 0 || process.argv.includes("--no-color");
|
|
2687
3295
|
var isVerbose = process.argv.includes("--verbose");
|
|
2688
3296
|
var isJson = process.argv.includes("--json");
|
|
@@ -2691,18 +3299,18 @@ function colorize(fn, text2) {
|
|
|
2691
3299
|
}
|
|
2692
3300
|
function info(message) {
|
|
2693
3301
|
if (isJson) return;
|
|
2694
|
-
console.log(`${colorize(
|
|
3302
|
+
console.log(`${colorize(import_picocolors9.default.cyan, "i")} ${message}`);
|
|
2695
3303
|
}
|
|
2696
3304
|
function error(message) {
|
|
2697
3305
|
if (isJson) return;
|
|
2698
|
-
console.error(`${colorize(
|
|
3306
|
+
console.error(`${colorize(import_picocolors9.default.red, "\u2717")} ${message}`);
|
|
2699
3307
|
}
|
|
2700
3308
|
function json(data) {
|
|
2701
3309
|
console.log(JSON.stringify(data, null, 2));
|
|
2702
3310
|
}
|
|
2703
3311
|
|
|
2704
3312
|
// src/commands/install.ts
|
|
2705
|
-
var install_default = (0,
|
|
3313
|
+
var install_default = (0, import_citty10.defineCommand)({
|
|
2706
3314
|
meta: {
|
|
2707
3315
|
name: "install",
|
|
2708
3316
|
description: "Install an MCP server into one or more AI clients"
|
|
@@ -2763,16 +3371,220 @@ async function restoreFromLockfile() {
|
|
|
2763
3371
|
p8.outro("Restore complete.");
|
|
2764
3372
|
}
|
|
2765
3373
|
|
|
3374
|
+
// src/commands/link.ts
|
|
3375
|
+
init_cjs_shims();
|
|
3376
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
3377
|
+
var import_citty11 = require("citty");
|
|
3378
|
+
var import_picocolors10 = __toESM(require("picocolors"), 1);
|
|
3379
|
+
init_client_detector();
|
|
3380
|
+
|
|
3381
|
+
// src/core/link-service.ts
|
|
3382
|
+
init_cjs_shims();
|
|
3383
|
+
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
3384
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
3385
|
+
init_lockfile();
|
|
3386
|
+
function detectLocalServer(dir) {
|
|
3387
|
+
if (!import_node_fs12.default.existsSync(dir)) {
|
|
3388
|
+
throw new Error(`Directory does not exist: ${dir}`);
|
|
3389
|
+
}
|
|
3390
|
+
const pkgPath = import_node_path14.default.join(dir, "package.json");
|
|
3391
|
+
if (import_node_fs12.default.existsSync(pkgPath)) {
|
|
3392
|
+
return detectNodeServer(dir, pkgPath);
|
|
3393
|
+
}
|
|
3394
|
+
const pyprojectPath = import_node_path14.default.join(dir, "pyproject.toml");
|
|
3395
|
+
if (import_node_fs12.default.existsSync(pyprojectPath)) {
|
|
3396
|
+
return detectPythonServer(dir, pyprojectPath);
|
|
3397
|
+
}
|
|
3398
|
+
throw new Error(
|
|
3399
|
+
`No package.json or pyproject.toml found in '${dir}'. Is this an MCP server project?`
|
|
3400
|
+
);
|
|
3401
|
+
}
|
|
3402
|
+
function detectNodeServer(dir, pkgPath) {
|
|
3403
|
+
const raw = import_node_fs12.default.readFileSync(pkgPath, "utf-8");
|
|
3404
|
+
const pkg = JSON.parse(raw);
|
|
3405
|
+
const name = String(pkg.name ?? import_node_path14.default.basename(dir));
|
|
3406
|
+
const version = String(pkg.version ?? "0.0.0");
|
|
3407
|
+
let entryPoint = null;
|
|
3408
|
+
if (pkg.bin) {
|
|
3409
|
+
if (typeof pkg.bin === "string") {
|
|
3410
|
+
entryPoint = import_node_path14.default.resolve(dir, pkg.bin);
|
|
3411
|
+
} else if (typeof pkg.bin === "object" && pkg.bin !== null) {
|
|
3412
|
+
const binObj = pkg.bin;
|
|
3413
|
+
const firstBin = Object.values(binObj)[0];
|
|
3414
|
+
if (firstBin) entryPoint = import_node_path14.default.resolve(dir, firstBin);
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
if (!entryPoint && pkg.main) {
|
|
3418
|
+
entryPoint = import_node_path14.default.resolve(dir, String(pkg.main));
|
|
3419
|
+
}
|
|
3420
|
+
if (!entryPoint) {
|
|
3421
|
+
const candidates = ["src/index.ts", "src/index.js", "index.ts", "index.js"];
|
|
3422
|
+
for (const c of candidates) {
|
|
3423
|
+
const candidate = import_node_path14.default.join(dir, c);
|
|
3424
|
+
if (import_node_fs12.default.existsSync(candidate)) {
|
|
3425
|
+
entryPoint = candidate;
|
|
3426
|
+
break;
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
if (!entryPoint) {
|
|
3431
|
+
throw new Error(`Cannot determine entry point for Node server in '${dir}'.`);
|
|
3432
|
+
}
|
|
3433
|
+
const isTs = entryPoint.endsWith(".ts");
|
|
3434
|
+
const command = isTs ? "npx" : "node";
|
|
3435
|
+
const args = isTs ? ["tsx", entryPoint] : [entryPoint];
|
|
3436
|
+
const mcpField = pkg.mcp;
|
|
3437
|
+
const envVars = [];
|
|
3438
|
+
if (mcpField?.env && Array.isArray(mcpField.env)) {
|
|
3439
|
+
for (const e of mcpField.env) {
|
|
3440
|
+
if (typeof e === "string") envVars.push(e);
|
|
3441
|
+
else if (typeof e === "object" && e !== null && "name" in e) {
|
|
3442
|
+
envVars.push(String(e.name));
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
return { name, version, command, args, envVars, absolutePath: dir, runtime: "node" };
|
|
3447
|
+
}
|
|
3448
|
+
function detectPythonServer(dir, pyprojectPath) {
|
|
3449
|
+
const raw = import_node_fs12.default.readFileSync(pyprojectPath, "utf-8");
|
|
3450
|
+
const name = extractTomlValue(raw, "name") ?? import_node_path14.default.basename(dir);
|
|
3451
|
+
const version = extractTomlValue(raw, "version") ?? "0.0.0";
|
|
3452
|
+
let pythonCmd = "python3";
|
|
3453
|
+
const venvPython = import_node_path14.default.join(dir, ".venv", "bin", "python");
|
|
3454
|
+
if (import_node_fs12.default.existsSync(venvPython)) {
|
|
3455
|
+
pythonCmd = venvPython;
|
|
3456
|
+
}
|
|
3457
|
+
const entryCandidate = [
|
|
3458
|
+
import_node_path14.default.join(dir, "main.py"),
|
|
3459
|
+
import_node_path14.default.join(dir, name.replace(/-/g, "_"), "main.py"),
|
|
3460
|
+
import_node_path14.default.join(dir, "__main__.py")
|
|
3461
|
+
].find((p13) => import_node_fs12.default.existsSync(p13));
|
|
3462
|
+
const entryPoint = entryCandidate ?? import_node_path14.default.join(dir, "main.py");
|
|
3463
|
+
return {
|
|
3464
|
+
name,
|
|
3465
|
+
version,
|
|
3466
|
+
command: pythonCmd,
|
|
3467
|
+
args: [entryPoint],
|
|
3468
|
+
envVars: [],
|
|
3469
|
+
absolutePath: dir,
|
|
3470
|
+
runtime: "python"
|
|
3471
|
+
};
|
|
3472
|
+
}
|
|
3473
|
+
function extractTomlValue(content, key) {
|
|
3474
|
+
const match = content.match(new RegExp(`^${key}\\s*=\\s*"([^"]+)"`, "m"));
|
|
3475
|
+
return match ? match[1] : null;
|
|
3476
|
+
}
|
|
3477
|
+
async function registerLinkedServer(linkResult, clients, lockfilePath, nameOverride) {
|
|
3478
|
+
const serverName = nameOverride ?? linkResult.name;
|
|
3479
|
+
const registered = [];
|
|
3480
|
+
for (const client of clients) {
|
|
3481
|
+
try {
|
|
3482
|
+
await client.addServer(serverName, {
|
|
3483
|
+
command: linkResult.command,
|
|
3484
|
+
args: linkResult.args
|
|
3485
|
+
});
|
|
3486
|
+
registered.push(client.type);
|
|
3487
|
+
} catch {
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
const lockEntry = {
|
|
3491
|
+
version: linkResult.version,
|
|
3492
|
+
source: "local",
|
|
3493
|
+
resolved: linkResult.absolutePath,
|
|
3494
|
+
integrity: "local",
|
|
3495
|
+
runtime: linkResult.runtime,
|
|
3496
|
+
command: linkResult.command,
|
|
3497
|
+
args: linkResult.args,
|
|
3498
|
+
envVars: linkResult.envVars,
|
|
3499
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3500
|
+
clients: registered
|
|
3501
|
+
};
|
|
3502
|
+
const existing = readLockfile(lockfilePath);
|
|
3503
|
+
existing.servers[serverName] = lockEntry;
|
|
3504
|
+
const { writeLockfile: writeLockfile2 } = await Promise.resolve().then(() => (init_lockfile(), lockfile_exports));
|
|
3505
|
+
writeLockfile2(existing, lockfilePath);
|
|
3506
|
+
return registered;
|
|
3507
|
+
}
|
|
3508
|
+
|
|
3509
|
+
// src/commands/link.ts
|
|
3510
|
+
var link_default = (0, import_citty11.defineCommand)({
|
|
3511
|
+
meta: {
|
|
3512
|
+
name: "link",
|
|
3513
|
+
description: "Register a local MCP server directory with AI clients"
|
|
3514
|
+
},
|
|
3515
|
+
args: {
|
|
3516
|
+
dir: {
|
|
3517
|
+
type: "positional",
|
|
3518
|
+
description: "Path to local MCP server directory (default: .)",
|
|
3519
|
+
required: false
|
|
3520
|
+
},
|
|
3521
|
+
client: {
|
|
3522
|
+
type: "string",
|
|
3523
|
+
description: "Register with specific client only (claude-desktop, cursor, vscode, windsurf)",
|
|
3524
|
+
alias: "c"
|
|
3525
|
+
},
|
|
3526
|
+
name: {
|
|
3527
|
+
type: "string",
|
|
3528
|
+
description: "Override the detected server name",
|
|
3529
|
+
alias: "n"
|
|
3530
|
+
}
|
|
3531
|
+
},
|
|
3532
|
+
async run({ args }) {
|
|
3533
|
+
const dirArg = args.dir ?? ".";
|
|
3534
|
+
const clientFilter = args.client;
|
|
3535
|
+
const nameOverride = args.name;
|
|
3536
|
+
const absoluteDir = import_node_path15.default.resolve(dirArg);
|
|
3537
|
+
let linkResult;
|
|
3538
|
+
try {
|
|
3539
|
+
linkResult = detectLocalServer(absoluteDir);
|
|
3540
|
+
} catch (err) {
|
|
3541
|
+
console.error(import_picocolors10.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
3542
|
+
process.exit(1);
|
|
3543
|
+
}
|
|
3544
|
+
const serverName = nameOverride ?? linkResult.name;
|
|
3545
|
+
console.log(import_picocolors10.default.dim(`
|
|
3546
|
+
Detected: ${import_picocolors10.default.cyan(serverName)} (${linkResult.runtime})`));
|
|
3547
|
+
console.log(import_picocolors10.default.dim(` Path: ${absoluteDir}`));
|
|
3548
|
+
console.log(import_picocolors10.default.dim(` Command: ${linkResult.command} ${linkResult.args.join(" ")}`));
|
|
3549
|
+
const allClients = await getInstalledClients();
|
|
3550
|
+
const clients = clientFilter ? allClients.filter((c) => c.type === clientFilter) : allClients;
|
|
3551
|
+
if (clientFilter && clients.length === 0) {
|
|
3552
|
+
console.error(import_picocolors10.default.red(` Error: Unknown client '${clientFilter}'.`));
|
|
3553
|
+
process.exit(1);
|
|
3554
|
+
}
|
|
3555
|
+
let registered;
|
|
3556
|
+
try {
|
|
3557
|
+
registered = await registerLinkedServer(linkResult, clients, void 0, nameOverride);
|
|
3558
|
+
} catch (err) {
|
|
3559
|
+
console.error(import_picocolors10.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
3560
|
+
process.exit(1);
|
|
3561
|
+
}
|
|
3562
|
+
if (registered.length === 0) {
|
|
3563
|
+
console.log(import_picocolors10.default.yellow(" Warning: No clients registered. Are any AI clients installed?"));
|
|
3564
|
+
console.log(import_picocolors10.default.dim(` Server saved to lockfile with source "local".`));
|
|
3565
|
+
} else {
|
|
3566
|
+
console.log(import_picocolors10.default.green(`
|
|
3567
|
+
Linked ${import_picocolors10.default.bold(serverName)} to: ${registered.join(", ")}
|
|
3568
|
+
`));
|
|
3569
|
+
console.log(import_picocolors10.default.dim(` Run ${import_picocolors10.default.cyan("mcpman list")} to verify.`));
|
|
3570
|
+
console.log(
|
|
3571
|
+
import_picocolors10.default.dim(` Run ${import_picocolors10.default.cyan(`mcpman watch ${serverName}`)} to start with auto-restart.`)
|
|
3572
|
+
);
|
|
3573
|
+
}
|
|
3574
|
+
console.log();
|
|
3575
|
+
}
|
|
3576
|
+
});
|
|
3577
|
+
|
|
2766
3578
|
// src/commands/list.ts
|
|
2767
3579
|
init_cjs_shims();
|
|
2768
|
-
var
|
|
2769
|
-
var
|
|
3580
|
+
var import_citty12 = require("citty");
|
|
3581
|
+
var import_picocolors11 = __toESM(require("picocolors"), 1);
|
|
2770
3582
|
var STATUS_ICON = {
|
|
2771
|
-
healthy:
|
|
2772
|
-
unhealthy:
|
|
2773
|
-
unknown:
|
|
3583
|
+
healthy: import_picocolors11.default.green("\u25CF"),
|
|
3584
|
+
unhealthy: import_picocolors11.default.red("\u25CF"),
|
|
3585
|
+
unknown: import_picocolors11.default.dim("\u25CB")
|
|
2774
3586
|
};
|
|
2775
|
-
var list_default = (0,
|
|
3587
|
+
var list_default = (0, import_citty12.defineCommand)({
|
|
2776
3588
|
meta: {
|
|
2777
3589
|
name: "list",
|
|
2778
3590
|
description: "List installed MCP servers"
|
|
@@ -2793,8 +3605,8 @@ var list_default = (0, import_citty9.defineCommand)({
|
|
|
2793
3605
|
if (servers.length === 0) {
|
|
2794
3606
|
const filter = args.client ? ` for client "${args.client}"` : "";
|
|
2795
3607
|
console.log(
|
|
2796
|
-
|
|
2797
|
-
`No MCP servers installed${filter}. Run ${
|
|
3608
|
+
import_picocolors11.default.dim(
|
|
3609
|
+
`No MCP servers installed${filter}. Run ${import_picocolors11.default.cyan("mcpman install <server>")} to get started.`
|
|
2798
3610
|
)
|
|
2799
3611
|
);
|
|
2800
3612
|
return;
|
|
@@ -2820,9 +3632,9 @@ var list_default = (0, import_citty9.defineCommand)({
|
|
|
2820
3632
|
const nameWidth = Math.max(4, ...withStatus.map((s) => s.name.length));
|
|
2821
3633
|
const clientsWidth = Math.max(7, ...withStatus.map((s) => formatClients(s.clients).length));
|
|
2822
3634
|
const header = ` ${pad("NAME", nameWidth)} ${pad("CLIENT(S)", clientsWidth)} ${pad("COMMAND", 20)} STATUS`;
|
|
2823
|
-
console.log(
|
|
3635
|
+
console.log(import_picocolors11.default.dim(header));
|
|
2824
3636
|
console.log(
|
|
2825
|
-
|
|
3637
|
+
import_picocolors11.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(clientsWidth)} ${"-".repeat(20)} ------`)
|
|
2826
3638
|
);
|
|
2827
3639
|
for (const s of withStatus) {
|
|
2828
3640
|
const icon = STATUS_ICON[s.status];
|
|
@@ -2837,7 +3649,7 @@ var list_default = (0, import_citty9.defineCommand)({
|
|
|
2837
3649
|
}
|
|
2838
3650
|
const clientSet = new Set(withStatus.flatMap((s) => s.clients));
|
|
2839
3651
|
console.log(
|
|
2840
|
-
|
|
3652
|
+
import_picocolors11.default.dim(
|
|
2841
3653
|
`
|
|
2842
3654
|
${withStatus.length} server${withStatus.length !== 1 ? "s" : ""} \xB7 ${clientSet.size} client${clientSet.size !== 1 ? "s" : ""}`
|
|
2843
3655
|
)
|
|
@@ -2863,10 +3675,11 @@ function formatClients(clients) {
|
|
|
2863
3675
|
// src/commands/logs.ts
|
|
2864
3676
|
init_cjs_shims();
|
|
2865
3677
|
var import_node_child_process4 = require("child_process");
|
|
2866
|
-
var
|
|
2867
|
-
var
|
|
3678
|
+
var import_citty13 = require("citty");
|
|
3679
|
+
var import_picocolors12 = __toESM(require("picocolors"), 1);
|
|
3680
|
+
init_lockfile();
|
|
2868
3681
|
init_vault_service();
|
|
2869
|
-
var logs_default = (0,
|
|
3682
|
+
var logs_default = (0, import_citty13.defineCommand)({
|
|
2870
3683
|
meta: {
|
|
2871
3684
|
name: "logs",
|
|
2872
3685
|
description: "Stream stdout/stderr from an MCP server"
|
|
@@ -2889,7 +3702,7 @@ var logs_default = (0, import_citty10.defineCommand)({
|
|
|
2889
3702
|
const lockfile = readLockfile();
|
|
2890
3703
|
const entry = lockfile.servers[serverName];
|
|
2891
3704
|
if (!entry) {
|
|
2892
|
-
console.error(
|
|
3705
|
+
console.error(import_picocolors12.default.red(` Error: Server '${serverName}' is not installed.`));
|
|
2893
3706
|
process.exit(1);
|
|
2894
3707
|
}
|
|
2895
3708
|
const lockfileEnv = parseEnvFlags(entry.envVars);
|
|
@@ -2899,24 +3712,24 @@ var logs_default = (0, import_citty10.defineCommand)({
|
|
|
2899
3712
|
...lockfileEnv,
|
|
2900
3713
|
...vaultEnv
|
|
2901
3714
|
};
|
|
2902
|
-
console.log(
|
|
3715
|
+
console.log(import_picocolors12.default.dim(` Streaming logs for ${import_picocolors12.default.cyan(serverName)}... (Ctrl+C to stop)
|
|
2903
3716
|
`));
|
|
2904
3717
|
const child = (0, import_node_child_process4.spawn)(entry.command, entry.args, {
|
|
2905
3718
|
env: finalEnv,
|
|
2906
3719
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2907
3720
|
});
|
|
2908
3721
|
child.stdout?.on("data", (chunk) => {
|
|
2909
|
-
process.stdout.write(
|
|
3722
|
+
process.stdout.write(import_picocolors12.default.dim("[stdout] ") + chunk.toString());
|
|
2910
3723
|
});
|
|
2911
3724
|
child.stderr?.on("data", (chunk) => {
|
|
2912
|
-
process.stderr.write(
|
|
3725
|
+
process.stderr.write(import_picocolors12.default.yellow("[stderr] ") + chunk.toString());
|
|
2913
3726
|
});
|
|
2914
3727
|
child.on("error", (err) => {
|
|
2915
|
-
console.error(
|
|
3728
|
+
console.error(import_picocolors12.default.red(` Failed to start '${serverName}': ${err.message}`));
|
|
2916
3729
|
process.exit(1);
|
|
2917
3730
|
});
|
|
2918
3731
|
child.on("close", (code) => {
|
|
2919
|
-
console.log(
|
|
3732
|
+
console.log(import_picocolors12.default.dim(`
|
|
2920
3733
|
Process exited with code ${code ?? 0}`));
|
|
2921
3734
|
process.exit(code ?? 0);
|
|
2922
3735
|
});
|
|
@@ -2942,10 +3755,10 @@ async function loadVaultSecrets(serverName) {
|
|
|
2942
3755
|
|
|
2943
3756
|
// src/commands/plugin.ts
|
|
2944
3757
|
init_cjs_shims();
|
|
2945
|
-
var
|
|
3758
|
+
var import_citty14 = require("citty");
|
|
2946
3759
|
var import_nanospinner3 = require("nanospinner");
|
|
2947
|
-
var
|
|
2948
|
-
var addCommand = (0,
|
|
3760
|
+
var import_picocolors13 = __toESM(require("picocolors"), 1);
|
|
3761
|
+
var addCommand = (0, import_citty14.defineCommand)({
|
|
2949
3762
|
meta: { name: "add", description: "Install a plugin package" },
|
|
2950
3763
|
args: {
|
|
2951
3764
|
package: {
|
|
@@ -2963,23 +3776,23 @@ var addCommand = (0, import_citty11.defineCommand)({
|
|
|
2963
3776
|
spinner5.stop();
|
|
2964
3777
|
if (loaded) {
|
|
2965
3778
|
console.log(
|
|
2966
|
-
`${
|
|
3779
|
+
`${import_picocolors13.default.green("\u2713")} Plugin ${import_picocolors13.default.bold(loaded.name)} installed (prefix: ${import_picocolors13.default.cyan(loaded.prefix)})`
|
|
2967
3780
|
);
|
|
2968
3781
|
} else {
|
|
2969
3782
|
console.log(
|
|
2970
|
-
`${
|
|
3783
|
+
`${import_picocolors13.default.yellow("\u26A0")} Package ${import_picocolors13.default.bold(pkg)} installed but does not export a valid mcpman plugin.`
|
|
2971
3784
|
);
|
|
2972
3785
|
}
|
|
2973
3786
|
} catch (err) {
|
|
2974
3787
|
spinner5.stop();
|
|
2975
3788
|
console.error(
|
|
2976
|
-
`${
|
|
3789
|
+
`${import_picocolors13.default.red("\u2717")} Failed to install plugin: ${err instanceof Error ? err.message : String(err)}`
|
|
2977
3790
|
);
|
|
2978
3791
|
process.exit(1);
|
|
2979
3792
|
}
|
|
2980
3793
|
}
|
|
2981
3794
|
});
|
|
2982
|
-
var removeCommand = (0,
|
|
3795
|
+
var removeCommand = (0, import_citty14.defineCommand)({
|
|
2983
3796
|
meta: { name: "remove", description: "Uninstall a plugin package" },
|
|
2984
3797
|
args: {
|
|
2985
3798
|
package: {
|
|
@@ -2992,46 +3805,46 @@ var removeCommand = (0, import_citty11.defineCommand)({
|
|
|
2992
3805
|
const pkg = args.package;
|
|
2993
3806
|
const installed = listPluginPackages();
|
|
2994
3807
|
if (!installed.includes(pkg)) {
|
|
2995
|
-
console.log(
|
|
3808
|
+
console.log(import_picocolors13.default.dim(`Plugin "${pkg}" is not installed.`));
|
|
2996
3809
|
return;
|
|
2997
3810
|
}
|
|
2998
3811
|
try {
|
|
2999
3812
|
removePluginPackage(pkg);
|
|
3000
|
-
console.log(`${
|
|
3813
|
+
console.log(`${import_picocolors13.default.green("\u2713")} Plugin ${import_picocolors13.default.bold(pkg)} removed.`);
|
|
3001
3814
|
} catch (err) {
|
|
3002
3815
|
console.error(
|
|
3003
|
-
`${
|
|
3816
|
+
`${import_picocolors13.default.red("\u2717")} Failed to remove plugin: ${err instanceof Error ? err.message : String(err)}`
|
|
3004
3817
|
);
|
|
3005
3818
|
process.exit(1);
|
|
3006
3819
|
}
|
|
3007
3820
|
}
|
|
3008
3821
|
});
|
|
3009
|
-
var listCommand2 = (0,
|
|
3822
|
+
var listCommand2 = (0, import_citty14.defineCommand)({
|
|
3010
3823
|
meta: { name: "list", description: "List installed plugins" },
|
|
3011
3824
|
run() {
|
|
3012
3825
|
const packages = listPluginPackages();
|
|
3013
3826
|
if (packages.length === 0) {
|
|
3014
|
-
console.log(
|
|
3827
|
+
console.log(import_picocolors13.default.dim("No plugins installed. Use `mcpman plugin add <package>`."));
|
|
3015
3828
|
return;
|
|
3016
3829
|
}
|
|
3017
3830
|
console.log("");
|
|
3018
|
-
console.log(
|
|
3831
|
+
console.log(import_picocolors13.default.bold("Installed plugins:"));
|
|
3019
3832
|
console.log("");
|
|
3020
3833
|
for (const pkg of packages) {
|
|
3021
3834
|
const loaded = loadPlugin(pkg);
|
|
3022
3835
|
if (loaded) {
|
|
3023
3836
|
console.log(
|
|
3024
|
-
` ${
|
|
3837
|
+
` ${import_picocolors13.default.green("\u25CF")} ${import_picocolors13.default.bold(loaded.name)} prefix: ${import_picocolors13.default.cyan(loaded.prefix)} pkg: ${import_picocolors13.default.dim(pkg)}`
|
|
3025
3838
|
);
|
|
3026
3839
|
} else {
|
|
3027
|
-
console.log(` ${
|
|
3840
|
+
console.log(` ${import_picocolors13.default.yellow("\u25CF")} ${import_picocolors13.default.dim(pkg)} ${import_picocolors13.default.yellow("(failed to load)")}`);
|
|
3028
3841
|
}
|
|
3029
3842
|
}
|
|
3030
3843
|
console.log("");
|
|
3031
|
-
console.log(
|
|
3844
|
+
console.log(import_picocolors13.default.dim(` ${packages.length} plugin${packages.length !== 1 ? "s" : ""} installed`));
|
|
3032
3845
|
}
|
|
3033
3846
|
});
|
|
3034
|
-
var plugin_default = (0,
|
|
3847
|
+
var plugin_default = (0, import_citty14.defineCommand)({
|
|
3035
3848
|
meta: {
|
|
3036
3849
|
name: "plugin",
|
|
3037
3850
|
description: "Manage mcpman plugins for custom registries"
|
|
@@ -3045,24 +3858,26 @@ var plugin_default = (0, import_citty11.defineCommand)({
|
|
|
3045
3858
|
|
|
3046
3859
|
// src/commands/profiles.ts
|
|
3047
3860
|
init_cjs_shims();
|
|
3048
|
-
var
|
|
3049
|
-
var
|
|
3861
|
+
var import_citty15 = require("citty");
|
|
3862
|
+
var import_picocolors14 = __toESM(require("picocolors"), 1);
|
|
3863
|
+
init_lockfile();
|
|
3050
3864
|
|
|
3051
3865
|
// src/core/profile-service.ts
|
|
3052
3866
|
init_cjs_shims();
|
|
3053
|
-
var
|
|
3054
|
-
var
|
|
3867
|
+
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
3868
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
3055
3869
|
init_paths();
|
|
3870
|
+
init_lockfile();
|
|
3056
3871
|
function ensureDir(dir = getProfilesDir()) {
|
|
3057
|
-
|
|
3872
|
+
import_node_fs13.default.mkdirSync(dir, { recursive: true });
|
|
3058
3873
|
}
|
|
3059
3874
|
function profilePath(name, dir = getProfilesDir()) {
|
|
3060
|
-
return
|
|
3875
|
+
return import_node_path16.default.join(dir, `${name}.json`);
|
|
3061
3876
|
}
|
|
3062
3877
|
function createProfile(name, description = "", dir = getProfilesDir()) {
|
|
3063
3878
|
ensureDir(dir);
|
|
3064
3879
|
const filePath = profilePath(name, dir);
|
|
3065
|
-
if (
|
|
3880
|
+
if (import_node_fs13.default.existsSync(filePath)) {
|
|
3066
3881
|
throw new Error(`Profile '${name}' already exists. Delete it first or use a different name.`);
|
|
3067
3882
|
}
|
|
3068
3883
|
const lockfile = readLockfile();
|
|
@@ -3072,16 +3887,16 @@ function createProfile(name, description = "", dir = getProfilesDir()) {
|
|
|
3072
3887
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3073
3888
|
servers: lockfile.servers
|
|
3074
3889
|
};
|
|
3075
|
-
|
|
3890
|
+
import_node_fs13.default.writeFileSync(filePath, JSON.stringify(profile, null, 2), "utf-8");
|
|
3076
3891
|
return profile;
|
|
3077
3892
|
}
|
|
3078
3893
|
function listProfiles(dir = getProfilesDir()) {
|
|
3079
3894
|
ensureDir(dir);
|
|
3080
|
-
const files =
|
|
3895
|
+
const files = import_node_fs13.default.readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
3081
3896
|
const profiles = [];
|
|
3082
3897
|
for (const file of files) {
|
|
3083
3898
|
try {
|
|
3084
|
-
const raw =
|
|
3899
|
+
const raw = import_node_fs13.default.readFileSync(import_node_path16.default.join(dir, file), "utf-8");
|
|
3085
3900
|
const data = JSON.parse(raw);
|
|
3086
3901
|
profiles.push(data);
|
|
3087
3902
|
} catch {
|
|
@@ -3091,9 +3906,9 @@ function listProfiles(dir = getProfilesDir()) {
|
|
|
3091
3906
|
}
|
|
3092
3907
|
function loadProfile(name, dir = getProfilesDir()) {
|
|
3093
3908
|
const filePath = profilePath(name, dir);
|
|
3094
|
-
if (!
|
|
3909
|
+
if (!import_node_fs13.default.existsSync(filePath)) return null;
|
|
3095
3910
|
try {
|
|
3096
|
-
const raw =
|
|
3911
|
+
const raw = import_node_fs13.default.readFileSync(filePath, "utf-8");
|
|
3097
3912
|
return JSON.parse(raw);
|
|
3098
3913
|
} catch {
|
|
3099
3914
|
return null;
|
|
@@ -3101,13 +3916,13 @@ function loadProfile(name, dir = getProfilesDir()) {
|
|
|
3101
3916
|
}
|
|
3102
3917
|
function deleteProfile(name, dir = getProfilesDir()) {
|
|
3103
3918
|
const filePath = profilePath(name, dir);
|
|
3104
|
-
if (!
|
|
3105
|
-
|
|
3919
|
+
if (!import_node_fs13.default.existsSync(filePath)) return false;
|
|
3920
|
+
import_node_fs13.default.unlinkSync(filePath);
|
|
3106
3921
|
return true;
|
|
3107
3922
|
}
|
|
3108
3923
|
|
|
3109
3924
|
// src/commands/profiles.ts
|
|
3110
|
-
var profiles_default = (0,
|
|
3925
|
+
var profiles_default = (0, import_citty15.defineCommand)({
|
|
3111
3926
|
meta: {
|
|
3112
3927
|
name: "profiles",
|
|
3113
3928
|
description: "Manage named server configuration profiles"
|
|
@@ -3136,16 +3951,16 @@ var profiles_default = (0, import_citty12.defineCommand)({
|
|
|
3136
3951
|
case "create": {
|
|
3137
3952
|
if (!name) {
|
|
3138
3953
|
console.error(
|
|
3139
|
-
|
|
3954
|
+
import_picocolors14.default.red(" Error: Profile name required. Usage: mcpman profiles create <name>")
|
|
3140
3955
|
);
|
|
3141
3956
|
process.exit(1);
|
|
3142
3957
|
}
|
|
3143
3958
|
try {
|
|
3144
3959
|
const profile = createProfile(name, args.description ?? "");
|
|
3145
3960
|
const count = Object.keys(profile.servers).length;
|
|
3146
|
-
console.log(
|
|
3961
|
+
console.log(import_picocolors14.default.green(` \u2713 Profile '${name}' created with ${count} server(s).`));
|
|
3147
3962
|
} catch (err) {
|
|
3148
|
-
console.error(
|
|
3963
|
+
console.error(import_picocolors14.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
3149
3964
|
process.exit(1);
|
|
3150
3965
|
}
|
|
3151
3966
|
break;
|
|
@@ -3153,38 +3968,38 @@ var profiles_default = (0, import_citty12.defineCommand)({
|
|
|
3153
3968
|
case "switch": {
|
|
3154
3969
|
if (!name) {
|
|
3155
3970
|
console.error(
|
|
3156
|
-
|
|
3971
|
+
import_picocolors14.default.red(" Error: Profile name required. Usage: mcpman profiles switch <name>")
|
|
3157
3972
|
);
|
|
3158
3973
|
process.exit(1);
|
|
3159
3974
|
}
|
|
3160
3975
|
const profile = loadProfile(name);
|
|
3161
3976
|
if (!profile) {
|
|
3162
|
-
console.error(
|
|
3977
|
+
console.error(import_picocolors14.default.red(` Error: Profile '${name}' not found.`));
|
|
3163
3978
|
process.exit(1);
|
|
3164
3979
|
}
|
|
3165
3980
|
const lockData = { lockfileVersion: 1, servers: profile.servers };
|
|
3166
3981
|
writeLockfile(lockData);
|
|
3167
3982
|
const count = Object.keys(profile.servers).length;
|
|
3168
|
-
console.log(
|
|
3169
|
-
console.log(
|
|
3983
|
+
console.log(import_picocolors14.default.green(` \u2713 Switched to profile '${name}' (${count} servers).`));
|
|
3984
|
+
console.log(import_picocolors14.default.dim(" Run mcpman sync to apply to all clients."));
|
|
3170
3985
|
break;
|
|
3171
3986
|
}
|
|
3172
3987
|
case "list": {
|
|
3173
3988
|
const profiles = listProfiles();
|
|
3174
3989
|
if (profiles.length === 0) {
|
|
3175
3990
|
console.log(
|
|
3176
|
-
|
|
3991
|
+
import_picocolors14.default.dim(" No profiles saved. Create one with: mcpman profiles create <name>")
|
|
3177
3992
|
);
|
|
3178
3993
|
return;
|
|
3179
3994
|
}
|
|
3180
|
-
console.log(
|
|
3995
|
+
console.log(import_picocolors14.default.bold(`
|
|
3181
3996
|
Profiles (${profiles.length})
|
|
3182
3997
|
`));
|
|
3183
3998
|
for (const p13 of profiles) {
|
|
3184
3999
|
const count = Object.keys(p13.servers).length;
|
|
3185
|
-
const desc = p13.description ?
|
|
4000
|
+
const desc = p13.description ? import_picocolors14.default.dim(` \u2014 ${p13.description}`) : "";
|
|
3186
4001
|
console.log(
|
|
3187
|
-
` ${
|
|
4002
|
+
` ${import_picocolors14.default.cyan("\u25CF")} ${import_picocolors14.default.bold(p13.name)} ${import_picocolors14.default.dim(`${count} server(s)`)}${desc}`
|
|
3188
4003
|
);
|
|
3189
4004
|
}
|
|
3190
4005
|
console.log();
|
|
@@ -3193,33 +4008,203 @@ var profiles_default = (0, import_citty12.defineCommand)({
|
|
|
3193
4008
|
case "delete": {
|
|
3194
4009
|
if (!name) {
|
|
3195
4010
|
console.error(
|
|
3196
|
-
|
|
4011
|
+
import_picocolors14.default.red(" Error: Profile name required. Usage: mcpman profiles delete <name>")
|
|
3197
4012
|
);
|
|
3198
4013
|
process.exit(1);
|
|
3199
4014
|
}
|
|
3200
4015
|
const deleted = deleteProfile(name);
|
|
3201
4016
|
if (deleted) {
|
|
3202
|
-
console.log(
|
|
4017
|
+
console.log(import_picocolors14.default.green(` \u2713 Profile '${name}' deleted.`));
|
|
3203
4018
|
} else {
|
|
3204
|
-
console.error(
|
|
4019
|
+
console.error(import_picocolors14.default.red(` Error: Profile '${name}' not found.`));
|
|
3205
4020
|
process.exit(1);
|
|
3206
4021
|
}
|
|
3207
4022
|
break;
|
|
3208
4023
|
}
|
|
3209
4024
|
default:
|
|
3210
4025
|
console.error(
|
|
3211
|
-
|
|
4026
|
+
import_picocolors14.default.red(` Unknown action '${action}'. Use: create, switch, list, or delete.`)
|
|
3212
4027
|
);
|
|
3213
4028
|
process.exit(1);
|
|
3214
4029
|
}
|
|
3215
4030
|
}
|
|
3216
4031
|
});
|
|
3217
4032
|
|
|
4033
|
+
// src/commands/registry.ts
|
|
4034
|
+
init_cjs_shims();
|
|
4035
|
+
var import_citty16 = require("citty");
|
|
4036
|
+
var import_picocolors15 = __toESM(require("picocolors"), 1);
|
|
4037
|
+
|
|
4038
|
+
// src/core/registry-manager.ts
|
|
4039
|
+
init_cjs_shims();
|
|
4040
|
+
var BUILTIN_REGISTRIES = [
|
|
4041
|
+
{ name: "npm", url: "https://registry.npmjs.org", builtin: true },
|
|
4042
|
+
{ name: "smithery", url: "https://registry.smithery.ai", builtin: true }
|
|
4043
|
+
];
|
|
4044
|
+
function validateUrl(url) {
|
|
4045
|
+
try {
|
|
4046
|
+
new URL(url);
|
|
4047
|
+
} catch {
|
|
4048
|
+
throw new Error(
|
|
4049
|
+
`Invalid URL: "${url}". Must be a valid URL (e.g. https://registry.example.com)`
|
|
4050
|
+
);
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
4053
|
+
function readCustomRegistries(configPath) {
|
|
4054
|
+
const config = readConfig(configPath);
|
|
4055
|
+
const raw = config.registries;
|
|
4056
|
+
if (!Array.isArray(raw)) return [];
|
|
4057
|
+
return raw.filter((r) => !r.builtin);
|
|
4058
|
+
}
|
|
4059
|
+
function writeCustomRegistries(entries, configPath) {
|
|
4060
|
+
const config = readConfig(configPath);
|
|
4061
|
+
config.registries = entries;
|
|
4062
|
+
writeConfig(config, configPath);
|
|
4063
|
+
}
|
|
4064
|
+
function getRegistries(configPath) {
|
|
4065
|
+
const custom = readCustomRegistries(configPath);
|
|
4066
|
+
return [...BUILTIN_REGISTRIES, ...custom];
|
|
4067
|
+
}
|
|
4068
|
+
function addRegistry(name, url, configPath) {
|
|
4069
|
+
validateUrl(url);
|
|
4070
|
+
const all = getRegistries(configPath);
|
|
4071
|
+
if (all.some((r) => r.name === name)) {
|
|
4072
|
+
throw new Error(`Registry '${name}' already exists. Use a different name or remove it first.`);
|
|
4073
|
+
}
|
|
4074
|
+
const custom = readCustomRegistries(configPath);
|
|
4075
|
+
custom.push({ name, url, builtin: false });
|
|
4076
|
+
writeCustomRegistries(custom, configPath);
|
|
4077
|
+
}
|
|
4078
|
+
function removeRegistry(name, configPath) {
|
|
4079
|
+
if (BUILTIN_REGISTRIES.some((r) => r.name === name)) {
|
|
4080
|
+
throw new Error(`Cannot remove built-in registry '${name}'.`);
|
|
4081
|
+
}
|
|
4082
|
+
const custom = readCustomRegistries(configPath);
|
|
4083
|
+
const idx = custom.findIndex((r) => r.name === name);
|
|
4084
|
+
if (idx === -1) {
|
|
4085
|
+
throw new Error(`Registry '${name}' not found.`);
|
|
4086
|
+
}
|
|
4087
|
+
custom.splice(idx, 1);
|
|
4088
|
+
writeCustomRegistries(custom, configPath);
|
|
4089
|
+
}
|
|
4090
|
+
function setDefaultRegistry(name, configPath) {
|
|
4091
|
+
const all = getRegistries(configPath);
|
|
4092
|
+
if (!all.some((r) => r.name === name)) {
|
|
4093
|
+
throw new Error(
|
|
4094
|
+
`Registry '${name}' not found. Add it first with: mcpman registry add ${name} <url>`
|
|
4095
|
+
);
|
|
4096
|
+
}
|
|
4097
|
+
const config = readConfig(configPath);
|
|
4098
|
+
config.defaultRegistry = name;
|
|
4099
|
+
writeConfig(config, configPath);
|
|
4100
|
+
}
|
|
4101
|
+
function getDefaultRegistry(configPath) {
|
|
4102
|
+
const config = readConfig(configPath);
|
|
4103
|
+
return String(config.defaultRegistry ?? "npm");
|
|
4104
|
+
}
|
|
4105
|
+
|
|
4106
|
+
// src/commands/registry.ts
|
|
4107
|
+
var registry_default = (0, import_citty16.defineCommand)({
|
|
4108
|
+
meta: {
|
|
4109
|
+
name: "registry",
|
|
4110
|
+
description: "Manage custom registry URLs"
|
|
4111
|
+
},
|
|
4112
|
+
args: {
|
|
4113
|
+
action: {
|
|
4114
|
+
type: "positional",
|
|
4115
|
+
description: "Action: list, add, remove, set-default",
|
|
4116
|
+
required: true
|
|
4117
|
+
},
|
|
4118
|
+
name: {
|
|
4119
|
+
type: "positional",
|
|
4120
|
+
description: "Registry name (for add/remove/set-default)",
|
|
4121
|
+
required: false
|
|
4122
|
+
},
|
|
4123
|
+
url: {
|
|
4124
|
+
type: "positional",
|
|
4125
|
+
description: "Registry URL (for add)",
|
|
4126
|
+
required: false
|
|
4127
|
+
}
|
|
4128
|
+
},
|
|
4129
|
+
async run({ args }) {
|
|
4130
|
+
const action = args.action.toLowerCase();
|
|
4131
|
+
const name = args.name;
|
|
4132
|
+
const url = args.url;
|
|
4133
|
+
switch (action) {
|
|
4134
|
+
case "list": {
|
|
4135
|
+
const registries = getRegistries();
|
|
4136
|
+
const defaultName = getDefaultRegistry();
|
|
4137
|
+
console.log(import_picocolors15.default.bold("\n Registries\n"));
|
|
4138
|
+
for (const r of registries) {
|
|
4139
|
+
const isDefault = r.name === defaultName;
|
|
4140
|
+
const defaultTag = isDefault ? import_picocolors15.default.green(" (default)") : "";
|
|
4141
|
+
const builtinTag = r.builtin ? import_picocolors15.default.dim(" [builtin]") : "";
|
|
4142
|
+
console.log(
|
|
4143
|
+
` ${isDefault ? import_picocolors15.default.green("\u25CF") : import_picocolors15.default.dim("\u25CB")} ${import_picocolors15.default.bold(r.name)}${defaultTag}${builtinTag}`
|
|
4144
|
+
);
|
|
4145
|
+
console.log(` ${import_picocolors15.default.dim(r.url)}`);
|
|
4146
|
+
}
|
|
4147
|
+
console.log();
|
|
4148
|
+
break;
|
|
4149
|
+
}
|
|
4150
|
+
case "add": {
|
|
4151
|
+
if (!name) {
|
|
4152
|
+
console.error(import_picocolors15.default.red(" Error: Usage: mcpman registry add <name> <url>"));
|
|
4153
|
+
process.exit(1);
|
|
4154
|
+
}
|
|
4155
|
+
if (!url) {
|
|
4156
|
+
console.error(import_picocolors15.default.red(" Error: Usage: mcpman registry add <name> <url>"));
|
|
4157
|
+
process.exit(1);
|
|
4158
|
+
}
|
|
4159
|
+
try {
|
|
4160
|
+
addRegistry(name, url);
|
|
4161
|
+
console.log(import_picocolors15.default.green(` Added registry '${name}' \u2192 ${url}`));
|
|
4162
|
+
} catch (err) {
|
|
4163
|
+
console.error(import_picocolors15.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
4164
|
+
process.exit(1);
|
|
4165
|
+
}
|
|
4166
|
+
break;
|
|
4167
|
+
}
|
|
4168
|
+
case "remove": {
|
|
4169
|
+
if (!name) {
|
|
4170
|
+
console.error(import_picocolors15.default.red(" Error: Usage: mcpman registry remove <name>"));
|
|
4171
|
+
process.exit(1);
|
|
4172
|
+
}
|
|
4173
|
+
try {
|
|
4174
|
+
removeRegistry(name);
|
|
4175
|
+
console.log(import_picocolors15.default.green(` Removed registry '${name}'.`));
|
|
4176
|
+
} catch (err) {
|
|
4177
|
+
console.error(import_picocolors15.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
4178
|
+
process.exit(1);
|
|
4179
|
+
}
|
|
4180
|
+
break;
|
|
4181
|
+
}
|
|
4182
|
+
case "set-default": {
|
|
4183
|
+
if (!name) {
|
|
4184
|
+
console.error(import_picocolors15.default.red(" Error: Usage: mcpman registry set-default <name>"));
|
|
4185
|
+
process.exit(1);
|
|
4186
|
+
}
|
|
4187
|
+
try {
|
|
4188
|
+
setDefaultRegistry(name);
|
|
4189
|
+
console.log(import_picocolors15.default.green(` Default registry set to '${name}'.`));
|
|
4190
|
+
} catch (err) {
|
|
4191
|
+
console.error(import_picocolors15.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
|
|
4192
|
+
process.exit(1);
|
|
4193
|
+
}
|
|
4194
|
+
break;
|
|
4195
|
+
}
|
|
4196
|
+
default:
|
|
4197
|
+
console.error(import_picocolors15.default.red(` Unknown action '${action}'. Use: list, add, remove, set-default.`));
|
|
4198
|
+
process.exit(1);
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
});
|
|
4202
|
+
|
|
3218
4203
|
// src/commands/remove.ts
|
|
3219
4204
|
init_cjs_shims();
|
|
3220
4205
|
var p9 = __toESM(require("@clack/prompts"), 1);
|
|
3221
|
-
var
|
|
3222
|
-
var
|
|
4206
|
+
var import_citty17 = require("citty");
|
|
4207
|
+
var import_picocolors16 = __toESM(require("picocolors"), 1);
|
|
3223
4208
|
init_client_detector();
|
|
3224
4209
|
var CLIENT_DISPLAY2 = {
|
|
3225
4210
|
"claude-desktop": "Claude",
|
|
@@ -3230,7 +4215,7 @@ var CLIENT_DISPLAY2 = {
|
|
|
3230
4215
|
function clientDisplayName(type) {
|
|
3231
4216
|
return CLIENT_DISPLAY2[type] ?? type;
|
|
3232
4217
|
}
|
|
3233
|
-
var remove_default = (0,
|
|
4218
|
+
var remove_default = (0, import_citty17.defineCommand)({
|
|
3234
4219
|
meta: {
|
|
3235
4220
|
name: "remove",
|
|
3236
4221
|
description: "Remove an MCP server from one or more AI clients"
|
|
@@ -3257,7 +4242,7 @@ var remove_default = (0, import_citty13.defineCommand)({
|
|
|
3257
4242
|
}
|
|
3258
4243
|
},
|
|
3259
4244
|
async run({ args }) {
|
|
3260
|
-
p9.intro(
|
|
4245
|
+
p9.intro(import_picocolors16.default.bold("mcpman remove"));
|
|
3261
4246
|
const serverName = args.server;
|
|
3262
4247
|
const servers = await getInstalledServers();
|
|
3263
4248
|
const match = servers.find((s) => s.name === serverName);
|
|
@@ -3267,7 +4252,7 @@ var remove_default = (0, import_citty13.defineCommand)({
|
|
|
3267
4252
|
(s) => s.name.includes(serverName) || serverName.includes(s.name)
|
|
3268
4253
|
);
|
|
3269
4254
|
if (similar.length > 0) {
|
|
3270
|
-
p9.log.info(`Did you mean: ${similar.map((s) =>
|
|
4255
|
+
p9.log.info(`Did you mean: ${similar.map((s) => import_picocolors16.default.cyan(s.name)).join(", ")}?`);
|
|
3271
4256
|
}
|
|
3272
4257
|
p9.outro("Nothing to remove.");
|
|
3273
4258
|
return;
|
|
@@ -3302,7 +4287,7 @@ var remove_default = (0, import_citty13.defineCommand)({
|
|
|
3302
4287
|
if (!args.yes) {
|
|
3303
4288
|
const clientNames = targetClients.map(clientDisplayName).join(", ");
|
|
3304
4289
|
const confirmed = await p9.confirm({
|
|
3305
|
-
message: `Remove ${
|
|
4290
|
+
message: `Remove ${import_picocolors16.default.cyan(serverName)} from ${import_picocolors16.default.yellow(clientNames)}?`
|
|
3306
4291
|
});
|
|
3307
4292
|
if (p9.isCancel(confirmed) || !confirmed) {
|
|
3308
4293
|
p9.outro("Cancelled.");
|
|
@@ -3327,20 +4312,21 @@ var remove_default = (0, import_citty13.defineCommand)({
|
|
|
3327
4312
|
}
|
|
3328
4313
|
if (errors.length > 0) {
|
|
3329
4314
|
for (const e of errors) p9.log.error(e);
|
|
3330
|
-
p9.outro(
|
|
4315
|
+
p9.outro(import_picocolors16.default.red("Completed with errors."));
|
|
3331
4316
|
process.exit(1);
|
|
3332
4317
|
}
|
|
3333
|
-
p9.outro(
|
|
4318
|
+
p9.outro(import_picocolors16.default.green(`Removed "${serverName}" successfully.`));
|
|
3334
4319
|
}
|
|
3335
4320
|
});
|
|
3336
4321
|
|
|
3337
4322
|
// src/commands/run.ts
|
|
3338
4323
|
init_cjs_shims();
|
|
3339
4324
|
var import_node_child_process5 = require("child_process");
|
|
3340
|
-
var
|
|
3341
|
-
var
|
|
4325
|
+
var import_citty18 = require("citty");
|
|
4326
|
+
var import_picocolors17 = __toESM(require("picocolors"), 1);
|
|
4327
|
+
init_lockfile();
|
|
3342
4328
|
init_vault_service();
|
|
3343
|
-
var run_default = (0,
|
|
4329
|
+
var run_default = (0, import_citty18.defineCommand)({
|
|
3344
4330
|
meta: {
|
|
3345
4331
|
name: "run",
|
|
3346
4332
|
description: "Run an installed MCP server with vault secrets injected"
|
|
@@ -3362,8 +4348,8 @@ var run_default = (0, import_citty14.defineCommand)({
|
|
|
3362
4348
|
const lockfile = readLockfile();
|
|
3363
4349
|
const entry = lockfile.servers[serverName];
|
|
3364
4350
|
if (!entry) {
|
|
3365
|
-
console.error(
|
|
3366
|
-
console.error(
|
|
4351
|
+
console.error(import_picocolors17.default.red(` Error: Server '${serverName}' is not installed.`));
|
|
4352
|
+
console.error(import_picocolors17.default.dim(` Run ${import_picocolors17.default.cyan("mcpman install <server>")} to install it first.`));
|
|
3367
4353
|
process.exit(1);
|
|
3368
4354
|
}
|
|
3369
4355
|
const lockfileEnv = parseEnvFlags(entry.envVars);
|
|
@@ -3375,7 +4361,7 @@ var run_default = (0, import_citty14.defineCommand)({
|
|
|
3375
4361
|
...vaultEnv,
|
|
3376
4362
|
...cliEnv
|
|
3377
4363
|
};
|
|
3378
|
-
console.log(
|
|
4364
|
+
console.log(import_picocolors17.default.dim(` Running ${import_picocolors17.default.cyan(serverName)}...`));
|
|
3379
4365
|
const child = (0, import_node_child_process5.spawn)(entry.command, entry.args, {
|
|
3380
4366
|
env: finalEnv,
|
|
3381
4367
|
stdio: "inherit"
|
|
@@ -3393,7 +4379,7 @@ var run_default = (0, import_citty14.defineCommand)({
|
|
|
3393
4379
|
resolve();
|
|
3394
4380
|
});
|
|
3395
4381
|
child.on("error", (err) => {
|
|
3396
|
-
console.error(
|
|
4382
|
+
console.error(import_picocolors17.default.red(` Failed to start '${serverName}': ${err.message}`));
|
|
3397
4383
|
process.exit(1);
|
|
3398
4384
|
resolve();
|
|
3399
4385
|
});
|
|
@@ -3409,16 +4395,16 @@ async function loadVaultSecrets2(serverName) {
|
|
|
3409
4395
|
const password2 = await getMasterPassword();
|
|
3410
4396
|
return getSecretsForServer(serverName, password2);
|
|
3411
4397
|
} catch {
|
|
3412
|
-
console.warn(
|
|
4398
|
+
console.warn(import_picocolors17.default.yellow(" Warning: Could not load vault secrets, continuing without them."));
|
|
3413
4399
|
return {};
|
|
3414
4400
|
}
|
|
3415
4401
|
}
|
|
3416
4402
|
|
|
3417
4403
|
// src/commands/search.ts
|
|
3418
4404
|
init_cjs_shims();
|
|
3419
|
-
var
|
|
4405
|
+
var import_citty19 = require("citty");
|
|
3420
4406
|
var import_nanospinner4 = require("nanospinner");
|
|
3421
|
-
var
|
|
4407
|
+
var import_picocolors18 = __toESM(require("picocolors"), 1);
|
|
3422
4408
|
|
|
3423
4409
|
// src/core/registry-search.ts
|
|
3424
4410
|
init_cjs_shims();
|
|
@@ -3492,10 +4478,10 @@ function pad2(s, width) {
|
|
|
3492
4478
|
function highlightMatch(name, query) {
|
|
3493
4479
|
const idx = name.toLowerCase().indexOf(query.toLowerCase());
|
|
3494
4480
|
if (idx === -1) return name;
|
|
3495
|
-
return name.slice(0, idx) +
|
|
4481
|
+
return name.slice(0, idx) + import_picocolors18.default.yellow(name.slice(idx, idx + query.length)) + name.slice(idx + query.length);
|
|
3496
4482
|
}
|
|
3497
4483
|
function formatDownloads(n) {
|
|
3498
|
-
if (!n) return
|
|
4484
|
+
if (!n) return import_picocolors18.default.dim("\u2014");
|
|
3499
4485
|
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
3500
4486
|
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
|
|
3501
4487
|
return String(n);
|
|
@@ -3506,9 +4492,9 @@ function printNpmResults(results, query) {
|
|
|
3506
4492
|
const dlWidth = 9;
|
|
3507
4493
|
const descMax = 50;
|
|
3508
4494
|
const header = ` ${pad2("NAME", nameWidth)} ${pad2("VERSION", verWidth)} ${pad2("DOWNLOADS", dlWidth)} DESCRIPTION`;
|
|
3509
|
-
console.log(
|
|
4495
|
+
console.log(import_picocolors18.default.dim(header));
|
|
3510
4496
|
console.log(
|
|
3511
|
-
|
|
4497
|
+
import_picocolors18.default.dim(
|
|
3512
4498
|
` ${"-".repeat(nameWidth)} ${"-".repeat(verWidth)} ${"-".repeat(dlWidth)} ${"-".repeat(descMax)}`
|
|
3513
4499
|
)
|
|
3514
4500
|
);
|
|
@@ -3516,8 +4502,8 @@ function printNpmResults(results, query) {
|
|
|
3516
4502
|
const name = highlightMatch(pad2(r.name, nameWidth), query);
|
|
3517
4503
|
const ver = pad2(r.version, verWidth);
|
|
3518
4504
|
const dl = pad2(formatDownloads(r.downloads), dlWidth);
|
|
3519
|
-
const desc = truncate2(r.description ||
|
|
3520
|
-
console.log(` ${name} ${
|
|
4505
|
+
const desc = truncate2(r.description || import_picocolors18.default.dim("(no description)"), descMax);
|
|
4506
|
+
console.log(` ${name} ${import_picocolors18.default.dim(ver)} ${dl} ${desc}`);
|
|
3521
4507
|
}
|
|
3522
4508
|
}
|
|
3523
4509
|
function printSmitheryResults(results, query) {
|
|
@@ -3525,19 +4511,19 @@ function printSmitheryResults(results, query) {
|
|
|
3525
4511
|
const usesWidth = 8;
|
|
3526
4512
|
const descMax = 50;
|
|
3527
4513
|
const header = ` ${pad2("NAME", nameWidth)} ${pad2("USES", usesWidth)} DESCRIPTION`;
|
|
3528
|
-
console.log(
|
|
4514
|
+
console.log(import_picocolors18.default.dim(header));
|
|
3529
4515
|
console.log(
|
|
3530
|
-
|
|
4516
|
+
import_picocolors18.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(usesWidth)} ${"-".repeat(descMax)}`)
|
|
3531
4517
|
);
|
|
3532
4518
|
for (const r of results) {
|
|
3533
4519
|
const name = highlightMatch(pad2(r.name, nameWidth), query);
|
|
3534
4520
|
const uses = pad2(formatDownloads(r.useCount), usesWidth);
|
|
3535
|
-
const badge = r.verified ?
|
|
3536
|
-
const desc = truncate2(r.description ||
|
|
4521
|
+
const badge = r.verified ? import_picocolors18.default.green(" \u2713") : "";
|
|
4522
|
+
const desc = truncate2(r.description || import_picocolors18.default.dim("(no description)"), descMax);
|
|
3537
4523
|
console.log(` ${name}${badge} ${uses} ${desc}`);
|
|
3538
4524
|
}
|
|
3539
4525
|
}
|
|
3540
|
-
var search_default = (0,
|
|
4526
|
+
var search_default = (0, import_citty19.defineCommand)({
|
|
3541
4527
|
meta: {
|
|
3542
4528
|
name: "search",
|
|
3543
4529
|
description: "Search for MCP servers on npm or Smithery registry"
|
|
@@ -3569,7 +4555,7 @@ var search_default = (0, import_citty15.defineCommand)({
|
|
|
3569
4555
|
const registry = args.registry.toLowerCase();
|
|
3570
4556
|
const limit = Math.min(Math.max(1, Number.parseInt(args.limit, 10) || 20), 100);
|
|
3571
4557
|
if (registry !== "npm" && registry !== "smithery") {
|
|
3572
|
-
console.error(
|
|
4558
|
+
console.error(import_picocolors18.default.red(` Unknown registry "${registry}". Use "npm" or "smithery".`));
|
|
3573
4559
|
process.exit(1);
|
|
3574
4560
|
}
|
|
3575
4561
|
const spinner5 = (0, import_nanospinner4.createSpinner)(`Searching ${registry} for "${query}"...`).start();
|
|
@@ -3577,20 +4563,20 @@ var search_default = (0, import_citty15.defineCommand)({
|
|
|
3577
4563
|
const results2 = await searchNpm(query, limit);
|
|
3578
4564
|
spinner5.stop();
|
|
3579
4565
|
if (results2.length === 0) {
|
|
3580
|
-
console.log(
|
|
4566
|
+
console.log(import_picocolors18.default.dim(`
|
|
3581
4567
|
No results found for "${query}" on npm.
|
|
3582
4568
|
`));
|
|
3583
4569
|
return;
|
|
3584
4570
|
}
|
|
3585
4571
|
console.log(
|
|
3586
|
-
|
|
4572
|
+
import_picocolors18.default.bold(
|
|
3587
4573
|
`
|
|
3588
4574
|
mcpman search \u2014 npm (${results2.length} result${results2.length !== 1 ? "s" : ""})
|
|
3589
4575
|
`
|
|
3590
4576
|
)
|
|
3591
4577
|
);
|
|
3592
4578
|
printNpmResults(results2, query);
|
|
3593
|
-
console.log(
|
|
4579
|
+
console.log(import_picocolors18.default.dim("\n Install with: mcpman install <name>\n"));
|
|
3594
4580
|
if (args.all) {
|
|
3595
4581
|
await printPluginResults(query, limit);
|
|
3596
4582
|
}
|
|
@@ -3599,20 +4585,20 @@ var search_default = (0, import_citty15.defineCommand)({
|
|
|
3599
4585
|
const results = await searchSmithery(query, limit);
|
|
3600
4586
|
spinner5.stop();
|
|
3601
4587
|
if (results.length === 0) {
|
|
3602
|
-
console.log(
|
|
4588
|
+
console.log(import_picocolors18.default.dim(`
|
|
3603
4589
|
No results found for "${query}" on Smithery.
|
|
3604
4590
|
`));
|
|
3605
4591
|
return;
|
|
3606
4592
|
}
|
|
3607
4593
|
console.log(
|
|
3608
|
-
|
|
4594
|
+
import_picocolors18.default.bold(
|
|
3609
4595
|
`
|
|
3610
4596
|
mcpman search \u2014 Smithery (${results.length} result${results.length !== 1 ? "s" : ""})
|
|
3611
4597
|
`
|
|
3612
4598
|
)
|
|
3613
4599
|
);
|
|
3614
4600
|
printSmitheryResults(results, query);
|
|
3615
|
-
console.log(
|
|
4601
|
+
console.log(import_picocolors18.default.dim("\n Install with: mcpman install <name>\n"));
|
|
3616
4602
|
if (args.all) {
|
|
3617
4603
|
await printPluginResults(query, limit);
|
|
3618
4604
|
}
|
|
@@ -3622,7 +4608,7 @@ async function printPluginResults(query, limit) {
|
|
|
3622
4608
|
const pluginResults = await searchPlugins(query, limit);
|
|
3623
4609
|
if (pluginResults.length === 0) return;
|
|
3624
4610
|
console.log(
|
|
3625
|
-
|
|
4611
|
+
import_picocolors18.default.bold(
|
|
3626
4612
|
`
|
|
3627
4613
|
Plugins (${pluginResults.length} result${pluginResults.length !== 1 ? "s" : ""})
|
|
3628
4614
|
`
|
|
@@ -3632,23 +4618,23 @@ async function printPluginResults(query, limit) {
|
|
|
3632
4618
|
const srcWidth = Math.max(6, ...pluginResults.map((r) => r.source.length));
|
|
3633
4619
|
const descMax = 50;
|
|
3634
4620
|
const header = ` ${pad2("NAME", nameWidth)} ${pad2("SOURCE", srcWidth)} DESCRIPTION`;
|
|
3635
|
-
console.log(
|
|
4621
|
+
console.log(import_picocolors18.default.dim(header));
|
|
3636
4622
|
console.log(
|
|
3637
|
-
|
|
4623
|
+
import_picocolors18.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(srcWidth)} ${"-".repeat(descMax)}`)
|
|
3638
4624
|
);
|
|
3639
4625
|
for (const r of pluginResults) {
|
|
3640
4626
|
const name = highlightMatch(pad2(r.name, nameWidth), query);
|
|
3641
4627
|
const src = pad2(r.source, srcWidth);
|
|
3642
|
-
const desc = truncate2(r.description ||
|
|
3643
|
-
console.log(` ${name} ${
|
|
4628
|
+
const desc = truncate2(r.description || import_picocolors18.default.dim("(no description)"), descMax);
|
|
4629
|
+
console.log(` ${name} ${import_picocolors18.default.dim(src)} ${desc}`);
|
|
3644
4630
|
}
|
|
3645
4631
|
}
|
|
3646
4632
|
|
|
3647
4633
|
// src/commands/secrets.ts
|
|
3648
4634
|
init_cjs_shims();
|
|
3649
4635
|
var p10 = __toESM(require("@clack/prompts"), 1);
|
|
3650
|
-
var
|
|
3651
|
-
var
|
|
4636
|
+
var import_citty20 = require("citty");
|
|
4637
|
+
var import_picocolors19 = __toESM(require("picocolors"), 1);
|
|
3652
4638
|
init_vault_service();
|
|
3653
4639
|
function maskValue(value) {
|
|
3654
4640
|
if (value.length <= 8) return "***";
|
|
@@ -3659,7 +4645,7 @@ function parseKeyValue(input) {
|
|
|
3659
4645
|
if (idx <= 0) return null;
|
|
3660
4646
|
return { key: input.slice(0, idx), value: input.slice(idx + 1) };
|
|
3661
4647
|
}
|
|
3662
|
-
var setCommand2 = (0,
|
|
4648
|
+
var setCommand2 = (0, import_citty20.defineCommand)({
|
|
3663
4649
|
meta: { name: "set", description: "Store an encrypted secret for a server" },
|
|
3664
4650
|
args: {
|
|
3665
4651
|
server: {
|
|
@@ -3676,10 +4662,10 @@ var setCommand2 = (0, import_citty16.defineCommand)({
|
|
|
3676
4662
|
async run({ args }) {
|
|
3677
4663
|
const parsed = parseKeyValue(args.keyvalue);
|
|
3678
4664
|
if (!parsed) {
|
|
3679
|
-
console.error(`${
|
|
4665
|
+
console.error(`${import_picocolors19.default.red("\u2717")} Invalid format. Expected KEY=VALUE`);
|
|
3680
4666
|
process.exit(1);
|
|
3681
4667
|
}
|
|
3682
|
-
p10.intro(
|
|
4668
|
+
p10.intro(import_picocolors19.default.cyan("mcpman secrets set"));
|
|
3683
4669
|
const isNew = listSecrets(args.server).length === 0 || !listSecrets(args.server)[0]?.keys.includes(parsed.key);
|
|
3684
4670
|
const vaultPath = (await Promise.resolve().then(() => (init_vault_service(), vault_service_exports))).getVaultPath();
|
|
3685
4671
|
const vaultExists = (await import("fs")).existsSync(vaultPath);
|
|
@@ -3688,16 +4674,16 @@ var setCommand2 = (0, import_citty16.defineCommand)({
|
|
|
3688
4674
|
spin.start("Encrypting secret...");
|
|
3689
4675
|
try {
|
|
3690
4676
|
setSecret(args.server, parsed.key, parsed.value, password2);
|
|
3691
|
-
spin.stop(`${
|
|
4677
|
+
spin.stop(`${import_picocolors19.default.green("\u2713")} Stored ${import_picocolors19.default.bold(parsed.key)} for ${import_picocolors19.default.cyan(args.server)}`);
|
|
3692
4678
|
} catch (err) {
|
|
3693
|
-
spin.stop(`${
|
|
3694
|
-
console.error(
|
|
4679
|
+
spin.stop(`${import_picocolors19.default.red("\u2717")} Failed to store secret`);
|
|
4680
|
+
console.error(import_picocolors19.default.dim(String(err)));
|
|
3695
4681
|
process.exit(1);
|
|
3696
4682
|
}
|
|
3697
|
-
p10.outro(
|
|
4683
|
+
p10.outro(import_picocolors19.default.dim("Secret encrypted and saved to vault."));
|
|
3698
4684
|
}
|
|
3699
4685
|
});
|
|
3700
|
-
var listCommand3 = (0,
|
|
4686
|
+
var listCommand3 = (0, import_citty20.defineCommand)({
|
|
3701
4687
|
meta: { name: "list", description: "List secret keys stored in the vault" },
|
|
3702
4688
|
args: {
|
|
3703
4689
|
server: {
|
|
@@ -3709,27 +4695,27 @@ var listCommand3 = (0, import_citty16.defineCommand)({
|
|
|
3709
4695
|
async run({ args }) {
|
|
3710
4696
|
const results = listSecrets(args.server || void 0);
|
|
3711
4697
|
if (results.length === 0) {
|
|
3712
|
-
const filter = args.server ? ` for ${
|
|
3713
|
-
console.log(
|
|
4698
|
+
const filter = args.server ? ` for ${import_picocolors19.default.cyan(args.server)}` : "";
|
|
4699
|
+
console.log(import_picocolors19.default.dim(`No secrets stored${filter}.`));
|
|
3714
4700
|
return;
|
|
3715
4701
|
}
|
|
3716
4702
|
console.log("");
|
|
3717
4703
|
for (const { server, keys } of results) {
|
|
3718
|
-
console.log(
|
|
4704
|
+
console.log(import_picocolors19.default.bold(import_picocolors19.default.cyan(server)));
|
|
3719
4705
|
for (const key of keys) {
|
|
3720
|
-
console.log(` ${
|
|
4706
|
+
console.log(` ${import_picocolors19.default.green("\u25CF")} ${import_picocolors19.default.bold(key)} ${import_picocolors19.default.dim(maskValue("\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"))}`);
|
|
3721
4707
|
}
|
|
3722
4708
|
console.log("");
|
|
3723
4709
|
}
|
|
3724
4710
|
const total = results.reduce((n, r) => n + r.keys.length, 0);
|
|
3725
4711
|
console.log(
|
|
3726
|
-
|
|
4712
|
+
import_picocolors19.default.dim(
|
|
3727
4713
|
` ${total} secret${total !== 1 ? "s" : ""} in ${results.length} server${results.length !== 1 ? "s" : ""}`
|
|
3728
4714
|
)
|
|
3729
4715
|
);
|
|
3730
4716
|
}
|
|
3731
4717
|
});
|
|
3732
|
-
var removeCommand2 = (0,
|
|
4718
|
+
var removeCommand2 = (0, import_citty20.defineCommand)({
|
|
3733
4719
|
meta: { name: "remove", description: "Delete a secret from the vault" },
|
|
3734
4720
|
args: {
|
|
3735
4721
|
server: {
|
|
@@ -3745,7 +4731,7 @@ var removeCommand2 = (0, import_citty16.defineCommand)({
|
|
|
3745
4731
|
},
|
|
3746
4732
|
async run({ args }) {
|
|
3747
4733
|
const confirmed = await p10.confirm({
|
|
3748
|
-
message: `Remove ${
|
|
4734
|
+
message: `Remove ${import_picocolors19.default.bold(args.key)} from ${import_picocolors19.default.cyan(args.server)}?`,
|
|
3749
4735
|
initialValue: false
|
|
3750
4736
|
});
|
|
3751
4737
|
if (p10.isCancel(confirmed) || !confirmed) {
|
|
@@ -3754,15 +4740,15 @@ var removeCommand2 = (0, import_citty16.defineCommand)({
|
|
|
3754
4740
|
}
|
|
3755
4741
|
try {
|
|
3756
4742
|
removeSecret(args.server, args.key);
|
|
3757
|
-
console.log(`${
|
|
4743
|
+
console.log(`${import_picocolors19.default.green("\u2713")} Removed ${import_picocolors19.default.bold(args.key)} from ${import_picocolors19.default.cyan(args.server)}`);
|
|
3758
4744
|
} catch (err) {
|
|
3759
|
-
console.error(`${
|
|
3760
|
-
console.error(
|
|
4745
|
+
console.error(`${import_picocolors19.default.red("\u2717")} Failed to remove secret`);
|
|
4746
|
+
console.error(import_picocolors19.default.dim(String(err)));
|
|
3761
4747
|
process.exit(1);
|
|
3762
4748
|
}
|
|
3763
4749
|
}
|
|
3764
4750
|
});
|
|
3765
|
-
var secrets_default = (0,
|
|
4751
|
+
var secrets_default = (0, import_citty20.defineCommand)({
|
|
3766
4752
|
meta: {
|
|
3767
4753
|
name: "secrets",
|
|
3768
4754
|
description: "Manage encrypted secrets for MCP servers"
|
|
@@ -3777,8 +4763,8 @@ var secrets_default = (0, import_citty16.defineCommand)({
|
|
|
3777
4763
|
// src/commands/sync.ts
|
|
3778
4764
|
init_cjs_shims();
|
|
3779
4765
|
var p11 = __toESM(require("@clack/prompts"), 1);
|
|
3780
|
-
var
|
|
3781
|
-
var
|
|
4766
|
+
var import_citty21 = require("citty");
|
|
4767
|
+
var import_picocolors20 = __toESM(require("picocolors"), 1);
|
|
3782
4768
|
|
|
3783
4769
|
// src/core/config-diff.ts
|
|
3784
4770
|
init_cjs_shims();
|
|
@@ -3845,6 +4831,9 @@ function computeDiffFromClient(sourceClient, clientConfigs, options = {}) {
|
|
|
3845
4831
|
return actions;
|
|
3846
4832
|
}
|
|
3847
4833
|
|
|
4834
|
+
// src/commands/sync.ts
|
|
4835
|
+
init_lockfile();
|
|
4836
|
+
|
|
3848
4837
|
// src/core/sync-engine.ts
|
|
3849
4838
|
init_cjs_shims();
|
|
3850
4839
|
init_client_detector();
|
|
@@ -3933,7 +4922,7 @@ var CLIENT_DISPLAY3 = {
|
|
|
3933
4922
|
vscode: "VS Code",
|
|
3934
4923
|
windsurf: "Windsurf"
|
|
3935
4924
|
};
|
|
3936
|
-
var sync_default = (0,
|
|
4925
|
+
var sync_default = (0, import_citty21.defineCommand)({
|
|
3937
4926
|
meta: {
|
|
3938
4927
|
name: "sync",
|
|
3939
4928
|
description: "Sync MCP server configs across all detected AI clients"
|
|
@@ -3960,7 +4949,7 @@ var sync_default = (0, import_citty17.defineCommand)({
|
|
|
3960
4949
|
}
|
|
3961
4950
|
},
|
|
3962
4951
|
async run({ args }) {
|
|
3963
|
-
p11.intro(`${
|
|
4952
|
+
p11.intro(`${import_picocolors20.default.cyan("mcpman sync")}`);
|
|
3964
4953
|
const sourceClient = args.source;
|
|
3965
4954
|
if (sourceClient && !VALID_CLIENTS.includes(sourceClient)) {
|
|
3966
4955
|
p11.log.error(
|
|
@@ -3996,20 +4985,20 @@ var sync_default = (0, import_citty17.defineCommand)({
|
|
|
3996
4985
|
const extraCount = actions.filter((a) => a.action === "extra").length;
|
|
3997
4986
|
const removeCount = actions.filter((a) => a.action === "remove").length;
|
|
3998
4987
|
if (addCount === 0 && removeCount === 0 && extraCount === 0) {
|
|
3999
|
-
p11.outro(
|
|
4988
|
+
p11.outro(import_picocolors20.default.green("All clients are in sync."));
|
|
4000
4989
|
process.exit(0);
|
|
4001
4990
|
}
|
|
4002
4991
|
const parts = [];
|
|
4003
|
-
if (addCount > 0) parts.push(
|
|
4004
|
-
if (removeCount > 0) parts.push(
|
|
4005
|
-
if (extraCount > 0) parts.push(
|
|
4992
|
+
if (addCount > 0) parts.push(import_picocolors20.default.green(`${addCount} to add`));
|
|
4993
|
+
if (removeCount > 0) parts.push(import_picocolors20.default.red(`${removeCount} to remove`));
|
|
4994
|
+
if (extraCount > 0) parts.push(import_picocolors20.default.yellow(`${extraCount} extra (informational)`));
|
|
4006
4995
|
p11.log.info(parts.join(" \xB7 "));
|
|
4007
4996
|
if (args["dry-run"]) {
|
|
4008
|
-
p11.outro(
|
|
4997
|
+
p11.outro(import_picocolors20.default.dim("Dry run \u2014 no changes applied."));
|
|
4009
4998
|
process.exit(1);
|
|
4010
4999
|
}
|
|
4011
5000
|
if (addCount === 0 && removeCount === 0) {
|
|
4012
|
-
p11.outro(
|
|
5001
|
+
p11.outro(import_picocolors20.default.dim("No additions needed. Extra servers left untouched."));
|
|
4013
5002
|
process.exit(1);
|
|
4014
5003
|
}
|
|
4015
5004
|
if (!args.yes) {
|
|
@@ -4021,7 +5010,7 @@ var sync_default = (0, import_citty17.defineCommand)({
|
|
|
4021
5010
|
initialValue: true
|
|
4022
5011
|
});
|
|
4023
5012
|
if (p11.isCancel(confirmed) || !confirmed) {
|
|
4024
|
-
p11.outro(
|
|
5013
|
+
p11.outro(import_picocolors20.default.dim("Cancelled \u2014 no changes applied."));
|
|
4025
5014
|
process.exit(0);
|
|
4026
5015
|
}
|
|
4027
5016
|
}
|
|
@@ -4040,7 +5029,7 @@ var sync_default = (0, import_citty17.defineCommand)({
|
|
|
4040
5029
|
}
|
|
4041
5030
|
}
|
|
4042
5031
|
p11.outro(
|
|
4043
|
-
result.failed === 0 ?
|
|
5032
|
+
result.failed === 0 ? import_picocolors20.default.green("Sync complete.") : import_picocolors20.default.yellow("Sync complete with errors.")
|
|
4044
5033
|
);
|
|
4045
5034
|
process.exit(result.failed > 0 ? 1 : 0);
|
|
4046
5035
|
}
|
|
@@ -4056,8 +5045,8 @@ function printDiffTable(actions) {
|
|
|
4056
5045
|
...actions.map((a) => CLIENT_DISPLAY3[a.client]?.length ?? a.client.length)
|
|
4057
5046
|
);
|
|
4058
5047
|
const header = ` ${pad3("SERVER", nameWidth)} ${pad3("CLIENT", clientWidth)} STATUS`;
|
|
4059
|
-
console.log(
|
|
4060
|
-
console.log(
|
|
5048
|
+
console.log(import_picocolors20.default.dim(header));
|
|
5049
|
+
console.log(import_picocolors20.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(clientWidth)} ------`));
|
|
4061
5050
|
for (const action of actions) {
|
|
4062
5051
|
const clientDisplay = CLIENT_DISPLAY3[action.client] ?? action.client;
|
|
4063
5052
|
const [icon, statusText] = formatAction(action.action);
|
|
@@ -4070,13 +5059,13 @@ function printDiffTable(actions) {
|
|
|
4070
5059
|
function formatAction(action) {
|
|
4071
5060
|
switch (action) {
|
|
4072
5061
|
case "add":
|
|
4073
|
-
return [
|
|
5062
|
+
return [import_picocolors20.default.green("+"), import_picocolors20.default.green("missing \u2014 will add")];
|
|
4074
5063
|
case "extra":
|
|
4075
|
-
return [
|
|
5064
|
+
return [import_picocolors20.default.yellow("?"), import_picocolors20.default.yellow("extra (not in lockfile)")];
|
|
4076
5065
|
case "remove":
|
|
4077
|
-
return [
|
|
5066
|
+
return [import_picocolors20.default.red("\u2013"), import_picocolors20.default.red("extra \u2014 will remove")];
|
|
4078
5067
|
case "ok":
|
|
4079
|
-
return [
|
|
5068
|
+
return [import_picocolors20.default.dim("\xB7"), import_picocolors20.default.dim("in sync")];
|
|
4080
5069
|
}
|
|
4081
5070
|
}
|
|
4082
5071
|
function pad3(s, width) {
|
|
@@ -4085,8 +5074,9 @@ function pad3(s, width) {
|
|
|
4085
5074
|
|
|
4086
5075
|
// src/commands/test-command.ts
|
|
4087
5076
|
init_cjs_shims();
|
|
4088
|
-
var
|
|
4089
|
-
var
|
|
5077
|
+
var import_citty22 = require("citty");
|
|
5078
|
+
var import_picocolors21 = __toESM(require("picocolors"), 1);
|
|
5079
|
+
init_lockfile();
|
|
4090
5080
|
|
|
4091
5081
|
// src/core/mcp-tester.ts
|
|
4092
5082
|
init_cjs_shims();
|
|
@@ -4186,7 +5176,7 @@ async function testMcpServer(serverName, command, args, env) {
|
|
|
4186
5176
|
|
|
4187
5177
|
// src/commands/test-command.ts
|
|
4188
5178
|
init_vault_service();
|
|
4189
|
-
var test_command_default = (0,
|
|
5179
|
+
var test_command_default = (0, import_citty22.defineCommand)({
|
|
4190
5180
|
meta: {
|
|
4191
5181
|
name: "test",
|
|
4192
5182
|
description: "Test MCP server connectivity and capabilities"
|
|
@@ -4207,10 +5197,10 @@ var test_command_default = (0, import_citty18.defineCommand)({
|
|
|
4207
5197
|
const lockfile = readLockfile();
|
|
4208
5198
|
const serverNames = args.all ? Object.keys(lockfile.servers) : args.server ? [args.server] : [];
|
|
4209
5199
|
if (serverNames.length === 0) {
|
|
4210
|
-
console.error(
|
|
5200
|
+
console.error(import_picocolors21.default.red(" Error: Specify a server name or use --all."));
|
|
4211
5201
|
process.exit(1);
|
|
4212
5202
|
}
|
|
4213
|
-
console.log(
|
|
5203
|
+
console.log(import_picocolors21.default.bold(`
|
|
4214
5204
|
mcpman test \u2014 ${serverNames.length} server(s)
|
|
4215
5205
|
`));
|
|
4216
5206
|
let passed = 0;
|
|
@@ -4218,7 +5208,7 @@ var test_command_default = (0, import_citty18.defineCommand)({
|
|
|
4218
5208
|
for (const name of serverNames) {
|
|
4219
5209
|
const entry = lockfile.servers[name];
|
|
4220
5210
|
if (!entry) {
|
|
4221
|
-
console.log(` ${
|
|
5211
|
+
console.log(` ${import_picocolors21.default.red("\u2717")} ${import_picocolors21.default.bold(name)} \u2014 not installed`);
|
|
4222
5212
|
failed++;
|
|
4223
5213
|
continue;
|
|
4224
5214
|
}
|
|
@@ -4229,27 +5219,27 @@ var test_command_default = (0, import_citty18.defineCommand)({
|
|
|
4229
5219
|
if (result.passed) {
|
|
4230
5220
|
passed++;
|
|
4231
5221
|
console.log(
|
|
4232
|
-
` ${
|
|
5222
|
+
` ${import_picocolors21.default.green("\u2713")} ${import_picocolors21.default.bold(name)} ${import_picocolors21.default.dim(`(${result.responseTimeMs}ms)`)}`
|
|
4233
5223
|
);
|
|
4234
5224
|
if (result.tools.length > 0) {
|
|
4235
|
-
console.log(
|
|
5225
|
+
console.log(import_picocolors21.default.dim(` Tools: ${result.tools.join(", ")}`));
|
|
4236
5226
|
}
|
|
4237
5227
|
} else {
|
|
4238
5228
|
failed++;
|
|
4239
|
-
console.log(` ${
|
|
5229
|
+
console.log(` ${import_picocolors21.default.red("\u2717")} ${import_picocolors21.default.bold(name)} ${import_picocolors21.default.dim(`(${result.responseTimeMs}ms)`)}`);
|
|
4240
5230
|
if (result.error) {
|
|
4241
|
-
console.log(` ${
|
|
5231
|
+
console.log(` ${import_picocolors21.default.red(result.error)}`);
|
|
4242
5232
|
}
|
|
4243
5233
|
console.log(
|
|
4244
|
-
` ${
|
|
5234
|
+
` ${import_picocolors21.default.dim("initialize:")} ${result.initializeOk ? import_picocolors21.default.green("ok") : import_picocolors21.default.red("fail")} ${import_picocolors21.default.dim("tools/list:")} ${result.toolsListOk ? import_picocolors21.default.green("ok") : import_picocolors21.default.red("fail")}`
|
|
4245
5235
|
);
|
|
4246
5236
|
}
|
|
4247
5237
|
}
|
|
4248
|
-
console.log(
|
|
5238
|
+
console.log(import_picocolors21.default.dim(`
|
|
4249
5239
|
${"\u2500".repeat(40)}`));
|
|
4250
5240
|
const parts = [];
|
|
4251
|
-
if (passed > 0) parts.push(
|
|
4252
|
-
if (failed > 0) parts.push(
|
|
5241
|
+
if (passed > 0) parts.push(import_picocolors21.default.green(`${passed} passed`));
|
|
5242
|
+
if (failed > 0) parts.push(import_picocolors21.default.red(`${failed} failed`));
|
|
4253
5243
|
console.log(` ${parts.join(", ")}
|
|
4254
5244
|
`);
|
|
4255
5245
|
if (failed > 0) process.exit(1);
|
|
@@ -4269,24 +5259,25 @@ async function loadVaultSecrets3(serverName) {
|
|
|
4269
5259
|
// src/commands/update.ts
|
|
4270
5260
|
init_cjs_shims();
|
|
4271
5261
|
var p12 = __toESM(require("@clack/prompts"), 1);
|
|
4272
|
-
var
|
|
4273
|
-
var
|
|
5262
|
+
var import_citty23 = require("citty");
|
|
5263
|
+
var import_picocolors23 = __toESM(require("picocolors"), 1);
|
|
5264
|
+
init_lockfile();
|
|
4274
5265
|
|
|
4275
5266
|
// src/core/update-notifier.ts
|
|
4276
5267
|
init_cjs_shims();
|
|
4277
|
-
var
|
|
4278
|
-
var
|
|
4279
|
-
var
|
|
4280
|
-
var
|
|
4281
|
-
var CACHE_FILE =
|
|
5268
|
+
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
5269
|
+
var import_node_os6 = __toESM(require("os"), 1);
|
|
5270
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
5271
|
+
var import_picocolors22 = __toESM(require("picocolors"), 1);
|
|
5272
|
+
var CACHE_FILE = import_node_path17.default.join(import_node_os6.default.homedir(), ".mcpman", ".update-check");
|
|
4282
5273
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
4283
5274
|
function writeUpdateCache(data) {
|
|
4284
5275
|
try {
|
|
4285
|
-
const dir =
|
|
4286
|
-
if (!
|
|
5276
|
+
const dir = import_node_path17.default.dirname(CACHE_FILE);
|
|
5277
|
+
if (!import_node_fs14.default.existsSync(dir)) import_node_fs14.default.mkdirSync(dir, { recursive: true });
|
|
4287
5278
|
const tmp = `${CACHE_FILE}.tmp`;
|
|
4288
|
-
|
|
4289
|
-
|
|
5279
|
+
import_node_fs14.default.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf-8");
|
|
5280
|
+
import_node_fs14.default.renameSync(tmp, CACHE_FILE);
|
|
4290
5281
|
} catch {
|
|
4291
5282
|
}
|
|
4292
5283
|
}
|
|
@@ -4309,19 +5300,19 @@ function printTable(updates) {
|
|
|
4309
5300
|
"LATEST".padEnd(VER_W),
|
|
4310
5301
|
"STATUS"
|
|
4311
5302
|
].join(" ");
|
|
4312
|
-
console.log(
|
|
5303
|
+
console.log(import_picocolors23.default.bold(`
|
|
4313
5304
|
${header}`));
|
|
4314
|
-
console.log(
|
|
5305
|
+
console.log(import_picocolors23.default.dim(` ${"\u2500".repeat(NAME_W + VER_W * 2 + 20)}`));
|
|
4315
5306
|
for (const u of updates) {
|
|
4316
5307
|
const nameCol = u.server.slice(0, NAME_W).padEnd(NAME_W);
|
|
4317
5308
|
const curCol = u.currentVersion.padEnd(VER_W);
|
|
4318
5309
|
const latCol = u.latestVersion.padEnd(VER_W);
|
|
4319
|
-
const statusCol = u.hasUpdate ?
|
|
5310
|
+
const statusCol = u.hasUpdate ? import_picocolors23.default.yellow(`Update available${u.updateType ? ` [${u.updateType}]` : ""}`) : import_picocolors23.default.green("Up to date");
|
|
4320
5311
|
console.log(` ${nameCol} ${curCol} ${latCol} ${statusCol}`);
|
|
4321
5312
|
}
|
|
4322
5313
|
console.log();
|
|
4323
5314
|
}
|
|
4324
|
-
var update_default = (0,
|
|
5315
|
+
var update_default = (0, import_citty23.defineCommand)({
|
|
4325
5316
|
meta: {
|
|
4326
5317
|
name: "update",
|
|
4327
5318
|
description: "Check for and apply updates to installed MCP servers"
|
|
@@ -4382,12 +5373,12 @@ var update_default = (0, import_citty19.defineCommand)({
|
|
|
4382
5373
|
printTable(updates);
|
|
4383
5374
|
const outdated = updates.filter((u) => u.hasUpdate);
|
|
4384
5375
|
if (outdated.length === 0) {
|
|
4385
|
-
console.log(
|
|
5376
|
+
console.log(import_picocolors23.default.green(" All servers are up to date."));
|
|
4386
5377
|
return;
|
|
4387
5378
|
}
|
|
4388
5379
|
if (args.check) {
|
|
4389
5380
|
console.log(
|
|
4390
|
-
|
|
5381
|
+
import_picocolors23.default.yellow(` ${outdated.length} update(s) available. Run mcpman update to apply.`)
|
|
4391
5382
|
);
|
|
4392
5383
|
return;
|
|
4393
5384
|
}
|
|
@@ -4408,10 +5399,10 @@ var update_default = (0, import_citty19.defineCommand)({
|
|
|
4408
5399
|
s.start(`Updating ${update.server}...`);
|
|
4409
5400
|
const result = await applyServerUpdate(update.server, servers[update.server], clients);
|
|
4410
5401
|
if (result.success) {
|
|
4411
|
-
s.stop(`${
|
|
5402
|
+
s.stop(`${import_picocolors23.default.green("\u2713")} ${update.server}: ${result.fromVersion} \u2192 ${result.toVersion}`);
|
|
4412
5403
|
successCount++;
|
|
4413
5404
|
} else {
|
|
4414
|
-
s.stop(`${
|
|
5405
|
+
s.stop(`${import_picocolors23.default.red("\u2717")} ${update.server}: ${result.error}`);
|
|
4415
5406
|
}
|
|
4416
5407
|
}
|
|
4417
5408
|
const freshLockfile = readLockfile(resolveLockfilePath());
|
|
@@ -4424,9 +5415,9 @@ var update_default = (0, import_citty19.defineCommand)({
|
|
|
4424
5415
|
// src/commands/upgrade.ts
|
|
4425
5416
|
init_cjs_shims();
|
|
4426
5417
|
var import_node_child_process7 = require("child_process");
|
|
4427
|
-
var
|
|
4428
|
-
var
|
|
4429
|
-
var upgrade_default = (0,
|
|
5418
|
+
var import_citty24 = require("citty");
|
|
5419
|
+
var import_picocolors24 = __toESM(require("picocolors"), 1);
|
|
5420
|
+
var upgrade_default = (0, import_citty24.defineCommand)({
|
|
4430
5421
|
meta: {
|
|
4431
5422
|
name: "upgrade",
|
|
4432
5423
|
description: "Upgrade mcpman to the latest version"
|
|
@@ -4439,41 +5430,453 @@ var upgrade_default = (0, import_citty20.defineCommand)({
|
|
|
4439
5430
|
}
|
|
4440
5431
|
},
|
|
4441
5432
|
async run({ args }) {
|
|
4442
|
-
console.log(
|
|
5433
|
+
console.log(import_picocolors24.default.dim(` Current version: ${APP_VERSION}`));
|
|
4443
5434
|
let latest;
|
|
4444
5435
|
try {
|
|
4445
5436
|
latest = (0, import_node_child_process7.execSync)("npm view mcpman version", { encoding: "utf-8", timeout: 15e3 }).trim();
|
|
4446
5437
|
} catch {
|
|
4447
|
-
console.error(
|
|
5438
|
+
console.error(import_picocolors24.default.red(" Error: Could not check latest version from npm."));
|
|
4448
5439
|
process.exit(1);
|
|
4449
5440
|
}
|
|
4450
5441
|
if (latest === APP_VERSION) {
|
|
4451
|
-
console.log(
|
|
5442
|
+
console.log(import_picocolors24.default.green(" \u2713 Already on the latest version."));
|
|
4452
5443
|
return;
|
|
4453
5444
|
}
|
|
4454
|
-
console.log(
|
|
5445
|
+
console.log(import_picocolors24.default.yellow(` Update available: ${APP_VERSION} \u2192 ${latest}`));
|
|
4455
5446
|
if (args.check) {
|
|
4456
|
-
console.log(
|
|
5447
|
+
console.log(import_picocolors24.default.dim(" Run mcpman upgrade to install."));
|
|
4457
5448
|
return;
|
|
4458
5449
|
}
|
|
4459
|
-
console.log(
|
|
5450
|
+
console.log(import_picocolors24.default.dim(" Installing..."));
|
|
4460
5451
|
try {
|
|
4461
5452
|
(0, import_node_child_process7.execSync)(`npm install -g mcpman@${latest}`, { stdio: "inherit", timeout: 6e4 });
|
|
4462
|
-
console.log(
|
|
5453
|
+
console.log(import_picocolors24.default.green(`
|
|
4463
5454
|
\u2713 Upgraded to mcpman@${latest}`));
|
|
4464
5455
|
} catch {
|
|
4465
|
-
console.error(
|
|
5456
|
+
console.error(import_picocolors24.default.red(" Error: Upgrade failed. Try manually: npm install -g mcpman@latest"));
|
|
4466
5457
|
process.exit(1);
|
|
4467
5458
|
}
|
|
4468
5459
|
}
|
|
4469
5460
|
});
|
|
4470
5461
|
|
|
5462
|
+
// src/commands/watch.ts
|
|
5463
|
+
init_cjs_shims();
|
|
5464
|
+
var import_citty25 = require("citty");
|
|
5465
|
+
var import_picocolors25 = __toESM(require("picocolors"), 1);
|
|
5466
|
+
|
|
5467
|
+
// src/core/file-watcher-service.ts
|
|
5468
|
+
init_cjs_shims();
|
|
5469
|
+
var import_node_child_process8 = require("child_process");
|
|
5470
|
+
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
5471
|
+
var IGNORE_PATTERNS = [
|
|
5472
|
+
"node_modules",
|
|
5473
|
+
".git",
|
|
5474
|
+
"dist",
|
|
5475
|
+
"build",
|
|
5476
|
+
"__pycache__",
|
|
5477
|
+
".pyc",
|
|
5478
|
+
".egg-info",
|
|
5479
|
+
".tox"
|
|
5480
|
+
];
|
|
5481
|
+
function shouldIgnore(filename) {
|
|
5482
|
+
return IGNORE_PATTERNS.some((p13) => filename.includes(p13));
|
|
5483
|
+
}
|
|
5484
|
+
function hasWatchedExtension(filename, extensions) {
|
|
5485
|
+
return extensions.some((ext) => filename.endsWith(`.${ext}`));
|
|
5486
|
+
}
|
|
5487
|
+
function timestamp() {
|
|
5488
|
+
return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
|
|
5489
|
+
}
|
|
5490
|
+
var ServerWatcher = class {
|
|
5491
|
+
child = null;
|
|
5492
|
+
watcher = null;
|
|
5493
|
+
restartCount = 0;
|
|
5494
|
+
debounceTimer = null;
|
|
5495
|
+
options = null;
|
|
5496
|
+
stopping = false;
|
|
5497
|
+
/** Start watching and spawn the initial server process */
|
|
5498
|
+
start(options) {
|
|
5499
|
+
this.options = options;
|
|
5500
|
+
this.stopping = false;
|
|
5501
|
+
console.log(`
|
|
5502
|
+
Watching ${options.serverName} (${options.watchDir})...`);
|
|
5503
|
+
console.log(` Extensions: ${options.extensions.join(", ")}`);
|
|
5504
|
+
console.log(` Debounce: ${options.debounceMs}ms
|
|
5505
|
+
`);
|
|
5506
|
+
this.spawnChild();
|
|
5507
|
+
try {
|
|
5508
|
+
this.watcher = import_node_fs15.default.watch(options.watchDir, { recursive: true }, (_event, filename) => {
|
|
5509
|
+
if (!filename) return;
|
|
5510
|
+
this.onFileChange(filename);
|
|
5511
|
+
});
|
|
5512
|
+
} catch (err) {
|
|
5513
|
+
console.error(
|
|
5514
|
+
` Warning: Could not watch directory: ${err instanceof Error ? err.message : String(err)}`
|
|
5515
|
+
);
|
|
5516
|
+
}
|
|
5517
|
+
}
|
|
5518
|
+
/** Gracefully stop watcher and child process */
|
|
5519
|
+
stop() {
|
|
5520
|
+
this.stopping = true;
|
|
5521
|
+
if (this.debounceTimer) {
|
|
5522
|
+
clearTimeout(this.debounceTimer);
|
|
5523
|
+
this.debounceTimer = null;
|
|
5524
|
+
}
|
|
5525
|
+
if (this.watcher) {
|
|
5526
|
+
this.watcher.close();
|
|
5527
|
+
this.watcher = null;
|
|
5528
|
+
}
|
|
5529
|
+
if (this.child && !this.child.killed) {
|
|
5530
|
+
this.child.kill("SIGTERM");
|
|
5531
|
+
}
|
|
5532
|
+
console.log(`
|
|
5533
|
+
Stopped. (${this.restartCount} restart${this.restartCount !== 1 ? "s" : ""})`);
|
|
5534
|
+
}
|
|
5535
|
+
/** Spawn the server child process, piping its stdio to parent */
|
|
5536
|
+
spawnChild() {
|
|
5537
|
+
if (!this.options) return;
|
|
5538
|
+
const { command, args, env, serverName, clearOnRestart } = this.options;
|
|
5539
|
+
if (clearOnRestart && this.restartCount > 0) {
|
|
5540
|
+
process.stdout.write("\x1Bc");
|
|
5541
|
+
}
|
|
5542
|
+
console.log(` [${timestamp()}] Starting ${serverName}...`);
|
|
5543
|
+
this.child = (0, import_node_child_process8.spawn)(command, args, { env, stdio: ["pipe", "pipe", "pipe"] });
|
|
5544
|
+
this.child.stdout?.on("data", (data) => {
|
|
5545
|
+
process.stdout.write(` [stdout] ${data.toString().trimEnd()}
|
|
5546
|
+
`);
|
|
5547
|
+
});
|
|
5548
|
+
this.child.stderr?.on("data", (data) => {
|
|
5549
|
+
process.stderr.write(` [stderr] ${data.toString().trimEnd()}
|
|
5550
|
+
`);
|
|
5551
|
+
});
|
|
5552
|
+
this.child.on("error", (err) => {
|
|
5553
|
+
console.error(` [${timestamp()}] Error: ${err.message}`);
|
|
5554
|
+
});
|
|
5555
|
+
this.child.on("close", (code) => {
|
|
5556
|
+
if (!this.stopping) {
|
|
5557
|
+
console.log(` [${timestamp()}] Process exited (code ${code ?? "?"})`);
|
|
5558
|
+
}
|
|
5559
|
+
});
|
|
5560
|
+
}
|
|
5561
|
+
/** Kill child process: SIGTERM first, then SIGKILL after 2s */
|
|
5562
|
+
async killChild() {
|
|
5563
|
+
if (!this.child || this.child.killed) return;
|
|
5564
|
+
const childRef = this.child;
|
|
5565
|
+
return new Promise((resolve) => {
|
|
5566
|
+
const child = childRef;
|
|
5567
|
+
const killTimer = setTimeout(() => {
|
|
5568
|
+
if (!child.killed) {
|
|
5569
|
+
child.kill("SIGKILL");
|
|
5570
|
+
}
|
|
5571
|
+
resolve();
|
|
5572
|
+
}, 2e3);
|
|
5573
|
+
child.on("close", () => {
|
|
5574
|
+
clearTimeout(killTimer);
|
|
5575
|
+
resolve();
|
|
5576
|
+
});
|
|
5577
|
+
child.kill("SIGTERM");
|
|
5578
|
+
});
|
|
5579
|
+
}
|
|
5580
|
+
/** Debounced file change handler */
|
|
5581
|
+
onFileChange(filename) {
|
|
5582
|
+
if (!this.options) return;
|
|
5583
|
+
if (shouldIgnore(filename)) return;
|
|
5584
|
+
if (!hasWatchedExtension(filename, this.options.extensions)) return;
|
|
5585
|
+
if (this.debounceTimer) {
|
|
5586
|
+
clearTimeout(this.debounceTimer);
|
|
5587
|
+
}
|
|
5588
|
+
this.debounceTimer = setTimeout(async () => {
|
|
5589
|
+
this.debounceTimer = null;
|
|
5590
|
+
this.restartCount++;
|
|
5591
|
+
console.log(` [${timestamp()}] File changed: ${filename}`);
|
|
5592
|
+
console.log(
|
|
5593
|
+
` [${timestamp()}] Restarting ${this.options?.serverName}... (restart #${this.restartCount})`
|
|
5594
|
+
);
|
|
5595
|
+
await this.killChild();
|
|
5596
|
+
this.spawnChild();
|
|
5597
|
+
}, this.options.debounceMs);
|
|
5598
|
+
}
|
|
5599
|
+
getRestartCount() {
|
|
5600
|
+
return this.restartCount;
|
|
5601
|
+
}
|
|
5602
|
+
};
|
|
5603
|
+
|
|
5604
|
+
// src/commands/watch.ts
|
|
5605
|
+
init_lockfile();
|
|
5606
|
+
init_vault_service();
|
|
5607
|
+
var DEFAULT_EXTENSIONS = ["ts", "js", "json", "py", "mjs", "cjs"];
|
|
5608
|
+
var DEFAULT_DEBOUNCE_MS = 300;
|
|
5609
|
+
var watch_default = (0, import_citty25.defineCommand)({
|
|
5610
|
+
meta: {
|
|
5611
|
+
name: "watch",
|
|
5612
|
+
description: "Watch a local MCP server for file changes and auto-restart"
|
|
5613
|
+
},
|
|
5614
|
+
args: {
|
|
5615
|
+
server: {
|
|
5616
|
+
type: "positional",
|
|
5617
|
+
description: "Server name (must be in lockfile)",
|
|
5618
|
+
required: true
|
|
5619
|
+
},
|
|
5620
|
+
dir: {
|
|
5621
|
+
type: "string",
|
|
5622
|
+
description: "Directory to watch (default: resolved path from lockfile)"
|
|
5623
|
+
},
|
|
5624
|
+
ext: {
|
|
5625
|
+
type: "string",
|
|
5626
|
+
description: `File extensions to watch, comma-separated (default: ${DEFAULT_EXTENSIONS.join(",")})`
|
|
5627
|
+
},
|
|
5628
|
+
delay: {
|
|
5629
|
+
type: "string",
|
|
5630
|
+
description: `Debounce delay in ms (default: ${DEFAULT_DEBOUNCE_MS})`
|
|
5631
|
+
},
|
|
5632
|
+
clear: {
|
|
5633
|
+
type: "boolean",
|
|
5634
|
+
description: "Clear terminal on each restart",
|
|
5635
|
+
default: false
|
|
5636
|
+
},
|
|
5637
|
+
env: {
|
|
5638
|
+
type: "string",
|
|
5639
|
+
description: "Override env var KEY=VAL (repeatable)",
|
|
5640
|
+
alias: "e"
|
|
5641
|
+
}
|
|
5642
|
+
},
|
|
5643
|
+
async run({ args }) {
|
|
5644
|
+
const serverName = args.server;
|
|
5645
|
+
const lockfile = readLockfile();
|
|
5646
|
+
const entry = lockfile.servers[serverName];
|
|
5647
|
+
if (!entry) {
|
|
5648
|
+
console.error(import_picocolors25.default.red(` Error: Server '${serverName}' not found in lockfile.`));
|
|
5649
|
+
console.error(import_picocolors25.default.dim(` Run ${import_picocolors25.default.cyan("mcpman link .")} to register a local server.`));
|
|
5650
|
+
process.exit(1);
|
|
5651
|
+
}
|
|
5652
|
+
let watchDir = args.dir;
|
|
5653
|
+
if (!watchDir) {
|
|
5654
|
+
if (entry.source === "local" && entry.resolved) {
|
|
5655
|
+
watchDir = entry.resolved;
|
|
5656
|
+
} else {
|
|
5657
|
+
console.error(import_picocolors25.default.red(` Error: Cannot determine watch directory for '${serverName}'.`));
|
|
5658
|
+
console.error(import_picocolors25.default.dim(" Use --dir to specify the directory to watch."));
|
|
5659
|
+
process.exit(1);
|
|
5660
|
+
}
|
|
5661
|
+
}
|
|
5662
|
+
const extensions = args.ext ? args.ext.split(",").map((e) => e.trim().replace(/^\./, "")) : DEFAULT_EXTENSIONS;
|
|
5663
|
+
const debounceMs = args.delay ? Number.parseInt(args.delay, 10) || DEFAULT_DEBOUNCE_MS : DEFAULT_DEBOUNCE_MS;
|
|
5664
|
+
const lockfileEnv = parseEnvFlags(entry.envVars);
|
|
5665
|
+
const vaultEnv = await loadVaultSecrets4(serverName);
|
|
5666
|
+
const cliEnv = parseEnvFlags(args.env);
|
|
5667
|
+
const finalEnv = {
|
|
5668
|
+
...process.env,
|
|
5669
|
+
...lockfileEnv,
|
|
5670
|
+
...vaultEnv,
|
|
5671
|
+
...cliEnv
|
|
5672
|
+
};
|
|
5673
|
+
const watcher = new ServerWatcher();
|
|
5674
|
+
const handleStop = () => {
|
|
5675
|
+
watcher.stop();
|
|
5676
|
+
process.exit(0);
|
|
5677
|
+
};
|
|
5678
|
+
process.on("SIGINT", handleStop);
|
|
5679
|
+
process.on("SIGTERM", handleStop);
|
|
5680
|
+
watcher.start({
|
|
5681
|
+
command: entry.command,
|
|
5682
|
+
args: entry.args,
|
|
5683
|
+
env: finalEnv,
|
|
5684
|
+
watchDir,
|
|
5685
|
+
extensions,
|
|
5686
|
+
debounceMs,
|
|
5687
|
+
clearOnRestart: args.clear,
|
|
5688
|
+
serverName
|
|
5689
|
+
});
|
|
5690
|
+
}
|
|
5691
|
+
});
|
|
5692
|
+
async function loadVaultSecrets4(serverName) {
|
|
5693
|
+
try {
|
|
5694
|
+
const entries = listSecrets(serverName);
|
|
5695
|
+
if (entries.length === 0 || entries[0].keys.length === 0) return {};
|
|
5696
|
+
const password2 = await getMasterPassword();
|
|
5697
|
+
return getSecretsForServer(serverName, password2);
|
|
5698
|
+
} catch {
|
|
5699
|
+
return {};
|
|
5700
|
+
}
|
|
5701
|
+
}
|
|
5702
|
+
|
|
5703
|
+
// src/commands/why.ts
|
|
5704
|
+
init_cjs_shims();
|
|
5705
|
+
var import_citty26 = require("citty");
|
|
5706
|
+
var import_picocolors26 = __toESM(require("picocolors"), 1);
|
|
5707
|
+
|
|
5708
|
+
// src/core/why-service.ts
|
|
5709
|
+
init_cjs_shims();
|
|
5710
|
+
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
5711
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
5712
|
+
init_paths();
|
|
5713
|
+
init_lockfile();
|
|
5714
|
+
var ALL_CLIENT_TYPES = ["claude-desktop", "cursor", "vscode", "windsurf"];
|
|
5715
|
+
async function getServerProvenance(serverName, lockfilePath, profilesDir) {
|
|
5716
|
+
const lockfile = readLockfile(lockfilePath);
|
|
5717
|
+
const entry = lockfile.servers[serverName];
|
|
5718
|
+
if (!entry) {
|
|
5719
|
+
const orphanedClients = await findOrphanedClients(serverName);
|
|
5720
|
+
const anyRegistered = orphanedClients.some((c) => c.registered);
|
|
5721
|
+
if (!anyRegistered) return null;
|
|
5722
|
+
return {
|
|
5723
|
+
name: serverName,
|
|
5724
|
+
version: "unknown",
|
|
5725
|
+
source: "unknown",
|
|
5726
|
+
resolved: "",
|
|
5727
|
+
integrity: "",
|
|
5728
|
+
installedAt: "",
|
|
5729
|
+
clients: orphanedClients,
|
|
5730
|
+
profiles: [],
|
|
5731
|
+
envVars: [],
|
|
5732
|
+
orphaned: true
|
|
5733
|
+
};
|
|
5734
|
+
}
|
|
5735
|
+
const clientStatuses = await buildClientStatuses(serverName, entry.clients);
|
|
5736
|
+
const profiles = scanProfiles(serverName, profilesDir ?? getProfilesDir());
|
|
5737
|
+
return {
|
|
5738
|
+
name: serverName,
|
|
5739
|
+
version: entry.version,
|
|
5740
|
+
source: entry.source,
|
|
5741
|
+
resolved: entry.resolved,
|
|
5742
|
+
integrity: entry.integrity,
|
|
5743
|
+
installedAt: entry.installedAt,
|
|
5744
|
+
clients: clientStatuses,
|
|
5745
|
+
profiles,
|
|
5746
|
+
envVars: entry.envVars ?? [],
|
|
5747
|
+
orphaned: false
|
|
5748
|
+
};
|
|
5749
|
+
}
|
|
5750
|
+
async function buildClientStatuses(serverName, lockfileClients) {
|
|
5751
|
+
return ALL_CLIENT_TYPES.map((type) => ({
|
|
5752
|
+
type,
|
|
5753
|
+
registered: lockfileClients.includes(type)
|
|
5754
|
+
}));
|
|
5755
|
+
}
|
|
5756
|
+
async function findOrphanedClients(serverName) {
|
|
5757
|
+
const { getInstalledClients: getInstalledClients2 } = await Promise.resolve().then(() => (init_client_detector(), client_detector_exports));
|
|
5758
|
+
const handlers = await getInstalledClients2();
|
|
5759
|
+
const results = [];
|
|
5760
|
+
for (const handler of handlers) {
|
|
5761
|
+
try {
|
|
5762
|
+
const config = await handler.readConfig();
|
|
5763
|
+
const registered = serverName in (config.servers ?? {});
|
|
5764
|
+
results.push({ type: handler.type, registered });
|
|
5765
|
+
} catch {
|
|
5766
|
+
results.push({ type: handler.type, registered: false });
|
|
5767
|
+
}
|
|
5768
|
+
}
|
|
5769
|
+
return results;
|
|
5770
|
+
}
|
|
5771
|
+
function scanProfiles(serverName, profilesDir) {
|
|
5772
|
+
const found = [];
|
|
5773
|
+
if (!import_node_fs16.default.existsSync(profilesDir)) return found;
|
|
5774
|
+
let files;
|
|
5775
|
+
try {
|
|
5776
|
+
files = import_node_fs16.default.readdirSync(profilesDir).filter((f) => f.endsWith(".json"));
|
|
5777
|
+
} catch {
|
|
5778
|
+
return found;
|
|
5779
|
+
}
|
|
5780
|
+
for (const file of files) {
|
|
5781
|
+
try {
|
|
5782
|
+
const raw = import_node_fs16.default.readFileSync(import_node_path18.default.join(profilesDir, file), "utf-8");
|
|
5783
|
+
const profile = JSON.parse(raw);
|
|
5784
|
+
if (serverName in (profile.servers ?? {})) {
|
|
5785
|
+
found.push(profile.name ?? file.replace(".json", ""));
|
|
5786
|
+
}
|
|
5787
|
+
} catch {
|
|
5788
|
+
}
|
|
5789
|
+
}
|
|
5790
|
+
return found.sort();
|
|
5791
|
+
}
|
|
5792
|
+
function formatWhyOutput(result) {
|
|
5793
|
+
const lines = [];
|
|
5794
|
+
lines.push(` Server: ${result.name}`);
|
|
5795
|
+
lines.push(` Version: ${result.version}`);
|
|
5796
|
+
lines.push(` Source: ${result.source}`);
|
|
5797
|
+
if (result.resolved) lines.push(` Resolved: ${result.resolved}`);
|
|
5798
|
+
if (result.integrity && result.integrity !== "local") {
|
|
5799
|
+
lines.push(` Integrity: ${result.integrity}`);
|
|
5800
|
+
}
|
|
5801
|
+
if (result.installedAt) lines.push(` Installed: ${result.installedAt}`);
|
|
5802
|
+
lines.push("");
|
|
5803
|
+
lines.push(" Clients:");
|
|
5804
|
+
for (const c of result.clients) {
|
|
5805
|
+
const status = c.registered ? "registered" : "not registered";
|
|
5806
|
+
lines.push(` ${c.type.padEnd(20)} ${status}`);
|
|
5807
|
+
}
|
|
5808
|
+
if (result.profiles.length > 0) {
|
|
5809
|
+
lines.push("");
|
|
5810
|
+
lines.push(" Profiles:");
|
|
5811
|
+
for (const p13 of result.profiles) {
|
|
5812
|
+
lines.push(` ${p13}`);
|
|
5813
|
+
}
|
|
5814
|
+
}
|
|
5815
|
+
if (result.envVars.length > 0) {
|
|
5816
|
+
lines.push("");
|
|
5817
|
+
lines.push(" Env Vars:");
|
|
5818
|
+
for (const v of result.envVars) {
|
|
5819
|
+
lines.push(` ${v}`);
|
|
5820
|
+
}
|
|
5821
|
+
}
|
|
5822
|
+
return lines.join("\n");
|
|
5823
|
+
}
|
|
5824
|
+
|
|
5825
|
+
// src/commands/why.ts
|
|
5826
|
+
var why_default = (0, import_citty26.defineCommand)({
|
|
5827
|
+
meta: {
|
|
5828
|
+
name: "why",
|
|
5829
|
+
description: "Show why a server is installed (provenance, clients, profiles)"
|
|
5830
|
+
},
|
|
5831
|
+
args: {
|
|
5832
|
+
server: {
|
|
5833
|
+
type: "positional",
|
|
5834
|
+
description: "Server name to inspect",
|
|
5835
|
+
required: true
|
|
5836
|
+
},
|
|
5837
|
+
json: {
|
|
5838
|
+
type: "boolean",
|
|
5839
|
+
description: "Output as JSON for scripting",
|
|
5840
|
+
default: false
|
|
5841
|
+
}
|
|
5842
|
+
},
|
|
5843
|
+
async run({ args }) {
|
|
5844
|
+
const serverName = args.server;
|
|
5845
|
+
const asJson = args.json;
|
|
5846
|
+
const result = await getServerProvenance(serverName);
|
|
5847
|
+
if (!result) {
|
|
5848
|
+
console.error(import_picocolors26.default.red(` Server '${serverName}' not found in lockfile or any client config.`));
|
|
5849
|
+
console.error(import_picocolors26.default.dim(` Run ${import_picocolors26.default.cyan("mcpman list")} to see installed servers.`));
|
|
5850
|
+
process.exit(1);
|
|
5851
|
+
}
|
|
5852
|
+
if (result.orphaned) {
|
|
5853
|
+
console.log(import_picocolors26.default.yellow(`
|
|
5854
|
+
Server '${serverName}' is orphaned:`));
|
|
5855
|
+
console.log(import_picocolors26.default.dim(" Found in client config(s) but not in lockfile."));
|
|
5856
|
+
console.log(import_picocolors26.default.dim(` Run ${import_picocolors26.default.cyan("mcpman sync --remove")} to clean up.
|
|
5857
|
+
`));
|
|
5858
|
+
const registeredClients = result.clients.filter((c) => c.registered).map((c) => c.type);
|
|
5859
|
+
if (registeredClients.length > 0) {
|
|
5860
|
+
console.log(` Registered in: ${registeredClients.join(", ")}`);
|
|
5861
|
+
}
|
|
5862
|
+
return;
|
|
5863
|
+
}
|
|
5864
|
+
if (asJson) {
|
|
5865
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5866
|
+
return;
|
|
5867
|
+
}
|
|
5868
|
+
console.log();
|
|
5869
|
+
console.log(formatWhyOutput(result));
|
|
5870
|
+
console.log();
|
|
5871
|
+
}
|
|
5872
|
+
});
|
|
5873
|
+
|
|
4471
5874
|
// src/index.ts
|
|
4472
5875
|
process.on("SIGINT", () => {
|
|
4473
5876
|
console.log("\nAborted.");
|
|
4474
5877
|
process.exit(130);
|
|
4475
5878
|
});
|
|
4476
|
-
var main = (0,
|
|
5879
|
+
var main = (0, import_citty27.defineCommand)({
|
|
4477
5880
|
meta: {
|
|
4478
5881
|
name: APP_NAME,
|
|
4479
5882
|
version: APP_VERSION,
|
|
@@ -4499,7 +5902,13 @@ var main = (0, import_citty21.defineCommand)({
|
|
|
4499
5902
|
profiles: profiles_default,
|
|
4500
5903
|
plugin: plugin_default,
|
|
4501
5904
|
export: export_command_default,
|
|
4502
|
-
import: import_command_default
|
|
5905
|
+
import: import_command_default,
|
|
5906
|
+
create: create_default,
|
|
5907
|
+
link: link_default,
|
|
5908
|
+
watch: watch_default,
|
|
5909
|
+
registry: registry_default,
|
|
5910
|
+
completions: completions_default,
|
|
5911
|
+
why: why_default
|
|
4503
5912
|
}
|
|
4504
5913
|
});
|
|
4505
|
-
(0,
|
|
5914
|
+
(0, import_citty27.runMain)(main);
|