@wuyax/mcps 0.1.0-beta.2 → 0.1.0-beta.3
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 +235 -19
- package/dist/{chunk-7V5XL4RI.js → chunk-BUKA3NPJ.js} +981 -280
- package/dist/cli.cjs +975 -352
- package/dist/cli.js +6 -7
- package/dist/index.cjs +1007 -308
- package/dist/index.d.cts +186 -23
- package/dist/index.d.ts +186 -23
- package/dist/index.js +34 -3
- package/package.json +3 -1
|
@@ -965,6 +965,74 @@ var agentConfigStore = new AgentConfigStore();
|
|
|
965
965
|
// src/utils/to-error-message.ts
|
|
966
966
|
var toErrorMessage = (error, fallback = "Unknown error") => error instanceof Error ? error.message : fallback;
|
|
967
967
|
|
|
968
|
+
// src/resolve-config-clusters.ts
|
|
969
|
+
var getCandidateAgentsForScope = (options = {}) => {
|
|
970
|
+
return options.global ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
971
|
+
};
|
|
972
|
+
var getCoHostedAgents = (agentType, options = {}) => {
|
|
973
|
+
const currentAgent = getMcpAgentConfig(agentType);
|
|
974
|
+
const currentTarget = resolveMcpConfigTarget(currentAgent, options);
|
|
975
|
+
const candidates = getCandidateAgentsForScope(options);
|
|
976
|
+
const coHosted = [];
|
|
977
|
+
for (const candidateType of candidates) {
|
|
978
|
+
if (candidateType === agentType) continue;
|
|
979
|
+
const candidateConfig = getMcpAgentConfig(candidateType);
|
|
980
|
+
const candidateTarget = resolveMcpConfigTarget(candidateConfig, options);
|
|
981
|
+
if (candidateTarget.configPath === currentTarget.configPath && candidateTarget.configKey === currentTarget.configKey) {
|
|
982
|
+
coHosted.push(candidateType);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
return coHosted;
|
|
986
|
+
};
|
|
987
|
+
var resolveConfigClusters = (agentTypes, options = {}) => {
|
|
988
|
+
const clustersByPath = /* @__PURE__ */ new Map();
|
|
989
|
+
for (const agentType of agentTypes) {
|
|
990
|
+
const agentConfig = getMcpAgentConfig(agentType);
|
|
991
|
+
const target = resolveMcpConfigTarget(agentConfig, options);
|
|
992
|
+
let keyMap = clustersByPath.get(target.configPath);
|
|
993
|
+
if (!keyMap) {
|
|
994
|
+
keyMap = /* @__PURE__ */ new Map();
|
|
995
|
+
clustersByPath.set(target.configPath, keyMap);
|
|
996
|
+
}
|
|
997
|
+
let cluster = keyMap.get(target.configKey);
|
|
998
|
+
if (!cluster) {
|
|
999
|
+
const allCoHosted = getCoHostedAgents(agentType, options);
|
|
1000
|
+
cluster = {
|
|
1001
|
+
configPath: target.configPath,
|
|
1002
|
+
configKey: target.configKey,
|
|
1003
|
+
targetAgents: [],
|
|
1004
|
+
coHostedAgents: allCoHosted
|
|
1005
|
+
};
|
|
1006
|
+
keyMap.set(target.configKey, cluster);
|
|
1007
|
+
}
|
|
1008
|
+
if (!cluster.targetAgents.includes(agentType)) {
|
|
1009
|
+
cluster.targetAgents.push(agentType);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
const clusters = [];
|
|
1013
|
+
for (const keyMap of clustersByPath.values()) {
|
|
1014
|
+
for (const cluster of keyMap.values()) {
|
|
1015
|
+
cluster.coHostedAgents = cluster.coHostedAgents.filter(
|
|
1016
|
+
(co) => !cluster.targetAgents.includes(co)
|
|
1017
|
+
);
|
|
1018
|
+
clusters.push(cluster);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
return clusters;
|
|
1022
|
+
};
|
|
1023
|
+
var sortAgentsWithClusters = (agentTypes, options = {}) => {
|
|
1024
|
+
const clusters = resolveConfigClusters(agentTypes, options);
|
|
1025
|
+
const sorted = [];
|
|
1026
|
+
for (const cluster of clusters) {
|
|
1027
|
+
for (const agent of cluster.targetAgents) {
|
|
1028
|
+
if (!sorted.includes(agent)) {
|
|
1029
|
+
sorted.push(agent);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
return sorted;
|
|
1034
|
+
};
|
|
1035
|
+
|
|
968
1036
|
// src/transforms/index.ts
|
|
969
1037
|
var DIALECT_PRESETS = {
|
|
970
1038
|
vscode: {
|
|
@@ -1180,12 +1248,18 @@ var installMcpServerForAgent = (serverName, serverConfig, agentType, options = {
|
|
|
1180
1248
|
const agent = getMcpAgentConfig(agentType);
|
|
1181
1249
|
const isGlobal = options.global ?? false;
|
|
1182
1250
|
const { target } = agentConfigStore.resolveTarget(agent, options);
|
|
1251
|
+
const coHosted = getCoHostedAgents(agentType, options);
|
|
1183
1252
|
try {
|
|
1184
1253
|
const transformed = transformServerConfigForAgent(agent, serverName, serverConfig, {
|
|
1185
1254
|
global: isGlobal
|
|
1186
1255
|
});
|
|
1187
1256
|
agentConfigStore.writeServer(agent, serverName, transformed, options);
|
|
1188
|
-
return {
|
|
1257
|
+
return {
|
|
1258
|
+
agent: agentType,
|
|
1259
|
+
success: true,
|
|
1260
|
+
path: target.configPath,
|
|
1261
|
+
coConfiguredAgents: coHosted.length > 0 ? coHosted : void 0
|
|
1262
|
+
};
|
|
1189
1263
|
} catch (error) {
|
|
1190
1264
|
return {
|
|
1191
1265
|
agent: agentType,
|
|
@@ -1195,9 +1269,62 @@ var installMcpServerForAgent = (serverName, serverConfig, agentType, options = {
|
|
|
1195
1269
|
};
|
|
1196
1270
|
}
|
|
1197
1271
|
};
|
|
1198
|
-
var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options = {}) =>
|
|
1199
|
-
|
|
1200
|
-
);
|
|
1272
|
+
var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options = {}) => {
|
|
1273
|
+
const clusters = resolveConfigClusters(agentTypes, options);
|
|
1274
|
+
const resultsByAgent = /* @__PURE__ */ new Map();
|
|
1275
|
+
const isGlobal = options.global ?? false;
|
|
1276
|
+
for (const cluster of clusters) {
|
|
1277
|
+
const primaryAgentType = cluster.targetAgents[0];
|
|
1278
|
+
const primaryAgent = getMcpAgentConfig(primaryAgentType);
|
|
1279
|
+
try {
|
|
1280
|
+
const transformed = transformServerConfigForAgent(primaryAgent, serverName, serverConfig, {
|
|
1281
|
+
global: isGlobal
|
|
1282
|
+
});
|
|
1283
|
+
agentConfigStore.writeServer(primaryAgent, serverName, transformed, options);
|
|
1284
|
+
for (const agentType of cluster.targetAgents) {
|
|
1285
|
+
resultsByAgent.set(agentType, {
|
|
1286
|
+
agent: agentType,
|
|
1287
|
+
success: true,
|
|
1288
|
+
path: cluster.configPath,
|
|
1289
|
+
coConfiguredAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
|
|
1290
|
+
});
|
|
1291
|
+
}
|
|
1292
|
+
} catch (error) {
|
|
1293
|
+
const errorMsg = toErrorMessage(error);
|
|
1294
|
+
for (const agentType of cluster.targetAgents) {
|
|
1295
|
+
resultsByAgent.set(agentType, {
|
|
1296
|
+
agent: agentType,
|
|
1297
|
+
success: false,
|
|
1298
|
+
path: cluster.configPath,
|
|
1299
|
+
error: errorMsg
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
return agentTypes.map((agentType) => resultsByAgent.get(agentType));
|
|
1305
|
+
};
|
|
1306
|
+
var installToCompatibleAgents = (serverName, serverConfig, options) => {
|
|
1307
|
+
const { allAgents, incompatible = [], global: isGlobal, cwd } = options;
|
|
1308
|
+
const incompatibleMap = new Map(incompatible.map((item) => [item.agent, item.reason]));
|
|
1309
|
+
const compatibleAgents = allAgents.filter((a) => !incompatibleMap.has(a));
|
|
1310
|
+
const installedResults = installMcpServerForAgents(serverName, serverConfig, compatibleAgents, {
|
|
1311
|
+
global: isGlobal,
|
|
1312
|
+
cwd
|
|
1313
|
+
});
|
|
1314
|
+
const installedMap = new Map(installedResults.map((r) => [r.agent, r]));
|
|
1315
|
+
return allAgents.map((agentType) => {
|
|
1316
|
+
const incompatibleReason = incompatibleMap.get(agentType);
|
|
1317
|
+
if (incompatibleReason) {
|
|
1318
|
+
return {
|
|
1319
|
+
agent: agentType,
|
|
1320
|
+
success: false,
|
|
1321
|
+
path: "",
|
|
1322
|
+
error: incompatibleReason
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
return installedMap.get(agentType);
|
|
1326
|
+
});
|
|
1327
|
+
};
|
|
1201
1328
|
|
|
1202
1329
|
// src/utils/parse-mcp-agent-list.ts
|
|
1203
1330
|
var parseMcpAgentList = (input7) => {
|
|
@@ -1401,18 +1528,11 @@ var installMcpServer = (options) => {
|
|
|
1401
1528
|
cwd,
|
|
1402
1529
|
transport: requestedTransport
|
|
1403
1530
|
});
|
|
1404
|
-
const
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
agent: agentType,
|
|
1410
|
-
success: false,
|
|
1411
|
-
path: "",
|
|
1412
|
-
error: incompatibleReason
|
|
1413
|
-
};
|
|
1414
|
-
}
|
|
1415
|
-
return installMcpServerForAgent(serverName, serverConfig, agentType, { global: isGlobal, cwd });
|
|
1531
|
+
const results = installToCompatibleAgents(serverName, serverConfig, {
|
|
1532
|
+
allAgents,
|
|
1533
|
+
incompatible,
|
|
1534
|
+
global: isGlobal,
|
|
1535
|
+
cwd
|
|
1416
1536
|
});
|
|
1417
1537
|
return { serverName, config: serverConfig, results };
|
|
1418
1538
|
};
|
|
@@ -1442,9 +1562,15 @@ var listInstalledMcpServers = (options = {}) => {
|
|
|
1442
1562
|
var removeMcpServerFromAgent = (serverName, agentType, options = {}) => {
|
|
1443
1563
|
const agent = getMcpAgentConfig(agentType);
|
|
1444
1564
|
const { target } = agentConfigStore.resolveTarget(agent, options);
|
|
1565
|
+
const coHosted = getCoHostedAgents(agentType, options);
|
|
1445
1566
|
try {
|
|
1446
1567
|
const { removed } = agentConfigStore.removeServer(agent, serverName, options);
|
|
1447
|
-
return {
|
|
1568
|
+
return {
|
|
1569
|
+
agent: agentType,
|
|
1570
|
+
path: target.configPath,
|
|
1571
|
+
removed,
|
|
1572
|
+
coAffectedAgents: removed && coHosted.length > 0 ? coHosted : void 0
|
|
1573
|
+
};
|
|
1448
1574
|
} catch (error) {
|
|
1449
1575
|
return {
|
|
1450
1576
|
agent: agentType,
|
|
@@ -1461,24 +1587,153 @@ var removeMcpServer = (options) => {
|
|
|
1461
1587
|
global: options.global,
|
|
1462
1588
|
cwd: options.cwd
|
|
1463
1589
|
});
|
|
1590
|
+
const clusters = resolveConfigClusters(allAgents, {
|
|
1591
|
+
global: options.global,
|
|
1592
|
+
cwd: options.cwd
|
|
1593
|
+
});
|
|
1464
1594
|
const results = [];
|
|
1465
|
-
for (const
|
|
1466
|
-
const
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1595
|
+
for (const cluster of clusters) {
|
|
1596
|
+
const primaryAgentType = cluster.targetAgents[0];
|
|
1597
|
+
const primaryAgent = getMcpAgentConfig(primaryAgentType);
|
|
1598
|
+
try {
|
|
1599
|
+
const { removed } = agentConfigStore.removeServer(primaryAgent, options.name, {
|
|
1600
|
+
global: options.global,
|
|
1601
|
+
cwd: options.cwd
|
|
1602
|
+
});
|
|
1603
|
+
if (removed) {
|
|
1604
|
+
for (const agentType of cluster.targetAgents) {
|
|
1605
|
+
results.push({
|
|
1606
|
+
agent: agentType,
|
|
1607
|
+
path: cluster.configPath,
|
|
1608
|
+
removed: true,
|
|
1609
|
+
coAffectedAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
|
|
1610
|
+
});
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
} catch (error) {
|
|
1614
|
+
const errorMsg = toErrorMessage(error);
|
|
1615
|
+
for (const agentType of cluster.targetAgents) {
|
|
1616
|
+
results.push({
|
|
1617
|
+
agent: agentType,
|
|
1618
|
+
path: cluster.configPath,
|
|
1619
|
+
removed: false,
|
|
1620
|
+
error: errorMsg
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1471
1624
|
}
|
|
1472
1625
|
return results;
|
|
1473
1626
|
};
|
|
1474
1627
|
|
|
1628
|
+
// src/update-mcp-server.ts
|
|
1629
|
+
var toRemoteServerConfig = (config, defaultTransport = "http") => {
|
|
1630
|
+
const {
|
|
1631
|
+
command: _droppedCommand,
|
|
1632
|
+
args: _droppedArgs,
|
|
1633
|
+
env: _droppedEnv,
|
|
1634
|
+
...remoteConfig
|
|
1635
|
+
} = config;
|
|
1636
|
+
return {
|
|
1637
|
+
...remoteConfig,
|
|
1638
|
+
type: remoteConfig.type ?? defaultTransport
|
|
1639
|
+
};
|
|
1640
|
+
};
|
|
1641
|
+
var toStdioServerConfig = (config) => {
|
|
1642
|
+
const {
|
|
1643
|
+
url: _droppedUrl,
|
|
1644
|
+
type: _droppedType,
|
|
1645
|
+
headers: _droppedHeaders,
|
|
1646
|
+
...stdioConfig
|
|
1647
|
+
} = config;
|
|
1648
|
+
return stdioConfig;
|
|
1649
|
+
};
|
|
1650
|
+
var detectUpdateTransition = (incoming, previous) => {
|
|
1651
|
+
if (!previous) {
|
|
1652
|
+
return incoming.url ? "switch-to-remote" : "switch-to-stdio";
|
|
1653
|
+
}
|
|
1654
|
+
if (incoming.url && !incoming.command) {
|
|
1655
|
+
return "switch-to-remote";
|
|
1656
|
+
}
|
|
1657
|
+
if (incoming.command && !incoming.url) {
|
|
1658
|
+
return "switch-to-stdio";
|
|
1659
|
+
}
|
|
1660
|
+
if (incoming.url || !incoming.command && previous.url) {
|
|
1661
|
+
return "merge-remote";
|
|
1662
|
+
}
|
|
1663
|
+
return "merge-stdio";
|
|
1664
|
+
};
|
|
1665
|
+
var sanitizeUpdatedServerConfig = (incoming, previous) => {
|
|
1666
|
+
const transition = detectUpdateTransition(incoming, previous);
|
|
1667
|
+
const targetTransport = incoming.type ?? previous?.type ?? "http";
|
|
1668
|
+
switch (transition) {
|
|
1669
|
+
case "switch-to-remote": {
|
|
1670
|
+
const cleanBase = previous ? toRemoteServerConfig(previous, targetTransport) : {};
|
|
1671
|
+
return toRemoteServerConfig({ ...cleanBase, ...incoming }, targetTransport);
|
|
1672
|
+
}
|
|
1673
|
+
case "switch-to-stdio": {
|
|
1674
|
+
const cleanBase = previous ? toStdioServerConfig(previous) : {};
|
|
1675
|
+
return toStdioServerConfig({ ...cleanBase, ...incoming });
|
|
1676
|
+
}
|
|
1677
|
+
case "merge-remote": {
|
|
1678
|
+
return toRemoteServerConfig({ ...previous, ...incoming }, targetTransport);
|
|
1679
|
+
}
|
|
1680
|
+
case "merge-stdio": {
|
|
1681
|
+
return toStdioServerConfig({ ...previous, ...incoming });
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
};
|
|
1685
|
+
var updateMcpServer = (options) => {
|
|
1686
|
+
const isGlobal = options.global ?? false;
|
|
1687
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1688
|
+
let previousConfig = options.previousConfig;
|
|
1689
|
+
if (!previousConfig) {
|
|
1690
|
+
const existing = listInstalledMcpServers({
|
|
1691
|
+
global: isGlobal,
|
|
1692
|
+
cwd,
|
|
1693
|
+
agents: options.agents
|
|
1694
|
+
});
|
|
1695
|
+
const found = existing.find((s) => s.serverName === options.serverName && s.serverConfig);
|
|
1696
|
+
if (found) {
|
|
1697
|
+
previousConfig = found.serverConfig;
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
const serverConfig = sanitizeUpdatedServerConfig(options.config, previousConfig);
|
|
1701
|
+
let targetAgents = options.agents;
|
|
1702
|
+
if (!targetAgents || targetAgents.length === 0) {
|
|
1703
|
+
const existing = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
1704
|
+
targetAgents = existing.filter((s) => s.serverName === options.serverName).map((s) => s.agent);
|
|
1705
|
+
}
|
|
1706
|
+
const requestedTransport = serverConfig.url ? serverConfig.type ?? "http" : "stdio";
|
|
1707
|
+
const { allAgents, incompatible } = resolveTargetAgents({
|
|
1708
|
+
requested: targetAgents,
|
|
1709
|
+
global: isGlobal,
|
|
1710
|
+
cwd,
|
|
1711
|
+
transport: requestedTransport
|
|
1712
|
+
});
|
|
1713
|
+
const results = installToCompatibleAgents(options.serverName, serverConfig, {
|
|
1714
|
+
allAgents,
|
|
1715
|
+
incompatible,
|
|
1716
|
+
global: isGlobal,
|
|
1717
|
+
cwd
|
|
1718
|
+
});
|
|
1719
|
+
return {
|
|
1720
|
+
serverName: options.serverName,
|
|
1721
|
+
config: serverConfig,
|
|
1722
|
+
results,
|
|
1723
|
+
incompatible
|
|
1724
|
+
};
|
|
1725
|
+
};
|
|
1726
|
+
|
|
1475
1727
|
// src/interactive/main-menu.ts
|
|
1476
|
-
import { select as
|
|
1477
|
-
import
|
|
1728
|
+
import { select as select8 } from "@inquirer/prompts";
|
|
1729
|
+
import pc15 from "picocolors";
|
|
1478
1730
|
|
|
1479
1731
|
// src/interactive/wizard-add.ts
|
|
1480
|
-
import { confirm as confirm5, input as input5, select as
|
|
1481
|
-
import
|
|
1732
|
+
import { confirm as confirm5, input as input5, select as select5 } from "@inquirer/prompts";
|
|
1733
|
+
import pc11 from "picocolors";
|
|
1734
|
+
|
|
1735
|
+
// src/utils/co-hosted-feedback.ts
|
|
1736
|
+
import pc2 from "picocolors";
|
|
1482
1737
|
|
|
1483
1738
|
// src/utils/logger.ts
|
|
1484
1739
|
import pc from "picocolors";
|
|
@@ -1497,13 +1752,284 @@ var logger = {
|
|
|
1497
1752
|
}
|
|
1498
1753
|
};
|
|
1499
1754
|
|
|
1755
|
+
// src/utils/co-hosted-feedback.ts
|
|
1756
|
+
var formatCoHostedBadge = (kind, agents) => {
|
|
1757
|
+
if (!agents || agents.length === 0) return "";
|
|
1758
|
+
const label = kind === "configured" ? "co-configured" : "co-affected";
|
|
1759
|
+
return ` ${pc2.yellow(`(${label}: ${agents.join(", ")})`)}`;
|
|
1760
|
+
};
|
|
1761
|
+
var logCoHostedNotice = (kind, agents) => {
|
|
1762
|
+
if (!agents || agents.length === 0) return;
|
|
1763
|
+
const actionText = kind === "configured" ? "Also configured for" : "Also affects";
|
|
1764
|
+
logger.info(
|
|
1765
|
+
` ${pc2.dim("Note:")} ${actionText} co-hosted agent(s): ${pc2.yellow(agents.join(", "))}`
|
|
1766
|
+
);
|
|
1767
|
+
};
|
|
1768
|
+
|
|
1500
1769
|
// src/interactive/prompts/agents.ts
|
|
1501
|
-
import
|
|
1770
|
+
import pc6 from "picocolors";
|
|
1771
|
+
|
|
1772
|
+
// src/interactive/utils/build-linked-agent-choices.ts
|
|
1502
1773
|
import pc3 from "picocolors";
|
|
1774
|
+
var buildLinkedAgentChoices = (options) => {
|
|
1775
|
+
const { agents, checkedAgents, detectedAgents = [], scopeOptions = {} } = options;
|
|
1776
|
+
const alignedCheckedSet = new Set(checkedAgents);
|
|
1777
|
+
for (const agent of checkedAgents) {
|
|
1778
|
+
const coHosted = getCoHostedAgents(agent, scopeOptions);
|
|
1779
|
+
for (const co of coHosted) {
|
|
1780
|
+
if (agents.includes(co)) {
|
|
1781
|
+
alignedCheckedSet.add(co);
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
return agents.map((agent) => {
|
|
1786
|
+
const config = getMcpAgentConfig(agent);
|
|
1787
|
+
const displayName = config?.displayName ?? agent;
|
|
1788
|
+
const isDetected = detectedAgents.includes(agent);
|
|
1789
|
+
const coHosted = getCoHostedAgents(agent, scopeOptions).filter(
|
|
1790
|
+
(co) => agents.includes(co)
|
|
1791
|
+
);
|
|
1792
|
+
const detectedBadge = isDetected ? pc3.green(" [detected]") : "";
|
|
1793
|
+
const sharedBadge = coHosted.length > 0 ? pc3.dim(` [shared: ${coHosted.join(", ")}]`) : "";
|
|
1794
|
+
const label = `${displayName} ${pc3.dim(`(${agent})`)}${detectedBadge}${sharedBadge}`;
|
|
1795
|
+
return {
|
|
1796
|
+
name: label,
|
|
1797
|
+
value: agent,
|
|
1798
|
+
checked: alignedCheckedSet.has(agent),
|
|
1799
|
+
linkedValues: coHosted,
|
|
1800
|
+
description: coHosted.length > 0 ? `Linked with ${coHosted.map((a) => getMcpAgentConfig(a).displayName).join(", ")} (shared configuration)` : void 0
|
|
1801
|
+
};
|
|
1802
|
+
});
|
|
1803
|
+
};
|
|
1804
|
+
|
|
1805
|
+
// src/interactive/prompts/linked-checkbox.ts
|
|
1806
|
+
import {
|
|
1807
|
+
Separator,
|
|
1808
|
+
ValidationError,
|
|
1809
|
+
createPrompt,
|
|
1810
|
+
isDownKey,
|
|
1811
|
+
isEnterKey,
|
|
1812
|
+
isNumberKey,
|
|
1813
|
+
isSpaceKey,
|
|
1814
|
+
isUpKey,
|
|
1815
|
+
makeTheme,
|
|
1816
|
+
useKeypress,
|
|
1817
|
+
useMemo,
|
|
1818
|
+
usePagination,
|
|
1819
|
+
usePrefix,
|
|
1820
|
+
useState
|
|
1821
|
+
} from "@inquirer/core";
|
|
1822
|
+
import pc4 from "picocolors";
|
|
1823
|
+
var defaultTheme = {
|
|
1824
|
+
icon: {
|
|
1825
|
+
checked: pc4.green("[x]"),
|
|
1826
|
+
unchecked: pc4.dim("[ ]"),
|
|
1827
|
+
cursor: pc4.cyan(">"),
|
|
1828
|
+
disabledChecked: pc4.dim("[x]"),
|
|
1829
|
+
disabledUnchecked: pc4.dim("[-]")
|
|
1830
|
+
},
|
|
1831
|
+
style: {
|
|
1832
|
+
disabled: (text) => pc4.dim(text),
|
|
1833
|
+
renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(", "),
|
|
1834
|
+
description: (text) => pc4.cyan(text),
|
|
1835
|
+
keysHelpTip: (keys) => keys.map(([key, action]) => `${pc4.bold(key)} ${pc4.dim(action)}`).join(pc4.dim(" | ")),
|
|
1836
|
+
highlight: (text) => pc4.cyan(text)
|
|
1837
|
+
},
|
|
1838
|
+
i18n: {
|
|
1839
|
+
disabledError: "This option is disabled and cannot be toggled."
|
|
1840
|
+
}
|
|
1841
|
+
};
|
|
1842
|
+
function isSelectable(item) {
|
|
1843
|
+
return !Separator.isSeparator(item) && !item.disabled;
|
|
1844
|
+
}
|
|
1845
|
+
function isNavigable(item) {
|
|
1846
|
+
return !Separator.isSeparator(item);
|
|
1847
|
+
}
|
|
1848
|
+
function isChecked(item) {
|
|
1849
|
+
return !Separator.isSeparator(item) && item.checked;
|
|
1850
|
+
}
|
|
1851
|
+
function normalizeChoices(choices) {
|
|
1852
|
+
return choices.map((choice) => {
|
|
1853
|
+
if (Separator.isSeparator(choice)) {
|
|
1854
|
+
return choice;
|
|
1855
|
+
}
|
|
1856
|
+
if (typeof choice !== "object" || choice === null || !("value" in choice)) {
|
|
1857
|
+
const name2 = String(choice);
|
|
1858
|
+
return {
|
|
1859
|
+
value: choice,
|
|
1860
|
+
name: name2,
|
|
1861
|
+
short: name2,
|
|
1862
|
+
checkedName: name2,
|
|
1863
|
+
disabled: false,
|
|
1864
|
+
checked: false,
|
|
1865
|
+
linkedValues: []
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
const name = choice.name ?? String(choice.value);
|
|
1869
|
+
return {
|
|
1870
|
+
value: choice.value,
|
|
1871
|
+
name,
|
|
1872
|
+
short: choice.short ?? name,
|
|
1873
|
+
checkedName: choice.checkedName ?? name,
|
|
1874
|
+
description: choice.description,
|
|
1875
|
+
disabled: choice.disabled ?? false,
|
|
1876
|
+
checked: choice.checked ?? false,
|
|
1877
|
+
linkedValues: choice.linkedValues ?? []
|
|
1878
|
+
};
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
var linkedCheckbox = createPrompt(
|
|
1882
|
+
(config, done) => {
|
|
1883
|
+
const { pageSize = 10, loop = true, required, validate = () => true } = config;
|
|
1884
|
+
const theme = makeTheme(defaultTheme, config.theme);
|
|
1885
|
+
const [status, setStatus] = useState("idle");
|
|
1886
|
+
const prefix = usePrefix({ status, theme });
|
|
1887
|
+
const [items, setItems] = useState(() => normalizeChoices(config.choices));
|
|
1888
|
+
const bounds = useMemo(() => {
|
|
1889
|
+
const first = items.findIndex(isNavigable);
|
|
1890
|
+
let last = -1;
|
|
1891
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
1892
|
+
if (isNavigable(items[i])) {
|
|
1893
|
+
last = i;
|
|
1894
|
+
break;
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
if (first === -1 || last === -1) {
|
|
1898
|
+
throw new ValidationError("[linkedCheckbox prompt] No selectable choices.");
|
|
1899
|
+
}
|
|
1900
|
+
return { first, last };
|
|
1901
|
+
}, [items]);
|
|
1902
|
+
const [active, setActive] = useState(bounds.first);
|
|
1903
|
+
const [errorMsg, setError] = useState();
|
|
1904
|
+
const toggleWithLinked = (targetIndex) => {
|
|
1905
|
+
const targetItem = items[targetIndex];
|
|
1906
|
+
if (!targetItem || Separator.isSeparator(targetItem) || targetItem.disabled) {
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
const nextChecked = !targetItem.checked;
|
|
1910
|
+
const targetValue = targetItem.value;
|
|
1911
|
+
const linked = new Set(targetItem.linkedValues);
|
|
1912
|
+
setItems(
|
|
1913
|
+
(prevItems) => prevItems.map((item) => {
|
|
1914
|
+
if (Separator.isSeparator(item) || item.disabled) {
|
|
1915
|
+
return item;
|
|
1916
|
+
}
|
|
1917
|
+
const isTargetOrLinked = item.value === targetValue || linked.has(item.value) || item.linkedValues.includes(targetValue);
|
|
1918
|
+
if (isTargetOrLinked) {
|
|
1919
|
+
return { ...item, checked: nextChecked };
|
|
1920
|
+
}
|
|
1921
|
+
return item;
|
|
1922
|
+
})
|
|
1923
|
+
);
|
|
1924
|
+
};
|
|
1925
|
+
useKeypress(async (key) => {
|
|
1926
|
+
if (isEnterKey(key)) {
|
|
1927
|
+
const selection = items.filter(isChecked);
|
|
1928
|
+
const isValid = await validate([...selection]);
|
|
1929
|
+
if (required && selection.length === 0) {
|
|
1930
|
+
setError("At least one choice must be selected");
|
|
1931
|
+
} else if (isValid === true) {
|
|
1932
|
+
setStatus("done");
|
|
1933
|
+
done(selection.map((choice) => choice.value));
|
|
1934
|
+
} else {
|
|
1935
|
+
setError(typeof isValid === "string" ? isValid : "You must select a valid value");
|
|
1936
|
+
}
|
|
1937
|
+
} else if (isUpKey(key) || isDownKey(key)) {
|
|
1938
|
+
if (errorMsg) setError(void 0);
|
|
1939
|
+
if (loop || isUpKey(key) && active !== bounds.first || isDownKey(key) && active !== bounds.last) {
|
|
1940
|
+
const offset = isUpKey(key) ? -1 : 1;
|
|
1941
|
+
let next = active;
|
|
1942
|
+
do {
|
|
1943
|
+
next = (next + offset + items.length) % items.length;
|
|
1944
|
+
} while (!isNavigable(items[next]));
|
|
1945
|
+
setActive(next);
|
|
1946
|
+
}
|
|
1947
|
+
} else if (isSpaceKey(key)) {
|
|
1948
|
+
const activeItem = items[active];
|
|
1949
|
+
if (activeItem && !Separator.isSeparator(activeItem)) {
|
|
1950
|
+
if (activeItem.disabled) {
|
|
1951
|
+
setError(theme.i18n.disabledError);
|
|
1952
|
+
} else {
|
|
1953
|
+
setError(void 0);
|
|
1954
|
+
toggleWithLinked(active);
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
} else if (key.name === "a") {
|
|
1958
|
+
const hasUnchecked = items.some((choice) => isSelectable(choice) && !choice.checked);
|
|
1959
|
+
setItems(
|
|
1960
|
+
(prevItems) => prevItems.map((item) => isSelectable(item) ? { ...item, checked: hasUnchecked } : item)
|
|
1961
|
+
);
|
|
1962
|
+
} else if (isNumberKey(key)) {
|
|
1963
|
+
const selectedIndex = Number(key.name) - 1;
|
|
1964
|
+
let selectableIndex = -1;
|
|
1965
|
+
const position = items.findIndex((item) => {
|
|
1966
|
+
if (Separator.isSeparator(item)) return false;
|
|
1967
|
+
selectableIndex++;
|
|
1968
|
+
return selectableIndex === selectedIndex;
|
|
1969
|
+
});
|
|
1970
|
+
const selectedItem = items[position];
|
|
1971
|
+
if (selectedItem && isSelectable(selectedItem)) {
|
|
1972
|
+
setActive(position);
|
|
1973
|
+
setError(void 0);
|
|
1974
|
+
toggleWithLinked(position);
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
});
|
|
1978
|
+
const message = theme.style.message(config.message, status);
|
|
1979
|
+
let description;
|
|
1980
|
+
const page = usePagination({
|
|
1981
|
+
items,
|
|
1982
|
+
active,
|
|
1983
|
+
renderItem({ item, isActive }) {
|
|
1984
|
+
if (Separator.isSeparator(item)) {
|
|
1985
|
+
return ` ${item.separator}`;
|
|
1986
|
+
}
|
|
1987
|
+
const cursor = isActive ? theme.icon.cursor : " ";
|
|
1988
|
+
if (item.disabled) {
|
|
1989
|
+
const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
|
|
1990
|
+
const checkbox2 = item.checked ? theme.icon.disabledChecked : theme.icon.disabledUnchecked;
|
|
1991
|
+
return theme.style.disabled(`${cursor} ${checkbox2} ${item.name} ${disabledLabel}`);
|
|
1992
|
+
}
|
|
1993
|
+
if (isActive) {
|
|
1994
|
+
description = item.description;
|
|
1995
|
+
}
|
|
1996
|
+
const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
|
|
1997
|
+
const name = item.checked ? item.checkedName : item.name;
|
|
1998
|
+
const color = isActive ? theme.style.highlight : (x) => x;
|
|
1999
|
+
return color(`${cursor} ${checkbox} ${name}`);
|
|
2000
|
+
},
|
|
2001
|
+
pageSize,
|
|
2002
|
+
loop
|
|
2003
|
+
});
|
|
2004
|
+
if (status === "done") {
|
|
2005
|
+
const selection = items.filter(isChecked);
|
|
2006
|
+
const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
|
|
2007
|
+
return [prefix, message, answer].filter(Boolean).join(" ");
|
|
2008
|
+
}
|
|
2009
|
+
const helpLine = theme.style.keysHelpTip([
|
|
2010
|
+
["up/down", "navigate"],
|
|
2011
|
+
["space", "toggle"],
|
|
2012
|
+
["a", "all"],
|
|
2013
|
+
["enter", "submit"]
|
|
2014
|
+
]);
|
|
2015
|
+
const lines = [
|
|
2016
|
+
[prefix, message].filter(Boolean).join(" "),
|
|
2017
|
+
page,
|
|
2018
|
+
helpLine
|
|
2019
|
+
];
|
|
2020
|
+
if (description) {
|
|
2021
|
+
lines.push(theme.style.description(description));
|
|
2022
|
+
}
|
|
2023
|
+
if (errorMsg) {
|
|
2024
|
+
lines.push(theme.style.error(errorMsg));
|
|
2025
|
+
}
|
|
2026
|
+
return lines.join("\n");
|
|
2027
|
+
}
|
|
2028
|
+
);
|
|
1503
2029
|
|
|
1504
2030
|
// src/interactive/prompts/scope.ts
|
|
1505
2031
|
import { select } from "@inquirer/prompts";
|
|
1506
|
-
import
|
|
2032
|
+
import pc5 from "picocolors";
|
|
1507
2033
|
var promptScope = async (options = {}) => {
|
|
1508
2034
|
const initialGlobal = options.defaultGlobal ?? options.global;
|
|
1509
2035
|
if (initialGlobal !== void 0) {
|
|
@@ -1514,11 +2040,11 @@ var promptScope = async (options = {}) => {
|
|
|
1514
2040
|
message: options.message ?? "Select MCP scope:",
|
|
1515
2041
|
choices: [
|
|
1516
2042
|
{
|
|
1517
|
-
name: `Current Project - ${
|
|
2043
|
+
name: `Current Project - ${pc5.dim(cwd)}`,
|
|
1518
2044
|
value: false
|
|
1519
2045
|
},
|
|
1520
2046
|
{
|
|
1521
|
-
name: `Global User Config - ${
|
|
2047
|
+
name: `Global User Config - ${pc5.dim("applies across all projects")}`,
|
|
1522
2048
|
value: true
|
|
1523
2049
|
}
|
|
1524
2050
|
]
|
|
@@ -1538,26 +2064,23 @@ var promptScopeAndAgents = async (options = {}) => {
|
|
|
1538
2064
|
cwd
|
|
1539
2065
|
});
|
|
1540
2066
|
const detected = resolution.detected;
|
|
1541
|
-
const
|
|
2067
|
+
const rawAvailable = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
2068
|
+
const availableAgentTypes = sortAgentsWithClusters(rawAvailable, { global: isGlobal, cwd });
|
|
1542
2069
|
if (detected.length > 0) {
|
|
1543
2070
|
logger.info(
|
|
1544
|
-
`Detected configured agents: ${
|
|
2071
|
+
`Detected configured agents: ${pc6.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
|
|
1545
2072
|
);
|
|
1546
2073
|
} else {
|
|
1547
2074
|
logger.warn(`No active ${isGlobal ? "global" : "project"} agents detected`);
|
|
1548
2075
|
}
|
|
1549
2076
|
const defaultChecked = options.defaultAgents && options.defaultAgents.length > 0 ? options.defaultAgents : detected;
|
|
1550
|
-
const choices =
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
name: label,
|
|
1556
|
-
value: agentType,
|
|
1557
|
-
checked: defaultChecked.includes(agentType)
|
|
1558
|
-
};
|
|
2077
|
+
const choices = buildLinkedAgentChoices({
|
|
2078
|
+
agents: availableAgentTypes,
|
|
2079
|
+
checkedAgents: defaultChecked,
|
|
2080
|
+
detectedAgents: detected,
|
|
2081
|
+
scopeOptions: { global: isGlobal, cwd }
|
|
1559
2082
|
});
|
|
1560
|
-
const selectedAgents = await
|
|
2083
|
+
const selectedAgents = await linkedCheckbox({
|
|
1561
2084
|
message: "Select target agents (Space to select, Enter to confirm):",
|
|
1562
2085
|
choices,
|
|
1563
2086
|
validate: (chosen) => {
|
|
@@ -1619,17 +2142,37 @@ var promptEditArgs = async (currentArgs = []) => {
|
|
|
1619
2142
|
};
|
|
1620
2143
|
|
|
1621
2144
|
// src/interactive/prompts/env.ts
|
|
1622
|
-
import { input as input3, password as password2, select as
|
|
1623
|
-
import
|
|
2145
|
+
import { input as input3, password as password2, select as select3 } from "@inquirer/prompts";
|
|
2146
|
+
import pc9 from "picocolors";
|
|
2147
|
+
|
|
2148
|
+
// src/utils/mask-secret.ts
|
|
2149
|
+
var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
|
|
2150
|
+
var maskSecretValue = (key, value) => {
|
|
2151
|
+
if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
|
|
2152
|
+
return value;
|
|
2153
|
+
}
|
|
2154
|
+
return `${value.slice(0, 2)}***${value.slice(-2)}`;
|
|
2155
|
+
};
|
|
2156
|
+
var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
|
|
2157
|
+
var maskSecretHeader = (key, value) => {
|
|
2158
|
+
if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
|
|
2159
|
+
return value;
|
|
2160
|
+
}
|
|
2161
|
+
return `${value.slice(0, 4)}***${value.slice(-3)}`;
|
|
2162
|
+
};
|
|
2163
|
+
|
|
2164
|
+
// src/interactive/prompts/kv.ts
|
|
2165
|
+
import { confirm as confirm2, input as input2, password, select as select2 } from "@inquirer/prompts";
|
|
2166
|
+
import pc8 from "picocolors";
|
|
1624
2167
|
|
|
1625
2168
|
// src/interactive/prompts/multiline.ts
|
|
1626
2169
|
import { createInterface } from "readline";
|
|
1627
2170
|
import { editor } from "@inquirer/prompts";
|
|
1628
|
-
import
|
|
2171
|
+
import pc7 from "picocolors";
|
|
1629
2172
|
var readMultilineTextFromTerminal = async (message, endHint = "When done pasting, enter END on a new line or press Enter twice to finish") => {
|
|
1630
|
-
console.log(
|
|
2173
|
+
console.log(pc7.cyan(`
|
|
1631
2174
|
${message}`));
|
|
1632
|
-
console.log(
|
|
2175
|
+
console.log(pc7.dim(` (Hint: ${endHint})
|
|
1633
2176
|
`));
|
|
1634
2177
|
return new Promise((resolve) => {
|
|
1635
2178
|
const rl = createInterface({
|
|
@@ -1684,24 +2227,22 @@ var promptEditorText = async (options) => {
|
|
|
1684
2227
|
};
|
|
1685
2228
|
|
|
1686
2229
|
// src/interactive/prompts/kv.ts
|
|
1687
|
-
import { confirm as confirm2, input as input2, password, select as select3 } from "@inquirer/prompts";
|
|
1688
|
-
import pc5 from "picocolors";
|
|
1689
2230
|
var promptEditKeyValueConfig = async (currentItems = {}, options) => {
|
|
1690
2231
|
let items = { ...currentItems };
|
|
1691
2232
|
while (true) {
|
|
1692
2233
|
const keys = Object.keys(items);
|
|
1693
2234
|
console.log();
|
|
1694
2235
|
if (keys.length === 0) {
|
|
1695
|
-
console.log(
|
|
2236
|
+
console.log(pc8.dim(` No ${options.itemsNoun} configured.`));
|
|
1696
2237
|
} else {
|
|
1697
|
-
console.log(
|
|
2238
|
+
console.log(pc8.cyan(pc8.bold(` Configured ${options.title} (${keys.length}):`)));
|
|
1698
2239
|
for (const [k, v] of Object.entries(items)) {
|
|
1699
2240
|
const sep = options.separator === "=" ? "=" : ": ";
|
|
1700
|
-
console.log(` ${
|
|
2241
|
+
console.log(` ${pc8.bold(k)}${sep}${pc8.dim(options.maskValue(k, v))}`);
|
|
1701
2242
|
}
|
|
1702
2243
|
}
|
|
1703
2244
|
console.log();
|
|
1704
|
-
const choice = await
|
|
2245
|
+
const choice = await select2({
|
|
1705
2246
|
message: `Manage ${options.itemsNoun}:`,
|
|
1706
2247
|
choices: [
|
|
1707
2248
|
{
|
|
@@ -1776,9 +2317,9 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
|
|
|
1776
2317
|
});
|
|
1777
2318
|
}
|
|
1778
2319
|
items[trimmedKey] = newVal;
|
|
1779
|
-
logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${
|
|
2320
|
+
logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${pc8.cyan(trimmedKey)}`);
|
|
1780
2321
|
} else if (choice === "delete") {
|
|
1781
|
-
const toDelete = await
|
|
2322
|
+
const toDelete = await select2({
|
|
1782
2323
|
message: `Select ${options.itemNoun} to delete:`,
|
|
1783
2324
|
choices: [
|
|
1784
2325
|
...keys.map((k) => ({ name: k, value: k })),
|
|
@@ -1787,7 +2328,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
|
|
|
1787
2328
|
});
|
|
1788
2329
|
if (toDelete !== "__cancel__") {
|
|
1789
2330
|
delete items[toDelete];
|
|
1790
|
-
logger.success(`Deleted: ${
|
|
2331
|
+
logger.success(`Deleted: ${pc8.cyan(toDelete)}`);
|
|
1791
2332
|
}
|
|
1792
2333
|
} else if (choice === "paste") {
|
|
1793
2334
|
const pasted = await readMultilineTextFromTerminal(options.pasteMessage);
|
|
@@ -1797,7 +2338,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
|
|
|
1797
2338
|
logger.warn(`No valid ${options.itemsNoun} recognized`);
|
|
1798
2339
|
} else {
|
|
1799
2340
|
if (keys.length > 0) {
|
|
1800
|
-
const pasteMode = await
|
|
2341
|
+
const pasteMode = await select2({
|
|
1801
2342
|
message: `How to apply pasted ${options.itemsNoun}?`,
|
|
1802
2343
|
choices: [
|
|
1803
2344
|
{ name: `Merge with existing ${options.itemsNoun}`, value: "merge" },
|
|
@@ -1812,7 +2353,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
|
|
|
1812
2353
|
} else {
|
|
1813
2354
|
items = parsed;
|
|
1814
2355
|
}
|
|
1815
|
-
logger.success(`Successfully applied ${
|
|
2356
|
+
logger.success(`Successfully applied ${pc8.cyan(String(count))} ${options.itemsNoun}`);
|
|
1816
2357
|
}
|
|
1817
2358
|
} else if (choice === "clear") {
|
|
1818
2359
|
const confirmClear = await confirm2({
|
|
@@ -1828,13 +2369,6 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
|
|
|
1828
2369
|
};
|
|
1829
2370
|
|
|
1830
2371
|
// src/interactive/prompts/env.ts
|
|
1831
|
-
var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
|
|
1832
|
-
var maskSecretValue = (key, value) => {
|
|
1833
|
-
if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
|
|
1834
|
-
return value;
|
|
1835
|
-
}
|
|
1836
|
-
return `${value.slice(0, 2)}***${value.slice(-2)}`;
|
|
1837
|
-
};
|
|
1838
2372
|
var formatEnvText = (env) => {
|
|
1839
2373
|
return Object.entries(env).map(([key, value]) => {
|
|
1840
2374
|
if (/[\s"']/.test(value)) {
|
|
@@ -1868,9 +2402,9 @@ var promptEnvConfig = async (initialEnv = {}) => {
|
|
|
1868
2402
|
const env = { ...initialEnv };
|
|
1869
2403
|
const initialCount = Object.keys(env).length;
|
|
1870
2404
|
if (initialCount > 0) {
|
|
1871
|
-
logger.info(`Includes ${
|
|
2405
|
+
logger.info(`Includes ${pc9.cyan(String(initialCount))} preset environment variables`);
|
|
1872
2406
|
}
|
|
1873
|
-
const mode = await
|
|
2407
|
+
const mode = await select3({
|
|
1874
2408
|
message: "Configure environment variables?",
|
|
1875
2409
|
choices: [
|
|
1876
2410
|
{
|
|
@@ -1906,9 +2440,9 @@ var promptEnvConfig = async (initialEnv = {}) => {
|
|
|
1906
2440
|
logger.warn("No valid KEY=VALUE pairs recognized");
|
|
1907
2441
|
} else {
|
|
1908
2442
|
Object.assign(env, parsed);
|
|
1909
|
-
logger.success(`Successfully parsed ${
|
|
2443
|
+
logger.success(`Successfully parsed ${pc9.cyan(String(count))} environment variables:`);
|
|
1910
2444
|
for (const [k, v] of Object.entries(parsed)) {
|
|
1911
|
-
console.log(` ${
|
|
2445
|
+
console.log(` ${pc9.bold(k)}=${pc9.dim(maskSecretValue(k, v))}`);
|
|
1912
2446
|
}
|
|
1913
2447
|
}
|
|
1914
2448
|
return env;
|
|
@@ -1939,7 +2473,7 @@ var promptEnvConfig = async (initialEnv = {}) => {
|
|
|
1939
2473
|
});
|
|
1940
2474
|
}
|
|
1941
2475
|
env[trimmedKey] = val;
|
|
1942
|
-
logger.success(`Added: ${
|
|
2476
|
+
logger.success(`Added: ${pc9.cyan(trimmedKey)}`);
|
|
1943
2477
|
}
|
|
1944
2478
|
return env;
|
|
1945
2479
|
};
|
|
@@ -1960,15 +2494,8 @@ var promptEditEnvConfig = async (currentEnv = {}) => promptEditKeyValueConfig(cu
|
|
|
1960
2494
|
});
|
|
1961
2495
|
|
|
1962
2496
|
// src/interactive/prompts/headers.ts
|
|
1963
|
-
import { input as input4, password as password3, select as
|
|
1964
|
-
import
|
|
1965
|
-
var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
|
|
1966
|
-
var maskSecretHeader = (key, value) => {
|
|
1967
|
-
if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
|
|
1968
|
-
return value;
|
|
1969
|
-
}
|
|
1970
|
-
return `${value.slice(0, 4)}***${value.slice(-3)}`;
|
|
1971
|
-
};
|
|
2497
|
+
import { input as input4, password as password3, select as select4 } from "@inquirer/prompts";
|
|
2498
|
+
import pc10 from "picocolors";
|
|
1972
2499
|
var formatHeadersText = (headers) => {
|
|
1973
2500
|
return Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join("\n");
|
|
1974
2501
|
};
|
|
@@ -2001,7 +2528,7 @@ var parseHeadersText = (rawText) => {
|
|
|
2001
2528
|
};
|
|
2002
2529
|
var promptHeadersConfig = async (initialHeaders = {}) => {
|
|
2003
2530
|
const headers = { ...initialHeaders };
|
|
2004
|
-
const mode = await
|
|
2531
|
+
const mode = await select4({
|
|
2005
2532
|
message: "Select HTTP headers configuration method:",
|
|
2006
2533
|
choices: [
|
|
2007
2534
|
{
|
|
@@ -2038,9 +2565,9 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
|
|
|
2038
2565
|
logger.warn("No valid Key: Value pairs recognized");
|
|
2039
2566
|
} else {
|
|
2040
2567
|
Object.assign(headers, parsed);
|
|
2041
|
-
logger.success(`Successfully parsed ${
|
|
2568
|
+
logger.success(`Successfully parsed ${pc10.cyan(String(count))} headers:`);
|
|
2042
2569
|
for (const [k, v] of Object.entries(parsed)) {
|
|
2043
|
-
console.log(` ${
|
|
2570
|
+
console.log(` ${pc10.bold(k)}: ${pc10.dim(maskSecretHeader(k, v))}`);
|
|
2044
2571
|
}
|
|
2045
2572
|
}
|
|
2046
2573
|
return headers;
|
|
@@ -2071,7 +2598,7 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
|
|
|
2071
2598
|
});
|
|
2072
2599
|
}
|
|
2073
2600
|
headers[trimmedName] = val;
|
|
2074
|
-
logger.success(`Added: ${
|
|
2601
|
+
logger.success(`Added: ${pc10.cyan(trimmedName)}`);
|
|
2075
2602
|
}
|
|
2076
2603
|
return headers;
|
|
2077
2604
|
};
|
|
@@ -2093,10 +2620,10 @@ var promptEditHeadersConfig = async (currentHeaders = {}) => promptEditKeyValueC
|
|
|
2093
2620
|
// src/interactive/wizard-add.ts
|
|
2094
2621
|
var wizardAdd = async (initial = {}) => {
|
|
2095
2622
|
const cwd = initial.cwd ?? process.cwd();
|
|
2096
|
-
logger.info(
|
|
2623
|
+
logger.info(pc11.bold("Welcome to the MCP interactive add wizard"));
|
|
2097
2624
|
let source = initial.source;
|
|
2098
2625
|
if (!source) {
|
|
2099
|
-
const sourceType = await
|
|
2626
|
+
const sourceType = await select5({
|
|
2100
2627
|
message: "Select MCP server type:",
|
|
2101
2628
|
choices: [
|
|
2102
2629
|
{
|
|
@@ -2151,7 +2678,7 @@ var wizardAdd = async (initial = {}) => {
|
|
|
2151
2678
|
if (parsed.type === "remote") {
|
|
2152
2679
|
if (!transport) {
|
|
2153
2680
|
const isSseUrl = /\/sse\b/i.test(parsed.value);
|
|
2154
|
-
transport = await
|
|
2681
|
+
transport = await select5({
|
|
2155
2682
|
message: "Select remote transport protocol:",
|
|
2156
2683
|
choices: [
|
|
2157
2684
|
{ name: "HTTP", value: "http" },
|
|
@@ -2183,25 +2710,25 @@ var wizardAdd = async (initial = {}) => {
|
|
|
2183
2710
|
if (parsed.type !== "remote") {
|
|
2184
2711
|
env = await promptEnvConfig(env);
|
|
2185
2712
|
}
|
|
2186
|
-
console.log("\n" +
|
|
2187
|
-
console.log(` ${
|
|
2188
|
-
console.log(` ${
|
|
2189
|
-
console.log(` ${
|
|
2190
|
-
console.log(` ${
|
|
2191
|
-
console.log(` ${
|
|
2713
|
+
console.log("\n" + pc11.cyan(pc11.bold("Configuration Preview:")));
|
|
2714
|
+
console.log(` ${pc11.bold("Server Name:")} ${pc11.green(serverName)}`);
|
|
2715
|
+
console.log(` ${pc11.bold("Server Type:")} ${pc11.magenta(parsed.type)}`);
|
|
2716
|
+
console.log(` ${pc11.bold("Source/Command:")} ${pc11.dim(source)}`);
|
|
2717
|
+
console.log(` ${pc11.bold("Scope:")} ${isGlobal ? pc11.yellow("Global") : pc11.blue("Project")}`);
|
|
2718
|
+
console.log(` ${pc11.bold("Target Agents:")} ${pc11.cyan(selectedAgents.join(", "))}`);
|
|
2192
2719
|
if (args.length > 0) {
|
|
2193
|
-
console.log(` ${
|
|
2720
|
+
console.log(` ${pc11.bold("Arguments:")} ${pc11.dim(args.join(" "))}`);
|
|
2194
2721
|
}
|
|
2195
2722
|
if (transport) {
|
|
2196
|
-
console.log(` ${
|
|
2723
|
+
console.log(` ${pc11.bold("Transport:")} ${pc11.magenta(transport)}`);
|
|
2197
2724
|
}
|
|
2198
2725
|
const envKeys = Object.keys(env);
|
|
2199
2726
|
if (envKeys.length > 0) {
|
|
2200
|
-
console.log(` ${
|
|
2727
|
+
console.log(` ${pc11.bold("Environment Variables:")} ${pc11.dim(envKeys.join(", "))} (${envKeys.length})`);
|
|
2201
2728
|
}
|
|
2202
2729
|
const headerKeys = Object.keys(headers);
|
|
2203
2730
|
if (headerKeys.length > 0) {
|
|
2204
|
-
console.log(` ${
|
|
2731
|
+
console.log(` ${pc11.bold("Headers:")} ${pc11.dim(headerKeys.join(", "))} (${headerKeys.length})`);
|
|
2205
2732
|
}
|
|
2206
2733
|
console.log();
|
|
2207
2734
|
const proceed = await confirm5({
|
|
@@ -2224,103 +2751,162 @@ var wizardAdd = async (initial = {}) => {
|
|
|
2224
2751
|
env
|
|
2225
2752
|
});
|
|
2226
2753
|
logger.info(
|
|
2227
|
-
`Writing ${
|
|
2754
|
+
`Writing ${pc11.bold(result.serverName)} to ${pc11.cyan(String(result.results.length))} agent config files...`
|
|
2228
2755
|
);
|
|
2229
2756
|
let allSuccess = true;
|
|
2230
2757
|
for (const record of result.results) {
|
|
2231
2758
|
if (record.success) {
|
|
2232
|
-
logger.success(
|
|
2759
|
+
logger.success(
|
|
2760
|
+
`${pc11.cyan(record.agent)}: Successfully written to ${pc11.dim(record.path)}${formatCoHostedBadge("configured", record.coConfiguredAgents)}`
|
|
2761
|
+
);
|
|
2233
2762
|
} else {
|
|
2234
2763
|
allSuccess = false;
|
|
2235
|
-
logger.error(`${
|
|
2764
|
+
logger.error(`${pc11.cyan(record.agent)}: Failed to write - ${record.error}`);
|
|
2236
2765
|
}
|
|
2237
2766
|
}
|
|
2238
2767
|
if (allSuccess) {
|
|
2239
|
-
logger.success(
|
|
2768
|
+
logger.success(pc11.bold(`MCP server "${serverName}" configured successfully!`));
|
|
2240
2769
|
}
|
|
2241
2770
|
return allSuccess;
|
|
2242
2771
|
};
|
|
2243
2772
|
|
|
2244
2773
|
// src/interactive/wizard-manage.ts
|
|
2245
|
-
import {
|
|
2246
|
-
import
|
|
2247
|
-
|
|
2248
|
-
// src/interactive/utils/group-installed-servers.ts
|
|
2249
|
-
var normalizeServerConfig = parseServerConfig;
|
|
2250
|
-
var groupInstalledServersByName = (installed) => {
|
|
2251
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
2252
|
-
for (const item of installed) {
|
|
2253
|
-
let entry = grouped.get(item.serverName);
|
|
2254
|
-
if (!entry) {
|
|
2255
|
-
entry = {
|
|
2256
|
-
serverName: item.serverName,
|
|
2257
|
-
agents: [],
|
|
2258
|
-
paths: [],
|
|
2259
|
-
config: normalizeServerConfig(item.config)
|
|
2260
|
-
};
|
|
2261
|
-
grouped.set(item.serverName, entry);
|
|
2262
|
-
}
|
|
2263
|
-
if (!entry.agents.includes(item.agent)) {
|
|
2264
|
-
entry.agents.push(item.agent);
|
|
2265
|
-
}
|
|
2266
|
-
if (!entry.paths.includes(item.path)) {
|
|
2267
|
-
entry.paths.push(item.path);
|
|
2268
|
-
}
|
|
2269
|
-
}
|
|
2270
|
-
return grouped;
|
|
2271
|
-
};
|
|
2774
|
+
import { confirm as confirm6, input as input6, select as select6 } from "@inquirer/prompts";
|
|
2775
|
+
import pc13 from "picocolors";
|
|
2272
2776
|
|
|
2273
|
-
// src/
|
|
2777
|
+
// src/utils/display-server-details.ts
|
|
2778
|
+
import pc12 from "picocolors";
|
|
2274
2779
|
var displayServerDetails = ({
|
|
2275
2780
|
serverName,
|
|
2276
2781
|
config,
|
|
2277
2782
|
agents,
|
|
2278
|
-
|
|
2783
|
+
hasDivergence,
|
|
2784
|
+
global: isGlobal,
|
|
2279
2785
|
titlePrefix = "MCP Server Details"
|
|
2280
2786
|
}) => {
|
|
2281
|
-
console.log("\n" +
|
|
2787
|
+
console.log("\n" + pc12.cyan(pc12.bold(`${titlePrefix}: [${serverName}]`)));
|
|
2282
2788
|
if (isGlobal !== void 0) {
|
|
2283
|
-
console.log(` ${
|
|
2789
|
+
console.log(` ${pc12.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
|
|
2284
2790
|
}
|
|
2285
2791
|
if (agents && agents.length > 0) {
|
|
2286
2792
|
console.log(
|
|
2287
|
-
` ${
|
|
2793
|
+
` ${pc12.bold("Configured Agents:")} ${pc12.green(agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
|
|
2794
|
+
);
|
|
2795
|
+
}
|
|
2796
|
+
if (hasDivergence) {
|
|
2797
|
+
console.log(
|
|
2798
|
+
` ${pc12.yellow(pc12.bold("Notice:"))} ${pc12.yellow("Configurations differ across installed agents. Showing configuration from the first agent.")}`
|
|
2288
2799
|
);
|
|
2289
2800
|
}
|
|
2290
2801
|
const isRemote = Boolean(config.url && config.url.length > 0);
|
|
2291
2802
|
if (isRemote) {
|
|
2292
|
-
console.log(` ${
|
|
2293
|
-
console.log(` ${
|
|
2803
|
+
console.log(` ${pc12.bold("Transport:")} ${pc12.magenta(config.type ?? "http")}`);
|
|
2804
|
+
console.log(` ${pc12.bold("URL:")} ${pc12.dim(config.url ?? "")}`);
|
|
2294
2805
|
const headerKeys = Object.keys(config.headers ?? {});
|
|
2295
2806
|
if (headerKeys.length > 0) {
|
|
2296
|
-
console.log(` ${
|
|
2807
|
+
console.log(` ${pc12.bold("Headers:")} ${pc12.cyan(String(headerKeys.length))}`);
|
|
2297
2808
|
for (const [k, v] of Object.entries(config.headers ?? {})) {
|
|
2298
|
-
console.log(` ${
|
|
2809
|
+
console.log(` ${pc12.bold(k)}: ${pc12.dim(maskSecretHeader(k, v))}`);
|
|
2299
2810
|
}
|
|
2300
2811
|
} else {
|
|
2301
|
-
console.log(` ${
|
|
2812
|
+
console.log(` ${pc12.bold("Headers:")} ${pc12.dim("(none)")}`);
|
|
2302
2813
|
}
|
|
2303
2814
|
} else {
|
|
2304
|
-
console.log(` ${
|
|
2815
|
+
console.log(` ${pc12.bold("Command:")} ${pc12.magenta(config.command ?? "")}`);
|
|
2305
2816
|
const argsStr = config.args && config.args.length > 0 ? config.args.join(" ") : "(none)";
|
|
2306
|
-
console.log(` ${
|
|
2817
|
+
console.log(` ${pc12.bold("Arguments:")} ${pc12.dim(argsStr)}`);
|
|
2307
2818
|
const envKeys = Object.keys(config.env ?? {});
|
|
2308
2819
|
if (envKeys.length > 0) {
|
|
2309
|
-
console.log(` ${
|
|
2820
|
+
console.log(` ${pc12.bold("Environment Variables:")} ${pc12.cyan(String(envKeys.length))}`);
|
|
2310
2821
|
for (const [k, v] of Object.entries(config.env ?? {})) {
|
|
2311
|
-
console.log(` ${
|
|
2822
|
+
console.log(` ${pc12.bold(k)}=${pc12.dim(maskSecretValue(k, v))}`);
|
|
2312
2823
|
}
|
|
2313
2824
|
} else {
|
|
2314
|
-
console.log(` ${
|
|
2825
|
+
console.log(` ${pc12.bold("Environment Variables:")} ${pc12.dim("(none)")}`);
|
|
2315
2826
|
}
|
|
2316
2827
|
}
|
|
2317
2828
|
console.log();
|
|
2318
2829
|
};
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2830
|
+
|
|
2831
|
+
// src/interactive/utils/group-installed-servers.ts
|
|
2832
|
+
var normalizeServerConfig = parseServerConfig;
|
|
2833
|
+
var groupInstalledServersByName = (installed) => {
|
|
2834
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
2835
|
+
for (const item of installed) {
|
|
2836
|
+
const itemConfig = normalizeServerConfig(item.config);
|
|
2837
|
+
let entry = grouped.get(item.serverName);
|
|
2838
|
+
if (!entry) {
|
|
2839
|
+
entry = {
|
|
2840
|
+
serverName: item.serverName,
|
|
2841
|
+
agents: [],
|
|
2842
|
+
paths: [],
|
|
2843
|
+
config: itemConfig,
|
|
2844
|
+
hasDivergence: false
|
|
2845
|
+
};
|
|
2846
|
+
grouped.set(item.serverName, entry);
|
|
2847
|
+
} else if (!entry.hasDivergence) {
|
|
2848
|
+
if (JSON.stringify(entry.config) !== JSON.stringify(itemConfig)) {
|
|
2849
|
+
entry.hasDivergence = true;
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
if (!entry.agents.includes(item.agent)) {
|
|
2853
|
+
entry.agents.push(item.agent);
|
|
2854
|
+
}
|
|
2855
|
+
if (!entry.paths.includes(item.path)) {
|
|
2856
|
+
entry.paths.push(item.path);
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
return grouped;
|
|
2860
|
+
};
|
|
2861
|
+
|
|
2862
|
+
// src/interactive/wizard-manage.ts
|
|
2863
|
+
var promptSwitchServerType = async (currentConfig, serverName) => {
|
|
2864
|
+
const isRemote = Boolean(currentConfig.url && currentConfig.url.length > 0);
|
|
2865
|
+
if (isRemote) {
|
|
2866
|
+
const newCmd = await input6({
|
|
2867
|
+
message: "Executable command (e.g. node, npx):",
|
|
2868
|
+
validate: (val) => val.trim() ? true : "Command cannot be empty"
|
|
2869
|
+
});
|
|
2870
|
+
const newArgs = await promptEditArgs([]);
|
|
2871
|
+
const newEnv = await promptEditEnvConfig({});
|
|
2872
|
+
logger.success(`Switched [${serverName}] configuration to stdio mode`);
|
|
2873
|
+
return {
|
|
2874
|
+
command: newCmd.trim(),
|
|
2875
|
+
args: newArgs.length > 0 ? newArgs : void 0,
|
|
2876
|
+
env: Object.keys(newEnv).length > 0 ? newEnv : void 0
|
|
2877
|
+
};
|
|
2878
|
+
}
|
|
2879
|
+
const newUrl = await input6({
|
|
2880
|
+
message: "Remote server URL:",
|
|
2881
|
+
validate: (val) => {
|
|
2882
|
+
const trimmed = val.trim();
|
|
2883
|
+
if (!trimmed) return "URL cannot be empty";
|
|
2884
|
+
if (!/^https?:\/\//i.test(trimmed)) {
|
|
2885
|
+
return "Please enter a valid URL starting with http:// or https://";
|
|
2886
|
+
}
|
|
2887
|
+
return true;
|
|
2888
|
+
}
|
|
2889
|
+
});
|
|
2890
|
+
const transport = await select6({
|
|
2891
|
+
message: "Select remote transport protocol:",
|
|
2892
|
+
choices: [
|
|
2893
|
+
{ name: "HTTP", value: "http" },
|
|
2894
|
+
{ name: "SSE (Server-Sent Events)", value: "sse" }
|
|
2895
|
+
],
|
|
2896
|
+
default: "http"
|
|
2897
|
+
});
|
|
2898
|
+
const newHeaders = await promptEditHeadersConfig({});
|
|
2899
|
+
logger.success(`Switched [${serverName}] configuration to remote mode`);
|
|
2900
|
+
return {
|
|
2901
|
+
url: newUrl.trim(),
|
|
2902
|
+
type: transport,
|
|
2903
|
+
headers: Object.keys(newHeaders).length > 0 ? newHeaders : void 0
|
|
2904
|
+
};
|
|
2905
|
+
};
|
|
2906
|
+
var handleEditServerConfig = async (options) => {
|
|
2907
|
+
const { targetGroup } = options;
|
|
2908
|
+
const isGlobal = options.global ?? false;
|
|
2909
|
+
const cwd = options.cwd ?? process.cwd();
|
|
2324
2910
|
const serverName = targetGroup.serverName;
|
|
2325
2911
|
let workingConfig = {
|
|
2326
2912
|
...targetGroup.config,
|
|
@@ -2339,6 +2925,7 @@ var handleEditServerConfig = async ({
|
|
|
2339
2925
|
{ name: "Edit HTTP Headers (headers)", value: "headers" },
|
|
2340
2926
|
{ name: "Edit Remote URL (url)", value: "url" },
|
|
2341
2927
|
{ name: "Edit Transport Protocol (type)", value: "transport" },
|
|
2928
|
+
{ name: "Switch to local command (stdio)", value: "switch_type" },
|
|
2342
2929
|
{ name: "Reset changes to original", value: "reset" },
|
|
2343
2930
|
{ name: "Save and apply changes", value: "save" },
|
|
2344
2931
|
{ name: "Cancel (discard changes)", value: "cancel" }
|
|
@@ -2346,11 +2933,12 @@ var handleEditServerConfig = async ({
|
|
|
2346
2933
|
{ name: "Edit Environment Variables (env)", value: "env" },
|
|
2347
2934
|
{ name: "Edit Command Arguments (args)", value: "args" },
|
|
2348
2935
|
{ name: "Edit Executable Command (command)", value: "command" },
|
|
2936
|
+
{ name: "Switch to remote server (HTTP/SSE)", value: "switch_type" },
|
|
2349
2937
|
{ name: "Reset changes to original", value: "reset" },
|
|
2350
2938
|
{ name: "Save and apply changes", value: "save" },
|
|
2351
2939
|
{ name: "Cancel (discard changes)", value: "cancel" }
|
|
2352
2940
|
];
|
|
2353
|
-
const editAction = await
|
|
2941
|
+
const editAction = await select6({
|
|
2354
2942
|
message: `What would you like to modify in [${serverName}]?`,
|
|
2355
2943
|
choices: editChoices
|
|
2356
2944
|
});
|
|
@@ -2368,6 +2956,10 @@ var handleEditServerConfig = async ({
|
|
|
2368
2956
|
logger.info("Configuration reset to original");
|
|
2369
2957
|
continue;
|
|
2370
2958
|
}
|
|
2959
|
+
if (editAction === "switch_type") {
|
|
2960
|
+
workingConfig = await promptSwitchServerType(workingConfig, serverName);
|
|
2961
|
+
continue;
|
|
2962
|
+
}
|
|
2371
2963
|
if (editAction === "env") {
|
|
2372
2964
|
workingConfig.env = await promptEditEnvConfig(workingConfig.env ?? {});
|
|
2373
2965
|
} else if (editAction === "args") {
|
|
@@ -2396,7 +2988,7 @@ var handleEditServerConfig = async ({
|
|
|
2396
2988
|
});
|
|
2397
2989
|
workingConfig.url = newUrl.trim();
|
|
2398
2990
|
} else if (editAction === "transport") {
|
|
2399
|
-
workingConfig.type = await
|
|
2991
|
+
workingConfig.type = await select6({
|
|
2400
2992
|
message: "Select remote transport protocol:",
|
|
2401
2993
|
choices: [
|
|
2402
2994
|
{ name: "HTTP", value: "http" },
|
|
@@ -2407,41 +2999,45 @@ var handleEditServerConfig = async ({
|
|
|
2407
2999
|
} else if (editAction === "save") {
|
|
2408
3000
|
let targetAgents = targetGroup.agents;
|
|
2409
3001
|
if (targetGroup.agents.length > 1) {
|
|
2410
|
-
|
|
3002
|
+
const sortedAgents = sortAgentsWithClusters(targetGroup.agents, { global: isGlobal, cwd });
|
|
3003
|
+
const choices = buildLinkedAgentChoices({
|
|
3004
|
+
agents: sortedAgents,
|
|
3005
|
+
checkedAgents: sortedAgents,
|
|
3006
|
+
scopeOptions: { global: isGlobal, cwd }
|
|
3007
|
+
});
|
|
3008
|
+
targetAgents = await linkedCheckbox({
|
|
2411
3009
|
message: "Select agents to update configuration (Space to toggle):",
|
|
2412
|
-
choices
|
|
2413
|
-
name: `${getMcpAgentConfig(a).displayName} (${a})`,
|
|
2414
|
-
value: a,
|
|
2415
|
-
checked: true
|
|
2416
|
-
})),
|
|
3010
|
+
choices,
|
|
2417
3011
|
loop: false,
|
|
2418
3012
|
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
2419
3013
|
});
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
if (isMcpTransportSupported(agentConfig, requestedTransport)) {
|
|
2427
|
-
compatibleAgents.push(agent);
|
|
2428
|
-
} else {
|
|
2429
|
-
const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
|
|
2430
|
-
incompatibleAgents.push({ agent, reason });
|
|
3014
|
+
if (targetAgents.length < targetGroup.agents.length) {
|
|
3015
|
+
const unselected = targetGroup.agents.filter((a) => !targetAgents.includes(a));
|
|
3016
|
+
const unselectedNames = unselected.map((a) => getMcpAgentConfig(a).displayName).join(", ");
|
|
3017
|
+
logger.info(
|
|
3018
|
+
`Note: Updating only a subset of agents. Server configurations will diverge from: ${unselectedNames}.`
|
|
3019
|
+
);
|
|
2431
3020
|
}
|
|
2432
3021
|
}
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
3022
|
+
const requestedTransport = workingConfig.url ? workingConfig.type ?? "http" : "stdio";
|
|
3023
|
+
const resolution = resolveTargetAgents({
|
|
3024
|
+
requested: targetAgents,
|
|
3025
|
+
global: isGlobal,
|
|
3026
|
+
cwd,
|
|
3027
|
+
transport: requestedTransport
|
|
3028
|
+
});
|
|
3029
|
+
if (resolution.incompatible.length > 0) {
|
|
3030
|
+
for (const item of resolution.incompatible) {
|
|
3031
|
+
logger.warn(`Skipping ${pc13.cyan(item.agent)}: ${item.reason}`);
|
|
2436
3032
|
}
|
|
2437
3033
|
}
|
|
2438
|
-
if (compatibleAgents.length === 0) {
|
|
3034
|
+
if (resolution.compatibleAgents.length === 0) {
|
|
2439
3035
|
logger.error(
|
|
2440
3036
|
`None of the selected agents support ${requestedTransport} transport. Cannot update.`
|
|
2441
3037
|
);
|
|
2442
3038
|
continue;
|
|
2443
3039
|
}
|
|
2444
|
-
const agentNames = compatibleAgents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
|
|
3040
|
+
const agentNames = resolution.compatibleAgents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
|
|
2445
3041
|
const confirmed = await confirm6({
|
|
2446
3042
|
message: `Confirm updating configuration for [${serverName}] across: ${agentNames}?`,
|
|
2447
3043
|
default: true
|
|
@@ -2450,22 +3046,32 @@ var handleEditServerConfig = async ({
|
|
|
2450
3046
|
logger.warn("Update cancelled");
|
|
2451
3047
|
continue;
|
|
2452
3048
|
}
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
3049
|
+
const updateResult = updateMcpServer({
|
|
3050
|
+
serverName,
|
|
3051
|
+
config: workingConfig,
|
|
3052
|
+
previousConfig: targetGroup.config,
|
|
3053
|
+
agents: resolution.compatibleAgents,
|
|
3054
|
+
global: isGlobal,
|
|
3055
|
+
cwd
|
|
3056
|
+
});
|
|
3057
|
+
let updatedAny = false;
|
|
3058
|
+
const succeededAgents = [];
|
|
3059
|
+
for (const res of updateResult.results) {
|
|
2458
3060
|
if (res.success) {
|
|
3061
|
+
updatedAny = true;
|
|
3062
|
+
succeededAgents.push(res.agent);
|
|
2459
3063
|
logger.success(
|
|
2460
|
-
`${
|
|
3064
|
+
`${pc13.cyan(res.agent)}: Successfully updated configuration in ${pc13.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
|
|
2461
3065
|
);
|
|
2462
3066
|
} else {
|
|
2463
|
-
logger.error(`${
|
|
3067
|
+
logger.error(`${pc13.cyan(res.agent)}: Update failed - ${res.error}`);
|
|
2464
3068
|
}
|
|
2465
3069
|
}
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
3070
|
+
if (updatedAny) {
|
|
3071
|
+
targetGroup.config = updateResult.config;
|
|
3072
|
+
logger.success(`Configuration for [${serverName}] updated successfully!`);
|
|
3073
|
+
return;
|
|
3074
|
+
}
|
|
2469
3075
|
}
|
|
2470
3076
|
}
|
|
2471
3077
|
};
|
|
@@ -2483,6 +3089,14 @@ var wizardManage = async (options = {}) => {
|
|
|
2483
3089
|
}
|
|
2484
3090
|
const grouped = groupInstalledServersByName(installed);
|
|
2485
3091
|
let pendingServerName = options.serverName;
|
|
3092
|
+
const refreshGroupedServers = () => {
|
|
3093
|
+
const freshInstalled = listInstalledMcpServers({ global: isGlobal, cwd });
|
|
3094
|
+
const freshGrouped = groupInstalledServersByName(freshInstalled);
|
|
3095
|
+
grouped.clear();
|
|
3096
|
+
for (const [name, grp] of freshGrouped) {
|
|
3097
|
+
grouped.set(name, grp);
|
|
3098
|
+
}
|
|
3099
|
+
};
|
|
2486
3100
|
while (true) {
|
|
2487
3101
|
let chosenServerName;
|
|
2488
3102
|
if (pendingServerName && grouped.has(pendingServerName)) {
|
|
@@ -2493,7 +3107,7 @@ var wizardManage = async (options = {}) => {
|
|
|
2493
3107
|
const choices = Array.from(grouped.values()).map((g) => {
|
|
2494
3108
|
const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
|
|
2495
3109
|
return {
|
|
2496
|
-
name: `${
|
|
3110
|
+
name: `${pc13.bold(g.serverName)} ${pc13.dim(`(configured in: ${agentNames})`)}`,
|
|
2497
3111
|
value: g.serverName
|
|
2498
3112
|
};
|
|
2499
3113
|
});
|
|
@@ -2501,7 +3115,7 @@ var wizardManage = async (options = {}) => {
|
|
|
2501
3115
|
name: `Back`,
|
|
2502
3116
|
value: "__back__"
|
|
2503
3117
|
});
|
|
2504
|
-
chosenServerName = await
|
|
3118
|
+
chosenServerName = await select6({
|
|
2505
3119
|
message: "Select MCP server to manage or sync:",
|
|
2506
3120
|
choices
|
|
2507
3121
|
});
|
|
@@ -2515,9 +3129,10 @@ var wizardManage = async (options = {}) => {
|
|
|
2515
3129
|
serverName: chosenServerName,
|
|
2516
3130
|
config: targetGroup.config,
|
|
2517
3131
|
agents: targetGroup.agents,
|
|
2518
|
-
isGlobal
|
|
3132
|
+
global: isGlobal,
|
|
3133
|
+
hasDivergence: targetGroup.hasDivergence
|
|
2519
3134
|
});
|
|
2520
|
-
const action = await
|
|
3135
|
+
const action = await select6({
|
|
2521
3136
|
message: `What would you like to do with [${chosenServerName}]?`,
|
|
2522
3137
|
choices: [
|
|
2523
3138
|
{
|
|
@@ -2538,27 +3153,30 @@ var wizardManage = async (options = {}) => {
|
|
|
2538
3153
|
if (action === "edit") {
|
|
2539
3154
|
await handleEditServerConfig({
|
|
2540
3155
|
targetGroup,
|
|
2541
|
-
isGlobal,
|
|
3156
|
+
global: isGlobal,
|
|
2542
3157
|
cwd
|
|
2543
3158
|
});
|
|
3159
|
+
refreshGroupedServers();
|
|
2544
3160
|
continue;
|
|
2545
3161
|
}
|
|
2546
3162
|
if (action === "sync") {
|
|
2547
3163
|
const allAllowedAgents = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
|
|
2548
|
-
const
|
|
2549
|
-
if (
|
|
3164
|
+
const rawCandidateAgents = allAllowedAgents.filter((a) => !targetGroup.agents.includes(a));
|
|
3165
|
+
if (rawCandidateAgents.length === 0) {
|
|
2550
3166
|
logger.info(
|
|
2551
3167
|
"All supported agents in this scope already have this MCP server configured; no sync needed"
|
|
2552
3168
|
);
|
|
2553
3169
|
continue;
|
|
2554
3170
|
}
|
|
2555
|
-
const
|
|
3171
|
+
const candidateAgents = sortAgentsWithClusters(rawCandidateAgents, { global: isGlobal, cwd });
|
|
3172
|
+
const choices = buildLinkedAgentChoices({
|
|
3173
|
+
agents: candidateAgents,
|
|
3174
|
+
checkedAgents: [],
|
|
3175
|
+
scopeOptions: { global: isGlobal, cwd }
|
|
3176
|
+
});
|
|
3177
|
+
const selectedToSync = await linkedCheckbox({
|
|
2556
3178
|
message: "Select target agents to sync to (Space to select):",
|
|
2557
|
-
choices
|
|
2558
|
-
name: `${getMcpAgentConfig(a).displayName} (${a})`,
|
|
2559
|
-
value: a,
|
|
2560
|
-
checked: false
|
|
2561
|
-
})),
|
|
3179
|
+
choices,
|
|
2562
3180
|
loop: false,
|
|
2563
3181
|
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
2564
3182
|
});
|
|
@@ -2570,25 +3188,37 @@ var wizardManage = async (options = {}) => {
|
|
|
2570
3188
|
logger.warn("Sync cancelled");
|
|
2571
3189
|
continue;
|
|
2572
3190
|
}
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
3191
|
+
const syncResult = updateMcpServer({
|
|
3192
|
+
serverName: chosenServerName,
|
|
3193
|
+
config: targetGroup.config,
|
|
3194
|
+
agents: selectedToSync,
|
|
3195
|
+
global: isGlobal,
|
|
3196
|
+
cwd
|
|
3197
|
+
});
|
|
3198
|
+
for (const item of syncResult.incompatible) {
|
|
3199
|
+
logger.warn(`Skipping ${pc13.cyan(item.agent)}: ${item.reason}`);
|
|
3200
|
+
}
|
|
3201
|
+
for (const res of syncResult.results) {
|
|
3202
|
+
if (syncResult.incompatible.some((i) => i.agent === res.agent)) {
|
|
3203
|
+
continue;
|
|
3204
|
+
}
|
|
2578
3205
|
if (res.success) {
|
|
2579
|
-
logger.success(
|
|
2580
|
-
|
|
3206
|
+
logger.success(
|
|
3207
|
+
`${pc13.cyan(res.agent)}: Successfully synced to ${pc13.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
|
|
3208
|
+
);
|
|
3209
|
+
targetGroup.agents.push(res.agent);
|
|
2581
3210
|
} else {
|
|
2582
|
-
logger.error(`${
|
|
3211
|
+
logger.error(`${pc13.cyan(res.agent)}: Sync failed - ${res.error}`);
|
|
2583
3212
|
}
|
|
2584
3213
|
}
|
|
3214
|
+
refreshGroupedServers();
|
|
2585
3215
|
}
|
|
2586
3216
|
}
|
|
2587
3217
|
};
|
|
2588
3218
|
|
|
2589
3219
|
// src/interactive/wizard-remove.ts
|
|
2590
|
-
import {
|
|
2591
|
-
import
|
|
3220
|
+
import { confirm as confirm7, select as select7 } from "@inquirer/prompts";
|
|
3221
|
+
import pc14 from "picocolors";
|
|
2592
3222
|
var wizardRemove = async (options = {}) => {
|
|
2593
3223
|
const cwd = options.cwd ?? process.cwd();
|
|
2594
3224
|
const isGlobal = await promptScope({
|
|
@@ -2605,29 +3235,30 @@ var wizardRemove = async (options = {}) => {
|
|
|
2605
3235
|
let serverName = options.name;
|
|
2606
3236
|
if (!serverName) {
|
|
2607
3237
|
const choices = Array.from(serverMap.values()).map((g) => ({
|
|
2608
|
-
name: `${
|
|
3238
|
+
name: `${pc14.bold(g.serverName)} ${pc14.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
|
|
2609
3239
|
value: g.serverName
|
|
2610
3240
|
}));
|
|
2611
|
-
serverName = await
|
|
3241
|
+
serverName = await select7({
|
|
2612
3242
|
message: "Select MCP server to remove:",
|
|
2613
3243
|
choices
|
|
2614
3244
|
});
|
|
2615
3245
|
}
|
|
2616
|
-
const
|
|
2617
|
-
if (
|
|
3246
|
+
const rawInstalledAgents = serverMap.get(serverName)?.agents || [];
|
|
3247
|
+
if (rawInstalledAgents.length === 0) {
|
|
2618
3248
|
logger.warn(`No agents found with [${serverName}] installed`);
|
|
2619
3249
|
return false;
|
|
2620
3250
|
}
|
|
3251
|
+
const installedAgents = sortAgentsWithClusters(rawInstalledAgents, { global: isGlobal, cwd });
|
|
2621
3252
|
let targetAgents = options.agents;
|
|
2622
3253
|
if (!targetAgents || targetAgents.length === 0) {
|
|
2623
|
-
|
|
3254
|
+
const choices = buildLinkedAgentChoices({
|
|
3255
|
+
agents: installedAgents,
|
|
3256
|
+
checkedAgents: installedAgents,
|
|
3257
|
+
scopeOptions: { global: isGlobal, cwd }
|
|
3258
|
+
});
|
|
3259
|
+
targetAgents = await linkedCheckbox({
|
|
2624
3260
|
message: `Select agents to remove [${serverName}] from:`,
|
|
2625
|
-
choices
|
|
2626
|
-
name: `${getMcpAgentConfig(agent)?.displayName ?? agent} (${agent})`,
|
|
2627
|
-
value: agent,
|
|
2628
|
-
checked: true
|
|
2629
|
-
})),
|
|
2630
|
-
loop: false,
|
|
3261
|
+
choices,
|
|
2631
3262
|
validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
|
|
2632
3263
|
});
|
|
2633
3264
|
} else {
|
|
@@ -2655,10 +3286,12 @@ var wizardRemove = async (options = {}) => {
|
|
|
2655
3286
|
let removedCount = 0;
|
|
2656
3287
|
for (const res of results) {
|
|
2657
3288
|
if (res.removed) {
|
|
2658
|
-
logger.success(
|
|
3289
|
+
logger.success(
|
|
3290
|
+
`${pc14.cyan(res.agent)}: Successfully removed from ${pc14.dim(res.path)}${formatCoHostedBadge("affected", res.coAffectedAgents)}`
|
|
3291
|
+
);
|
|
2659
3292
|
removedCount++;
|
|
2660
3293
|
} else if (res.error) {
|
|
2661
|
-
logger.error(`${
|
|
3294
|
+
logger.error(`${pc14.cyan(res.agent)}: Failed to remove - ${res.error}`);
|
|
2662
3295
|
}
|
|
2663
3296
|
}
|
|
2664
3297
|
if (removedCount > 0) {
|
|
@@ -2672,12 +3305,12 @@ var wizardRemove = async (options = {}) => {
|
|
|
2672
3305
|
// src/interactive/main-menu.ts
|
|
2673
3306
|
var mainMenu = async () => {
|
|
2674
3307
|
console.log();
|
|
2675
|
-
console.log(
|
|
2676
|
-
console.log(
|
|
3308
|
+
console.log(pc15.bold(pc15.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
|
|
3309
|
+
console.log(pc15.dim("Cross-platform MCP server configuration & synchronization tool"));
|
|
2677
3310
|
console.log();
|
|
2678
3311
|
while (true) {
|
|
2679
3312
|
try {
|
|
2680
|
-
const action = await
|
|
3313
|
+
const action = await select8({
|
|
2681
3314
|
message: "Select an action:",
|
|
2682
3315
|
choices: [
|
|
2683
3316
|
{
|
|
@@ -2699,7 +3332,7 @@ var mainMenu = async () => {
|
|
|
2699
3332
|
]
|
|
2700
3333
|
});
|
|
2701
3334
|
if (action === "exit") {
|
|
2702
|
-
console.log(
|
|
3335
|
+
console.log(pc15.dim("Goodbye!"));
|
|
2703
3336
|
break;
|
|
2704
3337
|
}
|
|
2705
3338
|
if (action === "add") {
|
|
@@ -2712,7 +3345,7 @@ var mainMenu = async () => {
|
|
|
2712
3345
|
console.log();
|
|
2713
3346
|
} catch (error) {
|
|
2714
3347
|
if (error?.name === "ExitPromptError") {
|
|
2715
|
-
console.log("\n" +
|
|
3348
|
+
console.log("\n" + pc15.dim("Exited."));
|
|
2716
3349
|
break;
|
|
2717
3350
|
}
|
|
2718
3351
|
throw error;
|
|
@@ -2720,9 +3353,16 @@ var mainMenu = async () => {
|
|
|
2720
3353
|
}
|
|
2721
3354
|
};
|
|
2722
3355
|
|
|
3356
|
+
// src/utils/resolve-transport.ts
|
|
3357
|
+
var resolveTransport = (input7) => {
|
|
3358
|
+
if (!input7) return void 0;
|
|
3359
|
+
if (input7 === "http" || input7 === "sse") return input7;
|
|
3360
|
+
throw new Error(`Unsupported transport "${input7}" (expected: http, sse)`);
|
|
3361
|
+
};
|
|
3362
|
+
|
|
2723
3363
|
// src/cli/manage.ts
|
|
2724
3364
|
import { Command } from "commander";
|
|
2725
|
-
import
|
|
3365
|
+
import pc16 from "picocolors";
|
|
2726
3366
|
|
|
2727
3367
|
// src/utils/parse-key-value-list.ts
|
|
2728
3368
|
var parseKeyValueList = (entries, separator) => {
|
|
@@ -2742,72 +3382,124 @@ var parseKeyValueList = (entries, separator) => {
|
|
|
2742
3382
|
};
|
|
2743
3383
|
|
|
2744
3384
|
// src/cli/manage.ts
|
|
2745
|
-
var
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
3385
|
+
var requireTargetServerGroup = (serverName, scope) => {
|
|
3386
|
+
const installed = listInstalledMcpServers(scope);
|
|
3387
|
+
const grouped = groupInstalledServersByName(installed);
|
|
3388
|
+
const targetGroup = grouped.get(serverName);
|
|
3389
|
+
if (!targetGroup) {
|
|
3390
|
+
logger.error(
|
|
3391
|
+
`MCP server "${serverName}" is not configured in ${scope.global ? "global" : "project"} scope.`
|
|
3392
|
+
);
|
|
3393
|
+
process.exitCode = 1;
|
|
3394
|
+
return void 0;
|
|
3395
|
+
}
|
|
3396
|
+
return targetGroup;
|
|
2749
3397
|
};
|
|
2750
|
-
var mcpManageCommand = new Command("manage").description("Inspect, modify, and sync installed MCP servers across coding agents").argument("[server-name]", "Optional server name to inspect or manage").option("-a, --agent <agents...>", "Target specific agents for update").option("-g, --global", "Manage global scope servers instead of project").option("-t, --transport <type>", "Transport type for remote servers (http or sse)").option("--header <header...>", "HTTP header (Header: Value), repeatable").option("--env <env...>", "Env var for stdio servers (KEY=VALUE), repeatable").option("--args <args...>", "CLI arguments for stdio/package servers").option("--command <command>", "Executable command for stdio servers").option("--url <url>", "Remote endpoint URL").option("-y, --yes", "Skip interactive prompts").action(async (serverName, options) => {
|
|
3398
|
+
var mcpManageCommand = new Command("manage").description("Inspect, modify, and sync installed MCP servers across coding agents").argument("[server-name]", "Optional server name to inspect or manage").option("-a, --agent <agents...>", "Target specific agents for update").option("-g, --global", "Manage global scope servers instead of project").option("-t, --transport <type>", "Transport type for remote servers (http or sse)").option("--header <header...>", "HTTP header (Header: Value), repeatable").option("--clear-headers", "Clear all HTTP headers for remote servers").option("--env <env...>", "Env var for stdio servers (KEY=VALUE), repeatable").option("--clear-env", "Clear all environment variables for stdio servers").option("--args <args...>", "CLI arguments for stdio/package servers").option("--clear-args", "Clear all arguments for stdio/package servers").option("--command <command>", "Executable command for stdio servers").option("--url <url>", "Remote endpoint URL").option("-y, --yes", "Skip interactive prompts").action(async (serverName, options) => {
|
|
2751
3399
|
try {
|
|
2752
3400
|
const cwd = process.cwd();
|
|
2753
3401
|
const isGlobal = Boolean(options.global);
|
|
2754
|
-
const hasModifications = options.command !== void 0 || options.args !== void 0 || options.env !== void 0 || options.header !== void 0 || options.url !== void 0 || options.transport !== void 0;
|
|
3402
|
+
const hasModifications = options.command !== void 0 || options.args !== void 0 || Boolean(options.clearArgs) || options.env !== void 0 || Boolean(options.clearEnv) || options.header !== void 0 || Boolean(options.clearHeaders) || options.url !== void 0 || options.transport !== void 0;
|
|
2755
3403
|
const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
|
|
2756
3404
|
if (hasModifications) {
|
|
3405
|
+
if (options.url !== void 0 && options.command !== void 0) {
|
|
3406
|
+
logger.error('Cannot specify both "--url" (remote) and "--command" (stdio) simultaneously.');
|
|
3407
|
+
process.exitCode = 1;
|
|
3408
|
+
return;
|
|
3409
|
+
}
|
|
2757
3410
|
if (!serverName) {
|
|
2758
3411
|
logger.error('Missing required argument: "server-name" when passing modification flags.');
|
|
2759
3412
|
process.exitCode = 1;
|
|
2760
3413
|
return;
|
|
2761
3414
|
}
|
|
2762
|
-
const
|
|
2763
|
-
const grouped = groupInstalledServersByName(installed);
|
|
2764
|
-
const targetGroup = grouped.get(serverName);
|
|
3415
|
+
const targetGroup = requireTargetServerGroup(serverName, { global: isGlobal, cwd });
|
|
2765
3416
|
if (!targetGroup) {
|
|
2766
|
-
logger.error(
|
|
2767
|
-
`MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
|
|
2768
|
-
);
|
|
2769
|
-
process.exitCode = 1;
|
|
2770
3417
|
return;
|
|
2771
3418
|
}
|
|
2772
|
-
const
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
3419
|
+
const isCurrentRemote = Boolean(targetGroup.config.url && targetGroup.config.url.length > 0);
|
|
3420
|
+
const willBeRemote = options.url !== void 0 ? true : options.command !== void 0 ? false : isCurrentRemote;
|
|
3421
|
+
if (willBeRemote) {
|
|
3422
|
+
const ignoredStdioFlags = [];
|
|
3423
|
+
if (options.env !== void 0) ignoredStdioFlags.push("--env");
|
|
3424
|
+
if (options.clearEnv) ignoredStdioFlags.push("--clear-env");
|
|
3425
|
+
if (options.args !== void 0) ignoredStdioFlags.push("--args");
|
|
3426
|
+
if (options.clearArgs) ignoredStdioFlags.push("--clear-args");
|
|
3427
|
+
if (ignoredStdioFlags.length > 0) {
|
|
3428
|
+
const hint = options.url !== void 0 ? "When configuring a remote server, stdio flags are ignored." : "Use --command to switch to stdio mode.";
|
|
3429
|
+
logger.warn(
|
|
3430
|
+
`Server "${serverName}" is a remote server. The following stdio flags will be ignored: ${ignoredStdioFlags.join(", ")}. ${hint}`
|
|
3431
|
+
);
|
|
3432
|
+
}
|
|
3433
|
+
} else {
|
|
3434
|
+
const ignoredRemoteFlags = [];
|
|
3435
|
+
if (options.header !== void 0) ignoredRemoteFlags.push("--header");
|
|
3436
|
+
if (options.clearHeaders) ignoredRemoteFlags.push("--clear-headers");
|
|
3437
|
+
if (options.transport !== void 0) ignoredRemoteFlags.push("--transport");
|
|
3438
|
+
if (ignoredRemoteFlags.length > 0) {
|
|
3439
|
+
const hint = options.command !== void 0 ? "When configuring a stdio server, remote flags are ignored." : "Use --url to switch to remote mode.";
|
|
3440
|
+
logger.warn(
|
|
3441
|
+
`Server "${serverName}" is a stdio server. The following remote flags will be ignored: ${ignoredRemoteFlags.join(", ")}. ${hint}`
|
|
3442
|
+
);
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
const incomingDelta = {};
|
|
2778
3446
|
if (options.command !== void 0) {
|
|
2779
|
-
|
|
3447
|
+
incomingDelta.command = options.command;
|
|
3448
|
+
}
|
|
3449
|
+
if (options.clearArgs) {
|
|
3450
|
+
incomingDelta.args = void 0;
|
|
2780
3451
|
}
|
|
2781
3452
|
if (options.args !== void 0) {
|
|
2782
|
-
|
|
3453
|
+
incomingDelta.args = options.args;
|
|
2783
3454
|
}
|
|
2784
3455
|
if (options.url !== void 0) {
|
|
2785
|
-
|
|
3456
|
+
incomingDelta.url = options.url;
|
|
2786
3457
|
}
|
|
2787
3458
|
if (options.transport !== void 0) {
|
|
2788
|
-
|
|
3459
|
+
incomingDelta.type = resolveTransport(options.transport);
|
|
3460
|
+
}
|
|
3461
|
+
if (options.clearEnv) {
|
|
3462
|
+
incomingDelta.env = void 0;
|
|
2789
3463
|
}
|
|
2790
3464
|
if (options.env !== void 0) {
|
|
2791
3465
|
const parsedEnv = parseKeyValueList(options.env, "=");
|
|
2792
|
-
|
|
3466
|
+
const baseEnv = options.clearEnv ? {} : targetGroup.config.env ?? {};
|
|
3467
|
+
incomingDelta.env = { ...baseEnv, ...parsedEnv };
|
|
3468
|
+
}
|
|
3469
|
+
if (options.clearHeaders) {
|
|
3470
|
+
incomingDelta.headers = void 0;
|
|
2793
3471
|
}
|
|
2794
3472
|
if (options.header !== void 0) {
|
|
2795
3473
|
const parsedHeaders = parseKeyValueList(options.header, ":");
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
|
|
2807
|
-
logger.warn(`Skipping ${pc12.cyan(agent)}: ${reason}`);
|
|
3474
|
+
const baseHeaders = options.clearHeaders ? {} : targetGroup.config.headers ?? {};
|
|
3475
|
+
incomingDelta.headers = { ...baseHeaders, ...parsedHeaders };
|
|
3476
|
+
}
|
|
3477
|
+
let targetAgents = targetGroup.agents;
|
|
3478
|
+
if (options.agent !== void 0) {
|
|
3479
|
+
const parsed = parseMcpAgentList(options.agent);
|
|
3480
|
+
if (!parsed || parsed.length === 0) {
|
|
3481
|
+
logger.error(`No valid agents recognized from: "${options.agent.join(", ")}".`);
|
|
3482
|
+
process.exitCode = 1;
|
|
3483
|
+
return;
|
|
2808
3484
|
}
|
|
3485
|
+
targetAgents = parsed;
|
|
3486
|
+
}
|
|
3487
|
+
const updateResult = updateMcpServer({
|
|
3488
|
+
serverName,
|
|
3489
|
+
config: incomingDelta,
|
|
3490
|
+
previousConfig: targetGroup.config,
|
|
3491
|
+
agents: targetAgents,
|
|
3492
|
+
global: isGlobal,
|
|
3493
|
+
cwd
|
|
3494
|
+
});
|
|
3495
|
+
for (const item of updateResult.incompatible) {
|
|
3496
|
+
logger.warn(`Skipping ${pc16.cyan(item.agent)}: ${item.reason}`);
|
|
2809
3497
|
}
|
|
2810
|
-
|
|
3498
|
+
const attemptedResults = updateResult.results.filter(
|
|
3499
|
+
(r) => !updateResult.incompatible.some((i) => i.agent === r.agent)
|
|
3500
|
+
);
|
|
3501
|
+
if (attemptedResults.length === 0) {
|
|
3502
|
+
const requestedTransport = updateResult.config.url ? updateResult.config.type ?? "http" : "stdio";
|
|
2811
3503
|
logger.error(
|
|
2812
3504
|
`None of the target agents support ${requestedTransport} transport. Update aborted.`
|
|
2813
3505
|
);
|
|
@@ -2815,19 +3507,16 @@ var mcpManageCommand = new Command("manage").description("Inspect, modify, and s
|
|
|
2815
3507
|
return;
|
|
2816
3508
|
}
|
|
2817
3509
|
logger.info(
|
|
2818
|
-
`Updating ${
|
|
3510
|
+
`Updating ${pc16.bold(serverName)} across ${pc16.cyan(String(attemptedResults.length))} agent(s)...`
|
|
2819
3511
|
);
|
|
2820
3512
|
let allSuccess = true;
|
|
2821
|
-
for (const
|
|
2822
|
-
const res = installMcpServerForAgent(serverName, updatedConfig, agent, {
|
|
2823
|
-
global: isGlobal,
|
|
2824
|
-
cwd
|
|
2825
|
-
});
|
|
3513
|
+
for (const res of attemptedResults) {
|
|
2826
3514
|
if (res.success) {
|
|
2827
|
-
logger.success(`${
|
|
3515
|
+
logger.success(`${pc16.cyan(res.agent)}: Successfully updated in ${pc16.dim(res.path)}`);
|
|
3516
|
+
logCoHostedNotice("configured", res.coConfiguredAgents);
|
|
2828
3517
|
} else {
|
|
2829
3518
|
allSuccess = false;
|
|
2830
|
-
logger.error(`${
|
|
3519
|
+
logger.error(`${pc16.cyan(res.agent)}: Update failed - ${res.error}`);
|
|
2831
3520
|
}
|
|
2832
3521
|
}
|
|
2833
3522
|
if (!allSuccess) {
|
|
@@ -2843,21 +3532,16 @@ var mcpManageCommand = new Command("manage").description("Inspect, modify, and s
|
|
|
2843
3532
|
process.exitCode = 1;
|
|
2844
3533
|
return;
|
|
2845
3534
|
}
|
|
2846
|
-
const
|
|
2847
|
-
const grouped = groupInstalledServersByName(installed);
|
|
2848
|
-
const targetGroup = grouped.get(serverName);
|
|
3535
|
+
const targetGroup = requireTargetServerGroup(serverName, { global: isGlobal, cwd });
|
|
2849
3536
|
if (!targetGroup) {
|
|
2850
|
-
logger.error(
|
|
2851
|
-
`MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
|
|
2852
|
-
);
|
|
2853
|
-
process.exitCode = 1;
|
|
2854
3537
|
return;
|
|
2855
3538
|
}
|
|
2856
3539
|
displayServerDetails({
|
|
2857
3540
|
serverName,
|
|
2858
3541
|
config: targetGroup.config,
|
|
2859
3542
|
agents: targetGroup.agents,
|
|
2860
|
-
isGlobal
|
|
3543
|
+
global: isGlobal,
|
|
3544
|
+
hasDivergence: targetGroup.hasDivergence
|
|
2861
3545
|
});
|
|
2862
3546
|
return;
|
|
2863
3547
|
}
|
|
@@ -2900,11 +3584,16 @@ export {
|
|
|
2900
3584
|
AgentConfigStore,
|
|
2901
3585
|
agentConfigStore,
|
|
2902
3586
|
toErrorMessage,
|
|
3587
|
+
getCandidateAgentsForScope,
|
|
3588
|
+
getCoHostedAgents,
|
|
3589
|
+
resolveConfigClusters,
|
|
3590
|
+
sortAgentsWithClusters,
|
|
2903
3591
|
transformServerConfig,
|
|
2904
3592
|
createAgentTransform,
|
|
2905
3593
|
transformServerConfigForAgent,
|
|
2906
3594
|
installMcpServerForAgent,
|
|
2907
3595
|
installMcpServerForAgents,
|
|
3596
|
+
installToCompatibleAgents,
|
|
2908
3597
|
parseMcpAgentList,
|
|
2909
3598
|
resolveTargetAgents,
|
|
2910
3599
|
extractPackageName,
|
|
@@ -2914,31 +3603,43 @@ export {
|
|
|
2914
3603
|
listInstalledMcpServers,
|
|
2915
3604
|
removeMcpServerFromAgent,
|
|
2916
3605
|
removeMcpServer,
|
|
3606
|
+
toRemoteServerConfig,
|
|
3607
|
+
toStdioServerConfig,
|
|
3608
|
+
detectUpdateTransition,
|
|
3609
|
+
sanitizeUpdatedServerConfig,
|
|
3610
|
+
updateMcpServer,
|
|
2917
3611
|
logger,
|
|
3612
|
+
logCoHostedNotice,
|
|
3613
|
+
buildLinkedAgentChoices,
|
|
3614
|
+
linkedCheckbox,
|
|
2918
3615
|
promptScope,
|
|
2919
3616
|
promptScopeAndAgents,
|
|
2920
3617
|
parseArgsString,
|
|
2921
3618
|
promptArgsConfig,
|
|
2922
3619
|
formatArgsString,
|
|
2923
3620
|
promptEditArgs,
|
|
2924
|
-
|
|
3621
|
+
SECRET_KEY_PATTERN,
|
|
2925
3622
|
maskSecretValue,
|
|
3623
|
+
SECRET_HEADER_PATTERN,
|
|
3624
|
+
maskSecretHeader,
|
|
3625
|
+
promptEditKeyValueConfig,
|
|
2926
3626
|
formatEnvText,
|
|
2927
3627
|
parseEnvText,
|
|
2928
3628
|
promptEnvConfig,
|
|
2929
3629
|
promptEditEnvConfig,
|
|
2930
|
-
maskSecretHeader,
|
|
2931
3630
|
formatHeadersText,
|
|
2932
3631
|
parseHeadersText,
|
|
2933
3632
|
promptHeadersConfig,
|
|
2934
3633
|
promptEditHeadersConfig,
|
|
2935
3634
|
wizardAdd,
|
|
3635
|
+
displayServerDetails,
|
|
2936
3636
|
normalizeServerConfig,
|
|
2937
3637
|
groupInstalledServersByName,
|
|
2938
|
-
|
|
3638
|
+
promptSwitchServerType,
|
|
2939
3639
|
wizardManage,
|
|
2940
3640
|
wizardRemove,
|
|
2941
3641
|
mainMenu,
|
|
3642
|
+
resolveTransport,
|
|
2942
3643
|
parseKeyValueList,
|
|
2943
3644
|
mcpManageCommand
|
|
2944
3645
|
};
|