@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.
@@ -452,9 +452,9 @@ var mcpAgentAliases = {
452
452
  var getMcpAgentConfig = (agentType) => mcpAgents[agentType];
453
453
  var getMcpAgentTypes = () => Object.values(mcpAgents).map((config) => config.name);
454
454
  var isMcpAgentType = (value) => value in mcpAgents;
455
- var resolveMcpAgentAlias = (input5) => {
456
- if (isMcpAgentType(input5)) return input5;
457
- return mcpAgentAliases[input5] ?? null;
455
+ var resolveMcpAgentAlias = (input7) => {
456
+ if (isMcpAgentType(input7)) return input7;
457
+ return mcpAgentAliases[input7] ?? null;
458
458
  };
459
459
  var isMcpTransportSupported = (agent, transport) => agent.supportedTransports.includes(transport);
460
460
  var detectProjectInstalledMcpAgents = (cwd) => getMcpAgentTypes().filter(
@@ -1200,11 +1200,11 @@ var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options =
1200
1200
  );
1201
1201
 
1202
1202
  // src/utils/parse-mcp-agent-list.ts
1203
- var parseMcpAgentList = (input5) => {
1204
- if (!input5 || input5.length === 0) return void 0;
1205
- if (input5.includes("*")) return getMcpAgentTypes();
1203
+ var parseMcpAgentList = (input7) => {
1204
+ if (!input7 || input7.length === 0) return void 0;
1205
+ if (input7.includes("*")) return getMcpAgentTypes();
1206
1206
  const resolved = [];
1207
- for (const value of input5) {
1207
+ for (const value of input7) {
1208
1208
  const agentType = resolveMcpAgentAlias(value);
1209
1209
  if (!agentType) throw new Error(`Unknown MCP agent "${value}"`);
1210
1210
  resolved.push(agentType);
@@ -1213,9 +1213,9 @@ var parseMcpAgentList = (input5) => {
1213
1213
  };
1214
1214
 
1215
1215
  // src/resolve-target-agents.ts
1216
- var normalizeRequestedAgents = (input5) => {
1217
- if (!input5 || input5.length === 0) return void 0;
1218
- const rawList = [...input5];
1216
+ var normalizeRequestedAgents = (input7) => {
1217
+ if (!input7 || input7.length === 0) return void 0;
1218
+ const rawList = [...input7];
1219
1219
  if (rawList.every((item) => isMcpAgentType(item))) {
1220
1220
  return rawList;
1221
1221
  }
@@ -1275,29 +1275,29 @@ var REMOTE_URL_REGEX = /^https?:\/\//i;
1275
1275
  var HAS_WHITESPACE_REGEX = /\s/;
1276
1276
  var PACKAGE_NAME_REGEX = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(?:@[^\s]+)?$/;
1277
1277
  var PATH_SEPARATOR_REGEX = /[/\\]/;
1278
- var stripVersionSuffix = (input5) => {
1279
- if (input5.startsWith("@")) {
1280
- const secondAtIndex = input5.indexOf("@", 1);
1281
- if (secondAtIndex > 0) return input5.slice(0, secondAtIndex);
1282
- return input5;
1283
- }
1284
- const atIndex = input5.lastIndexOf("@");
1285
- if (atIndex > 0) return input5.slice(0, atIndex);
1286
- return input5;
1287
- };
1288
- var stripScopePrefix = (input5) => {
1289
- if (!input5.startsWith("@") || !input5.includes("/")) return input5;
1290
- const parts = input5.split("/");
1291
- return parts[1] || input5;
1292
- };
1293
- var stripPathPrefix = (input5) => {
1294
- if (!PATH_SEPARATOR_REGEX.test(input5)) return input5;
1295
- const segments = input5.split(PATH_SEPARATOR_REGEX);
1278
+ var stripVersionSuffix = (input7) => {
1279
+ if (input7.startsWith("@")) {
1280
+ const secondAtIndex = input7.indexOf("@", 1);
1281
+ if (secondAtIndex > 0) return input7.slice(0, secondAtIndex);
1282
+ return input7;
1283
+ }
1284
+ const atIndex = input7.lastIndexOf("@");
1285
+ if (atIndex > 0) return input7.slice(0, atIndex);
1286
+ return input7;
1287
+ };
1288
+ var stripScopePrefix = (input7) => {
1289
+ if (!input7.startsWith("@") || !input7.includes("/")) return input7;
1290
+ const parts = input7.split("/");
1291
+ return parts[1] || input7;
1292
+ };
1293
+ var stripPathPrefix = (input7) => {
1294
+ if (!PATH_SEPARATOR_REGEX.test(input7)) return input7;
1295
+ const segments = input7.split(PATH_SEPARATOR_REGEX);
1296
1296
  const basename = segments[segments.length - 1];
1297
- return basename || input5;
1297
+ return basename || input7;
1298
1298
  };
1299
- var extractPackageName = (input5) => {
1300
- let name = stripVersionSuffix(input5);
1299
+ var extractPackageName = (input7) => {
1300
+ let name = stripVersionSuffix(input7);
1301
1301
  name = stripScopePrefix(name);
1302
1302
  name = stripPathPrefix(name);
1303
1303
  name = name.replace(SCRIPT_EXTENSION_REGEX, "");
@@ -1315,9 +1315,9 @@ var extractPackageName = (input5) => {
1315
1315
  }
1316
1316
  return name || MCP_DEFAULT_SERVER_NAME;
1317
1317
  };
1318
- var inferNameFromUrl = (input5) => {
1318
+ var inferNameFromUrl = (input7) => {
1319
1319
  try {
1320
- const url = new URL(input5);
1320
+ const url = new URL(input7);
1321
1321
  const host = url.hostname;
1322
1322
  const labels = host.split(".").filter((segment) => segment.length > 0);
1323
1323
  if (labels.length === 0) return MCP_DEFAULT_SERVER_NAME;
@@ -1346,8 +1346,8 @@ var inferNameFromCommand = (command) => {
1346
1346
  const firstNonFlag = tokens.find((token) => !token.startsWith("-"));
1347
1347
  return firstNonFlag ? extractPackageName(firstNonFlag) : MCP_DEFAULT_SERVER_NAME;
1348
1348
  };
1349
- var parseMcpSource = (input5) => {
1350
- const trimmed = input5.trim();
1349
+ var parseMcpSource = (input7) => {
1350
+ const trimmed = input7.trim();
1351
1351
  if (trimmed.length === 0) {
1352
1352
  throw new Error(
1353
1353
  "Invalid MCP source: input is empty. Expected a remote URL, an npm package, or a command line."
@@ -1473,12 +1473,12 @@ var removeMcpServer = (options) => {
1473
1473
  };
1474
1474
 
1475
1475
  // src/interactive/main-menu.ts
1476
- import { select as select8 } from "@inquirer/prompts";
1477
- import pc10 from "picocolors";
1476
+ import { select as select9 } from "@inquirer/prompts";
1477
+ import pc11 from "picocolors";
1478
1478
 
1479
1479
  // src/interactive/wizard-add.ts
1480
- import { confirm as confirm2, input as input4, select as select5 } from "@inquirer/prompts";
1481
- import pc7 from "picocolors";
1480
+ import { confirm as confirm5, input as input5, select as select6 } from "@inquirer/prompts";
1481
+ import pc8 from "picocolors";
1482
1482
 
1483
1483
  // src/utils/logger.ts
1484
1484
  import pc from "picocolors";
@@ -1602,10 +1602,25 @@ var promptArgsConfig = async (initialArgs = []) => {
1602
1602
  });
1603
1603
  return parseArgsString(raw.trim());
1604
1604
  };
1605
+ var formatArgsString = (args) => {
1606
+ return args.map((arg) => arg.includes(" ") || arg.includes('"') ? `"${arg.replace(/"/g, '\\"')}"` : arg).join(" ");
1607
+ };
1608
+ var promptEditArgs = async (currentArgs = []) => {
1609
+ const defaultStr = formatArgsString(currentArgs);
1610
+ const raw = await input({
1611
+ message: "Edit command arguments (space-separated, wrap paths with spaces in quotes, leave empty to clear):",
1612
+ default: defaultStr
1613
+ });
1614
+ const trimmed = raw.trim();
1615
+ if (!trimmed) {
1616
+ return [];
1617
+ }
1618
+ return parseArgsString(trimmed);
1619
+ };
1605
1620
 
1606
1621
  // src/interactive/prompts/env.ts
1607
- import { input as input2, password, select as select3 } from "@inquirer/prompts";
1608
- import pc5 from "picocolors";
1622
+ import { input as input3, password as password2, select as select4 } from "@inquirer/prompts";
1623
+ import pc6 from "picocolors";
1609
1624
 
1610
1625
  // src/interactive/prompts/multiline.ts
1611
1626
  import { createInterface } from "readline";
@@ -1668,8 +1683,166 @@ var promptEditorText = async (options) => {
1668
1683
  }
1669
1684
  };
1670
1685
 
1686
+ // src/interactive/prompts/kv.ts
1687
+ import { confirm as confirm2, input as input2, password, select as select3 } from "@inquirer/prompts";
1688
+ import pc5 from "picocolors";
1689
+ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1690
+ let items = { ...currentItems };
1691
+ while (true) {
1692
+ const keys = Object.keys(items);
1693
+ console.log();
1694
+ if (keys.length === 0) {
1695
+ console.log(pc5.dim(` No ${options.itemsNoun} configured.`));
1696
+ } else {
1697
+ console.log(pc5.cyan(pc5.bold(` Configured ${options.title} (${keys.length}):`)));
1698
+ for (const [k, v] of Object.entries(items)) {
1699
+ const sep = options.separator === "=" ? "=" : ": ";
1700
+ console.log(` ${pc5.bold(k)}${sep}${pc5.dim(options.maskValue(k, v))}`);
1701
+ }
1702
+ }
1703
+ console.log();
1704
+ const choice = await select3({
1705
+ message: `Manage ${options.itemsNoun}:`,
1706
+ choices: [
1707
+ {
1708
+ name: "Open in system default editor ($EDITOR)",
1709
+ value: "editor"
1710
+ },
1711
+ {
1712
+ name: `Add or modify a ${options.itemNoun}`,
1713
+ value: "upsert"
1714
+ },
1715
+ ...keys.length > 0 ? [
1716
+ {
1717
+ name: `Delete a ${options.itemNoun}`,
1718
+ value: "delete"
1719
+ }
1720
+ ] : [],
1721
+ {
1722
+ name: `Paste multiline ${options.itemsNoun} into terminal`,
1723
+ value: "paste"
1724
+ },
1725
+ ...keys.length > 0 ? [
1726
+ {
1727
+ name: `Clear all ${options.itemsNoun}`,
1728
+ value: "clear"
1729
+ }
1730
+ ] : [],
1731
+ {
1732
+ name: `Done (finish editing ${options.itemsNoun})`,
1733
+ value: "done"
1734
+ }
1735
+ ]
1736
+ });
1737
+ if (choice === "done") {
1738
+ return items;
1739
+ }
1740
+ if (choice === "editor") {
1741
+ const defaultText = options.formatText(items);
1742
+ const text = await promptEditorText({
1743
+ message: options.editorMessage,
1744
+ postfix: options.editorPostfix,
1745
+ defaultText
1746
+ });
1747
+ const parsed = options.parseText(text);
1748
+ items = parsed;
1749
+ logger.success(`${options.title} updated (${Object.keys(items).length} total)`);
1750
+ } else if (choice === "upsert") {
1751
+ const key = await input2({
1752
+ message: options.keyPromptMessage,
1753
+ validate: (val) => {
1754
+ const trimmed = val.trim();
1755
+ if (!trimmed) return `${options.itemNoun} name cannot be empty`;
1756
+ if (/\s/.test(trimmed)) return `${options.itemNoun} name cannot contain spaces`;
1757
+ return true;
1758
+ }
1759
+ });
1760
+ const trimmedKey = key.trim();
1761
+ const existingVal = items[trimmedKey];
1762
+ const isSecret = options.isSecretKey(trimmedKey);
1763
+ let newVal;
1764
+ if (isSecret) {
1765
+ newVal = await password({
1766
+ message: existingVal !== void 0 ? `New value for (${trimmedKey}) [leave empty to keep current]:` : `${options.valuePromptMessage} for (${trimmedKey}) [sensitive content masked]:`,
1767
+ mask: "*"
1768
+ });
1769
+ if (existingVal !== void 0 && newVal === "") {
1770
+ newVal = existingVal;
1771
+ }
1772
+ } else {
1773
+ newVal = await input2({
1774
+ message: `${options.valuePromptMessage} for (${trimmedKey}):`,
1775
+ default: existingVal
1776
+ });
1777
+ }
1778
+ items[trimmedKey] = newVal;
1779
+ logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${pc5.cyan(trimmedKey)}`);
1780
+ } else if (choice === "delete") {
1781
+ const toDelete = await select3({
1782
+ message: `Select ${options.itemNoun} to delete:`,
1783
+ choices: [
1784
+ ...keys.map((k) => ({ name: k, value: k })),
1785
+ { name: "Cancel", value: "__cancel__" }
1786
+ ]
1787
+ });
1788
+ if (toDelete !== "__cancel__") {
1789
+ delete items[toDelete];
1790
+ logger.success(`Deleted: ${pc5.cyan(toDelete)}`);
1791
+ }
1792
+ } else if (choice === "paste") {
1793
+ const pasted = await readMultilineTextFromTerminal(options.pasteMessage);
1794
+ const parsed = options.parseText(pasted);
1795
+ const count = Object.keys(parsed).length;
1796
+ if (count === 0) {
1797
+ logger.warn(`No valid ${options.itemsNoun} recognized`);
1798
+ } else {
1799
+ if (keys.length > 0) {
1800
+ const pasteMode = await select3({
1801
+ message: `How to apply pasted ${options.itemsNoun}?`,
1802
+ choices: [
1803
+ { name: `Merge with existing ${options.itemsNoun}`, value: "merge" },
1804
+ { name: `Replace all existing ${options.itemsNoun}`, value: "replace" }
1805
+ ]
1806
+ });
1807
+ if (pasteMode === "replace") {
1808
+ items = parsed;
1809
+ } else {
1810
+ Object.assign(items, parsed);
1811
+ }
1812
+ } else {
1813
+ items = parsed;
1814
+ }
1815
+ logger.success(`Successfully applied ${pc5.cyan(String(count))} ${options.itemsNoun}`);
1816
+ }
1817
+ } else if (choice === "clear") {
1818
+ const confirmClear = await confirm2({
1819
+ message: `Are you sure you want to clear all ${options.itemsNoun}?`,
1820
+ default: false
1821
+ });
1822
+ if (confirmClear) {
1823
+ items = {};
1824
+ logger.success(`Cleared all ${options.itemsNoun}`);
1825
+ }
1826
+ }
1827
+ }
1828
+ };
1829
+
1671
1830
  // src/interactive/prompts/env.ts
1672
1831
  var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
1832
+ var maskSecretValue = (key, value) => {
1833
+ if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
1834
+ return value;
1835
+ }
1836
+ return `${value.slice(0, 2)}***${value.slice(-2)}`;
1837
+ };
1838
+ var formatEnvText = (env) => {
1839
+ return Object.entries(env).map(([key, value]) => {
1840
+ if (/[\s"']/.test(value)) {
1841
+ return `${key}="${value.replace(/"/g, '\\"')}"`;
1842
+ }
1843
+ return `${key}=${value}`;
1844
+ }).join("\n");
1845
+ };
1673
1846
  var parseEnvText = (rawText) => {
1674
1847
  const result = {};
1675
1848
  const lines = rawText.split(/\r?\n/);
@@ -1695,9 +1868,9 @@ var promptEnvConfig = async (initialEnv = {}) => {
1695
1868
  const env = { ...initialEnv };
1696
1869
  const initialCount = Object.keys(env).length;
1697
1870
  if (initialCount > 0) {
1698
- logger.info(`Includes ${pc5.cyan(String(initialCount))} preset environment variables`);
1871
+ logger.info(`Includes ${pc6.cyan(String(initialCount))} preset environment variables`);
1699
1872
  }
1700
- const mode = await select3({
1873
+ const mode = await select4({
1701
1874
  message: "Configure environment variables?",
1702
1875
  choices: [
1703
1876
  {
@@ -1724,7 +1897,8 @@ var promptEnvConfig = async (initialEnv = {}) => {
1724
1897
  if (mode === "paste" || mode === "editor") {
1725
1898
  const pasted = mode === "editor" ? await promptEditorText({
1726
1899
  message: "Paste or edit environment variables in editor, then save and exit:",
1727
- postfix: ".env"
1900
+ postfix: ".env",
1901
+ defaultText: formatEnvText(env)
1728
1902
  }) : await readMultilineTextFromTerminal("Paste .env formatted content (multiline supported):");
1729
1903
  const parsed = parseEnvText(pasted);
1730
1904
  const count = Object.keys(parsed).length;
@@ -1732,17 +1906,16 @@ var promptEnvConfig = async (initialEnv = {}) => {
1732
1906
  logger.warn("No valid KEY=VALUE pairs recognized");
1733
1907
  } else {
1734
1908
  Object.assign(env, parsed);
1735
- logger.success(`Successfully parsed ${pc5.cyan(String(count))} environment variables:`);
1909
+ logger.success(`Successfully parsed ${pc6.cyan(String(count))} environment variables:`);
1736
1910
  for (const [k, v] of Object.entries(parsed)) {
1737
- const masked = SECRET_KEY_PATTERN.test(k) && v.length > 4 ? `${v.slice(0, 2)}***${v.slice(-2)}` : v;
1738
- console.log(` ${pc5.bold(k)}=${pc5.dim(masked)}`);
1911
+ console.log(` ${pc6.bold(k)}=${pc6.dim(maskSecretValue(k, v))}`);
1739
1912
  }
1740
1913
  }
1741
1914
  return env;
1742
1915
  }
1743
1916
  logger.info("Entering environment variables (leave key empty and press enter to finish):");
1744
1917
  while (true) {
1745
- const key = await input2({
1918
+ const key = await input3({
1746
1919
  message: "Variable name (Key, leave empty to finish):",
1747
1920
  validate: (val2) => {
1748
1921
  const trimmed = val2.trim();
@@ -1756,25 +1929,49 @@ var promptEnvConfig = async (initialEnv = {}) => {
1756
1929
  const isSecret = SECRET_KEY_PATTERN.test(trimmedKey);
1757
1930
  let val;
1758
1931
  if (isSecret) {
1759
- val = await password({
1932
+ val = await password2({
1760
1933
  message: `Value for (${trimmedKey}) [secret masked]:`,
1761
1934
  mask: "*"
1762
1935
  });
1763
1936
  } else {
1764
- val = await input2({
1937
+ val = await input3({
1765
1938
  message: `Value for (${trimmedKey}):`
1766
1939
  });
1767
1940
  }
1768
1941
  env[trimmedKey] = val;
1769
- logger.success(`Added: ${pc5.cyan(trimmedKey)}`);
1942
+ logger.success(`Added: ${pc6.cyan(trimmedKey)}`);
1770
1943
  }
1771
1944
  return env;
1772
1945
  };
1946
+ var promptEditEnvConfig = async (currentEnv = {}) => promptEditKeyValueConfig(currentEnv, {
1947
+ title: "Environment Variables",
1948
+ itemNoun: "variable",
1949
+ itemsNoun: "environment variables",
1950
+ separator: "=",
1951
+ editorPostfix: ".env",
1952
+ editorMessage: "Edit environment variables in editor, then save and exit:",
1953
+ pasteMessage: "Paste .env formatted content (multiline supported):",
1954
+ keyPromptMessage: "Variable name (Key):",
1955
+ valuePromptMessage: "Value",
1956
+ isSecretKey: (k) => SECRET_KEY_PATTERN.test(k),
1957
+ maskValue: maskSecretValue,
1958
+ formatText: formatEnvText,
1959
+ parseText: parseEnvText
1960
+ });
1773
1961
 
1774
1962
  // src/interactive/prompts/headers.ts
1775
- import { input as input3, password as password2, select as select4 } from "@inquirer/prompts";
1776
- import pc6 from "picocolors";
1963
+ import { input as input4, password as password3, select as select5 } from "@inquirer/prompts";
1964
+ import pc7 from "picocolors";
1777
1965
  var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
1966
+ var maskSecretHeader = (key, value) => {
1967
+ if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
1968
+ return value;
1969
+ }
1970
+ return `${value.slice(0, 4)}***${value.slice(-3)}`;
1971
+ };
1972
+ var formatHeadersText = (headers) => {
1973
+ return Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join("\n");
1974
+ };
1778
1975
  var parseHeadersText = (rawText) => {
1779
1976
  const result = {};
1780
1977
  const lines = rawText.split(/\r?\n/);
@@ -1804,7 +2001,7 @@ var parseHeadersText = (rawText) => {
1804
2001
  };
1805
2002
  var promptHeadersConfig = async (initialHeaders = {}) => {
1806
2003
  const headers = { ...initialHeaders };
1807
- const mode = await select4({
2004
+ const mode = await select5({
1808
2005
  message: "Select HTTP headers configuration method:",
1809
2006
  choices: [
1810
2007
  {
@@ -1830,7 +2027,8 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
1830
2027
  }
1831
2028
  if (mode === "paste" || mode === "editor") {
1832
2029
  const pasted = mode === "editor" ? await promptEditorText({
1833
- message: "Paste or edit HTTP headers in editor, then save and exit:"
2030
+ message: "Paste or edit HTTP headers in editor, then save and exit:",
2031
+ defaultText: formatHeadersText(headers)
1834
2032
  }) : await readMultilineTextFromTerminal(
1835
2033
  "Paste HTTP headers content (multiline supported, e.g. Authorization: Bearer ...):"
1836
2034
  );
@@ -1840,17 +2038,16 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
1840
2038
  logger.warn("No valid Key: Value pairs recognized");
1841
2039
  } else {
1842
2040
  Object.assign(headers, parsed);
1843
- logger.success(`Successfully parsed ${pc6.cyan(String(count))} headers:`);
2041
+ logger.success(`Successfully parsed ${pc7.cyan(String(count))} headers:`);
1844
2042
  for (const [k, v] of Object.entries(parsed)) {
1845
- const masked = SECRET_HEADER_PATTERN.test(k) && v.length > 8 ? `${v.slice(0, 4)}***${v.slice(-3)}` : v;
1846
- console.log(` ${pc6.bold(k)}: ${pc6.dim(masked)}`);
2043
+ console.log(` ${pc7.bold(k)}: ${pc7.dim(maskSecretHeader(k, v))}`);
1847
2044
  }
1848
2045
  }
1849
2046
  return headers;
1850
2047
  }
1851
2048
  logger.info("Entering HTTP headers (leave header name empty and press enter to finish):");
1852
2049
  while (true) {
1853
- const name = await input3({
2050
+ const name = await input4({
1854
2051
  message: "Header name (e.g. Authorization, leave empty to finish):",
1855
2052
  validate: (val2) => {
1856
2053
  const trimmed = val2.trim();
@@ -1864,28 +2061,42 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
1864
2061
  const isSecret = SECRET_HEADER_PATTERN.test(trimmedName);
1865
2062
  let val;
1866
2063
  if (isSecret) {
1867
- val = await password2({
2064
+ val = await password3({
1868
2065
  message: `Header value for (${trimmedName}) [sensitive content masked]:`,
1869
2066
  mask: "*"
1870
2067
  });
1871
2068
  } else {
1872
- val = await input3({
2069
+ val = await input4({
1873
2070
  message: `Header value for (${trimmedName}):`
1874
2071
  });
1875
2072
  }
1876
2073
  headers[trimmedName] = val;
1877
- logger.success(`Added: ${pc6.cyan(trimmedName)}`);
2074
+ logger.success(`Added: ${pc7.cyan(trimmedName)}`);
1878
2075
  }
1879
2076
  return headers;
1880
2077
  };
2078
+ var promptEditHeadersConfig = async (currentHeaders = {}) => promptEditKeyValueConfig(currentHeaders, {
2079
+ title: "HTTP Headers",
2080
+ itemNoun: "header",
2081
+ itemsNoun: "HTTP headers",
2082
+ separator: ":",
2083
+ editorMessage: "Edit HTTP headers in editor, then save and exit:",
2084
+ pasteMessage: "Paste HTTP headers content (multiline supported, e.g. Authorization: Bearer ...):",
2085
+ keyPromptMessage: "Header name (e.g. Authorization):",
2086
+ valuePromptMessage: "Header value",
2087
+ isSecretKey: (k) => SECRET_HEADER_PATTERN.test(k),
2088
+ maskValue: maskSecretHeader,
2089
+ formatText: formatHeadersText,
2090
+ parseText: parseHeadersText
2091
+ });
1881
2092
 
1882
2093
  // src/interactive/wizard-add.ts
1883
2094
  var wizardAdd = async (initial = {}) => {
1884
2095
  const cwd = initial.cwd ?? process.cwd();
1885
- logger.info(pc7.bold("Welcome to the MCP interactive add wizard"));
2096
+ logger.info(pc8.bold("Welcome to the MCP interactive add wizard"));
1886
2097
  let source = initial.source;
1887
2098
  if (!source) {
1888
- const sourceType = await select5({
2099
+ const sourceType = await select6({
1889
2100
  message: "Select MCP server type:",
1890
2101
  choices: [
1891
2102
  {
@@ -1903,12 +2114,12 @@ var wizardAdd = async (initial = {}) => {
1903
2114
  ]
1904
2115
  });
1905
2116
  if (sourceType === "npm") {
1906
- source = await input4({
1907
- message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres or mcp-server-git):",
2117
+ source = await input5({
2118
+ message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres):",
1908
2119
  validate: (val) => val.trim() ? true : "Package name cannot be empty"
1909
2120
  });
1910
2121
  } else if (sourceType === "remote") {
1911
- source = await input4({
2122
+ source = await input5({
1912
2123
  message: "Enter remote server URL (e.g. https://mcp.example.com/sse):",
1913
2124
  validate: (val) => {
1914
2125
  const trimmed = val.trim();
@@ -1918,7 +2129,7 @@ var wizardAdd = async (initial = {}) => {
1918
2129
  }
1919
2130
  });
1920
2131
  } else {
1921
- source = await input4({
2132
+ source = await input5({
1922
2133
  message: "Enter command and arguments (e.g. python -m my_mcp_server or docker run ...):",
1923
2134
  validate: (val) => val.trim() ? true : "Command cannot be empty"
1924
2135
  });
@@ -1928,7 +2139,7 @@ var wizardAdd = async (initial = {}) => {
1928
2139
  const parsed = parseMcpSource(source);
1929
2140
  let serverName = initial.name;
1930
2141
  if (!serverName) {
1931
- serverName = await input4({
2142
+ serverName = await input5({
1932
2143
  message: "MCP server name:",
1933
2144
  default: parsed.inferredName,
1934
2145
  validate: (val) => val.trim() ? true : "Server name cannot be empty"
@@ -1940,7 +2151,7 @@ var wizardAdd = async (initial = {}) => {
1940
2151
  if (parsed.type === "remote") {
1941
2152
  if (!transport) {
1942
2153
  const isSseUrl = /\/sse\b/i.test(parsed.value);
1943
- transport = await select5({
2154
+ transport = await select6({
1944
2155
  message: "Select remote transport protocol:",
1945
2156
  choices: [
1946
2157
  { name: "HTTP", value: "http" },
@@ -1950,7 +2161,7 @@ var wizardAdd = async (initial = {}) => {
1950
2161
  });
1951
2162
  }
1952
2163
  if (Object.keys(headers).length === 0) {
1953
- const needHeader = await confirm2({
2164
+ const needHeader = await confirm5({
1954
2165
  message: "Configure HTTP headers (e.g. Authorization Bearer token)?",
1955
2166
  default: false
1956
2167
  });
@@ -1972,28 +2183,28 @@ var wizardAdd = async (initial = {}) => {
1972
2183
  if (parsed.type !== "remote") {
1973
2184
  env = await promptEnvConfig(env);
1974
2185
  }
1975
- console.log("\n" + pc7.cyan(pc7.bold("Configuration Preview:")));
1976
- console.log(` ${pc7.bold("Server Name:")} ${pc7.green(serverName)}`);
1977
- console.log(` ${pc7.bold("Server Type:")} ${pc7.magenta(parsed.type)}`);
1978
- console.log(` ${pc7.bold("Source/Command:")} ${pc7.dim(source)}`);
1979
- console.log(` ${pc7.bold("Scope:")} ${isGlobal ? pc7.yellow("Global") : pc7.blue("Project")}`);
1980
- console.log(` ${pc7.bold("Target Agents:")} ${pc7.cyan(selectedAgents.join(", "))}`);
2186
+ console.log("\n" + pc8.cyan(pc8.bold("Configuration Preview:")));
2187
+ console.log(` ${pc8.bold("Server Name:")} ${pc8.green(serverName)}`);
2188
+ console.log(` ${pc8.bold("Server Type:")} ${pc8.magenta(parsed.type)}`);
2189
+ console.log(` ${pc8.bold("Source/Command:")} ${pc8.dim(source)}`);
2190
+ console.log(` ${pc8.bold("Scope:")} ${isGlobal ? pc8.yellow("Global") : pc8.blue("Project")}`);
2191
+ console.log(` ${pc8.bold("Target Agents:")} ${pc8.cyan(selectedAgents.join(", "))}`);
1981
2192
  if (args.length > 0) {
1982
- console.log(` ${pc7.bold("Arguments:")} ${pc7.dim(args.join(" "))}`);
2193
+ console.log(` ${pc8.bold("Arguments:")} ${pc8.dim(args.join(" "))}`);
1983
2194
  }
1984
2195
  if (transport) {
1985
- console.log(` ${pc7.bold("Transport:")} ${pc7.magenta(transport)}`);
2196
+ console.log(` ${pc8.bold("Transport:")} ${pc8.magenta(transport)}`);
1986
2197
  }
1987
2198
  const envKeys = Object.keys(env);
1988
2199
  if (envKeys.length > 0) {
1989
- console.log(` ${pc7.bold("Environment Variables:")} ${pc7.dim(envKeys.join(", "))} (${envKeys.length})`);
2200
+ console.log(` ${pc8.bold("Environment Variables:")} ${pc8.dim(envKeys.join(", "))} (${envKeys.length})`);
1990
2201
  }
1991
2202
  const headerKeys = Object.keys(headers);
1992
2203
  if (headerKeys.length > 0) {
1993
- console.log(` ${pc7.bold("Headers:")} ${pc7.dim(headerKeys.join(", "))} (${headerKeys.length})`);
2204
+ console.log(` ${pc8.bold("Headers:")} ${pc8.dim(headerKeys.join(", "))} (${headerKeys.length})`);
1994
2205
  }
1995
2206
  console.log();
1996
- const proceed = await confirm2({
2207
+ const proceed = await confirm5({
1997
2208
  message: "Confirm installation with this configuration?",
1998
2209
  default: true
1999
2210
  });
@@ -2013,26 +2224,26 @@ var wizardAdd = async (initial = {}) => {
2013
2224
  env
2014
2225
  });
2015
2226
  logger.info(
2016
- `Writing ${pc7.bold(result.serverName)} to ${pc7.cyan(String(result.results.length))} agent config files...`
2227
+ `Writing ${pc8.bold(result.serverName)} to ${pc8.cyan(String(result.results.length))} agent config files...`
2017
2228
  );
2018
2229
  let allSuccess = true;
2019
2230
  for (const record of result.results) {
2020
2231
  if (record.success) {
2021
- logger.success(`${pc7.cyan(record.agent)}: Successfully written to ${pc7.dim(record.path)}`);
2232
+ logger.success(`${pc8.cyan(record.agent)}: Successfully written to ${pc8.dim(record.path)}`);
2022
2233
  } else {
2023
2234
  allSuccess = false;
2024
- logger.error(`${pc7.cyan(record.agent)}: Failed to write - ${record.error}`);
2235
+ logger.error(`${pc8.cyan(record.agent)}: Failed to write - ${record.error}`);
2025
2236
  }
2026
2237
  }
2027
2238
  if (allSuccess) {
2028
- logger.success(pc7.bold(`MCP server "${serverName}" configured successfully!`));
2239
+ logger.success(pc8.bold(`MCP server "${serverName}" configured successfully!`));
2029
2240
  }
2030
2241
  return allSuccess;
2031
2242
  };
2032
2243
 
2033
2244
  // src/interactive/wizard-manage.ts
2034
- import { checkbox as checkbox2, confirm as confirm3, select as select6 } from "@inquirer/prompts";
2035
- import pc8 from "picocolors";
2245
+ import { checkbox as checkbox2, confirm as confirm6, input as input6, select as select7 } from "@inquirer/prompts";
2246
+ import pc9 from "picocolors";
2036
2247
 
2037
2248
  // src/interactive/utils/group-installed-servers.ts
2038
2249
  var normalizeServerConfig = parseServerConfig;
@@ -2060,6 +2271,204 @@ var groupInstalledServersByName = (installed) => {
2060
2271
  };
2061
2272
 
2062
2273
  // src/interactive/wizard-manage.ts
2274
+ var displayServerDetails = ({
2275
+ serverName,
2276
+ config,
2277
+ agents,
2278
+ isGlobal,
2279
+ titlePrefix = "MCP Server Details"
2280
+ }) => {
2281
+ console.log("\n" + pc9.cyan(pc9.bold(`${titlePrefix}: [${serverName}]`)));
2282
+ if (isGlobal !== void 0) {
2283
+ console.log(` ${pc9.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
2284
+ }
2285
+ if (agents && agents.length > 0) {
2286
+ console.log(
2287
+ ` ${pc9.bold("Configured Agents:")} ${pc9.green(agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2288
+ );
2289
+ }
2290
+ const isRemote = Boolean(config.url && config.url.length > 0);
2291
+ if (isRemote) {
2292
+ console.log(` ${pc9.bold("Transport:")} ${pc9.magenta(config.type ?? "http")}`);
2293
+ console.log(` ${pc9.bold("URL:")} ${pc9.dim(config.url ?? "")}`);
2294
+ const headerKeys = Object.keys(config.headers ?? {});
2295
+ if (headerKeys.length > 0) {
2296
+ console.log(` ${pc9.bold("Headers:")} ${pc9.cyan(String(headerKeys.length))}`);
2297
+ for (const [k, v] of Object.entries(config.headers ?? {})) {
2298
+ console.log(` ${pc9.bold(k)}: ${pc9.dim(maskSecretHeader(k, v))}`);
2299
+ }
2300
+ } else {
2301
+ console.log(` ${pc9.bold("Headers:")} ${pc9.dim("(none)")}`);
2302
+ }
2303
+ } else {
2304
+ console.log(` ${pc9.bold("Command:")} ${pc9.magenta(config.command ?? "")}`);
2305
+ const argsStr = config.args && config.args.length > 0 ? config.args.join(" ") : "(none)";
2306
+ console.log(` ${pc9.bold("Arguments:")} ${pc9.dim(argsStr)}`);
2307
+ const envKeys = Object.keys(config.env ?? {});
2308
+ if (envKeys.length > 0) {
2309
+ console.log(` ${pc9.bold("Environment Variables:")} ${pc9.cyan(String(envKeys.length))}`);
2310
+ for (const [k, v] of Object.entries(config.env ?? {})) {
2311
+ console.log(` ${pc9.bold(k)}=${pc9.dim(maskSecretValue(k, v))}`);
2312
+ }
2313
+ } else {
2314
+ console.log(` ${pc9.bold("Environment Variables:")} ${pc9.dim("(none)")}`);
2315
+ }
2316
+ }
2317
+ console.log();
2318
+ };
2319
+ var handleEditServerConfig = async ({
2320
+ targetGroup,
2321
+ isGlobal,
2322
+ cwd
2323
+ }) => {
2324
+ const serverName = targetGroup.serverName;
2325
+ let workingConfig = {
2326
+ ...targetGroup.config,
2327
+ args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
2328
+ env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
2329
+ headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
2330
+ };
2331
+ while (true) {
2332
+ const isRemote = Boolean(workingConfig.url && workingConfig.url.length > 0);
2333
+ displayServerDetails({
2334
+ serverName,
2335
+ config: workingConfig,
2336
+ titlePrefix: "Edit Server Configuration"
2337
+ });
2338
+ const editChoices = isRemote ? [
2339
+ { name: "Edit HTTP Headers (headers)", value: "headers" },
2340
+ { name: "Edit Remote URL (url)", value: "url" },
2341
+ { name: "Edit Transport Protocol (type)", value: "transport" },
2342
+ { name: "Reset changes to original", value: "reset" },
2343
+ { name: "Save and apply changes", value: "save" },
2344
+ { name: "Cancel (discard changes)", value: "cancel" }
2345
+ ] : [
2346
+ { name: "Edit Environment Variables (env)", value: "env" },
2347
+ { name: "Edit Command Arguments (args)", value: "args" },
2348
+ { name: "Edit Executable Command (command)", value: "command" },
2349
+ { name: "Reset changes to original", value: "reset" },
2350
+ { name: "Save and apply changes", value: "save" },
2351
+ { name: "Cancel (discard changes)", value: "cancel" }
2352
+ ];
2353
+ const editAction = await select7({
2354
+ message: `What would you like to modify in [${serverName}]?`,
2355
+ choices: editChoices
2356
+ });
2357
+ if (editAction === "cancel") {
2358
+ logger.info("Modification cancelled; changes discarded");
2359
+ return;
2360
+ }
2361
+ if (editAction === "reset") {
2362
+ workingConfig = {
2363
+ ...targetGroup.config,
2364
+ args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
2365
+ env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
2366
+ headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
2367
+ };
2368
+ logger.info("Configuration reset to original");
2369
+ continue;
2370
+ }
2371
+ if (editAction === "env") {
2372
+ workingConfig.env = await promptEditEnvConfig(workingConfig.env ?? {});
2373
+ } else if (editAction === "args") {
2374
+ workingConfig.args = await promptEditArgs(workingConfig.args ?? []);
2375
+ } else if (editAction === "command") {
2376
+ const newCmd = await input6({
2377
+ message: "Executable command:",
2378
+ default: workingConfig.command,
2379
+ validate: (val) => val.trim() ? true : "Command cannot be empty"
2380
+ });
2381
+ workingConfig.command = newCmd.trim();
2382
+ } else if (editAction === "headers") {
2383
+ workingConfig.headers = await promptEditHeadersConfig(workingConfig.headers ?? {});
2384
+ } else if (editAction === "url") {
2385
+ const newUrl = await input6({
2386
+ message: "Remote server URL:",
2387
+ default: workingConfig.url,
2388
+ validate: (val) => {
2389
+ const trimmed = val.trim();
2390
+ if (!trimmed) return "URL cannot be empty";
2391
+ if (!/^https?:\/\//i.test(trimmed)) {
2392
+ return "Please enter a valid URL starting with http:// or https://";
2393
+ }
2394
+ return true;
2395
+ }
2396
+ });
2397
+ workingConfig.url = newUrl.trim();
2398
+ } else if (editAction === "transport") {
2399
+ workingConfig.type = await select7({
2400
+ message: "Select remote transport protocol:",
2401
+ choices: [
2402
+ { name: "HTTP", value: "http" },
2403
+ { name: "SSE (Server-Sent Events)", value: "sse" }
2404
+ ],
2405
+ default: workingConfig.type === "sse" ? "sse" : "http"
2406
+ });
2407
+ } else if (editAction === "save") {
2408
+ let targetAgents = targetGroup.agents;
2409
+ if (targetGroup.agents.length > 1) {
2410
+ targetAgents = await checkbox2({
2411
+ message: "Select agents to update configuration (Space to toggle):",
2412
+ choices: targetGroup.agents.map((a) => ({
2413
+ name: `${getMcpAgentConfig(a).displayName} (${a})`,
2414
+ value: a,
2415
+ checked: true
2416
+ })),
2417
+ loop: false,
2418
+ validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2419
+ });
2420
+ }
2421
+ const requestedTransport = workingConfig.url ? workingConfig.type ?? "http" : "stdio";
2422
+ const compatibleAgents = [];
2423
+ const incompatibleAgents = [];
2424
+ for (const agent of targetAgents) {
2425
+ const agentConfig = getMcpAgentConfig(agent);
2426
+ if (isMcpTransportSupported(agentConfig, requestedTransport)) {
2427
+ compatibleAgents.push(agent);
2428
+ } else {
2429
+ const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
2430
+ incompatibleAgents.push({ agent, reason });
2431
+ }
2432
+ }
2433
+ if (incompatibleAgents.length > 0) {
2434
+ for (const item of incompatibleAgents) {
2435
+ logger.warn(`Skipping ${pc9.cyan(item.agent)}: ${item.reason}`);
2436
+ }
2437
+ }
2438
+ if (compatibleAgents.length === 0) {
2439
+ logger.error(
2440
+ `None of the selected agents support ${requestedTransport} transport. Cannot update.`
2441
+ );
2442
+ continue;
2443
+ }
2444
+ const agentNames = compatibleAgents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2445
+ const confirmed = await confirm6({
2446
+ message: `Confirm updating configuration for [${serverName}] across: ${agentNames}?`,
2447
+ default: true
2448
+ });
2449
+ if (!confirmed) {
2450
+ logger.warn("Update cancelled");
2451
+ continue;
2452
+ }
2453
+ for (const targetAgent of compatibleAgents) {
2454
+ const res = installMcpServerForAgent(serverName, workingConfig, targetAgent, {
2455
+ global: isGlobal,
2456
+ cwd
2457
+ });
2458
+ if (res.success) {
2459
+ logger.success(
2460
+ `${pc9.cyan(targetAgent)}: Successfully updated configuration in ${pc9.dim(res.path)}`
2461
+ );
2462
+ } else {
2463
+ logger.error(`${pc9.cyan(targetAgent)}: Update failed - ${res.error}`);
2464
+ }
2465
+ }
2466
+ targetGroup.config = workingConfig;
2467
+ logger.success(`Configuration for [${serverName}] updated successfully!`);
2468
+ return;
2469
+ }
2470
+ }
2471
+ };
2063
2472
  var wizardManage = async (options = {}) => {
2064
2473
  const cwd = options.cwd ?? process.cwd();
2065
2474
  const isGlobal = await promptScope({
@@ -2073,51 +2482,48 @@ var wizardManage = async (options = {}) => {
2073
2482
  return;
2074
2483
  }
2075
2484
  const grouped = groupInstalledServersByName(installed);
2485
+ let pendingServerName = options.serverName;
2076
2486
  while (true) {
2077
- const choices = Array.from(grouped.values()).map((g) => {
2078
- const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2079
- return {
2080
- name: `${pc8.bold(g.serverName)} ${pc8.dim(`(configured in: ${agentNames})`)}`,
2081
- value: g.serverName
2082
- };
2083
- });
2084
- choices.push({
2085
- name: `Back`,
2086
- value: "__back__"
2087
- });
2088
- const chosenServerName = await select6({
2089
- message: "Select MCP server to manage or sync:",
2090
- choices
2091
- });
2092
- if (chosenServerName === "__back__") {
2093
- return;
2487
+ let chosenServerName;
2488
+ if (pendingServerName && grouped.has(pendingServerName)) {
2489
+ chosenServerName = pendingServerName;
2490
+ pendingServerName = void 0;
2491
+ } else {
2492
+ pendingServerName = void 0;
2493
+ const choices = Array.from(grouped.values()).map((g) => {
2494
+ const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2495
+ return {
2496
+ name: `${pc9.bold(g.serverName)} ${pc9.dim(`(configured in: ${agentNames})`)}`,
2497
+ value: g.serverName
2498
+ };
2499
+ });
2500
+ choices.push({
2501
+ name: `Back`,
2502
+ value: "__back__"
2503
+ });
2504
+ chosenServerName = await select7({
2505
+ message: "Select MCP server to manage or sync:",
2506
+ choices
2507
+ });
2508
+ if (chosenServerName === "__back__") {
2509
+ return;
2510
+ }
2094
2511
  }
2095
2512
  const targetGroup = grouped.get(chosenServerName);
2096
2513
  if (!targetGroup) continue;
2097
- console.log("\n" + pc8.cyan(pc8.bold(`MCP Server Details: [${chosenServerName}]`)));
2098
- console.log(` ${pc8.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
2099
- console.log(
2100
- ` ${pc8.bold("Configured Agents:")} ${pc8.green(targetGroup.agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2101
- );
2102
- const cfg = targetGroup.config;
2103
- if (isRemoteServerConfig(cfg)) {
2104
- console.log(` ${pc8.bold("URL:")} ${pc8.dim(cfg.url)} (${cfg.type})`);
2105
- if (cfg.headers && Object.keys(cfg.headers).length > 0) {
2106
- console.log(` ${pc8.bold("Headers:")} ${Object.keys(cfg.headers).join(", ")}`);
2107
- }
2108
- } else if (isStdioServerConfig(cfg)) {
2109
- console.log(` ${pc8.bold("Command:")} ${pc8.magenta(cfg.command)}`);
2110
- if (cfg.args && cfg.args.length > 0) {
2111
- console.log(` ${pc8.bold("Arguments:")} ${pc8.dim(cfg.args.join(" "))}`);
2112
- }
2113
- if (cfg.env && Object.keys(cfg.env).length > 0) {
2114
- console.log(` ${pc8.bold("Environment Variables:")} ${pc8.dim(Object.keys(cfg.env).join(", "))}`);
2115
- }
2116
- }
2117
- console.log();
2118
- const action = await select6({
2514
+ displayServerDetails({
2515
+ serverName: chosenServerName,
2516
+ config: targetGroup.config,
2517
+ agents: targetGroup.agents,
2518
+ isGlobal
2519
+ });
2520
+ const action = await select7({
2119
2521
  message: `What would you like to do with [${chosenServerName}]?`,
2120
2522
  choices: [
2523
+ {
2524
+ name: "Edit server configuration",
2525
+ value: "edit"
2526
+ },
2121
2527
  {
2122
2528
  name: "Sync / clone to other agents",
2123
2529
  value: "sync"
@@ -2129,11 +2535,21 @@ var wizardManage = async (options = {}) => {
2129
2535
  ]
2130
2536
  });
2131
2537
  if (action === "back") continue;
2538
+ if (action === "edit") {
2539
+ await handleEditServerConfig({
2540
+ targetGroup,
2541
+ isGlobal,
2542
+ cwd
2543
+ });
2544
+ continue;
2545
+ }
2132
2546
  if (action === "sync") {
2133
2547
  const allAllowedAgents = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
2134
2548
  const candidateAgents = allAllowedAgents.filter((a) => !targetGroup.agents.includes(a));
2135
2549
  if (candidateAgents.length === 0) {
2136
- logger.info("All supported agents in this scope already have this MCP server configured; no sync needed");
2550
+ logger.info(
2551
+ "All supported agents in this scope already have this MCP server configured; no sync needed"
2552
+ );
2137
2553
  continue;
2138
2554
  }
2139
2555
  const selectedToSync = await checkbox2({
@@ -2143,9 +2559,10 @@ var wizardManage = async (options = {}) => {
2143
2559
  value: a,
2144
2560
  checked: false
2145
2561
  })),
2562
+ loop: false,
2146
2563
  validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2147
2564
  });
2148
- const confirmed = await confirm3({
2565
+ const confirmed = await confirm6({
2149
2566
  message: `Confirm syncing configuration of [${chosenServerName}] to: ${selectedToSync.join(", ")}?`,
2150
2567
  default: true
2151
2568
  });
@@ -2159,10 +2576,10 @@ var wizardManage = async (options = {}) => {
2159
2576
  cwd
2160
2577
  });
2161
2578
  if (res.success) {
2162
- logger.success(`${pc8.cyan(targetAgent)}: Successfully synced to ${pc8.dim(res.path)}`);
2579
+ logger.success(`${pc9.cyan(targetAgent)}: Successfully synced to ${pc9.dim(res.path)}`);
2163
2580
  targetGroup.agents.push(targetAgent);
2164
2581
  } else {
2165
- logger.error(`${pc8.cyan(targetAgent)}: Sync failed - ${res.error}`);
2582
+ logger.error(`${pc9.cyan(targetAgent)}: Sync failed - ${res.error}`);
2166
2583
  }
2167
2584
  }
2168
2585
  }
@@ -2170,8 +2587,8 @@ var wizardManage = async (options = {}) => {
2170
2587
  };
2171
2588
 
2172
2589
  // src/interactive/wizard-remove.ts
2173
- import { checkbox as checkbox3, confirm as confirm4, select as select7 } from "@inquirer/prompts";
2174
- import pc9 from "picocolors";
2590
+ import { checkbox as checkbox3, confirm as confirm7, select as select8 } from "@inquirer/prompts";
2591
+ import pc10 from "picocolors";
2175
2592
  var wizardRemove = async (options = {}) => {
2176
2593
  const cwd = options.cwd ?? process.cwd();
2177
2594
  const isGlobal = await promptScope({
@@ -2188,10 +2605,10 @@ var wizardRemove = async (options = {}) => {
2188
2605
  let serverName = options.name;
2189
2606
  if (!serverName) {
2190
2607
  const choices = Array.from(serverMap.values()).map((g) => ({
2191
- name: `${pc9.bold(g.serverName)} ${pc9.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
2608
+ name: `${pc10.bold(g.serverName)} ${pc10.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
2192
2609
  value: g.serverName
2193
2610
  }));
2194
- serverName = await select7({
2611
+ serverName = await select8({
2195
2612
  message: "Select MCP server to remove:",
2196
2613
  choices
2197
2614
  });
@@ -2210,6 +2627,7 @@ var wizardRemove = async (options = {}) => {
2210
2627
  value: agent,
2211
2628
  checked: true
2212
2629
  })),
2630
+ loop: false,
2213
2631
  validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2214
2632
  });
2215
2633
  } else {
@@ -2220,7 +2638,7 @@ var wizardRemove = async (options = {}) => {
2220
2638
  }
2221
2639
  targetAgents = validAgents;
2222
2640
  }
2223
- const confirmed = await confirm4({
2641
+ const confirmed = await confirm7({
2224
2642
  message: `Confirm removing MCP server [${serverName}] from ${targetAgents.join(", ")}?`,
2225
2643
  default: true
2226
2644
  });
@@ -2237,10 +2655,10 @@ var wizardRemove = async (options = {}) => {
2237
2655
  let removedCount = 0;
2238
2656
  for (const res of results) {
2239
2657
  if (res.removed) {
2240
- logger.success(`${pc9.cyan(res.agent)}: Successfully removed from ${pc9.dim(res.path)}`);
2658
+ logger.success(`${pc10.cyan(res.agent)}: Successfully removed from ${pc10.dim(res.path)}`);
2241
2659
  removedCount++;
2242
2660
  } else if (res.error) {
2243
- logger.error(`${pc9.cyan(res.agent)}: Failed to remove - ${res.error}`);
2661
+ logger.error(`${pc10.cyan(res.agent)}: Failed to remove - ${res.error}`);
2244
2662
  }
2245
2663
  }
2246
2664
  if (removedCount > 0) {
@@ -2254,12 +2672,12 @@ var wizardRemove = async (options = {}) => {
2254
2672
  // src/interactive/main-menu.ts
2255
2673
  var mainMenu = async () => {
2256
2674
  console.log();
2257
- console.log(pc10.bold(pc10.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
2258
- console.log(pc10.dim("Cross-platform MCP server configuration & synchronization tool"));
2675
+ console.log(pc11.bold(pc11.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
2676
+ console.log(pc11.dim("Cross-platform MCP server configuration & synchronization tool"));
2259
2677
  console.log();
2260
2678
  while (true) {
2261
2679
  try {
2262
- const action = await select8({
2680
+ const action = await select9({
2263
2681
  message: "Select an action:",
2264
2682
  choices: [
2265
2683
  {
@@ -2281,7 +2699,7 @@ var mainMenu = async () => {
2281
2699
  ]
2282
2700
  });
2283
2701
  if (action === "exit") {
2284
- console.log(pc10.dim("Goodbye!"));
2702
+ console.log(pc11.dim("Goodbye!"));
2285
2703
  break;
2286
2704
  }
2287
2705
  if (action === "add") {
@@ -2294,7 +2712,7 @@ var mainMenu = async () => {
2294
2712
  console.log();
2295
2713
  } catch (error) {
2296
2714
  if (error?.name === "ExitPromptError") {
2297
- console.log("\n" + pc10.dim("Exited."));
2715
+ console.log("\n" + pc11.dim("Exited."));
2298
2716
  break;
2299
2717
  }
2300
2718
  throw error;
@@ -2302,6 +2720,160 @@ var mainMenu = async () => {
2302
2720
  }
2303
2721
  };
2304
2722
 
2723
+ // src/cli/manage.ts
2724
+ import { Command } from "commander";
2725
+ import pc12 from "picocolors";
2726
+
2727
+ // src/utils/parse-key-value-list.ts
2728
+ var parseKeyValueList = (entries, separator) => {
2729
+ if (!entries || entries.length === 0) return {};
2730
+ const result = {};
2731
+ for (const entry of entries) {
2732
+ const splitIndex = entry.indexOf(separator);
2733
+ if (splitIndex === -1) {
2734
+ throw new Error(`Invalid entry "${entry}": expected "${separator}" separator`);
2735
+ }
2736
+ const key = entry.slice(0, splitIndex).trim();
2737
+ const value = entry.slice(splitIndex + separator.length).trim();
2738
+ if (!key) throw new Error(`Invalid entry "${entry}": empty key`);
2739
+ result[key] = value;
2740
+ }
2741
+ return result;
2742
+ };
2743
+
2744
+ // src/cli/manage.ts
2745
+ var resolveTransport = (input7) => {
2746
+ if (!input7) return void 0;
2747
+ if (input7 === "http" || input7 === "sse") return input7;
2748
+ throw new Error(`Unsupported transport "${input7}" (expected: http, sse)`);
2749
+ };
2750
+ var mcpManageCommand = new Command("manage").description("Inspect, modify, and sync installed MCP servers across coding agents").argument("[server-name]", "Optional server name to inspect or manage").option("-a, --agent <agents...>", "Target specific agents for update").option("-g, --global", "Manage global scope servers instead of project").option("-t, --transport <type>", "Transport type for remote servers (http or sse)").option("--header <header...>", "HTTP header (Header: Value), repeatable").option("--env <env...>", "Env var for stdio servers (KEY=VALUE), repeatable").option("--args <args...>", "CLI arguments for stdio/package servers").option("--command <command>", "Executable command for stdio servers").option("--url <url>", "Remote endpoint URL").option("-y, --yes", "Skip interactive prompts").action(async (serverName, options) => {
2751
+ try {
2752
+ const cwd = process.cwd();
2753
+ const isGlobal = Boolean(options.global);
2754
+ const hasModifications = options.command !== void 0 || options.args !== void 0 || options.env !== void 0 || options.header !== void 0 || options.url !== void 0 || options.transport !== void 0;
2755
+ const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
2756
+ if (hasModifications) {
2757
+ if (!serverName) {
2758
+ logger.error('Missing required argument: "server-name" when passing modification flags.');
2759
+ process.exitCode = 1;
2760
+ return;
2761
+ }
2762
+ const installed = listInstalledMcpServers({ global: isGlobal, cwd });
2763
+ const grouped = groupInstalledServersByName(installed);
2764
+ const targetGroup = grouped.get(serverName);
2765
+ if (!targetGroup) {
2766
+ logger.error(
2767
+ `MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
2768
+ );
2769
+ process.exitCode = 1;
2770
+ return;
2771
+ }
2772
+ const updatedConfig = {
2773
+ ...targetGroup.config,
2774
+ args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
2775
+ env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
2776
+ headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
2777
+ };
2778
+ if (options.command !== void 0) {
2779
+ updatedConfig.command = options.command;
2780
+ }
2781
+ if (options.args !== void 0) {
2782
+ updatedConfig.args = options.args;
2783
+ }
2784
+ if (options.url !== void 0) {
2785
+ updatedConfig.url = options.url;
2786
+ }
2787
+ if (options.transport !== void 0) {
2788
+ updatedConfig.type = resolveTransport(options.transport);
2789
+ }
2790
+ if (options.env !== void 0) {
2791
+ const parsedEnv = parseKeyValueList(options.env, "=");
2792
+ updatedConfig.env = { ...updatedConfig.env ?? {}, ...parsedEnv };
2793
+ }
2794
+ if (options.header !== void 0) {
2795
+ const parsedHeaders = parseKeyValueList(options.header, ":");
2796
+ updatedConfig.headers = { ...updatedConfig.headers ?? {}, ...parsedHeaders };
2797
+ }
2798
+ const targetAgents = options.agent ? parseMcpAgentList(options.agent) ?? targetGroup.agents : targetGroup.agents;
2799
+ const requestedTransport = updatedConfig.url ? updatedConfig.type ?? "http" : "stdio";
2800
+ const compatibleAgents = [];
2801
+ for (const agent of targetAgents) {
2802
+ const agentConfig = getMcpAgentConfig(agent);
2803
+ if (isMcpTransportSupported(agentConfig, requestedTransport)) {
2804
+ compatibleAgents.push(agent);
2805
+ } else {
2806
+ const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
2807
+ logger.warn(`Skipping ${pc12.cyan(agent)}: ${reason}`);
2808
+ }
2809
+ }
2810
+ if (compatibleAgents.length === 0) {
2811
+ logger.error(
2812
+ `None of the target agents support ${requestedTransport} transport. Update aborted.`
2813
+ );
2814
+ process.exitCode = 1;
2815
+ return;
2816
+ }
2817
+ logger.info(
2818
+ `Updating ${pc12.bold(serverName)} across ${pc12.cyan(String(compatibleAgents.length))} agent(s)...`
2819
+ );
2820
+ let allSuccess = true;
2821
+ for (const agent of compatibleAgents) {
2822
+ const res = installMcpServerForAgent(serverName, updatedConfig, agent, {
2823
+ global: isGlobal,
2824
+ cwd
2825
+ });
2826
+ if (res.success) {
2827
+ logger.success(`${pc12.cyan(agent)}: Successfully updated in ${pc12.dim(res.path)}`);
2828
+ } else {
2829
+ allSuccess = false;
2830
+ logger.error(`${pc12.cyan(agent)}: Update failed - ${res.error}`);
2831
+ }
2832
+ }
2833
+ if (!allSuccess) {
2834
+ process.exitCode = 1;
2835
+ }
2836
+ return;
2837
+ }
2838
+ if (!isInteractive) {
2839
+ if (!serverName) {
2840
+ logger.error(
2841
+ 'Missing required argument: "server-name" for non-interactive manage command. Specify a server name or use interactive terminal.'
2842
+ );
2843
+ process.exitCode = 1;
2844
+ return;
2845
+ }
2846
+ const installed = listInstalledMcpServers({ global: isGlobal, cwd });
2847
+ const grouped = groupInstalledServersByName(installed);
2848
+ const targetGroup = grouped.get(serverName);
2849
+ if (!targetGroup) {
2850
+ logger.error(
2851
+ `MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
2852
+ );
2853
+ process.exitCode = 1;
2854
+ return;
2855
+ }
2856
+ displayServerDetails({
2857
+ serverName,
2858
+ config: targetGroup.config,
2859
+ agents: targetGroup.agents,
2860
+ isGlobal
2861
+ });
2862
+ return;
2863
+ }
2864
+ await wizardManage({
2865
+ global: options.global,
2866
+ serverName
2867
+ });
2868
+ } catch (error) {
2869
+ if (error && typeof error === "object" && "name" in error && error.name === "ExitPromptError") {
2870
+ process.exit(0);
2871
+ }
2872
+ logger.error(toErrorMessage(error));
2873
+ process.exitCode = 1;
2874
+ }
2875
+ });
2876
+
2305
2877
  export {
2306
2878
  mcpAgents,
2307
2879
  mcpAgentAliases,
@@ -2347,14 +2919,26 @@ export {
2347
2919
  promptScopeAndAgents,
2348
2920
  parseArgsString,
2349
2921
  promptArgsConfig,
2922
+ formatArgsString,
2923
+ promptEditArgs,
2924
+ promptEditKeyValueConfig,
2925
+ maskSecretValue,
2926
+ formatEnvText,
2350
2927
  parseEnvText,
2351
2928
  promptEnvConfig,
2929
+ promptEditEnvConfig,
2930
+ maskSecretHeader,
2931
+ formatHeadersText,
2352
2932
  parseHeadersText,
2353
2933
  promptHeadersConfig,
2934
+ promptEditHeadersConfig,
2354
2935
  wizardAdd,
2355
2936
  normalizeServerConfig,
2356
2937
  groupInstalledServersByName,
2938
+ displayServerDetails,
2357
2939
  wizardManage,
2358
2940
  wizardRemove,
2359
- mainMenu
2941
+ mainMenu,
2942
+ parseKeyValueList,
2943
+ mcpManageCommand
2360
2944
  };