@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/dist/cli.cjs CHANGED
@@ -27,7 +27,7 @@ var import_commander5 = require("commander");
27
27
 
28
28
  // src/cli/add.ts
29
29
  var import_commander2 = require("commander");
30
- var import_picocolors13 = __toESM(require("picocolors"), 1);
30
+ var import_picocolors17 = __toESM(require("picocolors"), 1);
31
31
 
32
32
  // src/agents.ts
33
33
  var import_node_fs = require("fs");
@@ -994,6 +994,74 @@ var agentConfigStore = new AgentConfigStore();
994
994
  // src/utils/to-error-message.ts
995
995
  var toErrorMessage = (error, fallback = "Unknown error") => error instanceof Error ? error.message : fallback;
996
996
 
997
+ // src/resolve-config-clusters.ts
998
+ var getCandidateAgentsForScope = (options = {}) => {
999
+ return options.global ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
1000
+ };
1001
+ var getCoHostedAgents = (agentType, options = {}) => {
1002
+ const currentAgent = getMcpAgentConfig(agentType);
1003
+ const currentTarget = resolveMcpConfigTarget(currentAgent, options);
1004
+ const candidates = getCandidateAgentsForScope(options);
1005
+ const coHosted = [];
1006
+ for (const candidateType of candidates) {
1007
+ if (candidateType === agentType) continue;
1008
+ const candidateConfig = getMcpAgentConfig(candidateType);
1009
+ const candidateTarget = resolveMcpConfigTarget(candidateConfig, options);
1010
+ if (candidateTarget.configPath === currentTarget.configPath && candidateTarget.configKey === currentTarget.configKey) {
1011
+ coHosted.push(candidateType);
1012
+ }
1013
+ }
1014
+ return coHosted;
1015
+ };
1016
+ var resolveConfigClusters = (agentTypes, options = {}) => {
1017
+ const clustersByPath = /* @__PURE__ */ new Map();
1018
+ for (const agentType of agentTypes) {
1019
+ const agentConfig = getMcpAgentConfig(agentType);
1020
+ const target = resolveMcpConfigTarget(agentConfig, options);
1021
+ let keyMap = clustersByPath.get(target.configPath);
1022
+ if (!keyMap) {
1023
+ keyMap = /* @__PURE__ */ new Map();
1024
+ clustersByPath.set(target.configPath, keyMap);
1025
+ }
1026
+ let cluster = keyMap.get(target.configKey);
1027
+ if (!cluster) {
1028
+ const allCoHosted = getCoHostedAgents(agentType, options);
1029
+ cluster = {
1030
+ configPath: target.configPath,
1031
+ configKey: target.configKey,
1032
+ targetAgents: [],
1033
+ coHostedAgents: allCoHosted
1034
+ };
1035
+ keyMap.set(target.configKey, cluster);
1036
+ }
1037
+ if (!cluster.targetAgents.includes(agentType)) {
1038
+ cluster.targetAgents.push(agentType);
1039
+ }
1040
+ }
1041
+ const clusters = [];
1042
+ for (const keyMap of clustersByPath.values()) {
1043
+ for (const cluster of keyMap.values()) {
1044
+ cluster.coHostedAgents = cluster.coHostedAgents.filter(
1045
+ (co) => !cluster.targetAgents.includes(co)
1046
+ );
1047
+ clusters.push(cluster);
1048
+ }
1049
+ }
1050
+ return clusters;
1051
+ };
1052
+ var sortAgentsWithClusters = (agentTypes, options = {}) => {
1053
+ const clusters = resolveConfigClusters(agentTypes, options);
1054
+ const sorted = [];
1055
+ for (const cluster of clusters) {
1056
+ for (const agent of cluster.targetAgents) {
1057
+ if (!sorted.includes(agent)) {
1058
+ sorted.push(agent);
1059
+ }
1060
+ }
1061
+ }
1062
+ return sorted;
1063
+ };
1064
+
997
1065
  // src/transforms/index.ts
998
1066
  var DIALECT_PRESETS = {
999
1067
  vscode: {
@@ -1202,24 +1270,61 @@ var transformServerConfigForAgent = (agent, serverName, config, context = { glob
1202
1270
  };
1203
1271
 
1204
1272
  // src/installer.ts
1205
- var installMcpServerForAgent = (serverName, serverConfig, agentType, options = {}) => {
1206
- const agent = getMcpAgentConfig(agentType);
1273
+ var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options = {}) => {
1274
+ const clusters = resolveConfigClusters(agentTypes, options);
1275
+ const resultsByAgent = /* @__PURE__ */ new Map();
1207
1276
  const isGlobal = options.global ?? false;
1208
- const { target } = agentConfigStore.resolveTarget(agent, options);
1209
- try {
1210
- const transformed = transformServerConfigForAgent(agent, serverName, serverConfig, {
1211
- global: isGlobal
1212
- });
1213
- agentConfigStore.writeServer(agent, serverName, transformed, options);
1214
- return { agent: agentType, success: true, path: target.configPath };
1215
- } catch (error) {
1216
- return {
1217
- agent: agentType,
1218
- success: false,
1219
- path: target.configPath,
1220
- error: toErrorMessage(error)
1221
- };
1277
+ for (const cluster of clusters) {
1278
+ const primaryAgentType = cluster.targetAgents[0];
1279
+ const primaryAgent = getMcpAgentConfig(primaryAgentType);
1280
+ try {
1281
+ const transformed = transformServerConfigForAgent(primaryAgent, serverName, serverConfig, {
1282
+ global: isGlobal
1283
+ });
1284
+ agentConfigStore.writeServer(primaryAgent, serverName, transformed, options);
1285
+ for (const agentType of cluster.targetAgents) {
1286
+ resultsByAgent.set(agentType, {
1287
+ agent: agentType,
1288
+ success: true,
1289
+ path: cluster.configPath,
1290
+ coConfiguredAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
1291
+ });
1292
+ }
1293
+ } catch (error) {
1294
+ const errorMsg = toErrorMessage(error);
1295
+ for (const agentType of cluster.targetAgents) {
1296
+ resultsByAgent.set(agentType, {
1297
+ agent: agentType,
1298
+ success: false,
1299
+ path: cluster.configPath,
1300
+ error: errorMsg
1301
+ });
1302
+ }
1303
+ }
1222
1304
  }
1305
+ return agentTypes.map((agentType) => resultsByAgent.get(agentType));
1306
+ };
1307
+ var installToCompatibleAgents = (serverName, serverConfig, options) => {
1308
+ const { allAgents, incompatible = [], global: isGlobal, cwd } = options;
1309
+ const incompatibleMap = new Map(incompatible.map((item) => [item.agent, item.reason]));
1310
+ const compatibleAgents = allAgents.filter((a) => !incompatibleMap.has(a));
1311
+ const installedResults = installMcpServerForAgents(serverName, serverConfig, compatibleAgents, {
1312
+ global: isGlobal,
1313
+ cwd
1314
+ });
1315
+ const installedMap = new Map(installedResults.map((r) => [r.agent, r]));
1316
+ return allAgents.map((agentType) => {
1317
+ const incompatibleReason = incompatibleMap.get(agentType);
1318
+ if (incompatibleReason) {
1319
+ return {
1320
+ agent: agentType,
1321
+ success: false,
1322
+ path: "",
1323
+ error: incompatibleReason
1324
+ };
1325
+ }
1326
+ return installedMap.get(agentType);
1327
+ });
1223
1328
  };
1224
1329
 
1225
1330
  // src/utils/parse-mcp-agent-list.ts
@@ -1423,18 +1528,11 @@ var installMcpServer = (options) => {
1423
1528
  cwd,
1424
1529
  transport: requestedTransport
1425
1530
  });
1426
- const incompatibleMap = new Map(incompatible.map((item) => [item.agent, item.reason]));
1427
- const results = allAgents.map((agentType) => {
1428
- const incompatibleReason = incompatibleMap.get(agentType);
1429
- if (incompatibleReason) {
1430
- return {
1431
- agent: agentType,
1432
- success: false,
1433
- path: "",
1434
- error: incompatibleReason
1435
- };
1436
- }
1437
- return installMcpServerForAgent(serverName, serverConfig, agentType, { global: isGlobal, cwd });
1531
+ const results = installToCompatibleAgents(serverName, serverConfig, {
1532
+ allAgents,
1533
+ incompatible,
1534
+ global: isGlobal,
1535
+ cwd
1438
1536
  });
1439
1537
  return { serverName, config: serverConfig, results };
1440
1538
  };
@@ -1461,21 +1559,6 @@ var listInstalledMcpServers = (options = {}) => {
1461
1559
  };
1462
1560
 
1463
1561
  // src/remove.ts
1464
- var removeMcpServerFromAgent = (serverName, agentType, options = {}) => {
1465
- const agent = getMcpAgentConfig(agentType);
1466
- const { target } = agentConfigStore.resolveTarget(agent, options);
1467
- try {
1468
- const { removed } = agentConfigStore.removeServer(agent, serverName, options);
1469
- return { agent: agentType, path: target.configPath, removed };
1470
- } catch (error) {
1471
- return {
1472
- agent: agentType,
1473
- path: target.configPath,
1474
- removed: false,
1475
- error: toErrorMessage(error)
1476
- };
1477
- }
1478
- };
1479
1562
  var removeMcpServer = (options) => {
1480
1563
  const { allAgents } = resolveTargetAgents({
1481
1564
  requested: options.agents,
@@ -1483,24 +1566,153 @@ var removeMcpServer = (options) => {
1483
1566
  global: options.global,
1484
1567
  cwd: options.cwd
1485
1568
  });
1569
+ const clusters = resolveConfigClusters(allAgents, {
1570
+ global: options.global,
1571
+ cwd: options.cwd
1572
+ });
1486
1573
  const results = [];
1487
- for (const agentType of allAgents) {
1488
- const result = removeMcpServerFromAgent(options.name, agentType, {
1489
- global: options.global,
1490
- cwd: options.cwd
1491
- });
1492
- if (result.removed || result.error) results.push(result);
1574
+ for (const cluster of clusters) {
1575
+ const primaryAgentType = cluster.targetAgents[0];
1576
+ const primaryAgent = getMcpAgentConfig(primaryAgentType);
1577
+ try {
1578
+ const { removed } = agentConfigStore.removeServer(primaryAgent, options.name, {
1579
+ global: options.global,
1580
+ cwd: options.cwd
1581
+ });
1582
+ if (removed) {
1583
+ for (const agentType of cluster.targetAgents) {
1584
+ results.push({
1585
+ agent: agentType,
1586
+ path: cluster.configPath,
1587
+ removed: true,
1588
+ coAffectedAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
1589
+ });
1590
+ }
1591
+ }
1592
+ } catch (error) {
1593
+ const errorMsg = toErrorMessage(error);
1594
+ for (const agentType of cluster.targetAgents) {
1595
+ results.push({
1596
+ agent: agentType,
1597
+ path: cluster.configPath,
1598
+ removed: false,
1599
+ error: errorMsg
1600
+ });
1601
+ }
1602
+ }
1493
1603
  }
1494
1604
  return results;
1495
1605
  };
1496
1606
 
1607
+ // src/update-mcp-server.ts
1608
+ var toRemoteServerConfig = (config, defaultTransport = "http") => {
1609
+ const {
1610
+ command: _droppedCommand,
1611
+ args: _droppedArgs,
1612
+ env: _droppedEnv,
1613
+ ...remoteConfig
1614
+ } = config;
1615
+ return {
1616
+ ...remoteConfig,
1617
+ type: remoteConfig.type ?? defaultTransport
1618
+ };
1619
+ };
1620
+ var toStdioServerConfig = (config) => {
1621
+ const {
1622
+ url: _droppedUrl,
1623
+ type: _droppedType,
1624
+ headers: _droppedHeaders,
1625
+ ...stdioConfig
1626
+ } = config;
1627
+ return stdioConfig;
1628
+ };
1629
+ var detectUpdateTransition = (incoming, previous) => {
1630
+ if (!previous) {
1631
+ return incoming.url ? "switch-to-remote" : "switch-to-stdio";
1632
+ }
1633
+ if (incoming.url && !incoming.command) {
1634
+ return "switch-to-remote";
1635
+ }
1636
+ if (incoming.command && !incoming.url) {
1637
+ return "switch-to-stdio";
1638
+ }
1639
+ if (incoming.url || !incoming.command && previous.url) {
1640
+ return "merge-remote";
1641
+ }
1642
+ return "merge-stdio";
1643
+ };
1644
+ var sanitizeUpdatedServerConfig = (incoming, previous) => {
1645
+ const transition = detectUpdateTransition(incoming, previous);
1646
+ const targetTransport = incoming.type ?? previous?.type ?? "http";
1647
+ switch (transition) {
1648
+ case "switch-to-remote": {
1649
+ const cleanBase = previous ? toRemoteServerConfig(previous, targetTransport) : {};
1650
+ return toRemoteServerConfig({ ...cleanBase, ...incoming }, targetTransport);
1651
+ }
1652
+ case "switch-to-stdio": {
1653
+ const cleanBase = previous ? toStdioServerConfig(previous) : {};
1654
+ return toStdioServerConfig({ ...cleanBase, ...incoming });
1655
+ }
1656
+ case "merge-remote": {
1657
+ return toRemoteServerConfig({ ...previous, ...incoming }, targetTransport);
1658
+ }
1659
+ case "merge-stdio": {
1660
+ return toStdioServerConfig({ ...previous, ...incoming });
1661
+ }
1662
+ }
1663
+ };
1664
+ var updateMcpServer = (options) => {
1665
+ const isGlobal = options.global ?? false;
1666
+ const cwd = options.cwd ?? process.cwd();
1667
+ let previousConfig = options.previousConfig;
1668
+ if (!previousConfig) {
1669
+ const existing = listInstalledMcpServers({
1670
+ global: isGlobal,
1671
+ cwd,
1672
+ agents: options.agents
1673
+ });
1674
+ const found = existing.find((s) => s.serverName === options.serverName && s.serverConfig);
1675
+ if (found) {
1676
+ previousConfig = found.serverConfig;
1677
+ }
1678
+ }
1679
+ const serverConfig = sanitizeUpdatedServerConfig(options.config, previousConfig);
1680
+ let targetAgents = options.agents;
1681
+ if (!targetAgents || targetAgents.length === 0) {
1682
+ const existing = listInstalledMcpServers({ global: isGlobal, cwd });
1683
+ targetAgents = existing.filter((s) => s.serverName === options.serverName).map((s) => s.agent);
1684
+ }
1685
+ const requestedTransport = serverConfig.url ? serverConfig.type ?? "http" : "stdio";
1686
+ const { allAgents, incompatible } = resolveTargetAgents({
1687
+ requested: targetAgents,
1688
+ global: isGlobal,
1689
+ cwd,
1690
+ transport: requestedTransport
1691
+ });
1692
+ const results = installToCompatibleAgents(options.serverName, serverConfig, {
1693
+ allAgents,
1694
+ incompatible,
1695
+ global: isGlobal,
1696
+ cwd
1697
+ });
1698
+ return {
1699
+ serverName: options.serverName,
1700
+ config: serverConfig,
1701
+ results,
1702
+ incompatible
1703
+ };
1704
+ };
1705
+
1497
1706
  // src/interactive/main-menu.ts
1498
- var import_prompts11 = require("@inquirer/prompts");
1499
- var import_picocolors11 = __toESM(require("picocolors"), 1);
1707
+ var import_prompts10 = require("@inquirer/prompts");
1708
+ var import_picocolors15 = __toESM(require("picocolors"), 1);
1500
1709
 
1501
1710
  // src/interactive/wizard-add.ts
1502
- var import_prompts8 = require("@inquirer/prompts");
1503
- var import_picocolors8 = __toESM(require("picocolors"), 1);
1711
+ var import_prompts7 = require("@inquirer/prompts");
1712
+ var import_picocolors11 = __toESM(require("picocolors"), 1);
1713
+
1714
+ // src/utils/co-hosted-feedback.ts
1715
+ var import_picocolors2 = __toESM(require("picocolors"), 1);
1504
1716
 
1505
1717
  // src/utils/logger.ts
1506
1718
  var import_picocolors = __toESM(require("picocolors"), 1);
@@ -1519,13 +1731,269 @@ var logger = {
1519
1731
  }
1520
1732
  };
1521
1733
 
1734
+ // src/utils/co-hosted-feedback.ts
1735
+ var formatCoHostedBadge = (kind, agents) => {
1736
+ if (!agents || agents.length === 0) return "";
1737
+ const label = kind === "configured" ? "co-configured" : "co-affected";
1738
+ return ` ${import_picocolors2.default.yellow(`(${label}: ${agents.join(", ")})`)}`;
1739
+ };
1740
+ var logCoHostedNotice = (kind, agents) => {
1741
+ if (!agents || agents.length === 0) return;
1742
+ const actionText = kind === "configured" ? "Also configured for" : "Also affects";
1743
+ logger.info(
1744
+ ` ${import_picocolors2.default.dim("Note:")} ${actionText} co-hosted agent(s): ${import_picocolors2.default.yellow(agents.join(", "))}`
1745
+ );
1746
+ };
1747
+
1522
1748
  // src/interactive/prompts/agents.ts
1523
- var import_prompts2 = require("@inquirer/prompts");
1749
+ var import_picocolors6 = __toESM(require("picocolors"), 1);
1750
+
1751
+ // src/interactive/utils/build-linked-agent-choices.ts
1524
1752
  var import_picocolors3 = __toESM(require("picocolors"), 1);
1753
+ var buildLinkedAgentChoices = (options) => {
1754
+ const { agents, checkedAgents, detectedAgents = [], scopeOptions = {} } = options;
1755
+ const alignedCheckedSet = new Set(checkedAgents);
1756
+ for (const agent of checkedAgents) {
1757
+ const coHosted = getCoHostedAgents(agent, scopeOptions);
1758
+ for (const co of coHosted) {
1759
+ if (agents.includes(co)) {
1760
+ alignedCheckedSet.add(co);
1761
+ }
1762
+ }
1763
+ }
1764
+ return agents.map((agent) => {
1765
+ const config = getMcpAgentConfig(agent);
1766
+ const displayName = config?.displayName ?? agent;
1767
+ const isDetected = detectedAgents.includes(agent);
1768
+ const coHosted = getCoHostedAgents(agent, scopeOptions).filter(
1769
+ (co) => agents.includes(co)
1770
+ );
1771
+ const detectedBadge = isDetected ? import_picocolors3.default.green(" [detected]") : "";
1772
+ const sharedBadge = coHosted.length > 0 ? import_picocolors3.default.dim(` [shared: ${coHosted.join(", ")}]`) : "";
1773
+ const label = `${displayName} ${import_picocolors3.default.dim(`(${agent})`)}${detectedBadge}${sharedBadge}`;
1774
+ return {
1775
+ name: label,
1776
+ value: agent,
1777
+ checked: alignedCheckedSet.has(agent),
1778
+ linkedValues: coHosted,
1779
+ description: coHosted.length > 0 ? `Linked with ${coHosted.map((a) => getMcpAgentConfig(a).displayName).join(", ")} (shared configuration)` : void 0
1780
+ };
1781
+ });
1782
+ };
1783
+
1784
+ // src/interactive/prompts/linked-checkbox.ts
1785
+ var import_core = require("@inquirer/core");
1786
+ var import_picocolors4 = __toESM(require("picocolors"), 1);
1787
+ var defaultTheme = {
1788
+ icon: {
1789
+ checked: import_picocolors4.default.green("[x]"),
1790
+ unchecked: import_picocolors4.default.dim("[ ]"),
1791
+ cursor: import_picocolors4.default.cyan(">"),
1792
+ disabledChecked: import_picocolors4.default.dim("[x]"),
1793
+ disabledUnchecked: import_picocolors4.default.dim("[-]")
1794
+ },
1795
+ style: {
1796
+ disabled: (text) => import_picocolors4.default.dim(text),
1797
+ renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(", "),
1798
+ description: (text) => import_picocolors4.default.cyan(text),
1799
+ keysHelpTip: (keys) => keys.map(([key, action]) => `${import_picocolors4.default.bold(key)} ${import_picocolors4.default.dim(action)}`).join(import_picocolors4.default.dim(" | ")),
1800
+ highlight: (text) => import_picocolors4.default.cyan(text)
1801
+ },
1802
+ i18n: {
1803
+ disabledError: "This option is disabled and cannot be toggled."
1804
+ }
1805
+ };
1806
+ function isSelectable(item) {
1807
+ return !import_core.Separator.isSeparator(item) && !item.disabled;
1808
+ }
1809
+ function isNavigable(item) {
1810
+ return !import_core.Separator.isSeparator(item);
1811
+ }
1812
+ function isChecked(item) {
1813
+ return !import_core.Separator.isSeparator(item) && item.checked;
1814
+ }
1815
+ function normalizeChoices(choices) {
1816
+ return choices.map((choice) => {
1817
+ if (import_core.Separator.isSeparator(choice)) {
1818
+ return choice;
1819
+ }
1820
+ if (typeof choice !== "object" || choice === null || !("value" in choice)) {
1821
+ const name2 = String(choice);
1822
+ return {
1823
+ value: choice,
1824
+ name: name2,
1825
+ short: name2,
1826
+ checkedName: name2,
1827
+ disabled: false,
1828
+ checked: false,
1829
+ linkedValues: []
1830
+ };
1831
+ }
1832
+ const name = choice.name ?? String(choice.value);
1833
+ return {
1834
+ value: choice.value,
1835
+ name,
1836
+ short: choice.short ?? name,
1837
+ checkedName: choice.checkedName ?? name,
1838
+ description: choice.description,
1839
+ disabled: choice.disabled ?? false,
1840
+ checked: choice.checked ?? false,
1841
+ linkedValues: choice.linkedValues ?? []
1842
+ };
1843
+ });
1844
+ }
1845
+ var linkedCheckbox = (0, import_core.createPrompt)(
1846
+ (config, done) => {
1847
+ const { pageSize = 10, loop = true, required, validate = () => true } = config;
1848
+ const theme = (0, import_core.makeTheme)(defaultTheme, config.theme);
1849
+ const [status, setStatus] = (0, import_core.useState)("idle");
1850
+ const prefix = (0, import_core.usePrefix)({ status, theme });
1851
+ const [items, setItems] = (0, import_core.useState)(() => normalizeChoices(config.choices));
1852
+ const bounds = (0, import_core.useMemo)(() => {
1853
+ const first = items.findIndex(isNavigable);
1854
+ let last = -1;
1855
+ for (let i = items.length - 1; i >= 0; i--) {
1856
+ if (isNavigable(items[i])) {
1857
+ last = i;
1858
+ break;
1859
+ }
1860
+ }
1861
+ if (first === -1 || last === -1) {
1862
+ throw new import_core.ValidationError("[linkedCheckbox prompt] No selectable choices.");
1863
+ }
1864
+ return { first, last };
1865
+ }, [items]);
1866
+ const [active, setActive] = (0, import_core.useState)(bounds.first);
1867
+ const [errorMsg, setError] = (0, import_core.useState)();
1868
+ const toggleWithLinked = (targetIndex) => {
1869
+ const targetItem = items[targetIndex];
1870
+ if (!targetItem || import_core.Separator.isSeparator(targetItem) || targetItem.disabled) {
1871
+ return;
1872
+ }
1873
+ const nextChecked = !targetItem.checked;
1874
+ const targetValue = targetItem.value;
1875
+ const linked = new Set(targetItem.linkedValues);
1876
+ setItems(
1877
+ (prevItems) => prevItems.map((item) => {
1878
+ if (import_core.Separator.isSeparator(item) || item.disabled) {
1879
+ return item;
1880
+ }
1881
+ const isTargetOrLinked = item.value === targetValue || linked.has(item.value) || item.linkedValues.includes(targetValue);
1882
+ if (isTargetOrLinked) {
1883
+ return { ...item, checked: nextChecked };
1884
+ }
1885
+ return item;
1886
+ })
1887
+ );
1888
+ };
1889
+ (0, import_core.useKeypress)(async (key) => {
1890
+ if ((0, import_core.isEnterKey)(key)) {
1891
+ const selection = items.filter(isChecked);
1892
+ const isValid = await validate([...selection]);
1893
+ if (required && selection.length === 0) {
1894
+ setError("At least one choice must be selected");
1895
+ } else if (isValid === true) {
1896
+ setStatus("done");
1897
+ done(selection.map((choice) => choice.value));
1898
+ } else {
1899
+ setError(typeof isValid === "string" ? isValid : "You must select a valid value");
1900
+ }
1901
+ } else if ((0, import_core.isUpKey)(key) || (0, import_core.isDownKey)(key)) {
1902
+ if (errorMsg) setError(void 0);
1903
+ if (loop || (0, import_core.isUpKey)(key) && active !== bounds.first || (0, import_core.isDownKey)(key) && active !== bounds.last) {
1904
+ const offset = (0, import_core.isUpKey)(key) ? -1 : 1;
1905
+ let next = active;
1906
+ do {
1907
+ next = (next + offset + items.length) % items.length;
1908
+ } while (!isNavigable(items[next]));
1909
+ setActive(next);
1910
+ }
1911
+ } else if ((0, import_core.isSpaceKey)(key)) {
1912
+ const activeItem = items[active];
1913
+ if (activeItem && !import_core.Separator.isSeparator(activeItem)) {
1914
+ if (activeItem.disabled) {
1915
+ setError(theme.i18n.disabledError);
1916
+ } else {
1917
+ setError(void 0);
1918
+ toggleWithLinked(active);
1919
+ }
1920
+ }
1921
+ } else if (key.name === "a") {
1922
+ const hasUnchecked = items.some((choice) => isSelectable(choice) && !choice.checked);
1923
+ setItems(
1924
+ (prevItems) => prevItems.map((item) => isSelectable(item) ? { ...item, checked: hasUnchecked } : item)
1925
+ );
1926
+ } else if ((0, import_core.isNumberKey)(key)) {
1927
+ const selectedIndex = Number(key.name) - 1;
1928
+ let selectableIndex = -1;
1929
+ const position = items.findIndex((item) => {
1930
+ if (import_core.Separator.isSeparator(item)) return false;
1931
+ selectableIndex++;
1932
+ return selectableIndex === selectedIndex;
1933
+ });
1934
+ const selectedItem = items[position];
1935
+ if (selectedItem && isSelectable(selectedItem)) {
1936
+ setActive(position);
1937
+ setError(void 0);
1938
+ toggleWithLinked(position);
1939
+ }
1940
+ }
1941
+ });
1942
+ const message = theme.style.message(config.message, status);
1943
+ let description;
1944
+ const page = (0, import_core.usePagination)({
1945
+ items,
1946
+ active,
1947
+ renderItem({ item, isActive }) {
1948
+ if (import_core.Separator.isSeparator(item)) {
1949
+ return ` ${item.separator}`;
1950
+ }
1951
+ const cursor = isActive ? theme.icon.cursor : " ";
1952
+ if (item.disabled) {
1953
+ const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
1954
+ const checkbox2 = item.checked ? theme.icon.disabledChecked : theme.icon.disabledUnchecked;
1955
+ return theme.style.disabled(`${cursor} ${checkbox2} ${item.name} ${disabledLabel}`);
1956
+ }
1957
+ if (isActive) {
1958
+ description = item.description;
1959
+ }
1960
+ const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
1961
+ const name = item.checked ? item.checkedName : item.name;
1962
+ const color = isActive ? theme.style.highlight : (x) => x;
1963
+ return color(`${cursor} ${checkbox} ${name}`);
1964
+ },
1965
+ pageSize,
1966
+ loop
1967
+ });
1968
+ if (status === "done") {
1969
+ const selection = items.filter(isChecked);
1970
+ const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
1971
+ return [prefix, message, answer].filter(Boolean).join(" ");
1972
+ }
1973
+ const helpLine = theme.style.keysHelpTip([
1974
+ ["up/down", "navigate"],
1975
+ ["space", "toggle"],
1976
+ ["a", "all"],
1977
+ ["enter", "submit"]
1978
+ ]);
1979
+ const lines = [
1980
+ [prefix, message].filter(Boolean).join(" "),
1981
+ page,
1982
+ helpLine
1983
+ ];
1984
+ if (description) {
1985
+ lines.push(theme.style.description(description));
1986
+ }
1987
+ if (errorMsg) {
1988
+ lines.push(theme.style.error(errorMsg));
1989
+ }
1990
+ return lines.join("\n");
1991
+ }
1992
+ );
1525
1993
 
1526
1994
  // src/interactive/prompts/scope.ts
1527
1995
  var import_prompts = require("@inquirer/prompts");
1528
- var import_picocolors2 = __toESM(require("picocolors"), 1);
1996
+ var import_picocolors5 = __toESM(require("picocolors"), 1);
1529
1997
  var promptScope = async (options = {}) => {
1530
1998
  const initialGlobal = options.defaultGlobal ?? options.global;
1531
1999
  if (initialGlobal !== void 0) {
@@ -1536,11 +2004,11 @@ var promptScope = async (options = {}) => {
1536
2004
  message: options.message ?? "Select MCP scope:",
1537
2005
  choices: [
1538
2006
  {
1539
- name: `Current Project - ${import_picocolors2.default.dim(cwd)}`,
2007
+ name: `Current Project - ${import_picocolors5.default.dim(cwd)}`,
1540
2008
  value: false
1541
2009
  },
1542
2010
  {
1543
- name: `Global User Config - ${import_picocolors2.default.dim("applies across all projects")}`,
2011
+ name: `Global User Config - ${import_picocolors5.default.dim("applies across all projects")}`,
1544
2012
  value: true
1545
2013
  }
1546
2014
  ]
@@ -1560,26 +2028,23 @@ var promptScopeAndAgents = async (options = {}) => {
1560
2028
  cwd
1561
2029
  });
1562
2030
  const detected = resolution.detected;
1563
- const availableAgentTypes = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
2031
+ const rawAvailable = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
2032
+ const availableAgentTypes = sortAgentsWithClusters(rawAvailable, { global: isGlobal, cwd });
1564
2033
  if (detected.length > 0) {
1565
2034
  logger.info(
1566
- `Detected configured agents: ${import_picocolors3.default.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2035
+ `Detected configured agents: ${import_picocolors6.default.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
1567
2036
  );
1568
2037
  } else {
1569
2038
  logger.warn(`No active ${isGlobal ? "global" : "project"} agents detected`);
1570
2039
  }
1571
2040
  const defaultChecked = options.defaultAgents && options.defaultAgents.length > 0 ? options.defaultAgents : detected;
1572
- const choices = availableAgentTypes.map((agentType) => {
1573
- const config = getMcpAgentConfig(agentType);
1574
- const isDetected = detected.includes(agentType);
1575
- const label = `${config.displayName} ${import_picocolors3.default.dim(`(${agentType})`)}${isDetected ? import_picocolors3.default.green(" [detected]") : ""}`;
1576
- return {
1577
- name: label,
1578
- value: agentType,
1579
- checked: defaultChecked.includes(agentType)
1580
- };
2041
+ const choices = buildLinkedAgentChoices({
2042
+ agents: availableAgentTypes,
2043
+ checkedAgents: defaultChecked,
2044
+ detectedAgents: detected,
2045
+ scopeOptions: { global: isGlobal, cwd }
1581
2046
  });
1582
- const selectedAgents = await (0, import_prompts2.checkbox)({
2047
+ const selectedAgents = await linkedCheckbox({
1583
2048
  message: "Select target agents (Space to select, Enter to confirm):",
1584
2049
  choices,
1585
2050
  validate: (chosen) => {
@@ -1596,7 +2061,7 @@ var promptScopeAndAgents = async (options = {}) => {
1596
2061
  };
1597
2062
 
1598
2063
  // src/interactive/prompts/args.ts
1599
- var import_prompts3 = require("@inquirer/prompts");
2064
+ var import_prompts2 = require("@inquirer/prompts");
1600
2065
  var parseArgsString = (rawText) => {
1601
2066
  const matches = rawText.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
1602
2067
  if (!matches) return [];
@@ -1611,14 +2076,14 @@ var promptArgsConfig = async (initialArgs = []) => {
1611
2076
  if (initialArgs.length > 0) {
1612
2077
  return initialArgs;
1613
2078
  }
1614
- const needArgs = await (0, import_prompts3.confirm)({
2079
+ const needArgs = await (0, import_prompts2.confirm)({
1615
2080
  message: "Configure command arguments (e.g. file paths, connection strings)?",
1616
2081
  default: false
1617
2082
  });
1618
2083
  if (!needArgs) {
1619
2084
  return [];
1620
2085
  }
1621
- const raw = await (0, import_prompts3.input)({
2086
+ const raw = await (0, import_prompts2.input)({
1622
2087
  message: "Enter command arguments (space-separated, wrap paths with spaces in quotes):",
1623
2088
  validate: (val) => val.trim() ? true : "Arguments cannot be empty"
1624
2089
  });
@@ -1629,7 +2094,7 @@ var formatArgsString = (args) => {
1629
2094
  };
1630
2095
  var promptEditArgs = async (currentArgs = []) => {
1631
2096
  const defaultStr = formatArgsString(currentArgs);
1632
- const raw = await (0, import_prompts3.input)({
2097
+ const raw = await (0, import_prompts2.input)({
1633
2098
  message: "Edit command arguments (space-separated, wrap paths with spaces in quotes, leave empty to clear):",
1634
2099
  default: defaultStr
1635
2100
  });
@@ -1641,17 +2106,37 @@ var promptEditArgs = async (currentArgs = []) => {
1641
2106
  };
1642
2107
 
1643
2108
  // src/interactive/prompts/env.ts
1644
- var import_prompts6 = require("@inquirer/prompts");
1645
- var import_picocolors6 = __toESM(require("picocolors"), 1);
2109
+ var import_prompts5 = require("@inquirer/prompts");
2110
+ var import_picocolors9 = __toESM(require("picocolors"), 1);
2111
+
2112
+ // src/utils/mask-secret.ts
2113
+ var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
2114
+ var maskSecretValue = (key, value) => {
2115
+ if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
2116
+ return value;
2117
+ }
2118
+ return `${value.slice(0, 2)}***${value.slice(-2)}`;
2119
+ };
2120
+ var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
2121
+ var maskSecretHeader = (key, value) => {
2122
+ if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
2123
+ return value;
2124
+ }
2125
+ return `${value.slice(0, 4)}***${value.slice(-3)}`;
2126
+ };
2127
+
2128
+ // src/interactive/prompts/kv.ts
2129
+ var import_prompts4 = require("@inquirer/prompts");
2130
+ var import_picocolors8 = __toESM(require("picocolors"), 1);
1646
2131
 
1647
2132
  // src/interactive/prompts/multiline.ts
1648
2133
  var import_node_readline = require("readline");
1649
- var import_prompts4 = require("@inquirer/prompts");
1650
- var import_picocolors4 = __toESM(require("picocolors"), 1);
2134
+ var import_prompts3 = require("@inquirer/prompts");
2135
+ var import_picocolors7 = __toESM(require("picocolors"), 1);
1651
2136
  var readMultilineTextFromTerminal = async (message, endHint = "When done pasting, enter END on a new line or press Enter twice to finish") => {
1652
- console.log(import_picocolors4.default.cyan(`
2137
+ console.log(import_picocolors7.default.cyan(`
1653
2138
  ${message}`));
1654
- console.log(import_picocolors4.default.dim(` (Hint: ${endHint})
2139
+ console.log(import_picocolors7.default.dim(` (Hint: ${endHint})
1655
2140
  `));
1656
2141
  return new Promise((resolve) => {
1657
2142
  const rl = (0, import_node_readline.createInterface)({
@@ -1695,7 +2180,7 @@ ${message}`));
1695
2180
  };
1696
2181
  var promptEditorText = async (options) => {
1697
2182
  try {
1698
- return await (0, import_prompts4.editor)({
2183
+ return await (0, import_prompts3.editor)({
1699
2184
  message: options.message,
1700
2185
  default: options.defaultText ?? "",
1701
2186
  postfix: options.postfix
@@ -1706,24 +2191,22 @@ var promptEditorText = async (options) => {
1706
2191
  };
1707
2192
 
1708
2193
  // src/interactive/prompts/kv.ts
1709
- var import_prompts5 = require("@inquirer/prompts");
1710
- var import_picocolors5 = __toESM(require("picocolors"), 1);
1711
2194
  var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1712
2195
  let items = { ...currentItems };
1713
2196
  while (true) {
1714
2197
  const keys = Object.keys(items);
1715
2198
  console.log();
1716
2199
  if (keys.length === 0) {
1717
- console.log(import_picocolors5.default.dim(` No ${options.itemsNoun} configured.`));
2200
+ console.log(import_picocolors8.default.dim(` No ${options.itemsNoun} configured.`));
1718
2201
  } else {
1719
- console.log(import_picocolors5.default.cyan(import_picocolors5.default.bold(` Configured ${options.title} (${keys.length}):`)));
2202
+ console.log(import_picocolors8.default.cyan(import_picocolors8.default.bold(` Configured ${options.title} (${keys.length}):`)));
1720
2203
  for (const [k, v] of Object.entries(items)) {
1721
2204
  const sep = options.separator === "=" ? "=" : ": ";
1722
- console.log(` ${import_picocolors5.default.bold(k)}${sep}${import_picocolors5.default.dim(options.maskValue(k, v))}`);
2205
+ console.log(` ${import_picocolors8.default.bold(k)}${sep}${import_picocolors8.default.dim(options.maskValue(k, v))}`);
1723
2206
  }
1724
2207
  }
1725
2208
  console.log();
1726
- const choice = await (0, import_prompts5.select)({
2209
+ const choice = await (0, import_prompts4.select)({
1727
2210
  message: `Manage ${options.itemsNoun}:`,
1728
2211
  choices: [
1729
2212
  {
@@ -1770,7 +2253,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1770
2253
  items = parsed;
1771
2254
  logger.success(`${options.title} updated (${Object.keys(items).length} total)`);
1772
2255
  } else if (choice === "upsert") {
1773
- const key = await (0, import_prompts5.input)({
2256
+ const key = await (0, import_prompts4.input)({
1774
2257
  message: options.keyPromptMessage,
1775
2258
  validate: (val) => {
1776
2259
  const trimmed = val.trim();
@@ -1784,7 +2267,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1784
2267
  const isSecret = options.isSecretKey(trimmedKey);
1785
2268
  let newVal;
1786
2269
  if (isSecret) {
1787
- newVal = await (0, import_prompts5.password)({
2270
+ newVal = await (0, import_prompts4.password)({
1788
2271
  message: existingVal !== void 0 ? `New value for (${trimmedKey}) [leave empty to keep current]:` : `${options.valuePromptMessage} for (${trimmedKey}) [sensitive content masked]:`,
1789
2272
  mask: "*"
1790
2273
  });
@@ -1792,15 +2275,15 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1792
2275
  newVal = existingVal;
1793
2276
  }
1794
2277
  } else {
1795
- newVal = await (0, import_prompts5.input)({
2278
+ newVal = await (0, import_prompts4.input)({
1796
2279
  message: `${options.valuePromptMessage} for (${trimmedKey}):`,
1797
2280
  default: existingVal
1798
2281
  });
1799
2282
  }
1800
2283
  items[trimmedKey] = newVal;
1801
- logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${import_picocolors5.default.cyan(trimmedKey)}`);
2284
+ logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${import_picocolors8.default.cyan(trimmedKey)}`);
1802
2285
  } else if (choice === "delete") {
1803
- const toDelete = await (0, import_prompts5.select)({
2286
+ const toDelete = await (0, import_prompts4.select)({
1804
2287
  message: `Select ${options.itemNoun} to delete:`,
1805
2288
  choices: [
1806
2289
  ...keys.map((k) => ({ name: k, value: k })),
@@ -1809,7 +2292,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1809
2292
  });
1810
2293
  if (toDelete !== "__cancel__") {
1811
2294
  delete items[toDelete];
1812
- logger.success(`Deleted: ${import_picocolors5.default.cyan(toDelete)}`);
2295
+ logger.success(`Deleted: ${import_picocolors8.default.cyan(toDelete)}`);
1813
2296
  }
1814
2297
  } else if (choice === "paste") {
1815
2298
  const pasted = await readMultilineTextFromTerminal(options.pasteMessage);
@@ -1819,7 +2302,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1819
2302
  logger.warn(`No valid ${options.itemsNoun} recognized`);
1820
2303
  } else {
1821
2304
  if (keys.length > 0) {
1822
- const pasteMode = await (0, import_prompts5.select)({
2305
+ const pasteMode = await (0, import_prompts4.select)({
1823
2306
  message: `How to apply pasted ${options.itemsNoun}?`,
1824
2307
  choices: [
1825
2308
  { name: `Merge with existing ${options.itemsNoun}`, value: "merge" },
@@ -1834,10 +2317,10 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1834
2317
  } else {
1835
2318
  items = parsed;
1836
2319
  }
1837
- logger.success(`Successfully applied ${import_picocolors5.default.cyan(String(count))} ${options.itemsNoun}`);
2320
+ logger.success(`Successfully applied ${import_picocolors8.default.cyan(String(count))} ${options.itemsNoun}`);
1838
2321
  }
1839
2322
  } else if (choice === "clear") {
1840
- const confirmClear = await (0, import_prompts5.confirm)({
2323
+ const confirmClear = await (0, import_prompts4.confirm)({
1841
2324
  message: `Are you sure you want to clear all ${options.itemsNoun}?`,
1842
2325
  default: false
1843
2326
  });
@@ -1850,13 +2333,6 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1850
2333
  };
1851
2334
 
1852
2335
  // src/interactive/prompts/env.ts
1853
- var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
1854
- var maskSecretValue = (key, value) => {
1855
- if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
1856
- return value;
1857
- }
1858
- return `${value.slice(0, 2)}***${value.slice(-2)}`;
1859
- };
1860
2336
  var formatEnvText = (env) => {
1861
2337
  return Object.entries(env).map(([key, value]) => {
1862
2338
  if (/[\s"']/.test(value)) {
@@ -1890,9 +2366,9 @@ var promptEnvConfig = async (initialEnv = {}) => {
1890
2366
  const env = { ...initialEnv };
1891
2367
  const initialCount = Object.keys(env).length;
1892
2368
  if (initialCount > 0) {
1893
- logger.info(`Includes ${import_picocolors6.default.cyan(String(initialCount))} preset environment variables`);
2369
+ logger.info(`Includes ${import_picocolors9.default.cyan(String(initialCount))} preset environment variables`);
1894
2370
  }
1895
- const mode = await (0, import_prompts6.select)({
2371
+ const mode = await (0, import_prompts5.select)({
1896
2372
  message: "Configure environment variables?",
1897
2373
  choices: [
1898
2374
  {
@@ -1928,16 +2404,16 @@ var promptEnvConfig = async (initialEnv = {}) => {
1928
2404
  logger.warn("No valid KEY=VALUE pairs recognized");
1929
2405
  } else {
1930
2406
  Object.assign(env, parsed);
1931
- logger.success(`Successfully parsed ${import_picocolors6.default.cyan(String(count))} environment variables:`);
2407
+ logger.success(`Successfully parsed ${import_picocolors9.default.cyan(String(count))} environment variables:`);
1932
2408
  for (const [k, v] of Object.entries(parsed)) {
1933
- console.log(` ${import_picocolors6.default.bold(k)}=${import_picocolors6.default.dim(maskSecretValue(k, v))}`);
2409
+ console.log(` ${import_picocolors9.default.bold(k)}=${import_picocolors9.default.dim(maskSecretValue(k, v))}`);
1934
2410
  }
1935
2411
  }
1936
2412
  return env;
1937
2413
  }
1938
2414
  logger.info("Entering environment variables (leave key empty and press enter to finish):");
1939
2415
  while (true) {
1940
- const key = await (0, import_prompts6.input)({
2416
+ const key = await (0, import_prompts5.input)({
1941
2417
  message: "Variable name (Key, leave empty to finish):",
1942
2418
  validate: (val2) => {
1943
2419
  const trimmed = val2.trim();
@@ -1951,17 +2427,17 @@ var promptEnvConfig = async (initialEnv = {}) => {
1951
2427
  const isSecret = SECRET_KEY_PATTERN.test(trimmedKey);
1952
2428
  let val;
1953
2429
  if (isSecret) {
1954
- val = await (0, import_prompts6.password)({
2430
+ val = await (0, import_prompts5.password)({
1955
2431
  message: `Value for (${trimmedKey}) [secret masked]:`,
1956
2432
  mask: "*"
1957
2433
  });
1958
2434
  } else {
1959
- val = await (0, import_prompts6.input)({
2435
+ val = await (0, import_prompts5.input)({
1960
2436
  message: `Value for (${trimmedKey}):`
1961
2437
  });
1962
2438
  }
1963
2439
  env[trimmedKey] = val;
1964
- logger.success(`Added: ${import_picocolors6.default.cyan(trimmedKey)}`);
2440
+ logger.success(`Added: ${import_picocolors9.default.cyan(trimmedKey)}`);
1965
2441
  }
1966
2442
  return env;
1967
2443
  };
@@ -1982,15 +2458,8 @@ var promptEditEnvConfig = async (currentEnv = {}) => promptEditKeyValueConfig(cu
1982
2458
  });
1983
2459
 
1984
2460
  // src/interactive/prompts/headers.ts
1985
- var import_prompts7 = require("@inquirer/prompts");
1986
- var import_picocolors7 = __toESM(require("picocolors"), 1);
1987
- var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
1988
- var maskSecretHeader = (key, value) => {
1989
- if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
1990
- return value;
1991
- }
1992
- return `${value.slice(0, 4)}***${value.slice(-3)}`;
1993
- };
2461
+ var import_prompts6 = require("@inquirer/prompts");
2462
+ var import_picocolors10 = __toESM(require("picocolors"), 1);
1994
2463
  var formatHeadersText = (headers) => {
1995
2464
  return Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join("\n");
1996
2465
  };
@@ -2023,7 +2492,7 @@ var parseHeadersText = (rawText) => {
2023
2492
  };
2024
2493
  var promptHeadersConfig = async (initialHeaders = {}) => {
2025
2494
  const headers = { ...initialHeaders };
2026
- const mode = await (0, import_prompts7.select)({
2495
+ const mode = await (0, import_prompts6.select)({
2027
2496
  message: "Select HTTP headers configuration method:",
2028
2497
  choices: [
2029
2498
  {
@@ -2060,16 +2529,16 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
2060
2529
  logger.warn("No valid Key: Value pairs recognized");
2061
2530
  } else {
2062
2531
  Object.assign(headers, parsed);
2063
- logger.success(`Successfully parsed ${import_picocolors7.default.cyan(String(count))} headers:`);
2532
+ logger.success(`Successfully parsed ${import_picocolors10.default.cyan(String(count))} headers:`);
2064
2533
  for (const [k, v] of Object.entries(parsed)) {
2065
- console.log(` ${import_picocolors7.default.bold(k)}: ${import_picocolors7.default.dim(maskSecretHeader(k, v))}`);
2534
+ console.log(` ${import_picocolors10.default.bold(k)}: ${import_picocolors10.default.dim(maskSecretHeader(k, v))}`);
2066
2535
  }
2067
2536
  }
2068
2537
  return headers;
2069
2538
  }
2070
2539
  logger.info("Entering HTTP headers (leave header name empty and press enter to finish):");
2071
2540
  while (true) {
2072
- const name = await (0, import_prompts7.input)({
2541
+ const name = await (0, import_prompts6.input)({
2073
2542
  message: "Header name (e.g. Authorization, leave empty to finish):",
2074
2543
  validate: (val2) => {
2075
2544
  const trimmed = val2.trim();
@@ -2083,17 +2552,17 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
2083
2552
  const isSecret = SECRET_HEADER_PATTERN.test(trimmedName);
2084
2553
  let val;
2085
2554
  if (isSecret) {
2086
- val = await (0, import_prompts7.password)({
2555
+ val = await (0, import_prompts6.password)({
2087
2556
  message: `Header value for (${trimmedName}) [sensitive content masked]:`,
2088
2557
  mask: "*"
2089
2558
  });
2090
2559
  } else {
2091
- val = await (0, import_prompts7.input)({
2560
+ val = await (0, import_prompts6.input)({
2092
2561
  message: `Header value for (${trimmedName}):`
2093
2562
  });
2094
2563
  }
2095
2564
  headers[trimmedName] = val;
2096
- logger.success(`Added: ${import_picocolors7.default.cyan(trimmedName)}`);
2565
+ logger.success(`Added: ${import_picocolors10.default.cyan(trimmedName)}`);
2097
2566
  }
2098
2567
  return headers;
2099
2568
  };
@@ -2115,10 +2584,10 @@ var promptEditHeadersConfig = async (currentHeaders = {}) => promptEditKeyValueC
2115
2584
  // src/interactive/wizard-add.ts
2116
2585
  var wizardAdd = async (initial = {}) => {
2117
2586
  const cwd = initial.cwd ?? process.cwd();
2118
- logger.info(import_picocolors8.default.bold("Welcome to the MCP interactive add wizard"));
2587
+ logger.info(import_picocolors11.default.bold("Welcome to the MCP interactive add wizard"));
2119
2588
  let source = initial.source;
2120
2589
  if (!source) {
2121
- const sourceType = await (0, import_prompts8.select)({
2590
+ const sourceType = await (0, import_prompts7.select)({
2122
2591
  message: "Select MCP server type:",
2123
2592
  choices: [
2124
2593
  {
@@ -2136,12 +2605,12 @@ var wizardAdd = async (initial = {}) => {
2136
2605
  ]
2137
2606
  });
2138
2607
  if (sourceType === "npm") {
2139
- source = await (0, import_prompts8.input)({
2608
+ source = await (0, import_prompts7.input)({
2140
2609
  message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres):",
2141
2610
  validate: (val) => val.trim() ? true : "Package name cannot be empty"
2142
2611
  });
2143
2612
  } else if (sourceType === "remote") {
2144
- source = await (0, import_prompts8.input)({
2613
+ source = await (0, import_prompts7.input)({
2145
2614
  message: "Enter remote server URL (e.g. https://mcp.example.com/sse):",
2146
2615
  validate: (val) => {
2147
2616
  const trimmed = val.trim();
@@ -2151,7 +2620,7 @@ var wizardAdd = async (initial = {}) => {
2151
2620
  }
2152
2621
  });
2153
2622
  } else {
2154
- source = await (0, import_prompts8.input)({
2623
+ source = await (0, import_prompts7.input)({
2155
2624
  message: "Enter command and arguments (e.g. python -m my_mcp_server or docker run ...):",
2156
2625
  validate: (val) => val.trim() ? true : "Command cannot be empty"
2157
2626
  });
@@ -2161,7 +2630,7 @@ var wizardAdd = async (initial = {}) => {
2161
2630
  const parsed = parseMcpSource(source);
2162
2631
  let serverName = initial.name;
2163
2632
  if (!serverName) {
2164
- serverName = await (0, import_prompts8.input)({
2633
+ serverName = await (0, import_prompts7.input)({
2165
2634
  message: "MCP server name:",
2166
2635
  default: parsed.inferredName,
2167
2636
  validate: (val) => val.trim() ? true : "Server name cannot be empty"
@@ -2173,7 +2642,7 @@ var wizardAdd = async (initial = {}) => {
2173
2642
  if (parsed.type === "remote") {
2174
2643
  if (!transport) {
2175
2644
  const isSseUrl = /\/sse\b/i.test(parsed.value);
2176
- transport = await (0, import_prompts8.select)({
2645
+ transport = await (0, import_prompts7.select)({
2177
2646
  message: "Select remote transport protocol:",
2178
2647
  choices: [
2179
2648
  { name: "HTTP", value: "http" },
@@ -2183,7 +2652,7 @@ var wizardAdd = async (initial = {}) => {
2183
2652
  });
2184
2653
  }
2185
2654
  if (Object.keys(headers).length === 0) {
2186
- const needHeader = await (0, import_prompts8.confirm)({
2655
+ const needHeader = await (0, import_prompts7.confirm)({
2187
2656
  message: "Configure HTTP headers (e.g. Authorization Bearer token)?",
2188
2657
  default: false
2189
2658
  });
@@ -2205,28 +2674,28 @@ var wizardAdd = async (initial = {}) => {
2205
2674
  if (parsed.type !== "remote") {
2206
2675
  env = await promptEnvConfig(env);
2207
2676
  }
2208
- console.log("\n" + import_picocolors8.default.cyan(import_picocolors8.default.bold("Configuration Preview:")));
2209
- console.log(` ${import_picocolors8.default.bold("Server Name:")} ${import_picocolors8.default.green(serverName)}`);
2210
- console.log(` ${import_picocolors8.default.bold("Server Type:")} ${import_picocolors8.default.magenta(parsed.type)}`);
2211
- console.log(` ${import_picocolors8.default.bold("Source/Command:")} ${import_picocolors8.default.dim(source)}`);
2212
- console.log(` ${import_picocolors8.default.bold("Scope:")} ${isGlobal ? import_picocolors8.default.yellow("Global") : import_picocolors8.default.blue("Project")}`);
2213
- console.log(` ${import_picocolors8.default.bold("Target Agents:")} ${import_picocolors8.default.cyan(selectedAgents.join(", "))}`);
2677
+ console.log("\n" + import_picocolors11.default.cyan(import_picocolors11.default.bold("Configuration Preview:")));
2678
+ console.log(` ${import_picocolors11.default.bold("Server Name:")} ${import_picocolors11.default.green(serverName)}`);
2679
+ console.log(` ${import_picocolors11.default.bold("Server Type:")} ${import_picocolors11.default.magenta(parsed.type)}`);
2680
+ console.log(` ${import_picocolors11.default.bold("Source/Command:")} ${import_picocolors11.default.dim(source)}`);
2681
+ console.log(` ${import_picocolors11.default.bold("Scope:")} ${isGlobal ? import_picocolors11.default.yellow("Global") : import_picocolors11.default.blue("Project")}`);
2682
+ console.log(` ${import_picocolors11.default.bold("Target Agents:")} ${import_picocolors11.default.cyan(selectedAgents.join(", "))}`);
2214
2683
  if (args.length > 0) {
2215
- console.log(` ${import_picocolors8.default.bold("Arguments:")} ${import_picocolors8.default.dim(args.join(" "))}`);
2684
+ console.log(` ${import_picocolors11.default.bold("Arguments:")} ${import_picocolors11.default.dim(args.join(" "))}`);
2216
2685
  }
2217
2686
  if (transport) {
2218
- console.log(` ${import_picocolors8.default.bold("Transport:")} ${import_picocolors8.default.magenta(transport)}`);
2687
+ console.log(` ${import_picocolors11.default.bold("Transport:")} ${import_picocolors11.default.magenta(transport)}`);
2219
2688
  }
2220
2689
  const envKeys = Object.keys(env);
2221
2690
  if (envKeys.length > 0) {
2222
- console.log(` ${import_picocolors8.default.bold("Environment Variables:")} ${import_picocolors8.default.dim(envKeys.join(", "))} (${envKeys.length})`);
2691
+ console.log(` ${import_picocolors11.default.bold("Environment Variables:")} ${import_picocolors11.default.dim(envKeys.join(", "))} (${envKeys.length})`);
2223
2692
  }
2224
2693
  const headerKeys = Object.keys(headers);
2225
2694
  if (headerKeys.length > 0) {
2226
- console.log(` ${import_picocolors8.default.bold("Headers:")} ${import_picocolors8.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
2695
+ console.log(` ${import_picocolors11.default.bold("Headers:")} ${import_picocolors11.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
2227
2696
  }
2228
2697
  console.log();
2229
- const proceed = await (0, import_prompts8.confirm)({
2698
+ const proceed = await (0, import_prompts7.confirm)({
2230
2699
  message: "Confirm installation with this configuration?",
2231
2700
  default: true
2232
2701
  });
@@ -2246,103 +2715,162 @@ var wizardAdd = async (initial = {}) => {
2246
2715
  env
2247
2716
  });
2248
2717
  logger.info(
2249
- `Writing ${import_picocolors8.default.bold(result.serverName)} to ${import_picocolors8.default.cyan(String(result.results.length))} agent config files...`
2718
+ `Writing ${import_picocolors11.default.bold(result.serverName)} to ${import_picocolors11.default.cyan(String(result.results.length))} agent config files...`
2250
2719
  );
2251
2720
  let allSuccess = true;
2252
2721
  for (const record of result.results) {
2253
2722
  if (record.success) {
2254
- logger.success(`${import_picocolors8.default.cyan(record.agent)}: Successfully written to ${import_picocolors8.default.dim(record.path)}`);
2723
+ logger.success(
2724
+ `${import_picocolors11.default.cyan(record.agent)}: Successfully written to ${import_picocolors11.default.dim(record.path)}${formatCoHostedBadge("configured", record.coConfiguredAgents)}`
2725
+ );
2255
2726
  } else {
2256
2727
  allSuccess = false;
2257
- logger.error(`${import_picocolors8.default.cyan(record.agent)}: Failed to write - ${record.error}`);
2728
+ logger.error(`${import_picocolors11.default.cyan(record.agent)}: Failed to write - ${record.error}`);
2258
2729
  }
2259
2730
  }
2260
2731
  if (allSuccess) {
2261
- logger.success(import_picocolors8.default.bold(`MCP server "${serverName}" configured successfully!`));
2732
+ logger.success(import_picocolors11.default.bold(`MCP server "${serverName}" configured successfully!`));
2262
2733
  }
2263
2734
  return allSuccess;
2264
2735
  };
2265
2736
 
2266
2737
  // src/interactive/wizard-manage.ts
2267
- var import_prompts9 = require("@inquirer/prompts");
2268
- var import_picocolors9 = __toESM(require("picocolors"), 1);
2269
-
2270
- // src/interactive/utils/group-installed-servers.ts
2271
- var normalizeServerConfig = parseServerConfig;
2272
- var groupInstalledServersByName = (installed) => {
2273
- const grouped = /* @__PURE__ */ new Map();
2274
- for (const item of installed) {
2275
- let entry = grouped.get(item.serverName);
2276
- if (!entry) {
2277
- entry = {
2278
- serverName: item.serverName,
2279
- agents: [],
2280
- paths: [],
2281
- config: normalizeServerConfig(item.config)
2282
- };
2283
- grouped.set(item.serverName, entry);
2284
- }
2285
- if (!entry.agents.includes(item.agent)) {
2286
- entry.agents.push(item.agent);
2287
- }
2288
- if (!entry.paths.includes(item.path)) {
2289
- entry.paths.push(item.path);
2290
- }
2291
- }
2292
- return grouped;
2293
- };
2738
+ var import_prompts8 = require("@inquirer/prompts");
2739
+ var import_picocolors13 = __toESM(require("picocolors"), 1);
2294
2740
 
2295
- // src/interactive/wizard-manage.ts
2741
+ // src/utils/display-server-details.ts
2742
+ var import_picocolors12 = __toESM(require("picocolors"), 1);
2296
2743
  var displayServerDetails = ({
2297
2744
  serverName,
2298
2745
  config,
2299
2746
  agents,
2300
- isGlobal,
2747
+ hasDivergence,
2748
+ global: isGlobal,
2301
2749
  titlePrefix = "MCP Server Details"
2302
2750
  }) => {
2303
- console.log("\n" + import_picocolors9.default.cyan(import_picocolors9.default.bold(`${titlePrefix}: [${serverName}]`)));
2751
+ console.log("\n" + import_picocolors12.default.cyan(import_picocolors12.default.bold(`${titlePrefix}: [${serverName}]`)));
2304
2752
  if (isGlobal !== void 0) {
2305
- console.log(` ${import_picocolors9.default.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
2753
+ console.log(` ${import_picocolors12.default.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
2306
2754
  }
2307
2755
  if (agents && agents.length > 0) {
2308
2756
  console.log(
2309
- ` ${import_picocolors9.default.bold("Configured Agents:")} ${import_picocolors9.default.green(agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2757
+ ` ${import_picocolors12.default.bold("Configured Agents:")} ${import_picocolors12.default.green(agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2758
+ );
2759
+ }
2760
+ if (hasDivergence) {
2761
+ console.log(
2762
+ ` ${import_picocolors12.default.yellow(import_picocolors12.default.bold("Notice:"))} ${import_picocolors12.default.yellow("Configurations differ across installed agents. Showing configuration from the first agent.")}`
2310
2763
  );
2311
2764
  }
2312
2765
  const isRemote = Boolean(config.url && config.url.length > 0);
2313
2766
  if (isRemote) {
2314
- console.log(` ${import_picocolors9.default.bold("Transport:")} ${import_picocolors9.default.magenta(config.type ?? "http")}`);
2315
- console.log(` ${import_picocolors9.default.bold("URL:")} ${import_picocolors9.default.dim(config.url ?? "")}`);
2767
+ console.log(` ${import_picocolors12.default.bold("Transport:")} ${import_picocolors12.default.magenta(config.type ?? "http")}`);
2768
+ console.log(` ${import_picocolors12.default.bold("URL:")} ${import_picocolors12.default.dim(config.url ?? "")}`);
2316
2769
  const headerKeys = Object.keys(config.headers ?? {});
2317
2770
  if (headerKeys.length > 0) {
2318
- console.log(` ${import_picocolors9.default.bold("Headers:")} ${import_picocolors9.default.cyan(String(headerKeys.length))}`);
2771
+ console.log(` ${import_picocolors12.default.bold("Headers:")} ${import_picocolors12.default.cyan(String(headerKeys.length))}`);
2319
2772
  for (const [k, v] of Object.entries(config.headers ?? {})) {
2320
- console.log(` ${import_picocolors9.default.bold(k)}: ${import_picocolors9.default.dim(maskSecretHeader(k, v))}`);
2773
+ console.log(` ${import_picocolors12.default.bold(k)}: ${import_picocolors12.default.dim(maskSecretHeader(k, v))}`);
2321
2774
  }
2322
2775
  } else {
2323
- console.log(` ${import_picocolors9.default.bold("Headers:")} ${import_picocolors9.default.dim("(none)")}`);
2776
+ console.log(` ${import_picocolors12.default.bold("Headers:")} ${import_picocolors12.default.dim("(none)")}`);
2324
2777
  }
2325
2778
  } else {
2326
- console.log(` ${import_picocolors9.default.bold("Command:")} ${import_picocolors9.default.magenta(config.command ?? "")}`);
2779
+ console.log(` ${import_picocolors12.default.bold("Command:")} ${import_picocolors12.default.magenta(config.command ?? "")}`);
2327
2780
  const argsStr = config.args && config.args.length > 0 ? config.args.join(" ") : "(none)";
2328
- console.log(` ${import_picocolors9.default.bold("Arguments:")} ${import_picocolors9.default.dim(argsStr)}`);
2781
+ console.log(` ${import_picocolors12.default.bold("Arguments:")} ${import_picocolors12.default.dim(argsStr)}`);
2329
2782
  const envKeys = Object.keys(config.env ?? {});
2330
2783
  if (envKeys.length > 0) {
2331
- console.log(` ${import_picocolors9.default.bold("Environment Variables:")} ${import_picocolors9.default.cyan(String(envKeys.length))}`);
2784
+ console.log(` ${import_picocolors12.default.bold("Environment Variables:")} ${import_picocolors12.default.cyan(String(envKeys.length))}`);
2332
2785
  for (const [k, v] of Object.entries(config.env ?? {})) {
2333
- console.log(` ${import_picocolors9.default.bold(k)}=${import_picocolors9.default.dim(maskSecretValue(k, v))}`);
2786
+ console.log(` ${import_picocolors12.default.bold(k)}=${import_picocolors12.default.dim(maskSecretValue(k, v))}`);
2334
2787
  }
2335
2788
  } else {
2336
- console.log(` ${import_picocolors9.default.bold("Environment Variables:")} ${import_picocolors9.default.dim("(none)")}`);
2789
+ console.log(` ${import_picocolors12.default.bold("Environment Variables:")} ${import_picocolors12.default.dim("(none)")}`);
2337
2790
  }
2338
2791
  }
2339
2792
  console.log();
2340
2793
  };
2341
- var handleEditServerConfig = async ({
2342
- targetGroup,
2343
- isGlobal,
2344
- cwd
2345
- }) => {
2794
+
2795
+ // src/interactive/utils/group-installed-servers.ts
2796
+ var normalizeServerConfig = parseServerConfig;
2797
+ var groupInstalledServersByName = (installed) => {
2798
+ const grouped = /* @__PURE__ */ new Map();
2799
+ for (const item of installed) {
2800
+ const itemConfig = normalizeServerConfig(item.config);
2801
+ let entry = grouped.get(item.serverName);
2802
+ if (!entry) {
2803
+ entry = {
2804
+ serverName: item.serverName,
2805
+ agents: [],
2806
+ paths: [],
2807
+ config: itemConfig,
2808
+ hasDivergence: false
2809
+ };
2810
+ grouped.set(item.serverName, entry);
2811
+ } else if (!entry.hasDivergence) {
2812
+ if (JSON.stringify(entry.config) !== JSON.stringify(itemConfig)) {
2813
+ entry.hasDivergence = true;
2814
+ }
2815
+ }
2816
+ if (!entry.agents.includes(item.agent)) {
2817
+ entry.agents.push(item.agent);
2818
+ }
2819
+ if (!entry.paths.includes(item.path)) {
2820
+ entry.paths.push(item.path);
2821
+ }
2822
+ }
2823
+ return grouped;
2824
+ };
2825
+
2826
+ // src/interactive/wizard-manage.ts
2827
+ var promptSwitchServerType = async (currentConfig, serverName) => {
2828
+ const isRemote = Boolean(currentConfig.url && currentConfig.url.length > 0);
2829
+ if (isRemote) {
2830
+ const newCmd = await (0, import_prompts8.input)({
2831
+ message: "Executable command (e.g. node, npx):",
2832
+ validate: (val) => val.trim() ? true : "Command cannot be empty"
2833
+ });
2834
+ const newArgs = await promptEditArgs([]);
2835
+ const newEnv = await promptEditEnvConfig({});
2836
+ logger.success(`Switched [${serverName}] configuration to stdio mode`);
2837
+ return {
2838
+ command: newCmd.trim(),
2839
+ args: newArgs.length > 0 ? newArgs : void 0,
2840
+ env: Object.keys(newEnv).length > 0 ? newEnv : void 0
2841
+ };
2842
+ }
2843
+ const newUrl = await (0, import_prompts8.input)({
2844
+ message: "Remote server URL:",
2845
+ validate: (val) => {
2846
+ const trimmed = val.trim();
2847
+ if (!trimmed) return "URL cannot be empty";
2848
+ if (!/^https?:\/\//i.test(trimmed)) {
2849
+ return "Please enter a valid URL starting with http:// or https://";
2850
+ }
2851
+ return true;
2852
+ }
2853
+ });
2854
+ const transport = await (0, import_prompts8.select)({
2855
+ message: "Select remote transport protocol:",
2856
+ choices: [
2857
+ { name: "HTTP", value: "http" },
2858
+ { name: "SSE (Server-Sent Events)", value: "sse" }
2859
+ ],
2860
+ default: "http"
2861
+ });
2862
+ const newHeaders = await promptEditHeadersConfig({});
2863
+ logger.success(`Switched [${serverName}] configuration to remote mode`);
2864
+ return {
2865
+ url: newUrl.trim(),
2866
+ type: transport,
2867
+ headers: Object.keys(newHeaders).length > 0 ? newHeaders : void 0
2868
+ };
2869
+ };
2870
+ var handleEditServerConfig = async (options) => {
2871
+ const { targetGroup } = options;
2872
+ const isGlobal = options.global ?? false;
2873
+ const cwd = options.cwd ?? process.cwd();
2346
2874
  const serverName = targetGroup.serverName;
2347
2875
  let workingConfig = {
2348
2876
  ...targetGroup.config,
@@ -2361,6 +2889,7 @@ var handleEditServerConfig = async ({
2361
2889
  { name: "Edit HTTP Headers (headers)", value: "headers" },
2362
2890
  { name: "Edit Remote URL (url)", value: "url" },
2363
2891
  { name: "Edit Transport Protocol (type)", value: "transport" },
2892
+ { name: "Switch to local command (stdio)", value: "switch_type" },
2364
2893
  { name: "Reset changes to original", value: "reset" },
2365
2894
  { name: "Save and apply changes", value: "save" },
2366
2895
  { name: "Cancel (discard changes)", value: "cancel" }
@@ -2368,11 +2897,12 @@ var handleEditServerConfig = async ({
2368
2897
  { name: "Edit Environment Variables (env)", value: "env" },
2369
2898
  { name: "Edit Command Arguments (args)", value: "args" },
2370
2899
  { name: "Edit Executable Command (command)", value: "command" },
2900
+ { name: "Switch to remote server (HTTP/SSE)", value: "switch_type" },
2371
2901
  { name: "Reset changes to original", value: "reset" },
2372
2902
  { name: "Save and apply changes", value: "save" },
2373
2903
  { name: "Cancel (discard changes)", value: "cancel" }
2374
2904
  ];
2375
- const editAction = await (0, import_prompts9.select)({
2905
+ const editAction = await (0, import_prompts8.select)({
2376
2906
  message: `What would you like to modify in [${serverName}]?`,
2377
2907
  choices: editChoices
2378
2908
  });
@@ -2390,12 +2920,16 @@ var handleEditServerConfig = async ({
2390
2920
  logger.info("Configuration reset to original");
2391
2921
  continue;
2392
2922
  }
2923
+ if (editAction === "switch_type") {
2924
+ workingConfig = await promptSwitchServerType(workingConfig, serverName);
2925
+ continue;
2926
+ }
2393
2927
  if (editAction === "env") {
2394
2928
  workingConfig.env = await promptEditEnvConfig(workingConfig.env ?? {});
2395
2929
  } else if (editAction === "args") {
2396
2930
  workingConfig.args = await promptEditArgs(workingConfig.args ?? []);
2397
2931
  } else if (editAction === "command") {
2398
- const newCmd = await (0, import_prompts9.input)({
2932
+ const newCmd = await (0, import_prompts8.input)({
2399
2933
  message: "Executable command:",
2400
2934
  default: workingConfig.command,
2401
2935
  validate: (val) => val.trim() ? true : "Command cannot be empty"
@@ -2404,7 +2938,7 @@ var handleEditServerConfig = async ({
2404
2938
  } else if (editAction === "headers") {
2405
2939
  workingConfig.headers = await promptEditHeadersConfig(workingConfig.headers ?? {});
2406
2940
  } else if (editAction === "url") {
2407
- const newUrl = await (0, import_prompts9.input)({
2941
+ const newUrl = await (0, import_prompts8.input)({
2408
2942
  message: "Remote server URL:",
2409
2943
  default: workingConfig.url,
2410
2944
  validate: (val) => {
@@ -2418,7 +2952,7 @@ var handleEditServerConfig = async ({
2418
2952
  });
2419
2953
  workingConfig.url = newUrl.trim();
2420
2954
  } else if (editAction === "transport") {
2421
- workingConfig.type = await (0, import_prompts9.select)({
2955
+ workingConfig.type = await (0, import_prompts8.select)({
2422
2956
  message: "Select remote transport protocol:",
2423
2957
  choices: [
2424
2958
  { name: "HTTP", value: "http" },
@@ -2429,42 +2963,46 @@ var handleEditServerConfig = async ({
2429
2963
  } else if (editAction === "save") {
2430
2964
  let targetAgents = targetGroup.agents;
2431
2965
  if (targetGroup.agents.length > 1) {
2432
- targetAgents = await (0, import_prompts9.checkbox)({
2966
+ const sortedAgents = sortAgentsWithClusters(targetGroup.agents, { global: isGlobal, cwd });
2967
+ const choices = buildLinkedAgentChoices({
2968
+ agents: sortedAgents,
2969
+ checkedAgents: sortedAgents,
2970
+ scopeOptions: { global: isGlobal, cwd }
2971
+ });
2972
+ targetAgents = await linkedCheckbox({
2433
2973
  message: "Select agents to update configuration (Space to toggle):",
2434
- choices: targetGroup.agents.map((a) => ({
2435
- name: `${getMcpAgentConfig(a).displayName} (${a})`,
2436
- value: a,
2437
- checked: true
2438
- })),
2974
+ choices,
2439
2975
  loop: false,
2440
2976
  validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2441
2977
  });
2442
- }
2443
- const requestedTransport = workingConfig.url ? workingConfig.type ?? "http" : "stdio";
2444
- const compatibleAgents = [];
2445
- const incompatibleAgents = [];
2446
- for (const agent of targetAgents) {
2447
- const agentConfig = getMcpAgentConfig(agent);
2448
- if (isMcpTransportSupported(agentConfig, requestedTransport)) {
2449
- compatibleAgents.push(agent);
2450
- } else {
2451
- const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
2452
- incompatibleAgents.push({ agent, reason });
2978
+ if (targetAgents.length < targetGroup.agents.length) {
2979
+ const unselected = targetGroup.agents.filter((a) => !targetAgents.includes(a));
2980
+ const unselectedNames = unselected.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2981
+ logger.info(
2982
+ `Note: Updating only a subset of agents. Server configurations will diverge from: ${unselectedNames}.`
2983
+ );
2453
2984
  }
2454
2985
  }
2455
- if (incompatibleAgents.length > 0) {
2456
- for (const item of incompatibleAgents) {
2457
- logger.warn(`Skipping ${import_picocolors9.default.cyan(item.agent)}: ${item.reason}`);
2986
+ const requestedTransport = workingConfig.url ? workingConfig.type ?? "http" : "stdio";
2987
+ const resolution = resolveTargetAgents({
2988
+ requested: targetAgents,
2989
+ global: isGlobal,
2990
+ cwd,
2991
+ transport: requestedTransport
2992
+ });
2993
+ if (resolution.incompatible.length > 0) {
2994
+ for (const item of resolution.incompatible) {
2995
+ logger.warn(`Skipping ${import_picocolors13.default.cyan(item.agent)}: ${item.reason}`);
2458
2996
  }
2459
2997
  }
2460
- if (compatibleAgents.length === 0) {
2998
+ if (resolution.compatibleAgents.length === 0) {
2461
2999
  logger.error(
2462
3000
  `None of the selected agents support ${requestedTransport} transport. Cannot update.`
2463
3001
  );
2464
3002
  continue;
2465
3003
  }
2466
- const agentNames = compatibleAgents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2467
- const confirmed = await (0, import_prompts9.confirm)({
3004
+ const agentNames = resolution.compatibleAgents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
3005
+ const confirmed = await (0, import_prompts8.confirm)({
2468
3006
  message: `Confirm updating configuration for [${serverName}] across: ${agentNames}?`,
2469
3007
  default: true
2470
3008
  });
@@ -2472,22 +3010,32 @@ var handleEditServerConfig = async ({
2472
3010
  logger.warn("Update cancelled");
2473
3011
  continue;
2474
3012
  }
2475
- for (const targetAgent of compatibleAgents) {
2476
- const res = installMcpServerForAgent(serverName, workingConfig, targetAgent, {
2477
- global: isGlobal,
2478
- cwd
2479
- });
3013
+ const updateResult = updateMcpServer({
3014
+ serverName,
3015
+ config: workingConfig,
3016
+ previousConfig: targetGroup.config,
3017
+ agents: resolution.compatibleAgents,
3018
+ global: isGlobal,
3019
+ cwd
3020
+ });
3021
+ let updatedAny = false;
3022
+ const succeededAgents = [];
3023
+ for (const res of updateResult.results) {
2480
3024
  if (res.success) {
3025
+ updatedAny = true;
3026
+ succeededAgents.push(res.agent);
2481
3027
  logger.success(
2482
- `${import_picocolors9.default.cyan(targetAgent)}: Successfully updated configuration in ${import_picocolors9.default.dim(res.path)}`
3028
+ `${import_picocolors13.default.cyan(res.agent)}: Successfully updated configuration in ${import_picocolors13.default.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
2483
3029
  );
2484
3030
  } else {
2485
- logger.error(`${import_picocolors9.default.cyan(targetAgent)}: Update failed - ${res.error}`);
3031
+ logger.error(`${import_picocolors13.default.cyan(res.agent)}: Update failed - ${res.error}`);
2486
3032
  }
2487
3033
  }
2488
- targetGroup.config = workingConfig;
2489
- logger.success(`Configuration for [${serverName}] updated successfully!`);
2490
- return;
3034
+ if (updatedAny) {
3035
+ targetGroup.config = updateResult.config;
3036
+ logger.success(`Configuration for [${serverName}] updated successfully!`);
3037
+ return;
3038
+ }
2491
3039
  }
2492
3040
  }
2493
3041
  };
@@ -2505,6 +3053,14 @@ var wizardManage = async (options = {}) => {
2505
3053
  }
2506
3054
  const grouped = groupInstalledServersByName(installed);
2507
3055
  let pendingServerName = options.serverName;
3056
+ const refreshGroupedServers = () => {
3057
+ const freshInstalled = listInstalledMcpServers({ global: isGlobal, cwd });
3058
+ const freshGrouped = groupInstalledServersByName(freshInstalled);
3059
+ grouped.clear();
3060
+ for (const [name, grp] of freshGrouped) {
3061
+ grouped.set(name, grp);
3062
+ }
3063
+ };
2508
3064
  while (true) {
2509
3065
  let chosenServerName;
2510
3066
  if (pendingServerName && grouped.has(pendingServerName)) {
@@ -2515,7 +3071,7 @@ var wizardManage = async (options = {}) => {
2515
3071
  const choices = Array.from(grouped.values()).map((g) => {
2516
3072
  const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2517
3073
  return {
2518
- name: `${import_picocolors9.default.bold(g.serverName)} ${import_picocolors9.default.dim(`(configured in: ${agentNames})`)}`,
3074
+ name: `${import_picocolors13.default.bold(g.serverName)} ${import_picocolors13.default.dim(`(configured in: ${agentNames})`)}`,
2519
3075
  value: g.serverName
2520
3076
  };
2521
3077
  });
@@ -2523,7 +3079,7 @@ var wizardManage = async (options = {}) => {
2523
3079
  name: `Back`,
2524
3080
  value: "__back__"
2525
3081
  });
2526
- chosenServerName = await (0, import_prompts9.select)({
3082
+ chosenServerName = await (0, import_prompts8.select)({
2527
3083
  message: "Select MCP server to manage or sync:",
2528
3084
  choices
2529
3085
  });
@@ -2537,9 +3093,10 @@ var wizardManage = async (options = {}) => {
2537
3093
  serverName: chosenServerName,
2538
3094
  config: targetGroup.config,
2539
3095
  agents: targetGroup.agents,
2540
- isGlobal
3096
+ global: isGlobal,
3097
+ hasDivergence: targetGroup.hasDivergence
2541
3098
  });
2542
- const action = await (0, import_prompts9.select)({
3099
+ const action = await (0, import_prompts8.select)({
2543
3100
  message: `What would you like to do with [${chosenServerName}]?`,
2544
3101
  choices: [
2545
3102
  {
@@ -2560,31 +3117,34 @@ var wizardManage = async (options = {}) => {
2560
3117
  if (action === "edit") {
2561
3118
  await handleEditServerConfig({
2562
3119
  targetGroup,
2563
- isGlobal,
3120
+ global: isGlobal,
2564
3121
  cwd
2565
3122
  });
3123
+ refreshGroupedServers();
2566
3124
  continue;
2567
3125
  }
2568
3126
  if (action === "sync") {
2569
3127
  const allAllowedAgents = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
2570
- const candidateAgents = allAllowedAgents.filter((a) => !targetGroup.agents.includes(a));
2571
- if (candidateAgents.length === 0) {
3128
+ const rawCandidateAgents = allAllowedAgents.filter((a) => !targetGroup.agents.includes(a));
3129
+ if (rawCandidateAgents.length === 0) {
2572
3130
  logger.info(
2573
3131
  "All supported agents in this scope already have this MCP server configured; no sync needed"
2574
3132
  );
2575
3133
  continue;
2576
3134
  }
2577
- const selectedToSync = await (0, import_prompts9.checkbox)({
3135
+ const candidateAgents = sortAgentsWithClusters(rawCandidateAgents, { global: isGlobal, cwd });
3136
+ const choices = buildLinkedAgentChoices({
3137
+ agents: candidateAgents,
3138
+ checkedAgents: [],
3139
+ scopeOptions: { global: isGlobal, cwd }
3140
+ });
3141
+ const selectedToSync = await linkedCheckbox({
2578
3142
  message: "Select target agents to sync to (Space to select):",
2579
- choices: candidateAgents.map((a) => ({
2580
- name: `${getMcpAgentConfig(a).displayName} (${a})`,
2581
- value: a,
2582
- checked: false
2583
- })),
3143
+ choices,
2584
3144
  loop: false,
2585
3145
  validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2586
3146
  });
2587
- const confirmed = await (0, import_prompts9.confirm)({
3147
+ const confirmed = await (0, import_prompts8.confirm)({
2588
3148
  message: `Confirm syncing configuration of [${chosenServerName}] to: ${selectedToSync.join(", ")}?`,
2589
3149
  default: true
2590
3150
  });
@@ -2592,25 +3152,37 @@ var wizardManage = async (options = {}) => {
2592
3152
  logger.warn("Sync cancelled");
2593
3153
  continue;
2594
3154
  }
2595
- for (const targetAgent of selectedToSync) {
2596
- const res = installMcpServerForAgent(chosenServerName, targetGroup.config, targetAgent, {
2597
- global: isGlobal,
2598
- cwd
2599
- });
3155
+ const syncResult = updateMcpServer({
3156
+ serverName: chosenServerName,
3157
+ config: targetGroup.config,
3158
+ agents: selectedToSync,
3159
+ global: isGlobal,
3160
+ cwd
3161
+ });
3162
+ for (const item of syncResult.incompatible) {
3163
+ logger.warn(`Skipping ${import_picocolors13.default.cyan(item.agent)}: ${item.reason}`);
3164
+ }
3165
+ for (const res of syncResult.results) {
3166
+ if (syncResult.incompatible.some((i) => i.agent === res.agent)) {
3167
+ continue;
3168
+ }
2600
3169
  if (res.success) {
2601
- logger.success(`${import_picocolors9.default.cyan(targetAgent)}: Successfully synced to ${import_picocolors9.default.dim(res.path)}`);
2602
- targetGroup.agents.push(targetAgent);
3170
+ logger.success(
3171
+ `${import_picocolors13.default.cyan(res.agent)}: Successfully synced to ${import_picocolors13.default.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
3172
+ );
3173
+ targetGroup.agents.push(res.agent);
2603
3174
  } else {
2604
- logger.error(`${import_picocolors9.default.cyan(targetAgent)}: Sync failed - ${res.error}`);
3175
+ logger.error(`${import_picocolors13.default.cyan(res.agent)}: Sync failed - ${res.error}`);
2605
3176
  }
2606
3177
  }
3178
+ refreshGroupedServers();
2607
3179
  }
2608
3180
  }
2609
3181
  };
2610
3182
 
2611
3183
  // src/interactive/wizard-remove.ts
2612
- var import_prompts10 = require("@inquirer/prompts");
2613
- var import_picocolors10 = __toESM(require("picocolors"), 1);
3184
+ var import_prompts9 = require("@inquirer/prompts");
3185
+ var import_picocolors14 = __toESM(require("picocolors"), 1);
2614
3186
  var wizardRemove = async (options = {}) => {
2615
3187
  const cwd = options.cwd ?? process.cwd();
2616
3188
  const isGlobal = await promptScope({
@@ -2627,29 +3199,30 @@ var wizardRemove = async (options = {}) => {
2627
3199
  let serverName = options.name;
2628
3200
  if (!serverName) {
2629
3201
  const choices = Array.from(serverMap.values()).map((g) => ({
2630
- name: `${import_picocolors10.default.bold(g.serverName)} ${import_picocolors10.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
3202
+ name: `${import_picocolors14.default.bold(g.serverName)} ${import_picocolors14.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
2631
3203
  value: g.serverName
2632
3204
  }));
2633
- serverName = await (0, import_prompts10.select)({
3205
+ serverName = await (0, import_prompts9.select)({
2634
3206
  message: "Select MCP server to remove:",
2635
3207
  choices
2636
3208
  });
2637
3209
  }
2638
- const installedAgents = serverMap.get(serverName)?.agents || [];
2639
- if (installedAgents.length === 0) {
3210
+ const rawInstalledAgents = serverMap.get(serverName)?.agents || [];
3211
+ if (rawInstalledAgents.length === 0) {
2640
3212
  logger.warn(`No agents found with [${serverName}] installed`);
2641
3213
  return false;
2642
3214
  }
3215
+ const installedAgents = sortAgentsWithClusters(rawInstalledAgents, { global: isGlobal, cwd });
2643
3216
  let targetAgents = options.agents;
2644
3217
  if (!targetAgents || targetAgents.length === 0) {
2645
- targetAgents = await (0, import_prompts10.checkbox)({
3218
+ const choices = buildLinkedAgentChoices({
3219
+ agents: installedAgents,
3220
+ checkedAgents: installedAgents,
3221
+ scopeOptions: { global: isGlobal, cwd }
3222
+ });
3223
+ targetAgents = await linkedCheckbox({
2646
3224
  message: `Select agents to remove [${serverName}] from:`,
2647
- choices: installedAgents.map((agent) => ({
2648
- name: `${getMcpAgentConfig(agent)?.displayName ?? agent} (${agent})`,
2649
- value: agent,
2650
- checked: true
2651
- })),
2652
- loop: false,
3225
+ choices,
2653
3226
  validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2654
3227
  });
2655
3228
  } else {
@@ -2660,7 +3233,7 @@ var wizardRemove = async (options = {}) => {
2660
3233
  }
2661
3234
  targetAgents = validAgents;
2662
3235
  }
2663
- const confirmed = await (0, import_prompts10.confirm)({
3236
+ const confirmed = await (0, import_prompts9.confirm)({
2664
3237
  message: `Confirm removing MCP server [${serverName}] from ${targetAgents.join(", ")}?`,
2665
3238
  default: true
2666
3239
  });
@@ -2677,10 +3250,12 @@ var wizardRemove = async (options = {}) => {
2677
3250
  let removedCount = 0;
2678
3251
  for (const res of results) {
2679
3252
  if (res.removed) {
2680
- logger.success(`${import_picocolors10.default.cyan(res.agent)}: Successfully removed from ${import_picocolors10.default.dim(res.path)}`);
3253
+ logger.success(
3254
+ `${import_picocolors14.default.cyan(res.agent)}: Successfully removed from ${import_picocolors14.default.dim(res.path)}${formatCoHostedBadge("affected", res.coAffectedAgents)}`
3255
+ );
2681
3256
  removedCount++;
2682
3257
  } else if (res.error) {
2683
- logger.error(`${import_picocolors10.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
3258
+ logger.error(`${import_picocolors14.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
2684
3259
  }
2685
3260
  }
2686
3261
  if (removedCount > 0) {
@@ -2694,12 +3269,12 @@ var wizardRemove = async (options = {}) => {
2694
3269
  // src/interactive/main-menu.ts
2695
3270
  var mainMenu = async () => {
2696
3271
  console.log();
2697
- console.log(import_picocolors11.default.bold(import_picocolors11.default.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
2698
- console.log(import_picocolors11.default.dim("Cross-platform MCP server configuration & synchronization tool"));
3272
+ console.log(import_picocolors15.default.bold(import_picocolors15.default.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
3273
+ console.log(import_picocolors15.default.dim("Cross-platform MCP server configuration & synchronization tool"));
2699
3274
  console.log();
2700
3275
  while (true) {
2701
3276
  try {
2702
- const action = await (0, import_prompts11.select)({
3277
+ const action = await (0, import_prompts10.select)({
2703
3278
  message: "Select an action:",
2704
3279
  choices: [
2705
3280
  {
@@ -2721,7 +3296,7 @@ var mainMenu = async () => {
2721
3296
  ]
2722
3297
  });
2723
3298
  if (action === "exit") {
2724
- console.log(import_picocolors11.default.dim("Goodbye!"));
3299
+ console.log(import_picocolors15.default.dim("Goodbye!"));
2725
3300
  break;
2726
3301
  }
2727
3302
  if (action === "add") {
@@ -2734,7 +3309,7 @@ var mainMenu = async () => {
2734
3309
  console.log();
2735
3310
  } catch (error) {
2736
3311
  if (error?.name === "ExitPromptError") {
2737
- console.log("\n" + import_picocolors11.default.dim("Exited."));
3312
+ console.log("\n" + import_picocolors15.default.dim("Exited."));
2738
3313
  break;
2739
3314
  }
2740
3315
  throw error;
@@ -2742,9 +3317,16 @@ var mainMenu = async () => {
2742
3317
  }
2743
3318
  };
2744
3319
 
3320
+ // src/utils/resolve-transport.ts
3321
+ var resolveTransport = (input7) => {
3322
+ if (!input7) return void 0;
3323
+ if (input7 === "http" || input7 === "sse") return input7;
3324
+ throw new Error(`Unsupported transport "${input7}" (expected: http, sse)`);
3325
+ };
3326
+
2745
3327
  // src/cli/manage.ts
2746
3328
  var import_commander = require("commander");
2747
- var import_picocolors12 = __toESM(require("picocolors"), 1);
3329
+ var import_picocolors16 = __toESM(require("picocolors"), 1);
2748
3330
 
2749
3331
  // src/utils/parse-key-value-list.ts
2750
3332
  var parseKeyValueList = (entries, separator) => {
@@ -2764,72 +3346,124 @@ var parseKeyValueList = (entries, separator) => {
2764
3346
  };
2765
3347
 
2766
3348
  // src/cli/manage.ts
2767
- var resolveTransport = (input7) => {
2768
- if (!input7) return void 0;
2769
- if (input7 === "http" || input7 === "sse") return input7;
2770
- throw new Error(`Unsupported transport "${input7}" (expected: http, sse)`);
3349
+ var requireTargetServerGroup = (serverName, scope) => {
3350
+ const installed = listInstalledMcpServers(scope);
3351
+ const grouped = groupInstalledServersByName(installed);
3352
+ const targetGroup = grouped.get(serverName);
3353
+ if (!targetGroup) {
3354
+ logger.error(
3355
+ `MCP server "${serverName}" is not configured in ${scope.global ? "global" : "project"} scope.`
3356
+ );
3357
+ process.exitCode = 1;
3358
+ return void 0;
3359
+ }
3360
+ return targetGroup;
2771
3361
  };
2772
- var mcpManageCommand = new import_commander.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) => {
3362
+ var mcpManageCommand = new import_commander.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) => {
2773
3363
  try {
2774
3364
  const cwd = process.cwd();
2775
3365
  const isGlobal = Boolean(options.global);
2776
- 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;
3366
+ 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;
2777
3367
  const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
2778
3368
  if (hasModifications) {
3369
+ if (options.url !== void 0 && options.command !== void 0) {
3370
+ logger.error('Cannot specify both "--url" (remote) and "--command" (stdio) simultaneously.');
3371
+ process.exitCode = 1;
3372
+ return;
3373
+ }
2779
3374
  if (!serverName) {
2780
3375
  logger.error('Missing required argument: "server-name" when passing modification flags.');
2781
3376
  process.exitCode = 1;
2782
3377
  return;
2783
3378
  }
2784
- const installed = listInstalledMcpServers({ global: isGlobal, cwd });
2785
- const grouped = groupInstalledServersByName(installed);
2786
- const targetGroup = grouped.get(serverName);
3379
+ const targetGroup = requireTargetServerGroup(serverName, { global: isGlobal, cwd });
2787
3380
  if (!targetGroup) {
2788
- logger.error(
2789
- `MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
2790
- );
2791
- process.exitCode = 1;
2792
3381
  return;
2793
3382
  }
2794
- const updatedConfig = {
2795
- ...targetGroup.config,
2796
- args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
2797
- env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
2798
- headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
2799
- };
3383
+ const isCurrentRemote = Boolean(targetGroup.config.url && targetGroup.config.url.length > 0);
3384
+ const willBeRemote = options.url !== void 0 ? true : options.command !== void 0 ? false : isCurrentRemote;
3385
+ if (willBeRemote) {
3386
+ const ignoredStdioFlags = [];
3387
+ if (options.env !== void 0) ignoredStdioFlags.push("--env");
3388
+ if (options.clearEnv) ignoredStdioFlags.push("--clear-env");
3389
+ if (options.args !== void 0) ignoredStdioFlags.push("--args");
3390
+ if (options.clearArgs) ignoredStdioFlags.push("--clear-args");
3391
+ if (ignoredStdioFlags.length > 0) {
3392
+ const hint = options.url !== void 0 ? "When configuring a remote server, stdio flags are ignored." : "Use --command to switch to stdio mode.";
3393
+ logger.warn(
3394
+ `Server "${serverName}" is a remote server. The following stdio flags will be ignored: ${ignoredStdioFlags.join(", ")}. ${hint}`
3395
+ );
3396
+ }
3397
+ } else {
3398
+ const ignoredRemoteFlags = [];
3399
+ if (options.header !== void 0) ignoredRemoteFlags.push("--header");
3400
+ if (options.clearHeaders) ignoredRemoteFlags.push("--clear-headers");
3401
+ if (options.transport !== void 0) ignoredRemoteFlags.push("--transport");
3402
+ if (ignoredRemoteFlags.length > 0) {
3403
+ const hint = options.command !== void 0 ? "When configuring a stdio server, remote flags are ignored." : "Use --url to switch to remote mode.";
3404
+ logger.warn(
3405
+ `Server "${serverName}" is a stdio server. The following remote flags will be ignored: ${ignoredRemoteFlags.join(", ")}. ${hint}`
3406
+ );
3407
+ }
3408
+ }
3409
+ const incomingDelta = {};
2800
3410
  if (options.command !== void 0) {
2801
- updatedConfig.command = options.command;
3411
+ incomingDelta.command = options.command;
3412
+ }
3413
+ if (options.clearArgs) {
3414
+ incomingDelta.args = void 0;
2802
3415
  }
2803
3416
  if (options.args !== void 0) {
2804
- updatedConfig.args = options.args;
3417
+ incomingDelta.args = options.args;
2805
3418
  }
2806
3419
  if (options.url !== void 0) {
2807
- updatedConfig.url = options.url;
3420
+ incomingDelta.url = options.url;
2808
3421
  }
2809
3422
  if (options.transport !== void 0) {
2810
- updatedConfig.type = resolveTransport(options.transport);
3423
+ incomingDelta.type = resolveTransport(options.transport);
3424
+ }
3425
+ if (options.clearEnv) {
3426
+ incomingDelta.env = void 0;
2811
3427
  }
2812
3428
  if (options.env !== void 0) {
2813
3429
  const parsedEnv = parseKeyValueList(options.env, "=");
2814
- updatedConfig.env = { ...updatedConfig.env ?? {}, ...parsedEnv };
3430
+ const baseEnv = options.clearEnv ? {} : targetGroup.config.env ?? {};
3431
+ incomingDelta.env = { ...baseEnv, ...parsedEnv };
3432
+ }
3433
+ if (options.clearHeaders) {
3434
+ incomingDelta.headers = void 0;
2815
3435
  }
2816
3436
  if (options.header !== void 0) {
2817
3437
  const parsedHeaders = parseKeyValueList(options.header, ":");
2818
- updatedConfig.headers = { ...updatedConfig.headers ?? {}, ...parsedHeaders };
2819
- }
2820
- const targetAgents = options.agent ? parseMcpAgentList(options.agent) ?? targetGroup.agents : targetGroup.agents;
2821
- const requestedTransport = updatedConfig.url ? updatedConfig.type ?? "http" : "stdio";
2822
- const compatibleAgents = [];
2823
- for (const agent of targetAgents) {
2824
- const agentConfig = getMcpAgentConfig(agent);
2825
- if (isMcpTransportSupported(agentConfig, requestedTransport)) {
2826
- compatibleAgents.push(agent);
2827
- } else {
2828
- const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
2829
- logger.warn(`Skipping ${import_picocolors12.default.cyan(agent)}: ${reason}`);
3438
+ const baseHeaders = options.clearHeaders ? {} : targetGroup.config.headers ?? {};
3439
+ incomingDelta.headers = { ...baseHeaders, ...parsedHeaders };
3440
+ }
3441
+ let targetAgents = targetGroup.agents;
3442
+ if (options.agent !== void 0) {
3443
+ const parsed = parseMcpAgentList(options.agent);
3444
+ if (!parsed || parsed.length === 0) {
3445
+ logger.error(`No valid agents recognized from: "${options.agent.join(", ")}".`);
3446
+ process.exitCode = 1;
3447
+ return;
2830
3448
  }
3449
+ targetAgents = parsed;
2831
3450
  }
2832
- if (compatibleAgents.length === 0) {
3451
+ const updateResult = updateMcpServer({
3452
+ serverName,
3453
+ config: incomingDelta,
3454
+ previousConfig: targetGroup.config,
3455
+ agents: targetAgents,
3456
+ global: isGlobal,
3457
+ cwd
3458
+ });
3459
+ for (const item of updateResult.incompatible) {
3460
+ logger.warn(`Skipping ${import_picocolors16.default.cyan(item.agent)}: ${item.reason}`);
3461
+ }
3462
+ const attemptedResults = updateResult.results.filter(
3463
+ (r) => !updateResult.incompatible.some((i) => i.agent === r.agent)
3464
+ );
3465
+ if (attemptedResults.length === 0) {
3466
+ const requestedTransport = updateResult.config.url ? updateResult.config.type ?? "http" : "stdio";
2833
3467
  logger.error(
2834
3468
  `None of the target agents support ${requestedTransport} transport. Update aborted.`
2835
3469
  );
@@ -2837,19 +3471,16 @@ var mcpManageCommand = new import_commander.Command("manage").description("Inspe
2837
3471
  return;
2838
3472
  }
2839
3473
  logger.info(
2840
- `Updating ${import_picocolors12.default.bold(serverName)} across ${import_picocolors12.default.cyan(String(compatibleAgents.length))} agent(s)...`
3474
+ `Updating ${import_picocolors16.default.bold(serverName)} across ${import_picocolors16.default.cyan(String(attemptedResults.length))} agent(s)...`
2841
3475
  );
2842
3476
  let allSuccess = true;
2843
- for (const agent of compatibleAgents) {
2844
- const res = installMcpServerForAgent(serverName, updatedConfig, agent, {
2845
- global: isGlobal,
2846
- cwd
2847
- });
3477
+ for (const res of attemptedResults) {
2848
3478
  if (res.success) {
2849
- logger.success(`${import_picocolors12.default.cyan(agent)}: Successfully updated in ${import_picocolors12.default.dim(res.path)}`);
3479
+ logger.success(`${import_picocolors16.default.cyan(res.agent)}: Successfully updated in ${import_picocolors16.default.dim(res.path)}`);
3480
+ logCoHostedNotice("configured", res.coConfiguredAgents);
2850
3481
  } else {
2851
3482
  allSuccess = false;
2852
- logger.error(`${import_picocolors12.default.cyan(agent)}: Update failed - ${res.error}`);
3483
+ logger.error(`${import_picocolors16.default.cyan(res.agent)}: Update failed - ${res.error}`);
2853
3484
  }
2854
3485
  }
2855
3486
  if (!allSuccess) {
@@ -2865,21 +3496,16 @@ var mcpManageCommand = new import_commander.Command("manage").description("Inspe
2865
3496
  process.exitCode = 1;
2866
3497
  return;
2867
3498
  }
2868
- const installed = listInstalledMcpServers({ global: isGlobal, cwd });
2869
- const grouped = groupInstalledServersByName(installed);
2870
- const targetGroup = grouped.get(serverName);
3499
+ const targetGroup = requireTargetServerGroup(serverName, { global: isGlobal, cwd });
2871
3500
  if (!targetGroup) {
2872
- logger.error(
2873
- `MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
2874
- );
2875
- process.exitCode = 1;
2876
3501
  return;
2877
3502
  }
2878
3503
  displayServerDetails({
2879
3504
  serverName,
2880
3505
  config: targetGroup.config,
2881
3506
  agents: targetGroup.agents,
2882
- isGlobal
3507
+ global: isGlobal,
3508
+ hasDivergence: targetGroup.hasDivergence
2883
3509
  });
2884
3510
  return;
2885
3511
  }
@@ -2900,11 +3526,6 @@ var mcpManageCommand = new import_commander.Command("manage").description("Inspe
2900
3526
  var formatAgentList = (agentList, emptyLabel = "(none)") => agentList.length === 0 ? emptyLabel : agentList.join(", ");
2901
3527
 
2902
3528
  // src/cli/add.ts
2903
- var resolveTransport2 = (input7) => {
2904
- if (!input7) return void 0;
2905
- if (input7 === "http" || input7 === "sse") return input7;
2906
- throw new Error(`Unsupported transport "${input7}" (expected: http, sse)`);
2907
- };
2908
3529
  var mcpAddCommand = new import_commander2.Command("add").description("Add an MCP server to coding agents").argument("[source]", "Remote URL, npm package, or command line").option("-a, --agent <agents...>", "Target specific agents (use '*' for all)").option("-g, --global", "Install to user-level config instead of project").option("-t, --transport <type>", "Transport type for remote servers (http or sse)").option("--header <header...>", "HTTP header (Key: Value), repeatable").option("--env <env...>", "Env var for stdio servers (KEY=VALUE), repeatable").option("--args <args...>", "CLI arguments for stdio/package servers").option("-n, --name <name>", "Server name override").option("-y, --yes", "Skip all prompts").option("--all", "Install to all supported agents").action(async (source, options) => {
2909
3530
  try {
2910
3531
  const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
@@ -2914,7 +3535,7 @@ var mcpAddCommand = new import_commander2.Command("add").description("Add an MCP
2914
3535
  name: options.name,
2915
3536
  global: options.global,
2916
3537
  args: options.args,
2917
- transport: resolveTransport2(options.transport),
3538
+ transport: resolveTransport(options.transport),
2918
3539
  headers: parseKeyValueList(options.header, ":"),
2919
3540
  env: parseKeyValueList(options.env, "="),
2920
3541
  agents: options.all ? getMcpAgentTypes() : parseMcpAgentList(options.agent)
@@ -2929,7 +3550,7 @@ var mcpAddCommand = new import_commander2.Command("add").description("Add an MCP
2929
3550
  const parsed = parseMcpSource(source);
2930
3551
  const cwd = process.cwd();
2931
3552
  const isGlobal = Boolean(options.global);
2932
- const explicitTransport = resolveTransport2(options.transport);
3553
+ const explicitTransport = resolveTransport(options.transport);
2933
3554
  const transport = explicitTransport ?? (parsed.type === "remote" ? "http" : "stdio");
2934
3555
  const resolvedTargets = resolveTargetAgents({
2935
3556
  requested: options.agent,
@@ -2939,19 +3560,19 @@ var mcpAddCommand = new import_commander2.Command("add").description("Add an MCP
2939
3560
  transport
2940
3561
  });
2941
3562
  if (resolvedTargets.agents.length === 0) {
2942
- const message = resolvedTargets.diagnostic ?? `No ${isGlobal ? "global" : "project"}-installed MCP agents detected. Pass ${import_picocolors13.default.cyan("-a <agent>")} (e.g. ${import_picocolors13.default.cyan("-a cursor")}) or ${import_picocolors13.default.cyan("--all")} to install.`;
3563
+ const message = resolvedTargets.diagnostic ?? `No ${isGlobal ? "global" : "project"}-installed MCP agents detected. Pass ${import_picocolors17.default.cyan("-a <agent>")} (e.g. ${import_picocolors17.default.cyan("-a cursor")}) or ${import_picocolors17.default.cyan("--all")} to install.`;
2943
3564
  logger.warn(message);
2944
3565
  process.exitCode = 1;
2945
3566
  return;
2946
3567
  }
2947
3568
  if (resolvedTargets.isDetected) {
2948
3569
  logger.info(
2949
- `Detected ${isGlobal ? "global" : "project"} agents: ${import_picocolors13.default.cyan(formatAgentList(resolvedTargets.detected, "(none detected)"))}`
3570
+ `Detected ${isGlobal ? "global" : "project"} agents: ${import_picocolors17.default.cyan(formatAgentList(resolvedTargets.detected, "(none detected)"))}`
2950
3571
  );
2951
3572
  if (resolvedTargets.incompatible.length > 0) {
2952
3573
  const skippedList = resolvedTargets.incompatible.map((item) => `${item.agent} (${item.reason})`).join(", ");
2953
3574
  logger.info(
2954
- `Skipping detected agents incompatible with ${transport}: ${import_picocolors13.default.yellow(skippedList)}`
3575
+ `Skipping detected agents incompatible with ${transport}: ${import_picocolors17.default.yellow(skippedList)}`
2955
3576
  );
2956
3577
  }
2957
3578
  }
@@ -2968,13 +3589,14 @@ var mcpAddCommand = new import_commander2.Command("add").description("Add an MCP
2968
3589
  env: parseKeyValueList(options.env, "=")
2969
3590
  });
2970
3591
  logger.info(
2971
- `Installing ${import_picocolors13.default.bold(result.serverName)} (${import_picocolors13.default.cyan(parsed.type)}) to ${import_picocolors13.default.cyan(String(result.results.length))} agent(s)`
3592
+ `Installing ${import_picocolors17.default.bold(result.serverName)} (${import_picocolors17.default.cyan(parsed.type)}) to ${import_picocolors17.default.cyan(String(result.results.length))} agent(s)`
2972
3593
  );
2973
3594
  for (const record of result.results) {
2974
3595
  if (record.success) {
2975
- logger.success(`${import_picocolors13.default.cyan(record.agent)} ${import_picocolors13.default.dim(record.path)}`);
3596
+ logger.success(`${import_picocolors17.default.cyan(record.agent)} ${import_picocolors17.default.dim(record.path)}`);
3597
+ logCoHostedNotice("configured", record.coConfiguredAgents);
2976
3598
  } else {
2977
- logger.error(`${import_picocolors13.default.cyan(record.agent)}: ${record.error}`);
3599
+ logger.error(`${import_picocolors17.default.cyan(record.agent)}: ${record.error}`);
2978
3600
  }
2979
3601
  }
2980
3602
  if (result.results.some((record) => !record.success)) process.exitCode = 1;
@@ -2986,7 +3608,7 @@ var mcpAddCommand = new import_commander2.Command("add").description("Add an MCP
2986
3608
 
2987
3609
  // src/cli/list.ts
2988
3610
  var import_commander3 = require("commander");
2989
- var import_picocolors14 = __toESM(require("picocolors"), 1);
3611
+ var import_picocolors18 = __toESM(require("picocolors"), 1);
2990
3612
  var mcpListCommand = new import_commander3.Command("list").alias("ls").description("List installed MCP servers across agents").option("-g, --global", "List global configs instead of project").option("-a, --agent <agents...>", "Filter by specific agents").option("--json", "Output as JSON").action((options) => {
2991
3613
  try {
2992
3614
  const entries = listInstalledMcpServers({
@@ -3010,9 +3632,9 @@ var mcpListCommand = new import_commander3.Command("list").alias("ls").descripti
3010
3632
  }
3011
3633
  for (const [serverName, group] of grouped) {
3012
3634
  const agentLabels = group.map((record) => record.agent).join(", ");
3013
- console.log(` ${import_picocolors14.default.bold(serverName)} ${import_picocolors14.default.dim(`[${agentLabels}]`)}`);
3635
+ console.log(` ${import_picocolors18.default.bold(serverName)} ${import_picocolors18.default.dim(`[${agentLabels}]`)}`);
3014
3636
  const firstPath = group[0]?.path;
3015
- if (firstPath) console.log(` ${import_picocolors14.default.dim(firstPath)}`);
3637
+ if (firstPath) console.log(` ${import_picocolors18.default.dim(firstPath)}`);
3016
3638
  }
3017
3639
  } catch (error) {
3018
3640
  logger.error(toErrorMessage(error));
@@ -3022,7 +3644,7 @@ var mcpListCommand = new import_commander3.Command("list").alias("ls").descripti
3022
3644
 
3023
3645
  // src/cli/remove.ts
3024
3646
  var import_commander4 = require("commander");
3025
- var import_picocolors15 = __toESM(require("picocolors"), 1);
3647
+ var import_picocolors19 = __toESM(require("picocolors"), 1);
3026
3648
  var mcpRemoveCommand = new import_commander4.Command("remove").alias("rm").description("Remove an MCP server from agent configs").argument("[name]", "Server name").option("-g, --global", "Remove from global scope").option("-a, --agent <agents...>", "Filter by specific agents (use '*' for all)").option("-y, --yes", "Skip confirmation prompts").action(async (name, options) => {
3027
3649
  try {
3028
3650
  const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
@@ -3046,16 +3668,17 @@ var mcpRemoveCommand = new import_commander4.Command("remove").alias("rm").descr
3046
3668
  cwd: process.cwd()
3047
3669
  });
3048
3670
  if (results.length === 0) {
3049
- logger.warn(`No agent config contained ${import_picocolors15.default.bold(name)}`);
3671
+ logger.warn(`No agent config contained ${import_picocolors19.default.bold(name)}`);
3050
3672
  return;
3051
3673
  }
3052
3674
  for (const record of results) {
3053
3675
  if (record.removed) {
3054
3676
  logger.success(
3055
- `${import_picocolors15.default.cyan(record.agent)} removed ${import_picocolors15.default.bold(name)} ${import_picocolors15.default.dim(record.path)}`
3677
+ `${import_picocolors19.default.cyan(record.agent)} removed ${import_picocolors19.default.bold(name)} ${import_picocolors19.default.dim(record.path)}`
3056
3678
  );
3679
+ logCoHostedNotice("affected", record.coAffectedAgents);
3057
3680
  } else {
3058
- logger.error(`${import_picocolors15.default.cyan(record.agent)}: ${record.error ?? "not found"}`);
3681
+ logger.error(`${import_picocolors19.default.cyan(record.agent)}: ${record.error ?? "not found"}`);
3059
3682
  }
3060
3683
  }
3061
3684
  } catch (error) {
@@ -3065,7 +3688,7 @@ var mcpRemoveCommand = new import_commander4.Command("remove").alias("rm").descr
3065
3688
  });
3066
3689
 
3067
3690
  // src/cli.ts
3068
- var VERSION = "0.1.0-beta.2";
3691
+ var VERSION = "0.1.0-beta.3";
3069
3692
  process.on("SIGINT", () => process.exit(0));
3070
3693
  process.on("SIGTERM", () => process.exit(0));
3071
3694
  var program = new import_commander5.Command().name("mcps").description("Install, list, and remove MCP servers across AI coding agents").version(VERSION, "-v, --version", "display the version number");