@wuyax/mcps 0.1.0-beta.1 → 0.1.0-beta.2

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/index.cjs CHANGED
@@ -40,7 +40,11 @@ __export(src_exports, {
40
40
  createAgentTransform: () => createAgentTransform,
41
41
  detectGloballyInstalledMcpAgents: () => detectGloballyInstalledMcpAgents,
42
42
  detectProjectInstalledMcpAgents: () => detectProjectInstalledMcpAgents,
43
+ displayServerDetails: () => displayServerDetails,
43
44
  extractPackageName: () => extractPackageName,
45
+ formatArgsString: () => formatArgsString,
46
+ formatEnvText: () => formatEnvText,
47
+ formatHeadersText: () => formatHeadersText,
44
48
  getMcpAgentConfig: () => getMcpAgentConfig,
45
49
  getMcpAgentTypes: () => getMcpAgentTypes,
46
50
  getMcpAgentsSupportingProjectScope: () => getMcpAgentsSupportingProjectScope,
@@ -58,8 +62,11 @@ __export(src_exports, {
58
62
  listInstalledMcpServers: () => listInstalledMcpServers,
59
63
  listServersInConfigFile: () => listServersInConfigFile,
60
64
  mainMenu: () => mainMenu,
65
+ maskSecretHeader: () => maskSecretHeader,
66
+ maskSecretValue: () => maskSecretValue,
61
67
  mcpAgentAliases: () => mcpAgentAliases,
62
68
  mcpAgents: () => mcpAgents,
69
+ mcpManageCommand: () => mcpManageCommand,
63
70
  normalizeServerConfig: () => normalizeServerConfig,
64
71
  parseArgsString: () => parseArgsString,
65
72
  parseEnvText: () => parseEnvText,
@@ -68,6 +75,10 @@ __export(src_exports, {
68
75
  parseServerConfig: () => parseServerConfig,
69
76
  parseSource: () => parseMcpSource,
70
77
  promptArgsConfig: () => promptArgsConfig,
78
+ promptEditArgs: () => promptEditArgs,
79
+ promptEditEnvConfig: () => promptEditEnvConfig,
80
+ promptEditHeadersConfig: () => promptEditHeadersConfig,
81
+ promptEditKeyValueConfig: () => promptEditKeyValueConfig,
71
82
  promptEnvConfig: () => promptEnvConfig,
72
83
  promptHeadersConfig: () => promptHeadersConfig,
73
84
  promptScope: () => promptScope,
@@ -82,6 +93,8 @@ __export(src_exports, {
82
93
  resolveTargetAgents: () => resolveTargetAgents,
83
94
  transformServerConfig: () => transformServerConfig,
84
95
  transformServerConfigForAgent: () => transformServerConfigForAgent,
96
+ updateMcpServerForAgent: () => installMcpServerForAgent,
97
+ updateMcpServerForAgents: () => installMcpServerForAgents,
85
98
  wizardAdd: () => wizardAdd,
86
99
  wizardManage: () => wizardManage,
87
100
  wizardRemove: () => wizardRemove,
@@ -543,9 +556,9 @@ var mcpAgentAliases = {
543
556
  var getMcpAgentConfig = (agentType) => mcpAgents[agentType];
544
557
  var getMcpAgentTypes = () => Object.values(mcpAgents).map((config) => config.name);
545
558
  var isMcpAgentType = (value) => value in mcpAgents;
546
- var resolveMcpAgentAlias = (input5) => {
547
- if (isMcpAgentType(input5)) return input5;
548
- return mcpAgentAliases[input5] ?? null;
559
+ var resolveMcpAgentAlias = (input7) => {
560
+ if (isMcpAgentType(input7)) return input7;
561
+ return mcpAgentAliases[input7] ?? null;
549
562
  };
550
563
  var isMcpTransportSupported = (agent, transport) => agent.supportedTransports.includes(transport);
551
564
  var detectProjectInstalledMcpAgents = (cwd) => getMcpAgentTypes().filter(
@@ -1291,11 +1304,11 @@ var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options =
1291
1304
  );
1292
1305
 
1293
1306
  // src/utils/parse-mcp-agent-list.ts
1294
- var parseMcpAgentList = (input5) => {
1295
- if (!input5 || input5.length === 0) return void 0;
1296
- if (input5.includes("*")) return getMcpAgentTypes();
1307
+ var parseMcpAgentList = (input7) => {
1308
+ if (!input7 || input7.length === 0) return void 0;
1309
+ if (input7.includes("*")) return getMcpAgentTypes();
1297
1310
  const resolved = [];
1298
- for (const value of input5) {
1311
+ for (const value of input7) {
1299
1312
  const agentType = resolveMcpAgentAlias(value);
1300
1313
  if (!agentType) throw new Error(`Unknown MCP agent "${value}"`);
1301
1314
  resolved.push(agentType);
@@ -1304,9 +1317,9 @@ var parseMcpAgentList = (input5) => {
1304
1317
  };
1305
1318
 
1306
1319
  // src/resolve-target-agents.ts
1307
- var normalizeRequestedAgents = (input5) => {
1308
- if (!input5 || input5.length === 0) return void 0;
1309
- const rawList = [...input5];
1320
+ var normalizeRequestedAgents = (input7) => {
1321
+ if (!input7 || input7.length === 0) return void 0;
1322
+ const rawList = [...input7];
1310
1323
  if (rawList.every((item) => isMcpAgentType(item))) {
1311
1324
  return rawList;
1312
1325
  }
@@ -1366,29 +1379,29 @@ var REMOTE_URL_REGEX = /^https?:\/\//i;
1366
1379
  var HAS_WHITESPACE_REGEX = /\s/;
1367
1380
  var PACKAGE_NAME_REGEX = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(?:@[^\s]+)?$/;
1368
1381
  var PATH_SEPARATOR_REGEX = /[/\\]/;
1369
- var stripVersionSuffix = (input5) => {
1370
- if (input5.startsWith("@")) {
1371
- const secondAtIndex = input5.indexOf("@", 1);
1372
- if (secondAtIndex > 0) return input5.slice(0, secondAtIndex);
1373
- return input5;
1374
- }
1375
- const atIndex = input5.lastIndexOf("@");
1376
- if (atIndex > 0) return input5.slice(0, atIndex);
1377
- return input5;
1378
- };
1379
- var stripScopePrefix = (input5) => {
1380
- if (!input5.startsWith("@") || !input5.includes("/")) return input5;
1381
- const parts = input5.split("/");
1382
- return parts[1] || input5;
1383
- };
1384
- var stripPathPrefix = (input5) => {
1385
- if (!PATH_SEPARATOR_REGEX.test(input5)) return input5;
1386
- const segments = input5.split(PATH_SEPARATOR_REGEX);
1382
+ var stripVersionSuffix = (input7) => {
1383
+ if (input7.startsWith("@")) {
1384
+ const secondAtIndex = input7.indexOf("@", 1);
1385
+ if (secondAtIndex > 0) return input7.slice(0, secondAtIndex);
1386
+ return input7;
1387
+ }
1388
+ const atIndex = input7.lastIndexOf("@");
1389
+ if (atIndex > 0) return input7.slice(0, atIndex);
1390
+ return input7;
1391
+ };
1392
+ var stripScopePrefix = (input7) => {
1393
+ if (!input7.startsWith("@") || !input7.includes("/")) return input7;
1394
+ const parts = input7.split("/");
1395
+ return parts[1] || input7;
1396
+ };
1397
+ var stripPathPrefix = (input7) => {
1398
+ if (!PATH_SEPARATOR_REGEX.test(input7)) return input7;
1399
+ const segments = input7.split(PATH_SEPARATOR_REGEX);
1387
1400
  const basename = segments[segments.length - 1];
1388
- return basename || input5;
1401
+ return basename || input7;
1389
1402
  };
1390
- var extractPackageName = (input5) => {
1391
- let name = stripVersionSuffix(input5);
1403
+ var extractPackageName = (input7) => {
1404
+ let name = stripVersionSuffix(input7);
1392
1405
  name = stripScopePrefix(name);
1393
1406
  name = stripPathPrefix(name);
1394
1407
  name = name.replace(SCRIPT_EXTENSION_REGEX, "");
@@ -1406,9 +1419,9 @@ var extractPackageName = (input5) => {
1406
1419
  }
1407
1420
  return name || MCP_DEFAULT_SERVER_NAME;
1408
1421
  };
1409
- var inferNameFromUrl = (input5) => {
1422
+ var inferNameFromUrl = (input7) => {
1410
1423
  try {
1411
- const url = new URL(input5);
1424
+ const url = new URL(input7);
1412
1425
  const host = url.hostname;
1413
1426
  const labels = host.split(".").filter((segment) => segment.length > 0);
1414
1427
  if (labels.length === 0) return MCP_DEFAULT_SERVER_NAME;
@@ -1437,8 +1450,8 @@ var inferNameFromCommand = (command) => {
1437
1450
  const firstNonFlag = tokens.find((token) => !token.startsWith("-"));
1438
1451
  return firstNonFlag ? extractPackageName(firstNonFlag) : MCP_DEFAULT_SERVER_NAME;
1439
1452
  };
1440
- var parseMcpSource = (input5) => {
1441
- const trimmed = input5.trim();
1453
+ var parseMcpSource = (input7) => {
1454
+ const trimmed = input7.trim();
1442
1455
  if (trimmed.length === 0) {
1443
1456
  throw new Error(
1444
1457
  "Invalid MCP source: input is empty. Expected a remote URL, an npm package, or a command line."
@@ -1564,12 +1577,12 @@ var removeMcpServer = (options) => {
1564
1577
  };
1565
1578
 
1566
1579
  // src/interactive/main-menu.ts
1567
- var import_prompts10 = require("@inquirer/prompts");
1568
- var import_picocolors10 = __toESM(require("picocolors"), 1);
1580
+ var import_prompts11 = require("@inquirer/prompts");
1581
+ var import_picocolors11 = __toESM(require("picocolors"), 1);
1569
1582
 
1570
1583
  // src/interactive/wizard-add.ts
1571
- var import_prompts7 = require("@inquirer/prompts");
1572
- var import_picocolors7 = __toESM(require("picocolors"), 1);
1584
+ var import_prompts8 = require("@inquirer/prompts");
1585
+ var import_picocolors8 = __toESM(require("picocolors"), 1);
1573
1586
 
1574
1587
  // src/utils/logger.ts
1575
1588
  var import_picocolors = __toESM(require("picocolors"), 1);
@@ -1693,10 +1706,25 @@ var promptArgsConfig = async (initialArgs = []) => {
1693
1706
  });
1694
1707
  return parseArgsString(raw.trim());
1695
1708
  };
1709
+ var formatArgsString = (args) => {
1710
+ return args.map((arg) => arg.includes(" ") || arg.includes('"') ? `"${arg.replace(/"/g, '\\"')}"` : arg).join(" ");
1711
+ };
1712
+ var promptEditArgs = async (currentArgs = []) => {
1713
+ const defaultStr = formatArgsString(currentArgs);
1714
+ const raw = await (0, import_prompts3.input)({
1715
+ message: "Edit command arguments (space-separated, wrap paths with spaces in quotes, leave empty to clear):",
1716
+ default: defaultStr
1717
+ });
1718
+ const trimmed = raw.trim();
1719
+ if (!trimmed) {
1720
+ return [];
1721
+ }
1722
+ return parseArgsString(trimmed);
1723
+ };
1696
1724
 
1697
1725
  // src/interactive/prompts/env.ts
1698
- var import_prompts5 = require("@inquirer/prompts");
1699
- var import_picocolors5 = __toESM(require("picocolors"), 1);
1726
+ var import_prompts6 = require("@inquirer/prompts");
1727
+ var import_picocolors6 = __toESM(require("picocolors"), 1);
1700
1728
 
1701
1729
  // src/interactive/prompts/multiline.ts
1702
1730
  var import_node_readline = require("readline");
@@ -1759,8 +1787,166 @@ var promptEditorText = async (options) => {
1759
1787
  }
1760
1788
  };
1761
1789
 
1790
+ // src/interactive/prompts/kv.ts
1791
+ var import_prompts5 = require("@inquirer/prompts");
1792
+ var import_picocolors5 = __toESM(require("picocolors"), 1);
1793
+ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1794
+ let items = { ...currentItems };
1795
+ while (true) {
1796
+ const keys = Object.keys(items);
1797
+ console.log();
1798
+ if (keys.length === 0) {
1799
+ console.log(import_picocolors5.default.dim(` No ${options.itemsNoun} configured.`));
1800
+ } else {
1801
+ console.log(import_picocolors5.default.cyan(import_picocolors5.default.bold(` Configured ${options.title} (${keys.length}):`)));
1802
+ for (const [k, v] of Object.entries(items)) {
1803
+ const sep = options.separator === "=" ? "=" : ": ";
1804
+ console.log(` ${import_picocolors5.default.bold(k)}${sep}${import_picocolors5.default.dim(options.maskValue(k, v))}`);
1805
+ }
1806
+ }
1807
+ console.log();
1808
+ const choice = await (0, import_prompts5.select)({
1809
+ message: `Manage ${options.itemsNoun}:`,
1810
+ choices: [
1811
+ {
1812
+ name: "Open in system default editor ($EDITOR)",
1813
+ value: "editor"
1814
+ },
1815
+ {
1816
+ name: `Add or modify a ${options.itemNoun}`,
1817
+ value: "upsert"
1818
+ },
1819
+ ...keys.length > 0 ? [
1820
+ {
1821
+ name: `Delete a ${options.itemNoun}`,
1822
+ value: "delete"
1823
+ }
1824
+ ] : [],
1825
+ {
1826
+ name: `Paste multiline ${options.itemsNoun} into terminal`,
1827
+ value: "paste"
1828
+ },
1829
+ ...keys.length > 0 ? [
1830
+ {
1831
+ name: `Clear all ${options.itemsNoun}`,
1832
+ value: "clear"
1833
+ }
1834
+ ] : [],
1835
+ {
1836
+ name: `Done (finish editing ${options.itemsNoun})`,
1837
+ value: "done"
1838
+ }
1839
+ ]
1840
+ });
1841
+ if (choice === "done") {
1842
+ return items;
1843
+ }
1844
+ if (choice === "editor") {
1845
+ const defaultText = options.formatText(items);
1846
+ const text = await promptEditorText({
1847
+ message: options.editorMessage,
1848
+ postfix: options.editorPostfix,
1849
+ defaultText
1850
+ });
1851
+ const parsed = options.parseText(text);
1852
+ items = parsed;
1853
+ logger.success(`${options.title} updated (${Object.keys(items).length} total)`);
1854
+ } else if (choice === "upsert") {
1855
+ const key = await (0, import_prompts5.input)({
1856
+ message: options.keyPromptMessage,
1857
+ validate: (val) => {
1858
+ const trimmed = val.trim();
1859
+ if (!trimmed) return `${options.itemNoun} name cannot be empty`;
1860
+ if (/\s/.test(trimmed)) return `${options.itemNoun} name cannot contain spaces`;
1861
+ return true;
1862
+ }
1863
+ });
1864
+ const trimmedKey = key.trim();
1865
+ const existingVal = items[trimmedKey];
1866
+ const isSecret = options.isSecretKey(trimmedKey);
1867
+ let newVal;
1868
+ if (isSecret) {
1869
+ newVal = await (0, import_prompts5.password)({
1870
+ message: existingVal !== void 0 ? `New value for (${trimmedKey}) [leave empty to keep current]:` : `${options.valuePromptMessage} for (${trimmedKey}) [sensitive content masked]:`,
1871
+ mask: "*"
1872
+ });
1873
+ if (existingVal !== void 0 && newVal === "") {
1874
+ newVal = existingVal;
1875
+ }
1876
+ } else {
1877
+ newVal = await (0, import_prompts5.input)({
1878
+ message: `${options.valuePromptMessage} for (${trimmedKey}):`,
1879
+ default: existingVal
1880
+ });
1881
+ }
1882
+ items[trimmedKey] = newVal;
1883
+ logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${import_picocolors5.default.cyan(trimmedKey)}`);
1884
+ } else if (choice === "delete") {
1885
+ const toDelete = await (0, import_prompts5.select)({
1886
+ message: `Select ${options.itemNoun} to delete:`,
1887
+ choices: [
1888
+ ...keys.map((k) => ({ name: k, value: k })),
1889
+ { name: "Cancel", value: "__cancel__" }
1890
+ ]
1891
+ });
1892
+ if (toDelete !== "__cancel__") {
1893
+ delete items[toDelete];
1894
+ logger.success(`Deleted: ${import_picocolors5.default.cyan(toDelete)}`);
1895
+ }
1896
+ } else if (choice === "paste") {
1897
+ const pasted = await readMultilineTextFromTerminal(options.pasteMessage);
1898
+ const parsed = options.parseText(pasted);
1899
+ const count = Object.keys(parsed).length;
1900
+ if (count === 0) {
1901
+ logger.warn(`No valid ${options.itemsNoun} recognized`);
1902
+ } else {
1903
+ if (keys.length > 0) {
1904
+ const pasteMode = await (0, import_prompts5.select)({
1905
+ message: `How to apply pasted ${options.itemsNoun}?`,
1906
+ choices: [
1907
+ { name: `Merge with existing ${options.itemsNoun}`, value: "merge" },
1908
+ { name: `Replace all existing ${options.itemsNoun}`, value: "replace" }
1909
+ ]
1910
+ });
1911
+ if (pasteMode === "replace") {
1912
+ items = parsed;
1913
+ } else {
1914
+ Object.assign(items, parsed);
1915
+ }
1916
+ } else {
1917
+ items = parsed;
1918
+ }
1919
+ logger.success(`Successfully applied ${import_picocolors5.default.cyan(String(count))} ${options.itemsNoun}`);
1920
+ }
1921
+ } else if (choice === "clear") {
1922
+ const confirmClear = await (0, import_prompts5.confirm)({
1923
+ message: `Are you sure you want to clear all ${options.itemsNoun}?`,
1924
+ default: false
1925
+ });
1926
+ if (confirmClear) {
1927
+ items = {};
1928
+ logger.success(`Cleared all ${options.itemsNoun}`);
1929
+ }
1930
+ }
1931
+ }
1932
+ };
1933
+
1762
1934
  // src/interactive/prompts/env.ts
1763
1935
  var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
1936
+ var maskSecretValue = (key, value) => {
1937
+ if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
1938
+ return value;
1939
+ }
1940
+ return `${value.slice(0, 2)}***${value.slice(-2)}`;
1941
+ };
1942
+ var formatEnvText = (env) => {
1943
+ return Object.entries(env).map(([key, value]) => {
1944
+ if (/[\s"']/.test(value)) {
1945
+ return `${key}="${value.replace(/"/g, '\\"')}"`;
1946
+ }
1947
+ return `${key}=${value}`;
1948
+ }).join("\n");
1949
+ };
1764
1950
  var parseEnvText = (rawText) => {
1765
1951
  const result = {};
1766
1952
  const lines = rawText.split(/\r?\n/);
@@ -1786,9 +1972,9 @@ var promptEnvConfig = async (initialEnv = {}) => {
1786
1972
  const env = { ...initialEnv };
1787
1973
  const initialCount = Object.keys(env).length;
1788
1974
  if (initialCount > 0) {
1789
- logger.info(`Includes ${import_picocolors5.default.cyan(String(initialCount))} preset environment variables`);
1975
+ logger.info(`Includes ${import_picocolors6.default.cyan(String(initialCount))} preset environment variables`);
1790
1976
  }
1791
- const mode = await (0, import_prompts5.select)({
1977
+ const mode = await (0, import_prompts6.select)({
1792
1978
  message: "Configure environment variables?",
1793
1979
  choices: [
1794
1980
  {
@@ -1815,7 +2001,8 @@ var promptEnvConfig = async (initialEnv = {}) => {
1815
2001
  if (mode === "paste" || mode === "editor") {
1816
2002
  const pasted = mode === "editor" ? await promptEditorText({
1817
2003
  message: "Paste or edit environment variables in editor, then save and exit:",
1818
- postfix: ".env"
2004
+ postfix: ".env",
2005
+ defaultText: formatEnvText(env)
1819
2006
  }) : await readMultilineTextFromTerminal("Paste .env formatted content (multiline supported):");
1820
2007
  const parsed = parseEnvText(pasted);
1821
2008
  const count = Object.keys(parsed).length;
@@ -1823,17 +2010,16 @@ var promptEnvConfig = async (initialEnv = {}) => {
1823
2010
  logger.warn("No valid KEY=VALUE pairs recognized");
1824
2011
  } else {
1825
2012
  Object.assign(env, parsed);
1826
- logger.success(`Successfully parsed ${import_picocolors5.default.cyan(String(count))} environment variables:`);
2013
+ logger.success(`Successfully parsed ${import_picocolors6.default.cyan(String(count))} environment variables:`);
1827
2014
  for (const [k, v] of Object.entries(parsed)) {
1828
- const masked = SECRET_KEY_PATTERN.test(k) && v.length > 4 ? `${v.slice(0, 2)}***${v.slice(-2)}` : v;
1829
- console.log(` ${import_picocolors5.default.bold(k)}=${import_picocolors5.default.dim(masked)}`);
2015
+ console.log(` ${import_picocolors6.default.bold(k)}=${import_picocolors6.default.dim(maskSecretValue(k, v))}`);
1830
2016
  }
1831
2017
  }
1832
2018
  return env;
1833
2019
  }
1834
2020
  logger.info("Entering environment variables (leave key empty and press enter to finish):");
1835
2021
  while (true) {
1836
- const key = await (0, import_prompts5.input)({
2022
+ const key = await (0, import_prompts6.input)({
1837
2023
  message: "Variable name (Key, leave empty to finish):",
1838
2024
  validate: (val2) => {
1839
2025
  const trimmed = val2.trim();
@@ -1847,25 +2033,49 @@ var promptEnvConfig = async (initialEnv = {}) => {
1847
2033
  const isSecret = SECRET_KEY_PATTERN.test(trimmedKey);
1848
2034
  let val;
1849
2035
  if (isSecret) {
1850
- val = await (0, import_prompts5.password)({
2036
+ val = await (0, import_prompts6.password)({
1851
2037
  message: `Value for (${trimmedKey}) [secret masked]:`,
1852
2038
  mask: "*"
1853
2039
  });
1854
2040
  } else {
1855
- val = await (0, import_prompts5.input)({
2041
+ val = await (0, import_prompts6.input)({
1856
2042
  message: `Value for (${trimmedKey}):`
1857
2043
  });
1858
2044
  }
1859
2045
  env[trimmedKey] = val;
1860
- logger.success(`Added: ${import_picocolors5.default.cyan(trimmedKey)}`);
2046
+ logger.success(`Added: ${import_picocolors6.default.cyan(trimmedKey)}`);
1861
2047
  }
1862
2048
  return env;
1863
2049
  };
2050
+ var promptEditEnvConfig = async (currentEnv = {}) => promptEditKeyValueConfig(currentEnv, {
2051
+ title: "Environment Variables",
2052
+ itemNoun: "variable",
2053
+ itemsNoun: "environment variables",
2054
+ separator: "=",
2055
+ editorPostfix: ".env",
2056
+ editorMessage: "Edit environment variables in editor, then save and exit:",
2057
+ pasteMessage: "Paste .env formatted content (multiline supported):",
2058
+ keyPromptMessage: "Variable name (Key):",
2059
+ valuePromptMessage: "Value",
2060
+ isSecretKey: (k) => SECRET_KEY_PATTERN.test(k),
2061
+ maskValue: maskSecretValue,
2062
+ formatText: formatEnvText,
2063
+ parseText: parseEnvText
2064
+ });
1864
2065
 
1865
2066
  // src/interactive/prompts/headers.ts
1866
- var import_prompts6 = require("@inquirer/prompts");
1867
- var import_picocolors6 = __toESM(require("picocolors"), 1);
2067
+ var import_prompts7 = require("@inquirer/prompts");
2068
+ var import_picocolors7 = __toESM(require("picocolors"), 1);
1868
2069
  var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
2070
+ var maskSecretHeader = (key, value) => {
2071
+ if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
2072
+ return value;
2073
+ }
2074
+ return `${value.slice(0, 4)}***${value.slice(-3)}`;
2075
+ };
2076
+ var formatHeadersText = (headers) => {
2077
+ return Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join("\n");
2078
+ };
1869
2079
  var parseHeadersText = (rawText) => {
1870
2080
  const result = {};
1871
2081
  const lines = rawText.split(/\r?\n/);
@@ -1895,7 +2105,7 @@ var parseHeadersText = (rawText) => {
1895
2105
  };
1896
2106
  var promptHeadersConfig = async (initialHeaders = {}) => {
1897
2107
  const headers = { ...initialHeaders };
1898
- const mode = await (0, import_prompts6.select)({
2108
+ const mode = await (0, import_prompts7.select)({
1899
2109
  message: "Select HTTP headers configuration method:",
1900
2110
  choices: [
1901
2111
  {
@@ -1921,7 +2131,8 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
1921
2131
  }
1922
2132
  if (mode === "paste" || mode === "editor") {
1923
2133
  const pasted = mode === "editor" ? await promptEditorText({
1924
- message: "Paste or edit HTTP headers in editor, then save and exit:"
2134
+ message: "Paste or edit HTTP headers in editor, then save and exit:",
2135
+ defaultText: formatHeadersText(headers)
1925
2136
  }) : await readMultilineTextFromTerminal(
1926
2137
  "Paste HTTP headers content (multiline supported, e.g. Authorization: Bearer ...):"
1927
2138
  );
@@ -1931,17 +2142,16 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
1931
2142
  logger.warn("No valid Key: Value pairs recognized");
1932
2143
  } else {
1933
2144
  Object.assign(headers, parsed);
1934
- logger.success(`Successfully parsed ${import_picocolors6.default.cyan(String(count))} headers:`);
2145
+ logger.success(`Successfully parsed ${import_picocolors7.default.cyan(String(count))} headers:`);
1935
2146
  for (const [k, v] of Object.entries(parsed)) {
1936
- const masked = SECRET_HEADER_PATTERN.test(k) && v.length > 8 ? `${v.slice(0, 4)}***${v.slice(-3)}` : v;
1937
- console.log(` ${import_picocolors6.default.bold(k)}: ${import_picocolors6.default.dim(masked)}`);
2147
+ console.log(` ${import_picocolors7.default.bold(k)}: ${import_picocolors7.default.dim(maskSecretHeader(k, v))}`);
1938
2148
  }
1939
2149
  }
1940
2150
  return headers;
1941
2151
  }
1942
2152
  logger.info("Entering HTTP headers (leave header name empty and press enter to finish):");
1943
2153
  while (true) {
1944
- const name = await (0, import_prompts6.input)({
2154
+ const name = await (0, import_prompts7.input)({
1945
2155
  message: "Header name (e.g. Authorization, leave empty to finish):",
1946
2156
  validate: (val2) => {
1947
2157
  const trimmed = val2.trim();
@@ -1955,28 +2165,42 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
1955
2165
  const isSecret = SECRET_HEADER_PATTERN.test(trimmedName);
1956
2166
  let val;
1957
2167
  if (isSecret) {
1958
- val = await (0, import_prompts6.password)({
2168
+ val = await (0, import_prompts7.password)({
1959
2169
  message: `Header value for (${trimmedName}) [sensitive content masked]:`,
1960
2170
  mask: "*"
1961
2171
  });
1962
2172
  } else {
1963
- val = await (0, import_prompts6.input)({
2173
+ val = await (0, import_prompts7.input)({
1964
2174
  message: `Header value for (${trimmedName}):`
1965
2175
  });
1966
2176
  }
1967
2177
  headers[trimmedName] = val;
1968
- logger.success(`Added: ${import_picocolors6.default.cyan(trimmedName)}`);
2178
+ logger.success(`Added: ${import_picocolors7.default.cyan(trimmedName)}`);
1969
2179
  }
1970
2180
  return headers;
1971
2181
  };
2182
+ var promptEditHeadersConfig = async (currentHeaders = {}) => promptEditKeyValueConfig(currentHeaders, {
2183
+ title: "HTTP Headers",
2184
+ itemNoun: "header",
2185
+ itemsNoun: "HTTP headers",
2186
+ separator: ":",
2187
+ editorMessage: "Edit HTTP headers in editor, then save and exit:",
2188
+ pasteMessage: "Paste HTTP headers content (multiline supported, e.g. Authorization: Bearer ...):",
2189
+ keyPromptMessage: "Header name (e.g. Authorization):",
2190
+ valuePromptMessage: "Header value",
2191
+ isSecretKey: (k) => SECRET_HEADER_PATTERN.test(k),
2192
+ maskValue: maskSecretHeader,
2193
+ formatText: formatHeadersText,
2194
+ parseText: parseHeadersText
2195
+ });
1972
2196
 
1973
2197
  // src/interactive/wizard-add.ts
1974
2198
  var wizardAdd = async (initial = {}) => {
1975
2199
  const cwd = initial.cwd ?? process.cwd();
1976
- logger.info(import_picocolors7.default.bold("Welcome to the MCP interactive add wizard"));
2200
+ logger.info(import_picocolors8.default.bold("Welcome to the MCP interactive add wizard"));
1977
2201
  let source = initial.source;
1978
2202
  if (!source) {
1979
- const sourceType = await (0, import_prompts7.select)({
2203
+ const sourceType = await (0, import_prompts8.select)({
1980
2204
  message: "Select MCP server type:",
1981
2205
  choices: [
1982
2206
  {
@@ -1994,12 +2218,12 @@ var wizardAdd = async (initial = {}) => {
1994
2218
  ]
1995
2219
  });
1996
2220
  if (sourceType === "npm") {
1997
- source = await (0, import_prompts7.input)({
1998
- message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres or mcp-server-git):",
2221
+ source = await (0, import_prompts8.input)({
2222
+ message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres):",
1999
2223
  validate: (val) => val.trim() ? true : "Package name cannot be empty"
2000
2224
  });
2001
2225
  } else if (sourceType === "remote") {
2002
- source = await (0, import_prompts7.input)({
2226
+ source = await (0, import_prompts8.input)({
2003
2227
  message: "Enter remote server URL (e.g. https://mcp.example.com/sse):",
2004
2228
  validate: (val) => {
2005
2229
  const trimmed = val.trim();
@@ -2009,7 +2233,7 @@ var wizardAdd = async (initial = {}) => {
2009
2233
  }
2010
2234
  });
2011
2235
  } else {
2012
- source = await (0, import_prompts7.input)({
2236
+ source = await (0, import_prompts8.input)({
2013
2237
  message: "Enter command and arguments (e.g. python -m my_mcp_server or docker run ...):",
2014
2238
  validate: (val) => val.trim() ? true : "Command cannot be empty"
2015
2239
  });
@@ -2019,7 +2243,7 @@ var wizardAdd = async (initial = {}) => {
2019
2243
  const parsed = parseMcpSource(source);
2020
2244
  let serverName = initial.name;
2021
2245
  if (!serverName) {
2022
- serverName = await (0, import_prompts7.input)({
2246
+ serverName = await (0, import_prompts8.input)({
2023
2247
  message: "MCP server name:",
2024
2248
  default: parsed.inferredName,
2025
2249
  validate: (val) => val.trim() ? true : "Server name cannot be empty"
@@ -2031,7 +2255,7 @@ var wizardAdd = async (initial = {}) => {
2031
2255
  if (parsed.type === "remote") {
2032
2256
  if (!transport) {
2033
2257
  const isSseUrl = /\/sse\b/i.test(parsed.value);
2034
- transport = await (0, import_prompts7.select)({
2258
+ transport = await (0, import_prompts8.select)({
2035
2259
  message: "Select remote transport protocol:",
2036
2260
  choices: [
2037
2261
  { name: "HTTP", value: "http" },
@@ -2041,7 +2265,7 @@ var wizardAdd = async (initial = {}) => {
2041
2265
  });
2042
2266
  }
2043
2267
  if (Object.keys(headers).length === 0) {
2044
- const needHeader = await (0, import_prompts7.confirm)({
2268
+ const needHeader = await (0, import_prompts8.confirm)({
2045
2269
  message: "Configure HTTP headers (e.g. Authorization Bearer token)?",
2046
2270
  default: false
2047
2271
  });
@@ -2063,28 +2287,28 @@ var wizardAdd = async (initial = {}) => {
2063
2287
  if (parsed.type !== "remote") {
2064
2288
  env = await promptEnvConfig(env);
2065
2289
  }
2066
- console.log("\n" + import_picocolors7.default.cyan(import_picocolors7.default.bold("Configuration Preview:")));
2067
- console.log(` ${import_picocolors7.default.bold("Server Name:")} ${import_picocolors7.default.green(serverName)}`);
2068
- console.log(` ${import_picocolors7.default.bold("Server Type:")} ${import_picocolors7.default.magenta(parsed.type)}`);
2069
- console.log(` ${import_picocolors7.default.bold("Source/Command:")} ${import_picocolors7.default.dim(source)}`);
2070
- console.log(` ${import_picocolors7.default.bold("Scope:")} ${isGlobal ? import_picocolors7.default.yellow("Global") : import_picocolors7.default.blue("Project")}`);
2071
- console.log(` ${import_picocolors7.default.bold("Target Agents:")} ${import_picocolors7.default.cyan(selectedAgents.join(", "))}`);
2290
+ console.log("\n" + import_picocolors8.default.cyan(import_picocolors8.default.bold("Configuration Preview:")));
2291
+ console.log(` ${import_picocolors8.default.bold("Server Name:")} ${import_picocolors8.default.green(serverName)}`);
2292
+ console.log(` ${import_picocolors8.default.bold("Server Type:")} ${import_picocolors8.default.magenta(parsed.type)}`);
2293
+ console.log(` ${import_picocolors8.default.bold("Source/Command:")} ${import_picocolors8.default.dim(source)}`);
2294
+ console.log(` ${import_picocolors8.default.bold("Scope:")} ${isGlobal ? import_picocolors8.default.yellow("Global") : import_picocolors8.default.blue("Project")}`);
2295
+ console.log(` ${import_picocolors8.default.bold("Target Agents:")} ${import_picocolors8.default.cyan(selectedAgents.join(", "))}`);
2072
2296
  if (args.length > 0) {
2073
- console.log(` ${import_picocolors7.default.bold("Arguments:")} ${import_picocolors7.default.dim(args.join(" "))}`);
2297
+ console.log(` ${import_picocolors8.default.bold("Arguments:")} ${import_picocolors8.default.dim(args.join(" "))}`);
2074
2298
  }
2075
2299
  if (transport) {
2076
- console.log(` ${import_picocolors7.default.bold("Transport:")} ${import_picocolors7.default.magenta(transport)}`);
2300
+ console.log(` ${import_picocolors8.default.bold("Transport:")} ${import_picocolors8.default.magenta(transport)}`);
2077
2301
  }
2078
2302
  const envKeys = Object.keys(env);
2079
2303
  if (envKeys.length > 0) {
2080
- console.log(` ${import_picocolors7.default.bold("Environment Variables:")} ${import_picocolors7.default.dim(envKeys.join(", "))} (${envKeys.length})`);
2304
+ console.log(` ${import_picocolors8.default.bold("Environment Variables:")} ${import_picocolors8.default.dim(envKeys.join(", "))} (${envKeys.length})`);
2081
2305
  }
2082
2306
  const headerKeys = Object.keys(headers);
2083
2307
  if (headerKeys.length > 0) {
2084
- console.log(` ${import_picocolors7.default.bold("Headers:")} ${import_picocolors7.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
2308
+ console.log(` ${import_picocolors8.default.bold("Headers:")} ${import_picocolors8.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
2085
2309
  }
2086
2310
  console.log();
2087
- const proceed = await (0, import_prompts7.confirm)({
2311
+ const proceed = await (0, import_prompts8.confirm)({
2088
2312
  message: "Confirm installation with this configuration?",
2089
2313
  default: true
2090
2314
  });
@@ -2104,26 +2328,26 @@ var wizardAdd = async (initial = {}) => {
2104
2328
  env
2105
2329
  });
2106
2330
  logger.info(
2107
- `Writing ${import_picocolors7.default.bold(result.serverName)} to ${import_picocolors7.default.cyan(String(result.results.length))} agent config files...`
2331
+ `Writing ${import_picocolors8.default.bold(result.serverName)} to ${import_picocolors8.default.cyan(String(result.results.length))} agent config files...`
2108
2332
  );
2109
2333
  let allSuccess = true;
2110
2334
  for (const record of result.results) {
2111
2335
  if (record.success) {
2112
- logger.success(`${import_picocolors7.default.cyan(record.agent)}: Successfully written to ${import_picocolors7.default.dim(record.path)}`);
2336
+ logger.success(`${import_picocolors8.default.cyan(record.agent)}: Successfully written to ${import_picocolors8.default.dim(record.path)}`);
2113
2337
  } else {
2114
2338
  allSuccess = false;
2115
- logger.error(`${import_picocolors7.default.cyan(record.agent)}: Failed to write - ${record.error}`);
2339
+ logger.error(`${import_picocolors8.default.cyan(record.agent)}: Failed to write - ${record.error}`);
2116
2340
  }
2117
2341
  }
2118
2342
  if (allSuccess) {
2119
- logger.success(import_picocolors7.default.bold(`MCP server "${serverName}" configured successfully!`));
2343
+ logger.success(import_picocolors8.default.bold(`MCP server "${serverName}" configured successfully!`));
2120
2344
  }
2121
2345
  return allSuccess;
2122
2346
  };
2123
2347
 
2124
2348
  // src/interactive/wizard-manage.ts
2125
- var import_prompts8 = require("@inquirer/prompts");
2126
- var import_picocolors8 = __toESM(require("picocolors"), 1);
2349
+ var import_prompts9 = require("@inquirer/prompts");
2350
+ var import_picocolors9 = __toESM(require("picocolors"), 1);
2127
2351
 
2128
2352
  // src/interactive/utils/group-installed-servers.ts
2129
2353
  var normalizeServerConfig = parseServerConfig;
@@ -2151,6 +2375,204 @@ var groupInstalledServersByName = (installed) => {
2151
2375
  };
2152
2376
 
2153
2377
  // src/interactive/wizard-manage.ts
2378
+ var displayServerDetails = ({
2379
+ serverName,
2380
+ config,
2381
+ agents,
2382
+ isGlobal,
2383
+ titlePrefix = "MCP Server Details"
2384
+ }) => {
2385
+ console.log("\n" + import_picocolors9.default.cyan(import_picocolors9.default.bold(`${titlePrefix}: [${serverName}]`)));
2386
+ if (isGlobal !== void 0) {
2387
+ console.log(` ${import_picocolors9.default.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
2388
+ }
2389
+ if (agents && agents.length > 0) {
2390
+ console.log(
2391
+ ` ${import_picocolors9.default.bold("Configured Agents:")} ${import_picocolors9.default.green(agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2392
+ );
2393
+ }
2394
+ const isRemote = Boolean(config.url && config.url.length > 0);
2395
+ if (isRemote) {
2396
+ console.log(` ${import_picocolors9.default.bold("Transport:")} ${import_picocolors9.default.magenta(config.type ?? "http")}`);
2397
+ console.log(` ${import_picocolors9.default.bold("URL:")} ${import_picocolors9.default.dim(config.url ?? "")}`);
2398
+ const headerKeys = Object.keys(config.headers ?? {});
2399
+ if (headerKeys.length > 0) {
2400
+ console.log(` ${import_picocolors9.default.bold("Headers:")} ${import_picocolors9.default.cyan(String(headerKeys.length))}`);
2401
+ for (const [k, v] of Object.entries(config.headers ?? {})) {
2402
+ console.log(` ${import_picocolors9.default.bold(k)}: ${import_picocolors9.default.dim(maskSecretHeader(k, v))}`);
2403
+ }
2404
+ } else {
2405
+ console.log(` ${import_picocolors9.default.bold("Headers:")} ${import_picocolors9.default.dim("(none)")}`);
2406
+ }
2407
+ } else {
2408
+ console.log(` ${import_picocolors9.default.bold("Command:")} ${import_picocolors9.default.magenta(config.command ?? "")}`);
2409
+ const argsStr = config.args && config.args.length > 0 ? config.args.join(" ") : "(none)";
2410
+ console.log(` ${import_picocolors9.default.bold("Arguments:")} ${import_picocolors9.default.dim(argsStr)}`);
2411
+ const envKeys = Object.keys(config.env ?? {});
2412
+ if (envKeys.length > 0) {
2413
+ console.log(` ${import_picocolors9.default.bold("Environment Variables:")} ${import_picocolors9.default.cyan(String(envKeys.length))}`);
2414
+ for (const [k, v] of Object.entries(config.env ?? {})) {
2415
+ console.log(` ${import_picocolors9.default.bold(k)}=${import_picocolors9.default.dim(maskSecretValue(k, v))}`);
2416
+ }
2417
+ } else {
2418
+ console.log(` ${import_picocolors9.default.bold("Environment Variables:")} ${import_picocolors9.default.dim("(none)")}`);
2419
+ }
2420
+ }
2421
+ console.log();
2422
+ };
2423
+ var handleEditServerConfig = async ({
2424
+ targetGroup,
2425
+ isGlobal,
2426
+ cwd
2427
+ }) => {
2428
+ const serverName = targetGroup.serverName;
2429
+ let workingConfig = {
2430
+ ...targetGroup.config,
2431
+ args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
2432
+ env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
2433
+ headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
2434
+ };
2435
+ while (true) {
2436
+ const isRemote = Boolean(workingConfig.url && workingConfig.url.length > 0);
2437
+ displayServerDetails({
2438
+ serverName,
2439
+ config: workingConfig,
2440
+ titlePrefix: "Edit Server Configuration"
2441
+ });
2442
+ const editChoices = isRemote ? [
2443
+ { name: "Edit HTTP Headers (headers)", value: "headers" },
2444
+ { name: "Edit Remote URL (url)", value: "url" },
2445
+ { name: "Edit Transport Protocol (type)", value: "transport" },
2446
+ { name: "Reset changes to original", value: "reset" },
2447
+ { name: "Save and apply changes", value: "save" },
2448
+ { name: "Cancel (discard changes)", value: "cancel" }
2449
+ ] : [
2450
+ { name: "Edit Environment Variables (env)", value: "env" },
2451
+ { name: "Edit Command Arguments (args)", value: "args" },
2452
+ { name: "Edit Executable Command (command)", value: "command" },
2453
+ { name: "Reset changes to original", value: "reset" },
2454
+ { name: "Save and apply changes", value: "save" },
2455
+ { name: "Cancel (discard changes)", value: "cancel" }
2456
+ ];
2457
+ const editAction = await (0, import_prompts9.select)({
2458
+ message: `What would you like to modify in [${serverName}]?`,
2459
+ choices: editChoices
2460
+ });
2461
+ if (editAction === "cancel") {
2462
+ logger.info("Modification cancelled; changes discarded");
2463
+ return;
2464
+ }
2465
+ if (editAction === "reset") {
2466
+ workingConfig = {
2467
+ ...targetGroup.config,
2468
+ args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
2469
+ env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
2470
+ headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
2471
+ };
2472
+ logger.info("Configuration reset to original");
2473
+ continue;
2474
+ }
2475
+ if (editAction === "env") {
2476
+ workingConfig.env = await promptEditEnvConfig(workingConfig.env ?? {});
2477
+ } else if (editAction === "args") {
2478
+ workingConfig.args = await promptEditArgs(workingConfig.args ?? []);
2479
+ } else if (editAction === "command") {
2480
+ const newCmd = await (0, import_prompts9.input)({
2481
+ message: "Executable command:",
2482
+ default: workingConfig.command,
2483
+ validate: (val) => val.trim() ? true : "Command cannot be empty"
2484
+ });
2485
+ workingConfig.command = newCmd.trim();
2486
+ } else if (editAction === "headers") {
2487
+ workingConfig.headers = await promptEditHeadersConfig(workingConfig.headers ?? {});
2488
+ } else if (editAction === "url") {
2489
+ const newUrl = await (0, import_prompts9.input)({
2490
+ message: "Remote server URL:",
2491
+ default: workingConfig.url,
2492
+ validate: (val) => {
2493
+ const trimmed = val.trim();
2494
+ if (!trimmed) return "URL cannot be empty";
2495
+ if (!/^https?:\/\//i.test(trimmed)) {
2496
+ return "Please enter a valid URL starting with http:// or https://";
2497
+ }
2498
+ return true;
2499
+ }
2500
+ });
2501
+ workingConfig.url = newUrl.trim();
2502
+ } else if (editAction === "transport") {
2503
+ workingConfig.type = await (0, import_prompts9.select)({
2504
+ message: "Select remote transport protocol:",
2505
+ choices: [
2506
+ { name: "HTTP", value: "http" },
2507
+ { name: "SSE (Server-Sent Events)", value: "sse" }
2508
+ ],
2509
+ default: workingConfig.type === "sse" ? "sse" : "http"
2510
+ });
2511
+ } else if (editAction === "save") {
2512
+ let targetAgents = targetGroup.agents;
2513
+ if (targetGroup.agents.length > 1) {
2514
+ targetAgents = await (0, import_prompts9.checkbox)({
2515
+ message: "Select agents to update configuration (Space to toggle):",
2516
+ choices: targetGroup.agents.map((a) => ({
2517
+ name: `${getMcpAgentConfig(a).displayName} (${a})`,
2518
+ value: a,
2519
+ checked: true
2520
+ })),
2521
+ loop: false,
2522
+ validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2523
+ });
2524
+ }
2525
+ const requestedTransport = workingConfig.url ? workingConfig.type ?? "http" : "stdio";
2526
+ const compatibleAgents = [];
2527
+ const incompatibleAgents = [];
2528
+ for (const agent of targetAgents) {
2529
+ const agentConfig = getMcpAgentConfig(agent);
2530
+ if (isMcpTransportSupported(agentConfig, requestedTransport)) {
2531
+ compatibleAgents.push(agent);
2532
+ } else {
2533
+ const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
2534
+ incompatibleAgents.push({ agent, reason });
2535
+ }
2536
+ }
2537
+ if (incompatibleAgents.length > 0) {
2538
+ for (const item of incompatibleAgents) {
2539
+ logger.warn(`Skipping ${import_picocolors9.default.cyan(item.agent)}: ${item.reason}`);
2540
+ }
2541
+ }
2542
+ if (compatibleAgents.length === 0) {
2543
+ logger.error(
2544
+ `None of the selected agents support ${requestedTransport} transport. Cannot update.`
2545
+ );
2546
+ continue;
2547
+ }
2548
+ const agentNames = compatibleAgents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2549
+ const confirmed = await (0, import_prompts9.confirm)({
2550
+ message: `Confirm updating configuration for [${serverName}] across: ${agentNames}?`,
2551
+ default: true
2552
+ });
2553
+ if (!confirmed) {
2554
+ logger.warn("Update cancelled");
2555
+ continue;
2556
+ }
2557
+ for (const targetAgent of compatibleAgents) {
2558
+ const res = installMcpServerForAgent(serverName, workingConfig, targetAgent, {
2559
+ global: isGlobal,
2560
+ cwd
2561
+ });
2562
+ if (res.success) {
2563
+ logger.success(
2564
+ `${import_picocolors9.default.cyan(targetAgent)}: Successfully updated configuration in ${import_picocolors9.default.dim(res.path)}`
2565
+ );
2566
+ } else {
2567
+ logger.error(`${import_picocolors9.default.cyan(targetAgent)}: Update failed - ${res.error}`);
2568
+ }
2569
+ }
2570
+ targetGroup.config = workingConfig;
2571
+ logger.success(`Configuration for [${serverName}] updated successfully!`);
2572
+ return;
2573
+ }
2574
+ }
2575
+ };
2154
2576
  var wizardManage = async (options = {}) => {
2155
2577
  const cwd = options.cwd ?? process.cwd();
2156
2578
  const isGlobal = await promptScope({
@@ -2164,51 +2586,48 @@ var wizardManage = async (options = {}) => {
2164
2586
  return;
2165
2587
  }
2166
2588
  const grouped = groupInstalledServersByName(installed);
2589
+ let pendingServerName = options.serverName;
2167
2590
  while (true) {
2168
- const choices = Array.from(grouped.values()).map((g) => {
2169
- const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2170
- return {
2171
- name: `${import_picocolors8.default.bold(g.serverName)} ${import_picocolors8.default.dim(`(configured in: ${agentNames})`)}`,
2172
- value: g.serverName
2173
- };
2174
- });
2175
- choices.push({
2176
- name: `Back`,
2177
- value: "__back__"
2178
- });
2179
- const chosenServerName = await (0, import_prompts8.select)({
2180
- message: "Select MCP server to manage or sync:",
2181
- choices
2182
- });
2183
- if (chosenServerName === "__back__") {
2184
- return;
2591
+ let chosenServerName;
2592
+ if (pendingServerName && grouped.has(pendingServerName)) {
2593
+ chosenServerName = pendingServerName;
2594
+ pendingServerName = void 0;
2595
+ } else {
2596
+ pendingServerName = void 0;
2597
+ const choices = Array.from(grouped.values()).map((g) => {
2598
+ const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2599
+ return {
2600
+ name: `${import_picocolors9.default.bold(g.serverName)} ${import_picocolors9.default.dim(`(configured in: ${agentNames})`)}`,
2601
+ value: g.serverName
2602
+ };
2603
+ });
2604
+ choices.push({
2605
+ name: `Back`,
2606
+ value: "__back__"
2607
+ });
2608
+ chosenServerName = await (0, import_prompts9.select)({
2609
+ message: "Select MCP server to manage or sync:",
2610
+ choices
2611
+ });
2612
+ if (chosenServerName === "__back__") {
2613
+ return;
2614
+ }
2185
2615
  }
2186
2616
  const targetGroup = grouped.get(chosenServerName);
2187
2617
  if (!targetGroup) continue;
2188
- console.log("\n" + import_picocolors8.default.cyan(import_picocolors8.default.bold(`MCP Server Details: [${chosenServerName}]`)));
2189
- console.log(` ${import_picocolors8.default.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
2190
- console.log(
2191
- ` ${import_picocolors8.default.bold("Configured Agents:")} ${import_picocolors8.default.green(targetGroup.agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2192
- );
2193
- const cfg = targetGroup.config;
2194
- if (isRemoteServerConfig(cfg)) {
2195
- console.log(` ${import_picocolors8.default.bold("URL:")} ${import_picocolors8.default.dim(cfg.url)} (${cfg.type})`);
2196
- if (cfg.headers && Object.keys(cfg.headers).length > 0) {
2197
- console.log(` ${import_picocolors8.default.bold("Headers:")} ${Object.keys(cfg.headers).join(", ")}`);
2198
- }
2199
- } else if (isStdioServerConfig(cfg)) {
2200
- console.log(` ${import_picocolors8.default.bold("Command:")} ${import_picocolors8.default.magenta(cfg.command)}`);
2201
- if (cfg.args && cfg.args.length > 0) {
2202
- console.log(` ${import_picocolors8.default.bold("Arguments:")} ${import_picocolors8.default.dim(cfg.args.join(" "))}`);
2203
- }
2204
- if (cfg.env && Object.keys(cfg.env).length > 0) {
2205
- console.log(` ${import_picocolors8.default.bold("Environment Variables:")} ${import_picocolors8.default.dim(Object.keys(cfg.env).join(", "))}`);
2206
- }
2207
- }
2208
- console.log();
2209
- const action = await (0, import_prompts8.select)({
2618
+ displayServerDetails({
2619
+ serverName: chosenServerName,
2620
+ config: targetGroup.config,
2621
+ agents: targetGroup.agents,
2622
+ isGlobal
2623
+ });
2624
+ const action = await (0, import_prompts9.select)({
2210
2625
  message: `What would you like to do with [${chosenServerName}]?`,
2211
2626
  choices: [
2627
+ {
2628
+ name: "Edit server configuration",
2629
+ value: "edit"
2630
+ },
2212
2631
  {
2213
2632
  name: "Sync / clone to other agents",
2214
2633
  value: "sync"
@@ -2220,23 +2639,34 @@ var wizardManage = async (options = {}) => {
2220
2639
  ]
2221
2640
  });
2222
2641
  if (action === "back") continue;
2642
+ if (action === "edit") {
2643
+ await handleEditServerConfig({
2644
+ targetGroup,
2645
+ isGlobal,
2646
+ cwd
2647
+ });
2648
+ continue;
2649
+ }
2223
2650
  if (action === "sync") {
2224
2651
  const allAllowedAgents = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
2225
2652
  const candidateAgents = allAllowedAgents.filter((a) => !targetGroup.agents.includes(a));
2226
2653
  if (candidateAgents.length === 0) {
2227
- logger.info("All supported agents in this scope already have this MCP server configured; no sync needed");
2654
+ logger.info(
2655
+ "All supported agents in this scope already have this MCP server configured; no sync needed"
2656
+ );
2228
2657
  continue;
2229
2658
  }
2230
- const selectedToSync = await (0, import_prompts8.checkbox)({
2659
+ const selectedToSync = await (0, import_prompts9.checkbox)({
2231
2660
  message: "Select target agents to sync to (Space to select):",
2232
2661
  choices: candidateAgents.map((a) => ({
2233
2662
  name: `${getMcpAgentConfig(a).displayName} (${a})`,
2234
2663
  value: a,
2235
2664
  checked: false
2236
2665
  })),
2666
+ loop: false,
2237
2667
  validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2238
2668
  });
2239
- const confirmed = await (0, import_prompts8.confirm)({
2669
+ const confirmed = await (0, import_prompts9.confirm)({
2240
2670
  message: `Confirm syncing configuration of [${chosenServerName}] to: ${selectedToSync.join(", ")}?`,
2241
2671
  default: true
2242
2672
  });
@@ -2250,10 +2680,10 @@ var wizardManage = async (options = {}) => {
2250
2680
  cwd
2251
2681
  });
2252
2682
  if (res.success) {
2253
- logger.success(`${import_picocolors8.default.cyan(targetAgent)}: Successfully synced to ${import_picocolors8.default.dim(res.path)}`);
2683
+ logger.success(`${import_picocolors9.default.cyan(targetAgent)}: Successfully synced to ${import_picocolors9.default.dim(res.path)}`);
2254
2684
  targetGroup.agents.push(targetAgent);
2255
2685
  } else {
2256
- logger.error(`${import_picocolors8.default.cyan(targetAgent)}: Sync failed - ${res.error}`);
2686
+ logger.error(`${import_picocolors9.default.cyan(targetAgent)}: Sync failed - ${res.error}`);
2257
2687
  }
2258
2688
  }
2259
2689
  }
@@ -2261,8 +2691,8 @@ var wizardManage = async (options = {}) => {
2261
2691
  };
2262
2692
 
2263
2693
  // src/interactive/wizard-remove.ts
2264
- var import_prompts9 = require("@inquirer/prompts");
2265
- var import_picocolors9 = __toESM(require("picocolors"), 1);
2694
+ var import_prompts10 = require("@inquirer/prompts");
2695
+ var import_picocolors10 = __toESM(require("picocolors"), 1);
2266
2696
  var wizardRemove = async (options = {}) => {
2267
2697
  const cwd = options.cwd ?? process.cwd();
2268
2698
  const isGlobal = await promptScope({
@@ -2279,10 +2709,10 @@ var wizardRemove = async (options = {}) => {
2279
2709
  let serverName = options.name;
2280
2710
  if (!serverName) {
2281
2711
  const choices = Array.from(serverMap.values()).map((g) => ({
2282
- name: `${import_picocolors9.default.bold(g.serverName)} ${import_picocolors9.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
2712
+ name: `${import_picocolors10.default.bold(g.serverName)} ${import_picocolors10.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
2283
2713
  value: g.serverName
2284
2714
  }));
2285
- serverName = await (0, import_prompts9.select)({
2715
+ serverName = await (0, import_prompts10.select)({
2286
2716
  message: "Select MCP server to remove:",
2287
2717
  choices
2288
2718
  });
@@ -2294,13 +2724,14 @@ var wizardRemove = async (options = {}) => {
2294
2724
  }
2295
2725
  let targetAgents = options.agents;
2296
2726
  if (!targetAgents || targetAgents.length === 0) {
2297
- targetAgents = await (0, import_prompts9.checkbox)({
2727
+ targetAgents = await (0, import_prompts10.checkbox)({
2298
2728
  message: `Select agents to remove [${serverName}] from:`,
2299
2729
  choices: installedAgents.map((agent) => ({
2300
2730
  name: `${getMcpAgentConfig(agent)?.displayName ?? agent} (${agent})`,
2301
2731
  value: agent,
2302
2732
  checked: true
2303
2733
  })),
2734
+ loop: false,
2304
2735
  validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2305
2736
  });
2306
2737
  } else {
@@ -2311,7 +2742,7 @@ var wizardRemove = async (options = {}) => {
2311
2742
  }
2312
2743
  targetAgents = validAgents;
2313
2744
  }
2314
- const confirmed = await (0, import_prompts9.confirm)({
2745
+ const confirmed = await (0, import_prompts10.confirm)({
2315
2746
  message: `Confirm removing MCP server [${serverName}] from ${targetAgents.join(", ")}?`,
2316
2747
  default: true
2317
2748
  });
@@ -2328,10 +2759,10 @@ var wizardRemove = async (options = {}) => {
2328
2759
  let removedCount = 0;
2329
2760
  for (const res of results) {
2330
2761
  if (res.removed) {
2331
- logger.success(`${import_picocolors9.default.cyan(res.agent)}: Successfully removed from ${import_picocolors9.default.dim(res.path)}`);
2762
+ logger.success(`${import_picocolors10.default.cyan(res.agent)}: Successfully removed from ${import_picocolors10.default.dim(res.path)}`);
2332
2763
  removedCount++;
2333
2764
  } else if (res.error) {
2334
- logger.error(`${import_picocolors9.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
2765
+ logger.error(`${import_picocolors10.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
2335
2766
  }
2336
2767
  }
2337
2768
  if (removedCount > 0) {
@@ -2345,12 +2776,12 @@ var wizardRemove = async (options = {}) => {
2345
2776
  // src/interactive/main-menu.ts
2346
2777
  var mainMenu = async () => {
2347
2778
  console.log();
2348
- console.log(import_picocolors10.default.bold(import_picocolors10.default.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
2349
- console.log(import_picocolors10.default.dim("Cross-platform MCP server configuration & synchronization tool"));
2779
+ console.log(import_picocolors11.default.bold(import_picocolors11.default.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
2780
+ console.log(import_picocolors11.default.dim("Cross-platform MCP server configuration & synchronization tool"));
2350
2781
  console.log();
2351
2782
  while (true) {
2352
2783
  try {
2353
- const action = await (0, import_prompts10.select)({
2784
+ const action = await (0, import_prompts11.select)({
2354
2785
  message: "Select an action:",
2355
2786
  choices: [
2356
2787
  {
@@ -2372,7 +2803,7 @@ var mainMenu = async () => {
2372
2803
  ]
2373
2804
  });
2374
2805
  if (action === "exit") {
2375
- console.log(import_picocolors10.default.dim("Goodbye!"));
2806
+ console.log(import_picocolors11.default.dim("Goodbye!"));
2376
2807
  break;
2377
2808
  }
2378
2809
  if (action === "add") {
@@ -2385,13 +2816,167 @@ var mainMenu = async () => {
2385
2816
  console.log();
2386
2817
  } catch (error) {
2387
2818
  if (error?.name === "ExitPromptError") {
2388
- console.log("\n" + import_picocolors10.default.dim("Exited."));
2819
+ console.log("\n" + import_picocolors11.default.dim("Exited."));
2389
2820
  break;
2390
2821
  }
2391
2822
  throw error;
2392
2823
  }
2393
2824
  }
2394
2825
  };
2826
+
2827
+ // src/cli/manage.ts
2828
+ var import_commander = require("commander");
2829
+ var import_picocolors12 = __toESM(require("picocolors"), 1);
2830
+
2831
+ // src/utils/parse-key-value-list.ts
2832
+ var parseKeyValueList = (entries, separator) => {
2833
+ if (!entries || entries.length === 0) return {};
2834
+ const result = {};
2835
+ for (const entry of entries) {
2836
+ const splitIndex = entry.indexOf(separator);
2837
+ if (splitIndex === -1) {
2838
+ throw new Error(`Invalid entry "${entry}": expected "${separator}" separator`);
2839
+ }
2840
+ const key = entry.slice(0, splitIndex).trim();
2841
+ const value = entry.slice(splitIndex + separator.length).trim();
2842
+ if (!key) throw new Error(`Invalid entry "${entry}": empty key`);
2843
+ result[key] = value;
2844
+ }
2845
+ return result;
2846
+ };
2847
+
2848
+ // src/cli/manage.ts
2849
+ var resolveTransport = (input7) => {
2850
+ if (!input7) return void 0;
2851
+ if (input7 === "http" || input7 === "sse") return input7;
2852
+ throw new Error(`Unsupported transport "${input7}" (expected: http, sse)`);
2853
+ };
2854
+ 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) => {
2855
+ try {
2856
+ const cwd = process.cwd();
2857
+ const isGlobal = Boolean(options.global);
2858
+ 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;
2859
+ const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
2860
+ if (hasModifications) {
2861
+ if (!serverName) {
2862
+ logger.error('Missing required argument: "server-name" when passing modification flags.');
2863
+ process.exitCode = 1;
2864
+ return;
2865
+ }
2866
+ const installed = listInstalledMcpServers({ global: isGlobal, cwd });
2867
+ const grouped = groupInstalledServersByName(installed);
2868
+ const targetGroup = grouped.get(serverName);
2869
+ if (!targetGroup) {
2870
+ logger.error(
2871
+ `MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
2872
+ );
2873
+ process.exitCode = 1;
2874
+ return;
2875
+ }
2876
+ const updatedConfig = {
2877
+ ...targetGroup.config,
2878
+ args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
2879
+ env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
2880
+ headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
2881
+ };
2882
+ if (options.command !== void 0) {
2883
+ updatedConfig.command = options.command;
2884
+ }
2885
+ if (options.args !== void 0) {
2886
+ updatedConfig.args = options.args;
2887
+ }
2888
+ if (options.url !== void 0) {
2889
+ updatedConfig.url = options.url;
2890
+ }
2891
+ if (options.transport !== void 0) {
2892
+ updatedConfig.type = resolveTransport(options.transport);
2893
+ }
2894
+ if (options.env !== void 0) {
2895
+ const parsedEnv = parseKeyValueList(options.env, "=");
2896
+ updatedConfig.env = { ...updatedConfig.env ?? {}, ...parsedEnv };
2897
+ }
2898
+ if (options.header !== void 0) {
2899
+ const parsedHeaders = parseKeyValueList(options.header, ":");
2900
+ updatedConfig.headers = { ...updatedConfig.headers ?? {}, ...parsedHeaders };
2901
+ }
2902
+ const targetAgents = options.agent ? parseMcpAgentList(options.agent) ?? targetGroup.agents : targetGroup.agents;
2903
+ const requestedTransport = updatedConfig.url ? updatedConfig.type ?? "http" : "stdio";
2904
+ const compatibleAgents = [];
2905
+ for (const agent of targetAgents) {
2906
+ const agentConfig = getMcpAgentConfig(agent);
2907
+ if (isMcpTransportSupported(agentConfig, requestedTransport)) {
2908
+ compatibleAgents.push(agent);
2909
+ } else {
2910
+ const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
2911
+ logger.warn(`Skipping ${import_picocolors12.default.cyan(agent)}: ${reason}`);
2912
+ }
2913
+ }
2914
+ if (compatibleAgents.length === 0) {
2915
+ logger.error(
2916
+ `None of the target agents support ${requestedTransport} transport. Update aborted.`
2917
+ );
2918
+ process.exitCode = 1;
2919
+ return;
2920
+ }
2921
+ logger.info(
2922
+ `Updating ${import_picocolors12.default.bold(serverName)} across ${import_picocolors12.default.cyan(String(compatibleAgents.length))} agent(s)...`
2923
+ );
2924
+ let allSuccess = true;
2925
+ for (const agent of compatibleAgents) {
2926
+ const res = installMcpServerForAgent(serverName, updatedConfig, agent, {
2927
+ global: isGlobal,
2928
+ cwd
2929
+ });
2930
+ if (res.success) {
2931
+ logger.success(`${import_picocolors12.default.cyan(agent)}: Successfully updated in ${import_picocolors12.default.dim(res.path)}`);
2932
+ } else {
2933
+ allSuccess = false;
2934
+ logger.error(`${import_picocolors12.default.cyan(agent)}: Update failed - ${res.error}`);
2935
+ }
2936
+ }
2937
+ if (!allSuccess) {
2938
+ process.exitCode = 1;
2939
+ }
2940
+ return;
2941
+ }
2942
+ if (!isInteractive) {
2943
+ if (!serverName) {
2944
+ logger.error(
2945
+ 'Missing required argument: "server-name" for non-interactive manage command. Specify a server name or use interactive terminal.'
2946
+ );
2947
+ process.exitCode = 1;
2948
+ return;
2949
+ }
2950
+ const installed = listInstalledMcpServers({ global: isGlobal, cwd });
2951
+ const grouped = groupInstalledServersByName(installed);
2952
+ const targetGroup = grouped.get(serverName);
2953
+ if (!targetGroup) {
2954
+ logger.error(
2955
+ `MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
2956
+ );
2957
+ process.exitCode = 1;
2958
+ return;
2959
+ }
2960
+ displayServerDetails({
2961
+ serverName,
2962
+ config: targetGroup.config,
2963
+ agents: targetGroup.agents,
2964
+ isGlobal
2965
+ });
2966
+ return;
2967
+ }
2968
+ await wizardManage({
2969
+ global: options.global,
2970
+ serverName
2971
+ });
2972
+ } catch (error) {
2973
+ if (error && typeof error === "object" && "name" in error && error.name === "ExitPromptError") {
2974
+ process.exit(0);
2975
+ }
2976
+ logger.error(toErrorMessage(error));
2977
+ process.exitCode = 1;
2978
+ }
2979
+ });
2395
2980
  // Annotate the CommonJS export names for ESM import in node:
2396
2981
  0 && (module.exports = {
2397
2982
  AgentConfigStore,
@@ -2404,7 +2989,11 @@ var mainMenu = async () => {
2404
2989
  createAgentTransform,
2405
2990
  detectGloballyInstalledMcpAgents,
2406
2991
  detectProjectInstalledMcpAgents,
2992
+ displayServerDetails,
2407
2993
  extractPackageName,
2994
+ formatArgsString,
2995
+ formatEnvText,
2996
+ formatHeadersText,
2408
2997
  getMcpAgentConfig,
2409
2998
  getMcpAgentTypes,
2410
2999
  getMcpAgentsSupportingProjectScope,
@@ -2422,8 +3011,11 @@ var mainMenu = async () => {
2422
3011
  listInstalledMcpServers,
2423
3012
  listServersInConfigFile,
2424
3013
  mainMenu,
3014
+ maskSecretHeader,
3015
+ maskSecretValue,
2425
3016
  mcpAgentAliases,
2426
3017
  mcpAgents,
3018
+ mcpManageCommand,
2427
3019
  normalizeServerConfig,
2428
3020
  parseArgsString,
2429
3021
  parseEnvText,
@@ -2432,6 +3024,10 @@ var mainMenu = async () => {
2432
3024
  parseServerConfig,
2433
3025
  parseSource,
2434
3026
  promptArgsConfig,
3027
+ promptEditArgs,
3028
+ promptEditEnvConfig,
3029
+ promptEditHeadersConfig,
3030
+ promptEditKeyValueConfig,
2435
3031
  promptEnvConfig,
2436
3032
  promptHeadersConfig,
2437
3033
  promptScope,
@@ -2446,6 +3042,8 @@ var mainMenu = async () => {
2446
3042
  resolveTargetAgents,
2447
3043
  transformServerConfig,
2448
3044
  transformServerConfigForAgent,
3045
+ updateMcpServerForAgent,
3046
+ updateMcpServerForAgents,
2449
3047
  wizardAdd,
2450
3048
  wizardManage,
2451
3049
  wizardRemove,