@wuyax/mcps 0.1.0-beta.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,79 +1,351 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/interactive/index.ts
31
+ var interactive_exports = {};
32
+ __export(interactive_exports, {
33
+ buildLinkedAgentChoices: () => buildLinkedAgentChoices,
34
+ formatArgsString: () => formatArgsString,
35
+ formatEnvText: () => formatEnvText,
36
+ formatHeadersText: () => formatHeadersText,
37
+ linkedCheckbox: () => linkedCheckbox,
38
+ mainMenu: () => mainMenu,
39
+ parseArgsString: () => parseArgsString,
40
+ parseEnvText: () => parseEnvText,
41
+ parseHeadersText: () => parseHeadersText,
42
+ promptArgsConfig: () => promptArgsConfig,
43
+ promptEditArgs: () => promptEditArgs,
44
+ promptEditEnvConfig: () => promptEditEnvConfig,
45
+ promptEditHeadersConfig: () => promptEditHeadersConfig,
46
+ promptEditKeyValueConfig: () => promptEditKeyValueConfig,
47
+ promptEditorText: () => promptEditorText,
48
+ promptEnvConfig: () => promptEnvConfig,
49
+ promptHeadersConfig: () => promptHeadersConfig,
50
+ promptScope: () => promptScope,
51
+ promptScopeAndAgents: () => promptScopeAndAgents,
52
+ promptSwitchServerType: () => promptSwitchServerType,
53
+ readMultilineTextFromTerminal: () => readMultilineTextFromTerminal,
54
+ wizardAdd: () => wizardAdd,
55
+ wizardManage: () => wizardManage,
56
+ wizardRemove: () => wizardRemove
57
+ });
58
+ module.exports = __toCommonJS(interactive_exports);
59
+
60
+ // src/interactive/prompts/linked-checkbox.ts
61
+ var import_core = require("@inquirer/core");
62
+ var import_picocolors = __toESM(require("picocolors"), 1);
63
+ var defaultTheme = {
64
+ icon: {
65
+ checked: import_picocolors.default.green("[x]"),
66
+ unchecked: import_picocolors.default.dim("[ ]"),
67
+ cursor: import_picocolors.default.cyan(">"),
68
+ disabledChecked: import_picocolors.default.dim("[x]"),
69
+ disabledUnchecked: import_picocolors.default.dim("[-]")
70
+ },
71
+ style: {
72
+ disabled: (text) => import_picocolors.default.dim(text),
73
+ renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(", "),
74
+ description: (text) => import_picocolors.default.cyan(text),
75
+ keysHelpTip: (keys) => keys.map(([key, action]) => `${import_picocolors.default.bold(key)} ${import_picocolors.default.dim(action)}`).join(import_picocolors.default.dim(" | ")),
76
+ highlight: (text) => import_picocolors.default.cyan(text)
77
+ },
78
+ i18n: {
79
+ disabledError: "This option is disabled and cannot be toggled."
80
+ }
81
+ };
82
+ function isSelectable(item) {
83
+ return !import_core.Separator.isSeparator(item) && !item.disabled;
84
+ }
85
+ function isNavigable(item) {
86
+ return !import_core.Separator.isSeparator(item);
87
+ }
88
+ function isChecked(item) {
89
+ return !import_core.Separator.isSeparator(item) && item.checked;
90
+ }
91
+ function normalizeChoices(choices) {
92
+ return choices.map((choice) => {
93
+ if (import_core.Separator.isSeparator(choice)) {
94
+ return choice;
95
+ }
96
+ if (typeof choice !== "object" || choice === null || !("value" in choice)) {
97
+ const name2 = String(choice);
98
+ return {
99
+ value: choice,
100
+ name: name2,
101
+ short: name2,
102
+ checkedName: name2,
103
+ disabled: false,
104
+ checked: false,
105
+ linkedValues: []
106
+ };
107
+ }
108
+ const name = choice.name ?? String(choice.value);
109
+ return {
110
+ value: choice.value,
111
+ name,
112
+ short: choice.short ?? name,
113
+ checkedName: choice.checkedName ?? name,
114
+ description: choice.description,
115
+ disabled: choice.disabled ?? false,
116
+ checked: choice.checked ?? false,
117
+ linkedValues: choice.linkedValues ?? []
118
+ };
119
+ });
120
+ }
121
+ var linkedCheckbox = (0, import_core.createPrompt)(
122
+ (config, done) => {
123
+ const { pageSize = 10, loop = true, required, validate = () => true } = config;
124
+ const theme = (0, import_core.makeTheme)(defaultTheme, config.theme);
125
+ const [status, setStatus] = (0, import_core.useState)("idle");
126
+ const prefix = (0, import_core.usePrefix)({ status, theme });
127
+ const [items, setItems] = (0, import_core.useState)(() => normalizeChoices(config.choices));
128
+ const bounds = (0, import_core.useMemo)(() => {
129
+ const first = items.findIndex(isNavigable);
130
+ let last = -1;
131
+ for (let i = items.length - 1; i >= 0; i--) {
132
+ if (isNavigable(items[i])) {
133
+ last = i;
134
+ break;
135
+ }
136
+ }
137
+ if (first === -1 || last === -1) {
138
+ throw new import_core.ValidationError("[linkedCheckbox prompt] No selectable choices.");
139
+ }
140
+ return { first, last };
141
+ }, [items]);
142
+ const [active, setActive] = (0, import_core.useState)(bounds.first);
143
+ const [errorMsg, setError] = (0, import_core.useState)();
144
+ const toggleWithLinked = (targetIndex) => {
145
+ const targetItem = items[targetIndex];
146
+ if (!targetItem || import_core.Separator.isSeparator(targetItem) || targetItem.disabled) {
147
+ return;
148
+ }
149
+ const nextChecked = !targetItem.checked;
150
+ const targetValue = targetItem.value;
151
+ const linked = new Set(targetItem.linkedValues);
152
+ setItems(
153
+ (prevItems) => prevItems.map((item) => {
154
+ if (import_core.Separator.isSeparator(item) || item.disabled) {
155
+ return item;
156
+ }
157
+ const isTargetOrLinked = item.value === targetValue || linked.has(item.value) || item.linkedValues.includes(targetValue);
158
+ if (isTargetOrLinked) {
159
+ return { ...item, checked: nextChecked };
160
+ }
161
+ return item;
162
+ })
163
+ );
164
+ };
165
+ (0, import_core.useKeypress)(async (key) => {
166
+ if ((0, import_core.isEnterKey)(key)) {
167
+ const selection = items.filter(isChecked);
168
+ const isValid = await validate([...selection]);
169
+ if (required && selection.length === 0) {
170
+ setError("At least one choice must be selected");
171
+ } else if (isValid === true) {
172
+ setStatus("done");
173
+ done(selection.map((choice) => choice.value));
174
+ } else {
175
+ setError(typeof isValid === "string" ? isValid : "You must select a valid value");
176
+ }
177
+ } else if ((0, import_core.isUpKey)(key) || (0, import_core.isDownKey)(key)) {
178
+ if (errorMsg) setError(void 0);
179
+ if (loop || (0, import_core.isUpKey)(key) && active !== bounds.first || (0, import_core.isDownKey)(key) && active !== bounds.last) {
180
+ const offset = (0, import_core.isUpKey)(key) ? -1 : 1;
181
+ let next = active;
182
+ do {
183
+ next = (next + offset + items.length) % items.length;
184
+ } while (!isNavigable(items[next]));
185
+ setActive(next);
186
+ }
187
+ } else if ((0, import_core.isSpaceKey)(key)) {
188
+ const activeItem = items[active];
189
+ if (activeItem && !import_core.Separator.isSeparator(activeItem)) {
190
+ if (activeItem.disabled) {
191
+ setError(theme.i18n.disabledError);
192
+ } else {
193
+ setError(void 0);
194
+ toggleWithLinked(active);
195
+ }
196
+ }
197
+ } else if (key.name === "a") {
198
+ const hasUnchecked = items.some((choice) => isSelectable(choice) && !choice.checked);
199
+ setItems(
200
+ (prevItems) => prevItems.map((item) => isSelectable(item) ? { ...item, checked: hasUnchecked } : item)
201
+ );
202
+ } else if ((0, import_core.isNumberKey)(key)) {
203
+ const selectedIndex = Number(key.name) - 1;
204
+ let selectableIndex = -1;
205
+ const position = items.findIndex((item) => {
206
+ if (import_core.Separator.isSeparator(item)) return false;
207
+ selectableIndex++;
208
+ return selectableIndex === selectedIndex;
209
+ });
210
+ const selectedItem = items[position];
211
+ if (selectedItem && isSelectable(selectedItem)) {
212
+ setActive(position);
213
+ setError(void 0);
214
+ toggleWithLinked(position);
215
+ }
216
+ }
217
+ });
218
+ const message = theme.style.message(config.message, status);
219
+ let description;
220
+ const page = (0, import_core.usePagination)({
221
+ items,
222
+ active,
223
+ renderItem({ item, isActive }) {
224
+ if (import_core.Separator.isSeparator(item)) {
225
+ return ` ${item.separator}`;
226
+ }
227
+ const cursor = isActive ? theme.icon.cursor : " ";
228
+ if (item.disabled) {
229
+ const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
230
+ const checkbox2 = item.checked ? theme.icon.disabledChecked : theme.icon.disabledUnchecked;
231
+ return theme.style.disabled(`${cursor} ${checkbox2} ${item.name} ${disabledLabel}`);
232
+ }
233
+ if (isActive) {
234
+ description = item.description;
235
+ }
236
+ const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
237
+ const name = item.checked ? item.checkedName : item.name;
238
+ const color = isActive ? theme.style.highlight : (x) => x;
239
+ return color(`${cursor} ${checkbox} ${name}`);
240
+ },
241
+ pageSize,
242
+ loop
243
+ });
244
+ if (status === "done") {
245
+ const selection = items.filter(isChecked);
246
+ const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
247
+ return [prefix, message, answer].filter(Boolean).join(" ");
248
+ }
249
+ const helpLine = theme.style.keysHelpTip([
250
+ ["up/down", "navigate"],
251
+ ["space", "toggle"],
252
+ ["a", "all"],
253
+ ["enter", "submit"]
254
+ ]);
255
+ const lines = [
256
+ [prefix, message].filter(Boolean).join(" "),
257
+ page,
258
+ helpLine
259
+ ];
260
+ if (description) {
261
+ lines.push(theme.style.description(description));
262
+ }
263
+ if (errorMsg) {
264
+ lines.push(theme.style.error(errorMsg));
265
+ }
266
+ return lines.join("\n");
267
+ }
268
+ );
269
+
270
+ // src/interactive/utils/build-linked-agent-choices.ts
271
+ var import_picocolors2 = __toESM(require("picocolors"), 1);
272
+
1
273
  // src/agents.ts
2
- import { existsSync } from "fs";
3
- import { homedir, platform } from "os";
4
- import { join } from "path";
5
- var home = homedir();
274
+ var import_node_fs = require("fs");
275
+ var import_node_os = require("os");
276
+ var import_node_path = require("path");
277
+ var home = (0, import_node_os.homedir)();
6
278
  var getPlatformPaths = () => {
7
- const currentPlatform = platform();
279
+ const currentPlatform = (0, import_node_os.platform)();
8
280
  if (currentPlatform === "win32") {
9
- const appData = process.env.APPDATA || join(home, "AppData", "Roaming");
281
+ const appData = process.env.APPDATA || (0, import_node_path.join)(home, "AppData", "Roaming");
10
282
  return {
11
283
  appSupport: appData,
12
- vscodePath: join(appData, "Code", "User"),
13
- traePath: join(appData, "Trae", "User"),
14
- gooseConfigPath: join(appData, "Block", "goose", "config", "config.yaml"),
15
- zedConfigPath: join(appData, "Zed", "settings.json")
284
+ vscodePath: (0, import_node_path.join)(appData, "Code", "User"),
285
+ traePath: (0, import_node_path.join)(appData, "Trae", "User"),
286
+ gooseConfigPath: (0, import_node_path.join)(appData, "Block", "goose", "config", "config.yaml"),
287
+ zedConfigPath: (0, import_node_path.join)(appData, "Zed", "settings.json")
16
288
  };
17
289
  }
18
290
  if (currentPlatform === "darwin") {
19
291
  return {
20
- appSupport: join(home, "Library", "Application Support"),
21
- vscodePath: join(home, "Library", "Application Support", "Code", "User"),
22
- traePath: join(home, "Library", "Application Support", "Trae", "User"),
23
- gooseConfigPath: join(home, ".config", "goose", "config.yaml"),
24
- zedConfigPath: join(home, ".config", "zed", "settings.json")
292
+ appSupport: (0, import_node_path.join)(home, "Library", "Application Support"),
293
+ vscodePath: (0, import_node_path.join)(home, "Library", "Application Support", "Code", "User"),
294
+ traePath: (0, import_node_path.join)(home, "Library", "Application Support", "Trae", "User"),
295
+ gooseConfigPath: (0, import_node_path.join)(home, ".config", "goose", "config.yaml"),
296
+ zedConfigPath: (0, import_node_path.join)(home, ".config", "zed", "settings.json")
25
297
  };
26
298
  }
27
- const configDir = process.env.XDG_CONFIG_HOME || join(home, ".config");
299
+ const configDir = process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config");
28
300
  return {
29
301
  appSupport: configDir,
30
- vscodePath: join(configDir, "Code", "User"),
31
- traePath: join(configDir, "Trae", "User"),
32
- gooseConfigPath: join(configDir, "goose", "config.yaml"),
33
- zedConfigPath: join(configDir, "zed", "settings.json")
302
+ vscodePath: (0, import_node_path.join)(configDir, "Code", "User"),
303
+ traePath: (0, import_node_path.join)(configDir, "Trae", "User"),
304
+ gooseConfigPath: (0, import_node_path.join)(configDir, "goose", "config.yaml"),
305
+ zedConfigPath: (0, import_node_path.join)(configDir, "zed", "settings.json")
34
306
  };
35
307
  };
36
308
  var { appSupport, vscodePath, traePath, gooseConfigPath, zedConfigPath } = getPlatformPaths();
37
- var ampConfigDir = process.env.AMP_HOME?.trim() || join(process.env.XDG_CONFIG_HOME || join(home, ".config"), "amp");
38
- var ampGlobalConfigPath = existsSync(join(ampConfigDir, "settings.jsonc")) ? join(ampConfigDir, "settings.jsonc") : join(ampConfigDir, "settings.json");
39
- var antigravityMcpConfigPath = join(home, ".gemini", "config", "mcp_config.json");
40
- var augmentConfigDir = process.env.AUGMENT_HOME?.trim() || join(home, ".augment");
41
- var augmentGlobalConfigPath = existsSync(join(augmentConfigDir, "settings.jsonc")) ? join(augmentConfigDir, "settings.jsonc") : join(augmentConfigDir, "settings.json");
42
- var clineDir = process.env.CLINE_DIR || join(home, ".cline");
43
- var clineCliConfigPath = join(clineDir, "mcp.json");
44
- var clineExtensionConfigPath = join(
309
+ var ampConfigDir = process.env.AMP_HOME?.trim() || (0, import_node_path.join)(process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config"), "amp");
310
+ var ampGlobalConfigPath = (0, import_node_fs.existsSync)((0, import_node_path.join)(ampConfigDir, "settings.jsonc")) ? (0, import_node_path.join)(ampConfigDir, "settings.jsonc") : (0, import_node_path.join)(ampConfigDir, "settings.json");
311
+ var antigravityMcpConfigPath = (0, import_node_path.join)(home, ".gemini", "config", "mcp_config.json");
312
+ var augmentConfigDir = process.env.AUGMENT_HOME?.trim() || (0, import_node_path.join)(home, ".augment");
313
+ var augmentGlobalConfigPath = (0, import_node_fs.existsSync)((0, import_node_path.join)(augmentConfigDir, "settings.jsonc")) ? (0, import_node_path.join)(augmentConfigDir, "settings.jsonc") : (0, import_node_path.join)(augmentConfigDir, "settings.json");
314
+ var clineDir = process.env.CLINE_DIR || (0, import_node_path.join)(home, ".cline");
315
+ var clineCliConfigPath = (0, import_node_path.join)(clineDir, "mcp.json");
316
+ var clineExtensionConfigPath = (0, import_node_path.join)(
45
317
  vscodePath,
46
318
  "globalStorage",
47
319
  "saoudrizwan.claude-dev",
48
320
  "settings",
49
321
  "cline_mcp_settings.json"
50
322
  );
51
- var copilotConfigPath = join(
52
- process.env.COPILOT_HOME?.trim() || join(home, ".copilot"),
323
+ var copilotConfigPath = (0, import_node_path.join)(
324
+ process.env.COPILOT_HOME?.trim() || (0, import_node_path.join)(home, ".copilot"),
53
325
  "mcp-config.json"
54
326
  );
55
- var grokConfigPath = join(
56
- process.env.GROK_HOME?.trim() || join(home, ".grok"),
327
+ var grokConfigPath = (0, import_node_path.join)(
328
+ process.env.GROK_HOME?.trim() || (0, import_node_path.join)(home, ".grok"),
57
329
  "config.toml"
58
330
  );
59
- var kimiCodeConfigPath = join(
60
- process.env.KIMI_CODE_HOME?.trim() || join(home, ".kimi-code"),
331
+ var kimiCodeConfigPath = (0, import_node_path.join)(
332
+ process.env.KIMI_CODE_HOME?.trim() || (0, import_node_path.join)(home, ".kimi-code"),
61
333
  "mcp.json"
62
334
  );
63
- var kiroConfigPath = join(
64
- process.env.KIRO_HOME?.trim() || join(home, ".kiro"),
335
+ var kiroConfigPath = (0, import_node_path.join)(
336
+ process.env.KIRO_HOME?.trim() || (0, import_node_path.join)(home, ".kiro"),
65
337
  "settings",
66
338
  "mcp.json"
67
339
  );
68
- var qoderConfigPath = join(
69
- process.env.QODER_HOME?.trim() || join(home, ".qoder"),
340
+ var qoderConfigPath = (0, import_node_path.join)(
341
+ process.env.QODER_HOME?.trim() || (0, import_node_path.join)(home, ".qoder"),
70
342
  "settings.json"
71
343
  );
72
- var qwenCodeConfigPath = join(
73
- process.env.QWEN_CODE_HOME?.trim() || process.env.QWEN_HOME?.trim() || join(home, ".qwen"),
344
+ var qwenCodeConfigPath = (0, import_node_path.join)(
345
+ process.env.QWEN_CODE_HOME?.trim() || process.env.QWEN_HOME?.trim() || (0, import_node_path.join)(home, ".qwen"),
74
346
  "settings.json"
75
347
  );
76
- var traeConfigPath = existsSync(join(home, ".trae", "mcp.json")) ? join(home, ".trae", "mcp.json") : join(traePath, "mcp.json");
348
+ var traeConfigPath = (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".trae", "mcp.json")) ? (0, import_node_path.join)(home, ".trae", "mcp.json") : (0, import_node_path.join)(traePath, "mcp.json");
77
349
  var ALL_TRANSPORTS = ["stdio", "http", "sse"];
78
350
  var mcpAgents = {
79
351
  // https://ampcode.com/docs/markdown/customize/mcp
@@ -85,19 +357,19 @@ var mcpAgents = {
85
357
  configKey: "amp.mcpServers",
86
358
  format: "jsonc",
87
359
  supportedTransports: ALL_TRANSPORTS,
88
- detectGlobalInstall: () => existsSync(ampConfigDir) || existsSync(join(home, ".amp")),
89
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".amp", "settings.json")) || existsSync(join(cwd, ".amp", "settings.jsonc")) || existsSync(join(cwd, ".amp")),
360
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(ampConfigDir) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".amp")),
361
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".amp", "settings.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".amp", "settings.jsonc")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".amp")),
90
362
  resolveConfigPath: ({ global: isGlobal, cwd }) => {
91
363
  if (isGlobal) {
92
- if (existsSync(join(ampConfigDir, "settings.jsonc"))) {
93
- return join(ampConfigDir, "settings.jsonc");
364
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(ampConfigDir, "settings.jsonc"))) {
365
+ return (0, import_node_path.join)(ampConfigDir, "settings.jsonc");
94
366
  }
95
367
  return ampGlobalConfigPath;
96
368
  }
97
- if (existsSync(join(cwd, ".amp", "settings.jsonc"))) {
98
- return join(cwd, ".amp", "settings.jsonc");
369
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".amp", "settings.jsonc"))) {
370
+ return (0, import_node_path.join)(cwd, ".amp", "settings.jsonc");
99
371
  }
100
- return join(cwd, ".amp", "settings.json");
372
+ return (0, import_node_path.join)(cwd, ".amp", "settings.json");
101
373
  },
102
374
  transformDialect: "amp"
103
375
  },
@@ -109,8 +381,8 @@ var mcpAgents = {
109
381
  configKey: "mcpServers",
110
382
  format: "jsonc",
111
383
  supportedTransports: ALL_TRANSPORTS,
112
- detectGlobalInstall: () => existsSync(join(home, ".gemini", "antigravity")) || existsSync(join(home, ".gemini", "config")),
113
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".agents", "mcp_config.json")) || existsSync(join(cwd, ".agents"))
384
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".gemini", "antigravity")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".gemini", "config")),
385
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".agents", "mcp_config.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".agents"))
114
386
  },
115
387
  // https://antigravity.google/docs/cli/mcp/
116
388
  "antigravity-cli": {
@@ -121,8 +393,8 @@ var mcpAgents = {
121
393
  configKey: "mcpServers",
122
394
  format: "jsonc",
123
395
  supportedTransports: ALL_TRANSPORTS,
124
- detectGlobalInstall: () => existsSync(join(home, ".gemini", "antigravity-cli")),
125
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".agents", "mcp_config.json")) || existsSync(join(cwd, ".agents"))
396
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".gemini", "antigravity-cli")),
397
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".agents", "mcp_config.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".agents"))
126
398
  },
127
399
  // https://docs.augmentcode.com/cli/integrations.md
128
400
  augment: {
@@ -133,19 +405,19 @@ var mcpAgents = {
133
405
  configKey: "mcpServers",
134
406
  format: "jsonc",
135
407
  supportedTransports: ALL_TRANSPORTS,
136
- detectGlobalInstall: () => existsSync(augmentConfigDir) || existsSync(join(home, ".augment")),
137
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".augment", "settings.json")) || existsSync(join(cwd, ".augment", "settings.jsonc")) || existsSync(join(cwd, ".augment")),
408
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(augmentConfigDir) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".augment")),
409
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".augment", "settings.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".augment", "settings.jsonc")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".augment")),
138
410
  resolveConfigPath: ({ global: isGlobal, cwd }) => {
139
411
  if (isGlobal) {
140
- if (existsSync(join(augmentConfigDir, "settings.jsonc"))) {
141
- return join(augmentConfigDir, "settings.jsonc");
412
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(augmentConfigDir, "settings.jsonc"))) {
413
+ return (0, import_node_path.join)(augmentConfigDir, "settings.jsonc");
142
414
  }
143
415
  return augmentGlobalConfigPath;
144
416
  }
145
- if (existsSync(join(cwd, ".augment", "settings.jsonc"))) {
146
- return join(cwd, ".augment", "settings.jsonc");
417
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".augment", "settings.jsonc"))) {
418
+ return (0, import_node_path.join)(cwd, ".augment", "settings.jsonc");
147
419
  }
148
- return join(cwd, ".augment", "settings.json");
420
+ return (0, import_node_path.join)(cwd, ".augment", "settings.json");
149
421
  },
150
422
  transformDialect: "augment"
151
423
  },
@@ -157,13 +429,13 @@ var mcpAgents = {
157
429
  configKey: "mcpServers",
158
430
  format: "jsonc",
159
431
  supportedTransports: ALL_TRANSPORTS,
160
- detectGlobalInstall: () => existsSync(clineExtensionConfigPath),
161
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".cline", "mcp.json")) || existsSync(join(cwd, ".cline")),
432
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(clineExtensionConfigPath),
433
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cline", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cline")),
162
434
  resolveConfigPath: ({ global: isGlobal, cwd }) => {
163
435
  if (isGlobal) {
164
436
  return clineExtensionConfigPath;
165
437
  }
166
- return join(cwd, ".cline", "mcp.json");
438
+ return (0, import_node_path.join)(cwd, ".cline", "mcp.json");
167
439
  },
168
440
  transformDialect: "cline"
169
441
  },
@@ -176,13 +448,13 @@ var mcpAgents = {
176
448
  configKey: "mcpServers",
177
449
  format: "jsonc",
178
450
  supportedTransports: ALL_TRANSPORTS,
179
- detectGlobalInstall: () => existsSync(clineDir),
180
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".cline", "mcp.json")) || existsSync(join(cwd, ".cline")),
451
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(clineDir),
452
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cline", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cline")),
181
453
  resolveConfigPath: ({ global: isGlobal, cwd }) => {
182
454
  if (isGlobal) {
183
455
  return clineCliConfigPath;
184
456
  }
185
- return join(cwd, ".cline", "mcp.json");
457
+ return (0, import_node_path.join)(cwd, ".cline", "mcp.json");
186
458
  },
187
459
  transformDialect: "cline"
188
460
  },
@@ -190,59 +462,59 @@ var mcpAgents = {
190
462
  "claude-code": {
191
463
  name: "claude-code",
192
464
  displayName: "Claude Code",
193
- globalConfigPath: join(home, ".claude.json"),
465
+ globalConfigPath: (0, import_node_path.join)(home, ".claude.json"),
194
466
  projectConfigPath: ".mcp.json",
195
467
  configKey: "mcpServers",
196
468
  format: "jsonc",
197
469
  supportedTransports: ALL_TRANSPORTS,
198
- detectGlobalInstall: () => existsSync(join(home, ".claude.json")),
199
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".mcp.json"))
470
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".claude.json")),
471
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".mcp.json"))
200
472
  },
201
473
  "claude-desktop": {
202
474
  name: "claude-desktop",
203
475
  displayName: "Claude Desktop",
204
- globalConfigPath: join(appSupport, "Claude", "claude_desktop_config.json"),
476
+ globalConfigPath: (0, import_node_path.join)(appSupport, "Claude", "claude_desktop_config.json"),
205
477
  configKey: "mcpServers",
206
478
  format: "jsonc",
207
479
  supportedTransports: ["stdio"],
208
480
  unsupportedTransportMessage: "Claude Desktop currently supports only stdio MCP servers. Use a package name or command instead of a URL.",
209
- detectGlobalInstall: () => existsSync(join(appSupport, "Claude", "claude_desktop_config.json"))
481
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(appSupport, "Claude", "claude_desktop_config.json"))
210
482
  },
211
483
  // https://learn.chatgpt.com/docs/extend/mcp?surface=app
212
484
  codex: {
213
485
  name: "codex",
214
486
  displayName: "Codex",
215
- globalConfigPath: join(process.env.CODEX_HOME?.trim() || join(home, ".codex"), "config.toml"),
487
+ globalConfigPath: (0, import_node_path.join)(process.env.CODEX_HOME?.trim() || (0, import_node_path.join)(home, ".codex"), "config.toml"),
216
488
  projectConfigPath: ".codex/config.toml",
217
489
  configKey: "mcp_servers",
218
490
  format: "toml",
219
491
  supportedTransports: ALL_TRANSPORTS,
220
- detectGlobalInstall: () => existsSync(process.env.CODEX_HOME?.trim() || join(home, ".codex")),
221
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".codex", "config.toml")),
492
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(process.env.CODEX_HOME?.trim() || (0, import_node_path.join)(home, ".codex")),
493
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".codex", "config.toml")),
222
494
  transformDialect: "augment"
223
495
  },
224
496
  // https://cursor.com/help/customization/mcp
225
497
  cursor: {
226
498
  name: "cursor",
227
499
  displayName: "Cursor",
228
- globalConfigPath: join(home, ".cursor", "mcp.json"),
500
+ globalConfigPath: (0, import_node_path.join)(home, ".cursor", "mcp.json"),
229
501
  projectConfigPath: ".cursor/mcp.json",
230
502
  configKey: "mcpServers",
231
503
  format: "jsonc",
232
504
  supportedTransports: ALL_TRANSPORTS,
233
- detectGlobalInstall: () => existsSync(join(home, ".cursor")),
234
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".cursor", "mcp.json"))
505
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".cursor")),
506
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cursor", "mcp.json"))
235
507
  },
236
508
  "gemini-cli": {
237
509
  name: "gemini-cli",
238
510
  displayName: "Gemini CLI",
239
- globalConfigPath: join(home, ".gemini", "settings.json"),
511
+ globalConfigPath: (0, import_node_path.join)(home, ".gemini", "settings.json"),
240
512
  projectConfigPath: ".gemini/settings.json",
241
513
  configKey: "mcpServers",
242
514
  format: "jsonc",
243
515
  supportedTransports: ALL_TRANSPORTS,
244
- detectGlobalInstall: () => existsSync(join(home, ".gemini")),
245
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".gemini", "settings.json"))
516
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".gemini")),
517
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".gemini", "settings.json"))
246
518
  },
247
519
  // https://docs.x.ai/build/features/mcp-servers.md
248
520
  grok: {
@@ -253,8 +525,8 @@ var mcpAgents = {
253
525
  configKey: "mcp_servers",
254
526
  format: "toml",
255
527
  supportedTransports: ALL_TRANSPORTS,
256
- detectGlobalInstall: () => existsSync(grokConfigPath) || existsSync(process.env.GROK_HOME?.trim() || join(home, ".grok")),
257
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".grok", "config.toml")) || existsSync(join(cwd, ".grok")),
528
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(grokConfigPath) || (0, import_node_fs.existsSync)(process.env.GROK_HOME?.trim() || (0, import_node_path.join)(home, ".grok")),
529
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".grok", "config.toml")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".grok")),
258
530
  transformDialect: "grok"
259
531
  },
260
532
  // https://goose-docs.ai/docs/guides/config-files/
@@ -266,8 +538,8 @@ var mcpAgents = {
266
538
  configKey: "extensions",
267
539
  format: "yaml",
268
540
  supportedTransports: ALL_TRANSPORTS,
269
- detectGlobalInstall: () => existsSync(gooseConfigPath),
270
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".goose", "config.yaml")),
541
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(gooseConfigPath),
542
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".goose", "config.yaml")),
271
543
  transformDialect: "goose"
272
544
  },
273
545
  "github-copilot-cli": {
@@ -278,8 +550,8 @@ var mcpAgents = {
278
550
  configKey: "mcpServers",
279
551
  format: "jsonc",
280
552
  supportedTransports: ALL_TRANSPORTS,
281
- detectGlobalInstall: () => existsSync(copilotConfigPath) || existsSync(process.env.COPILOT_HOME?.trim() || join(home, ".copilot")),
282
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".mcp.json")) || existsSync(join(cwd, ".github", "mcp.json")),
553
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(copilotConfigPath) || (0, import_node_fs.existsSync)(process.env.COPILOT_HOME?.trim() || (0, import_node_path.join)(home, ".copilot")),
554
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".github", "mcp.json")),
283
555
  transformDialect: "vscode"
284
556
  },
285
557
  // https://www.kimi.com/code/docs/en/kimi-code-cli/customization/mcp.html
@@ -291,8 +563,8 @@ var mcpAgents = {
291
563
  configKey: "mcpServers",
292
564
  format: "jsonc",
293
565
  supportedTransports: ALL_TRANSPORTS,
294
- detectGlobalInstall: () => existsSync(kimiCodeConfigPath) || existsSync(process.env.KIMI_CODE_HOME?.trim() || join(home, ".kimi-code")),
295
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".kimi-code", "mcp.json")) || existsSync(join(cwd, ".kimi-code")),
566
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(kimiCodeConfigPath) || (0, import_node_fs.existsSync)(process.env.KIMI_CODE_HOME?.trim() || (0, import_node_path.join)(home, ".kimi-code")),
567
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".kimi-code", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".kimi-code")),
296
568
  transformDialect: "kimi-code"
297
569
  },
298
570
  // https://kiro.dev/docs/mcp/configuration.md
@@ -304,16 +576,16 @@ var mcpAgents = {
304
576
  configKey: "mcpServers",
305
577
  format: "jsonc",
306
578
  supportedTransports: ALL_TRANSPORTS,
307
- detectGlobalInstall: () => existsSync(kiroConfigPath) || existsSync(process.env.KIRO_HOME?.trim() || join(home, ".kiro")),
308
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".kiro", "settings", "mcp.json")) || existsSync(join(cwd, ".kiro")),
579
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(kiroConfigPath) || (0, import_node_fs.existsSync)(process.env.KIRO_HOME?.trim() || (0, import_node_path.join)(home, ".kiro")),
580
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".kiro", "settings", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".kiro")),
309
581
  transformDialect: "kiro"
310
582
  },
311
583
  // https://opencode.ai/docs/config/
312
584
  opencode: {
313
585
  name: "opencode",
314
586
  displayName: "OpenCode",
315
- globalConfigPath: join(
316
- process.env.XDG_CONFIG_HOME || join(home, ".config"),
587
+ globalConfigPath: (0, import_node_path.join)(
588
+ process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config"),
317
589
  "opencode",
318
590
  "opencode.json"
319
591
  ),
@@ -321,21 +593,21 @@ var mcpAgents = {
321
593
  configKey: "mcp",
322
594
  format: "jsonc",
323
595
  supportedTransports: ALL_TRANSPORTS,
324
- detectGlobalInstall: () => existsSync(join(process.env.XDG_CONFIG_HOME || join(home, ".config"), "opencode")),
325
- detectProjectInstall: (cwd) => existsSync(join(cwd, "opencode.json")),
596
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config"), "opencode")),
597
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, "opencode.json")),
326
598
  transformDialect: "opencode"
327
599
  },
328
600
  // https://pi.dev/packages/pi-mcp-extension
329
601
  pi: {
330
602
  name: "pi",
331
603
  displayName: "Pi",
332
- globalConfigPath: join(home, ".pi", "agent", "mcp.json"),
604
+ globalConfigPath: (0, import_node_path.join)(home, ".pi", "agent", "mcp.json"),
333
605
  projectConfigPath: ".pi/mcp.json",
334
606
  configKey: "mcpServers",
335
607
  format: "jsonc",
336
608
  supportedTransports: ALL_TRANSPORTS,
337
- detectGlobalInstall: () => existsSync(join(home, ".pi")),
338
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".pi", "mcp.json")) || existsSync(join(cwd, ".pi")),
609
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".pi")),
610
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".pi", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".pi")),
339
611
  transformDialect: "pi"
340
612
  },
341
613
  // https://docs.qoder.com/zh/cli/mcp-servers.md
@@ -347,14 +619,14 @@ var mcpAgents = {
347
619
  configKey: "mcpServers",
348
620
  format: "jsonc",
349
621
  supportedTransports: ALL_TRANSPORTS,
350
- detectGlobalInstall: () => existsSync(qoderConfigPath) || existsSync(process.env.QODER_HOME?.trim() || join(home, ".qoder")),
351
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".mcp.json")) || existsSync(join(cwd, ".qoder", "settings.json")) || existsSync(join(cwd, ".qoder")),
622
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(qoderConfigPath) || (0, import_node_fs.existsSync)(process.env.QODER_HOME?.trim() || (0, import_node_path.join)(home, ".qoder")),
623
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".qoder", "settings.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".qoder")),
352
624
  resolveConfigPath: ({ global: isGlobal, cwd }) => {
353
625
  if (isGlobal) return qoderConfigPath;
354
- if (existsSync(join(cwd, ".qoder", "settings.json"))) {
355
- return join(cwd, ".qoder", "settings.json");
626
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".qoder", "settings.json"))) {
627
+ return (0, import_node_path.join)(cwd, ".qoder", "settings.json");
356
628
  }
357
- return join(cwd, ".mcp.json");
629
+ return (0, import_node_path.join)(cwd, ".mcp.json");
358
630
  }
359
631
  },
360
632
  // https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/
@@ -366,10 +638,10 @@ var mcpAgents = {
366
638
  configKey: "mcpServers",
367
639
  format: "jsonc",
368
640
  supportedTransports: ALL_TRANSPORTS,
369
- detectGlobalInstall: () => existsSync(qwenCodeConfigPath) || existsSync(
370
- process.env.QWEN_CODE_HOME?.trim() || process.env.QWEN_HOME?.trim() || join(home, ".qwen")
641
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(qwenCodeConfigPath) || (0, import_node_fs.existsSync)(
642
+ process.env.QWEN_CODE_HOME?.trim() || process.env.QWEN_HOME?.trim() || (0, import_node_path.join)(home, ".qwen")
371
643
  ),
372
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".qwen", "settings.json")) || existsSync(join(cwd, ".qwen")),
644
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".qwen", "settings.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".qwen")),
373
645
  transformDialect: "qwen-code"
374
646
  },
375
647
  // https://docs.trae.ai/ide/add-mcp-servers?_lang=en
@@ -381,16 +653,16 @@ var mcpAgents = {
381
653
  configKey: "mcpServers",
382
654
  format: "jsonc",
383
655
  supportedTransports: ALL_TRANSPORTS,
384
- detectGlobalInstall: () => existsSync(traeConfigPath) || existsSync(join(home, ".trae", "mcp.json")) || existsSync(join(home, ".trae")) || existsSync(traePath) || existsSync(join(appSupport, "Trae")),
385
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".trae", "mcp.json")) || existsSync(join(cwd, ".trae")),
656
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(traeConfigPath) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".trae", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".trae")) || (0, import_node_fs.existsSync)(traePath) || (0, import_node_fs.existsSync)((0, import_node_path.join)(appSupport, "Trae")),
657
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".trae", "mcp.json")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".trae")),
386
658
  resolveConfigPath: ({ global: isGlobal, cwd }) => {
387
659
  if (isGlobal) {
388
- if (existsSync(join(home, ".trae", "mcp.json"))) {
389
- return join(home, ".trae", "mcp.json");
660
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".trae", "mcp.json"))) {
661
+ return (0, import_node_path.join)(home, ".trae", "mcp.json");
390
662
  }
391
663
  return traeConfigPath;
392
664
  }
393
- return join(cwd, ".trae", "mcp.json");
665
+ return (0, import_node_path.join)(cwd, ".trae", "mcp.json");
394
666
  },
395
667
  transformDialect: "trae"
396
668
  },
@@ -398,13 +670,13 @@ var mcpAgents = {
398
670
  vscode: {
399
671
  name: "vscode",
400
672
  displayName: "VS Code",
401
- globalConfigPath: join(vscodePath, "mcp.json"),
673
+ globalConfigPath: (0, import_node_path.join)(vscodePath, "mcp.json"),
402
674
  projectConfigPath: ".vscode/mcp.json",
403
675
  configKey: "servers",
404
676
  format: "jsonc",
405
677
  supportedTransports: ALL_TRANSPORTS,
406
- detectGlobalInstall: () => existsSync(join(vscodePath, "mcp.json")) || existsSync(vscodePath),
407
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".vscode", "mcp.json")),
678
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(vscodePath, "mcp.json")) || (0, import_node_fs.existsSync)(vscodePath),
679
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".vscode", "mcp.json")),
408
680
  transformDialect: "vscode"
409
681
  },
410
682
  // https://zed.dev/docs/ai/mcp.md
@@ -416,8 +688,8 @@ var mcpAgents = {
416
688
  configKey: "context_servers",
417
689
  format: "jsonc",
418
690
  supportedTransports: ALL_TRANSPORTS,
419
- detectGlobalInstall: () => existsSync(zedConfigPath) || existsSync(join(process.env.XDG_CONFIG_HOME || join(home, ".config"), "zed")) || existsSync(join(appSupport, "Zed")),
420
- detectProjectInstall: (cwd) => existsSync(join(cwd, ".zed", "settings.json")),
691
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(zedConfigPath) || (0, import_node_fs.existsSync)((0, import_node_path.join)(process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config"), "zed")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(appSupport, "Zed")),
692
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".zed", "settings.json")),
421
693
  transformDialect: "zed"
422
694
  }
423
695
  };
@@ -463,6 +735,84 @@ var detectProjectInstalledMcpAgents = (cwd) => getMcpAgentTypes().filter(
463
735
  var detectGloballyInstalledMcpAgents = () => getMcpAgentTypes().filter((type) => mcpAgents[type].detectGlobalInstall());
464
736
  var getMcpAgentsSupportingProjectScope = () => getMcpAgentTypes().filter((type) => Boolean(mcpAgents[type].projectConfigPath));
465
737
 
738
+ // src/config-store.ts
739
+ var import_node_fs6 = require("fs");
740
+ var import_node_path3 = require("path");
741
+
742
+ // src/utils/is-plain-object.ts
743
+ var isPlainObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
744
+
745
+ // src/utils/get-nested-value.ts
746
+ var getNestedValue = (source, dottedKey) => {
747
+ if (!source) return void 0;
748
+ if (dottedKey in source) return source[dottedKey];
749
+ const segments = dottedKey.split(".");
750
+ let cursor = source;
751
+ for (const segment of segments) {
752
+ if (!isPlainObject(cursor)) return void 0;
753
+ cursor = cursor[segment];
754
+ }
755
+ return cursor;
756
+ };
757
+
758
+ // src/formats/json.ts
759
+ var import_node_fs3 = require("fs");
760
+ var import_jsonc_parser = require("jsonc-parser");
761
+
762
+ // src/utils/ensure-parent-dir.ts
763
+ var import_node_fs2 = require("fs");
764
+ var import_node_path2 = require("path");
765
+ var ensureParentDir = (filePath) => {
766
+ const parentDir = (0, import_node_path2.dirname)(filePath);
767
+ if (!(0, import_node_fs2.existsSync)(parentDir)) (0, import_node_fs2.mkdirSync)(parentDir, { recursive: true });
768
+ };
769
+
770
+ // src/utils/set-nested-value.ts
771
+ var DANGEROUS_KEY_SEGMENTS = /* @__PURE__ */ new Set([
772
+ "__proto__",
773
+ "prototype",
774
+ "constructor"
775
+ ]);
776
+ var assertSafeSegment = (segment) => {
777
+ if (DANGEROUS_KEY_SEGMENTS.has(segment)) {
778
+ throw new Error(`Refusing to write to unsafe key segment "${segment}"`);
779
+ }
780
+ };
781
+ var setNestedValue = (target, dottedKey, value) => {
782
+ if (dottedKey in target) {
783
+ assertSafeSegment(dottedKey);
784
+ target[dottedKey] = value;
785
+ return;
786
+ }
787
+ const segments = dottedKey.split(".");
788
+ let cursor = target;
789
+ for (let segmentIndex = 0; segmentIndex < segments.length - 1; segmentIndex += 1) {
790
+ const segment = segments[segmentIndex];
791
+ assertSafeSegment(segment);
792
+ const existing = cursor[segment];
793
+ if (isPlainObject(existing)) {
794
+ cursor = existing;
795
+ continue;
796
+ }
797
+ const next = {};
798
+ cursor[segment] = next;
799
+ cursor = next;
800
+ }
801
+ const finalSegment = segments[segments.length - 1];
802
+ assertSafeSegment(finalSegment);
803
+ cursor[finalSegment] = value;
804
+ };
805
+
806
+ // src/utils/walk-nested-object.ts
807
+ var walkNestedObject = (root, segments) => {
808
+ let cursor = root;
809
+ for (const segment of segments) {
810
+ if (!isPlainObject(cursor)) return void 0;
811
+ cursor = cursor[segment];
812
+ }
813
+ return isPlainObject(cursor) ? cursor : void 0;
814
+ };
815
+
466
816
  // src/constants.ts
467
817
  var DEFAULT_REMOTE_TRANSPORT = "http";
468
818
  var NPX_COMMAND = "npx";
@@ -506,164 +856,21 @@ var KNOWN_COMMAND_RUNNERS = /* @__PURE__ */ new Set([
506
856
  ]);
507
857
  var SCRIPT_EXTENSION_REGEX = /\.(?:js|ts|mjs|cjs|py|sh|rb|go)$/i;
508
858
 
509
- // src/build-server-config.ts
510
- var buildMcpServerConfig = (parsed, options = {}) => {
511
- if (parsed.type === "remote") {
512
- const config2 = {
513
- type: options.transport ?? DEFAULT_REMOTE_TRANSPORT,
514
- url: parsed.value
515
- };
516
- if (options.headers && Object.keys(options.headers).length > 0) {
517
- config2.headers = options.headers;
518
- }
519
- return config2;
520
- }
521
- if (parsed.type === "command") {
522
- const parts = parsed.value.split(/\s+/);
523
- const command = parts[0] ?? "";
524
- const args = parts.slice(1);
525
- if (options.args && options.args.length > 0) {
526
- args.push(...options.args);
527
- }
528
- const config2 = { command, args };
529
- if (options.env && Object.keys(options.env).length > 0) {
530
- config2.env = options.env;
531
- }
532
- return config2;
533
- }
534
- const packageArgs = [NPX_DASH_Y, parsed.value];
535
- if (options.args && options.args.length > 0) {
536
- packageArgs.push(...options.args);
537
- }
538
- const config = {
539
- command: NPX_COMMAND,
540
- args: packageArgs
541
- };
542
- if (options.env && Object.keys(options.env).length > 0) {
543
- config.env = options.env;
544
- }
545
- return config;
546
- };
547
-
548
- // src/parse-server-config.ts
549
- var isRemoteServerConfig = (config) => typeof config.url === "string" && config.url.length > 0;
550
- var isStdioServerConfig = (config) => typeof config.command === "string" && config.command.length > 0;
551
- var parseServerConfig = (raw) => {
552
- if (!raw || typeof raw !== "object") return {};
553
- const data = raw;
554
- const rawUrl = typeof data.url === "string" && data.url.trim().length > 0 ? data.url.trim() : void 0;
555
- const rawHttpUrl = typeof data.httpUrl === "string" && data.httpUrl.trim().length > 0 ? data.httpUrl.trim() : void 0;
556
- const remoteUrl = rawHttpUrl ?? rawUrl;
557
- if (remoteUrl) {
558
- const transport = data.type === "sse" || data.transport === "sse" ? "sse" : "http";
559
- const headers = data.headers && typeof data.headers === "object" ? data.headers : void 0;
560
- return {
561
- type: transport,
562
- url: remoteUrl,
563
- headers
564
- };
565
- }
566
- if (typeof data.command === "string" && data.command.trim().length > 0) {
567
- const args = Array.isArray(data.args) ? data.args.filter((item) => typeof item === "string") : void 0;
568
- const env = data.env && typeof data.env === "object" ? data.env : void 0;
569
- return {
570
- command: data.command.trim(),
571
- args,
572
- env
573
- };
574
- }
575
- return {};
576
- };
577
-
578
- // src/utils/is-plain-object.ts
579
- var isPlainObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
580
-
581
- // src/utils/get-nested-value.ts
582
- var getNestedValue = (source, dottedKey) => {
583
- if (!source) return void 0;
584
- if (dottedKey in source) return source[dottedKey];
585
- const segments = dottedKey.split(".");
586
- let cursor = source;
587
- for (const segment of segments) {
588
- if (!isPlainObject(cursor)) return void 0;
589
- cursor = cursor[segment];
590
- }
591
- return cursor;
592
- };
593
-
594
- // src/formats/json.ts
595
- import { existsSync as existsSync3, readFileSync, writeFileSync } from "fs";
596
- import { applyEdits, modify, parse as parseJsonc } from "jsonc-parser";
597
-
598
- // src/utils/ensure-parent-dir.ts
599
- import { existsSync as existsSync2, mkdirSync } from "fs";
600
- import { dirname } from "path";
601
- var ensureParentDir = (filePath) => {
602
- const parentDir = dirname(filePath);
603
- if (!existsSync2(parentDir)) mkdirSync(parentDir, { recursive: true });
604
- };
605
-
606
- // src/utils/set-nested-value.ts
607
- var DANGEROUS_KEY_SEGMENTS = /* @__PURE__ */ new Set([
608
- "__proto__",
609
- "prototype",
610
- "constructor"
611
- ]);
612
- var assertSafeSegment = (segment) => {
613
- if (DANGEROUS_KEY_SEGMENTS.has(segment)) {
614
- throw new Error(`Refusing to write to unsafe key segment "${segment}"`);
615
- }
616
- };
617
- var setNestedValue = (target, dottedKey, value) => {
618
- if (dottedKey in target) {
619
- assertSafeSegment(dottedKey);
620
- target[dottedKey] = value;
621
- return;
622
- }
623
- const segments = dottedKey.split(".");
624
- let cursor = target;
625
- for (let segmentIndex = 0; segmentIndex < segments.length - 1; segmentIndex += 1) {
626
- const segment = segments[segmentIndex];
627
- assertSafeSegment(segment);
628
- const existing = cursor[segment];
629
- if (isPlainObject(existing)) {
630
- cursor = existing;
631
- continue;
632
- }
633
- const next = {};
634
- cursor[segment] = next;
635
- cursor = next;
636
- }
637
- const finalSegment = segments[segments.length - 1];
638
- assertSafeSegment(finalSegment);
639
- cursor[finalSegment] = value;
640
- };
641
-
642
- // src/utils/walk-nested-object.ts
643
- var walkNestedObject = (root, segments) => {
644
- let cursor = root;
645
- for (const segment of segments) {
646
- if (!isPlainObject(cursor)) return void 0;
647
- cursor = cursor[segment];
648
- }
649
- return isPlainObject(cursor) ? cursor : void 0;
650
- };
651
-
652
859
  // src/formats/json.ts
653
860
  var JSONC_FORMATTING = {
654
861
  insertSpaces: true,
655
862
  tabSize: DEFAULT_JSON_INDENT_SPACES,
656
863
  eol: "\n"
657
864
  };
658
- var readFileOrEmpty = (filePath) => existsSync3(filePath) ? readFileSync(filePath, "utf-8") : "";
865
+ var readFileOrEmpty = (filePath) => (0, import_node_fs3.existsSync)(filePath) ? (0, import_node_fs3.readFileSync)(filePath, "utf-8") : "";
659
866
  var writeWithTrailingNewline = (filePath, contents) => {
660
- writeFileSync(filePath, contents.endsWith("\n") ? contents : `${contents}
867
+ (0, import_node_fs3.writeFileSync)(filePath, contents.endsWith("\n") ? contents : `${contents}
661
868
  `, "utf-8");
662
869
  };
663
870
  var readJsoncConfig = (filePath) => {
664
871
  const raw = readFileOrEmpty(filePath);
665
872
  if (!raw.trim()) return {};
666
- const parsed = parseJsonc(raw);
873
+ const parsed = (0, import_jsonc_parser.parse)(raw);
667
874
  return isPlainObject(parsed) ? parsed : {};
668
875
  };
669
876
  var resolvePathPrefix = (root, dottedKey) => {
@@ -681,10 +888,10 @@ var setJsoncNestedValue = (filePath, dottedKey, serverName, serverConfig) => {
681
888
  const existing = readJsoncConfig(filePath);
682
889
  const pathPrefix = resolvePathPrefix(existing, dottedKey);
683
890
  const path = [...pathPrefix, serverName];
684
- const edits = modify(sourceText, path, serverConfig, {
891
+ const edits = (0, import_jsonc_parser.modify)(sourceText, path, serverConfig, {
685
892
  formattingOptions: JSONC_FORMATTING
686
893
  });
687
- writeWithTrailingNewline(filePath, applyEdits(sourceText, edits));
894
+ writeWithTrailingNewline(filePath, (0, import_jsonc_parser.applyEdits)(sourceText, edits));
688
895
  };
689
896
  var writeJsonConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
690
897
  ensureParentDir(filePath);
@@ -698,7 +905,7 @@ var writeJsonConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
698
905
  } else {
699
906
  setNestedValue(existing, dottedKey, servers);
700
907
  }
701
- writeFileSync(
908
+ (0, import_node_fs3.writeFileSync)(
702
909
  filePath,
703
910
  `${JSON.stringify(existing, null, DEFAULT_JSON_INDENT_SPACES)}
704
911
  `,
@@ -706,25 +913,25 @@ var writeJsonConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
706
913
  );
707
914
  };
708
915
  var removeJsoncConfigKey = (filePath, dottedKey, serverName) => {
709
- if (!existsSync3(filePath)) return false;
710
- const sourceText = readFileSync(filePath, "utf-8");
916
+ if (!(0, import_node_fs3.existsSync)(filePath)) return false;
917
+ const sourceText = (0, import_node_fs3.readFileSync)(filePath, "utf-8");
711
918
  if (!sourceText.trim()) return false;
712
919
  const existing = readJsoncConfig(filePath);
713
920
  const pathPrefix = resolvePathPrefix(existing, dottedKey);
714
921
  const parentObject = walkNestedObject(existing, pathPrefix);
715
922
  if (!parentObject || !(serverName in parentObject)) return false;
716
923
  const path = [...pathPrefix, serverName];
717
- const edits = modify(sourceText, path, void 0, {
924
+ const edits = (0, import_jsonc_parser.modify)(sourceText, path, void 0, {
718
925
  formattingOptions: JSONC_FORMATTING
719
926
  });
720
927
  if (edits.length === 0) return false;
721
- writeWithTrailingNewline(filePath, applyEdits(sourceText, edits));
928
+ writeWithTrailingNewline(filePath, (0, import_jsonc_parser.applyEdits)(sourceText, edits));
722
929
  return true;
723
930
  };
724
931
 
725
932
  // src/formats/toml.ts
726
- import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
727
- import TOML from "@iarna/toml";
933
+ var import_node_fs4 = require("fs");
934
+ var import_toml = __toESM(require("@iarna/toml"), 1);
728
935
 
729
936
  // src/utils/delete-nested-value.ts
730
937
  var DANGEROUS_KEY_SEGMENTS2 = /* @__PURE__ */ new Set([
@@ -757,10 +964,10 @@ var deleteNestedValue = (target, dottedKey) => {
757
964
  // src/formats/toml.ts
758
965
  var toTomlJsonMap = (value) => JSON.parse(JSON.stringify(value));
759
966
  var readTomlConfig = (filePath) => {
760
- if (!existsSync4(filePath)) return {};
761
- const raw = readFileSync2(filePath, "utf-8");
967
+ if (!(0, import_node_fs4.existsSync)(filePath)) return {};
968
+ const raw = (0, import_node_fs4.readFileSync)(filePath, "utf-8");
762
969
  if (!raw.trim()) return {};
763
- const parsed = TOML.parse(raw);
970
+ const parsed = import_toml.default.parse(raw);
764
971
  return isPlainObject(parsed) ? parsed : {};
765
972
  };
766
973
  var writeTomlConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
@@ -770,24 +977,24 @@ var writeTomlConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
770
977
  const servers = existingServers ? { ...existingServers } : {};
771
978
  servers[serverName] = serverConfig;
772
979
  setNestedValue(existing, dottedKey, servers);
773
- writeFileSync2(filePath, TOML.stringify(toTomlJsonMap(existing)), "utf-8");
980
+ (0, import_node_fs4.writeFileSync)(filePath, import_toml.default.stringify(toTomlJsonMap(existing)), "utf-8");
774
981
  };
775
982
  var removeTomlConfigKey = (filePath, dottedKey, serverName) => {
776
- if (!existsSync4(filePath)) return false;
983
+ if (!(0, import_node_fs4.existsSync)(filePath)) return false;
777
984
  const existing = readTomlConfig(filePath);
778
985
  const didRemove = deleteNestedValue(existing, `${dottedKey}.${serverName}`);
779
- if (didRemove) writeFileSync2(filePath, TOML.stringify(toTomlJsonMap(existing)), "utf-8");
986
+ if (didRemove) (0, import_node_fs4.writeFileSync)(filePath, import_toml.default.stringify(toTomlJsonMap(existing)), "utf-8");
780
987
  return didRemove;
781
988
  };
782
989
 
783
990
  // src/formats/yaml.ts
784
- import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
785
- import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
991
+ var import_node_fs5 = require("fs");
992
+ var import_yaml = require("yaml");
786
993
  var readYamlConfig = (filePath) => {
787
- if (!existsSync5(filePath)) return {};
788
- const raw = readFileSync3(filePath, "utf-8");
994
+ if (!(0, import_node_fs5.existsSync)(filePath)) return {};
995
+ const raw = (0, import_node_fs5.readFileSync)(filePath, "utf-8");
789
996
  if (!raw.trim()) return {};
790
- const parsed = parseYaml(raw);
997
+ const parsed = (0, import_yaml.parse)(raw);
791
998
  return isPlainObject(parsed) ? parsed : {};
792
999
  };
793
1000
  var writeYamlConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
@@ -797,13 +1004,13 @@ var writeYamlConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
797
1004
  const servers = existingServers ? { ...existingServers } : {};
798
1005
  servers[serverName] = serverConfig;
799
1006
  setNestedValue(existing, dottedKey, servers);
800
- writeFileSync3(filePath, stringifyYaml(existing), "utf-8");
1007
+ (0, import_node_fs5.writeFileSync)(filePath, (0, import_yaml.stringify)(existing), "utf-8");
801
1008
  };
802
1009
  var removeYamlConfigKey = (filePath, dottedKey, serverName) => {
803
- if (!existsSync5(filePath)) return false;
1010
+ if (!(0, import_node_fs5.existsSync)(filePath)) return false;
804
1011
  const existing = readYamlConfig(filePath);
805
1012
  const didRemove = deleteNestedValue(existing, `${dottedKey}.${serverName}`);
806
- if (didRemove) writeFileSync3(filePath, stringifyYaml(existing), "utf-8");
1013
+ if (didRemove) (0, import_node_fs5.writeFileSync)(filePath, (0, import_yaml.stringify)(existing), "utf-8");
807
1014
  return didRemove;
808
1015
  };
809
1016
 
@@ -858,181 +1065,6 @@ var listServersInConfigFile = (filePath, format, dottedKey) => {
858
1065
  return isPlainObject(entries) ? entries : {};
859
1066
  };
860
1067
 
861
- // src/config-store.ts
862
- import { existsSync as existsSync6 } from "fs";
863
-
864
- // src/resolve-config-target.ts
865
- import { join as join2 } from "path";
866
- var resolveMcpConfigTarget = (agent, options = {}) => {
867
- const isGlobal = options.global ?? false;
868
- const cwd = options.cwd ?? process.cwd();
869
- const configPath = agent.resolveConfigPath ? agent.resolveConfigPath({ global: isGlobal, cwd }) : !isGlobal && agent.projectConfigPath ? join2(cwd, agent.projectConfigPath) : agent.globalConfigPath;
870
- const configKey = !isGlobal && agent.projectConfigKey ? agent.projectConfigKey : agent.configKey;
871
- return { configPath, configKey };
872
- };
873
-
874
- // src/config-store.ts
875
- var FsConfigStoreAdapter = class {
876
- exists(filePath) {
877
- return existsSync6(filePath);
878
- }
879
- read(target) {
880
- return readConfigFile(target.filePath, target.format);
881
- }
882
- writeServer(target, serverName, serverConfig) {
883
- if (!target.dottedKey) {
884
- throw new Error(`Cannot write server: missing dottedKey for ${target.filePath}`);
885
- }
886
- writeServerToConfigFile(
887
- target.filePath,
888
- target.format,
889
- target.dottedKey,
890
- serverName,
891
- serverConfig
892
- );
893
- }
894
- removeServer(target, serverName) {
895
- if (!target.dottedKey) return false;
896
- return removeServerFromConfigFile(
897
- target.filePath,
898
- target.format,
899
- target.dottedKey,
900
- serverName
901
- );
902
- }
903
- listServers(target) {
904
- if (!target.dottedKey) return {};
905
- return listServersInConfigFile(target.filePath, target.format, target.dottedKey);
906
- }
907
- };
908
- var AgentConfigStore = class {
909
- constructor(adapter = new FsConfigStoreAdapter()) {
910
- this.adapter = adapter;
911
- }
912
- adapter;
913
- getAdapter() {
914
- return this.adapter;
915
- }
916
- resolveTarget(agent, options = {}) {
917
- const agentConfig = typeof agent === "string" ? getMcpAgentConfig(agent) : agent;
918
- const target = resolveMcpConfigTarget(agentConfig, options);
919
- return { agent: agentConfig, target };
920
- }
921
- resolveDescriptor(agent, options = {}) {
922
- const { agent: agentConfig, target } = this.resolveTarget(agent, options);
923
- return {
924
- filePath: target.configPath,
925
- format: agentConfig.format,
926
- dottedKey: target.configKey
927
- };
928
- }
929
- writeServer(agent, serverName, serverConfig, options = {}) {
930
- const descriptor = this.resolveDescriptor(agent, options);
931
- this.adapter.writeServer(descriptor, serverName, serverConfig);
932
- return { path: descriptor.filePath };
933
- }
934
- removeServer(agent, serverName, options = {}) {
935
- const descriptor = this.resolveDescriptor(agent, options);
936
- if (!this.adapter.exists(descriptor.filePath)) {
937
- return { path: descriptor.filePath, removed: false };
938
- }
939
- const removed = this.adapter.removeServer(descriptor, serverName);
940
- return { path: descriptor.filePath, removed };
941
- }
942
- listServers(agent, options = {}) {
943
- const descriptor = this.resolveDescriptor(agent, options);
944
- if (!this.adapter.exists(descriptor.filePath)) {
945
- return { path: descriptor.filePath, exists: false, servers: {} };
946
- }
947
- const servers = this.adapter.listServers(descriptor);
948
- return { path: descriptor.filePath, exists: true, servers };
949
- }
950
- read(agent, options = {}) {
951
- const descriptor = this.resolveDescriptor(agent, options);
952
- if (!this.adapter.exists(descriptor.filePath)) {
953
- return {};
954
- }
955
- return this.adapter.read(descriptor);
956
- }
957
- readServer(agent, serverName, options = {}) {
958
- const { exists, servers } = this.listServers(agent, options);
959
- if (!exists) return void 0;
960
- return servers[serverName];
961
- }
962
- };
963
- var agentConfigStore = new AgentConfigStore();
964
-
965
- // src/utils/to-error-message.ts
966
- var toErrorMessage = (error, fallback = "Unknown error") => error instanceof Error ? error.message : fallback;
967
-
968
- // src/resolve-config-clusters.ts
969
- var getCandidateAgentsForScope = (options = {}) => {
970
- return options.global ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
971
- };
972
- var getCoHostedAgents = (agentType, options = {}) => {
973
- const currentAgent = getMcpAgentConfig(agentType);
974
- const currentTarget = resolveMcpConfigTarget(currentAgent, options);
975
- const candidates = getCandidateAgentsForScope(options);
976
- const coHosted = [];
977
- for (const candidateType of candidates) {
978
- if (candidateType === agentType) continue;
979
- const candidateConfig = getMcpAgentConfig(candidateType);
980
- const candidateTarget = resolveMcpConfigTarget(candidateConfig, options);
981
- if (candidateTarget.configPath === currentTarget.configPath && candidateTarget.configKey === currentTarget.configKey) {
982
- coHosted.push(candidateType);
983
- }
984
- }
985
- return coHosted;
986
- };
987
- var resolveConfigClusters = (agentTypes, options = {}) => {
988
- const clustersByPath = /* @__PURE__ */ new Map();
989
- for (const agentType of agentTypes) {
990
- const agentConfig = getMcpAgentConfig(agentType);
991
- const target = resolveMcpConfigTarget(agentConfig, options);
992
- let keyMap = clustersByPath.get(target.configPath);
993
- if (!keyMap) {
994
- keyMap = /* @__PURE__ */ new Map();
995
- clustersByPath.set(target.configPath, keyMap);
996
- }
997
- let cluster = keyMap.get(target.configKey);
998
- if (!cluster) {
999
- const allCoHosted = getCoHostedAgents(agentType, options);
1000
- cluster = {
1001
- configPath: target.configPath,
1002
- configKey: target.configKey,
1003
- targetAgents: [],
1004
- coHostedAgents: allCoHosted
1005
- };
1006
- keyMap.set(target.configKey, cluster);
1007
- }
1008
- if (!cluster.targetAgents.includes(agentType)) {
1009
- cluster.targetAgents.push(agentType);
1010
- }
1011
- }
1012
- const clusters = [];
1013
- for (const keyMap of clustersByPath.values()) {
1014
- for (const cluster of keyMap.values()) {
1015
- cluster.coHostedAgents = cluster.coHostedAgents.filter(
1016
- (co) => !cluster.targetAgents.includes(co)
1017
- );
1018
- clusters.push(cluster);
1019
- }
1020
- }
1021
- return clusters;
1022
- };
1023
- var sortAgentsWithClusters = (agentTypes, options = {}) => {
1024
- const clusters = resolveConfigClusters(agentTypes, options);
1025
- const sorted = [];
1026
- for (const cluster of clusters) {
1027
- for (const agent of cluster.targetAgents) {
1028
- if (!sorted.includes(agent)) {
1029
- sorted.push(agent);
1030
- }
1031
- }
1032
- }
1033
- return sorted;
1034
- };
1035
-
1036
1068
  // src/transforms/index.ts
1037
1069
  var DIALECT_PRESETS = {
1038
1070
  vscode: {
@@ -1230,9 +1262,6 @@ var transformServerConfig = (serverName, config, dialect, _context) => {
1230
1262
  }
1231
1263
  return transformStdioConfig(serverName, config, options);
1232
1264
  };
1233
- var createAgentTransform = (dialect) => {
1234
- return (serverName, config, context) => transformServerConfig(serverName, config, dialect, context);
1235
- };
1236
1265
  var transformServerConfigForAgent = (agent, serverName, config, context = { global: false }) => {
1237
1266
  if (agent.transformConfig) {
1238
1267
  return agent.transformConfig(serverName, config, context);
@@ -1243,389 +1272,415 @@ var transformServerConfigForAgent = (agent, serverName, config, context = { glob
1243
1272
  return config;
1244
1273
  };
1245
1274
 
1246
- // src/installer.ts
1247
- var installMcpServerForAgent = (serverName, serverConfig, agentType, options = {}) => {
1248
- const agent = getMcpAgentConfig(agentType);
1275
+ // src/utils/to-error-message.ts
1276
+ var toErrorMessage = (error, fallback = "Unknown error") => error instanceof Error ? error.message : fallback;
1277
+
1278
+ // src/config-store.ts
1279
+ var resolveMcpConfigTarget = (agent, options = {}) => {
1249
1280
  const isGlobal = options.global ?? false;
1250
- const { target } = agentConfigStore.resolveTarget(agent, options);
1251
- const coHosted = getCoHostedAgents(agentType, options);
1252
- try {
1253
- const transformed = transformServerConfigForAgent(agent, serverName, serverConfig, {
1254
- global: isGlobal
1255
- });
1256
- agentConfigStore.writeServer(agent, serverName, transformed, options);
1257
- return {
1258
- agent: agentType,
1259
- success: true,
1260
- path: target.configPath,
1261
- coConfiguredAgents: coHosted.length > 0 ? coHosted : void 0
1262
- };
1263
- } catch (error) {
1264
- return {
1265
- agent: agentType,
1266
- success: false,
1267
- path: target.configPath,
1268
- error: toErrorMessage(error)
1269
- };
1270
- }
1281
+ const cwd = options.cwd ?? process.cwd();
1282
+ const configPath = agent.resolveConfigPath ? agent.resolveConfigPath({ global: isGlobal, cwd }) : !isGlobal && agent.projectConfigPath ? (0, import_node_path3.join)(cwd, agent.projectConfigPath) : agent.globalConfigPath;
1283
+ const configKey = !isGlobal && agent.projectConfigKey ? agent.projectConfigKey : agent.configKey;
1284
+ return { configPath, configKey };
1271
1285
  };
1272
- var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options = {}) => {
1273
- const clusters = resolveConfigClusters(agentTypes, options);
1274
- const resultsByAgent = /* @__PURE__ */ new Map();
1275
- const isGlobal = options.global ?? false;
1276
- for (const cluster of clusters) {
1277
- const primaryAgentType = cluster.targetAgents[0];
1278
- const primaryAgent = getMcpAgentConfig(primaryAgentType);
1279
- try {
1280
- const transformed = transformServerConfigForAgent(primaryAgent, serverName, serverConfig, {
1281
- global: isGlobal
1282
- });
1283
- agentConfigStore.writeServer(primaryAgent, serverName, transformed, options);
1284
- for (const agentType of cluster.targetAgents) {
1285
- resultsByAgent.set(agentType, {
1286
- agent: agentType,
1287
- success: true,
1288
- path: cluster.configPath,
1289
- coConfiguredAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
1290
- });
1291
- }
1292
- } catch (error) {
1293
- const errorMsg = toErrorMessage(error);
1294
- for (const agentType of cluster.targetAgents) {
1295
- resultsByAgent.set(agentType, {
1296
- agent: agentType,
1297
- success: false,
1298
- path: cluster.configPath,
1299
- error: errorMsg
1300
- });
1301
- }
1302
- }
1303
- }
1304
- return agentTypes.map((agentType) => resultsByAgent.get(agentType));
1286
+ var getCandidateAgentsForScope = (options = {}) => {
1287
+ return options.global ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
1305
1288
  };
1306
- var installToCompatibleAgents = (serverName, serverConfig, options) => {
1307
- const { allAgents, incompatible = [], global: isGlobal, cwd } = options;
1308
- const incompatibleMap = new Map(incompatible.map((item) => [item.agent, item.reason]));
1309
- const compatibleAgents = allAgents.filter((a) => !incompatibleMap.has(a));
1310
- const installedResults = installMcpServerForAgents(serverName, serverConfig, compatibleAgents, {
1311
- global: isGlobal,
1312
- cwd
1313
- });
1314
- const installedMap = new Map(installedResults.map((r) => [r.agent, r]));
1315
- return allAgents.map((agentType) => {
1316
- const incompatibleReason = incompatibleMap.get(agentType);
1317
- if (incompatibleReason) {
1318
- return {
1319
- agent: agentType,
1320
- success: false,
1321
- path: "",
1322
- error: incompatibleReason
1323
- };
1289
+ var FsConfigStoreAdapter = class {
1290
+ exists(filePath) {
1291
+ return (0, import_node_fs6.existsSync)(filePath);
1292
+ }
1293
+ read(target) {
1294
+ return readConfigFile(target.filePath, target.format);
1295
+ }
1296
+ writeServer(target, serverName, serverConfig) {
1297
+ if (!target.dottedKey) {
1298
+ throw new Error(`Cannot write server: missing dottedKey for ${target.filePath}`);
1324
1299
  }
1325
- return installedMap.get(agentType);
1326
- });
1327
- };
1328
-
1329
- // src/utils/parse-mcp-agent-list.ts
1330
- var parseMcpAgentList = (input7) => {
1331
- if (!input7 || input7.length === 0) return void 0;
1332
- if (input7.includes("*")) return getMcpAgentTypes();
1333
- const resolved = [];
1334
- for (const value of input7) {
1335
- const agentType = resolveMcpAgentAlias(value);
1336
- if (!agentType) throw new Error(`Unknown MCP agent "${value}"`);
1337
- resolved.push(agentType);
1300
+ writeServerToConfigFile(
1301
+ target.filePath,
1302
+ target.format,
1303
+ target.dottedKey,
1304
+ serverName,
1305
+ serverConfig
1306
+ );
1338
1307
  }
1339
- return resolved;
1340
- };
1341
-
1342
- // src/resolve-target-agents.ts
1343
- var normalizeRequestedAgents = (input7) => {
1344
- if (!input7 || input7.length === 0) return void 0;
1345
- const rawList = [...input7];
1346
- if (rawList.every((item) => isMcpAgentType(item))) {
1347
- return rawList;
1308
+ removeServer(target, serverName) {
1309
+ if (!target.dottedKey) return false;
1310
+ return removeServerFromConfigFile(
1311
+ target.filePath,
1312
+ target.format,
1313
+ target.dottedKey,
1314
+ serverName
1315
+ );
1316
+ }
1317
+ listServers(target) {
1318
+ if (!target.dottedKey) return {};
1319
+ return listServersInConfigFile(target.filePath, target.format, target.dottedKey);
1348
1320
  }
1349
- return parseMcpAgentList(rawList);
1350
1321
  };
1351
- var resolveTargetAgents = (query = {}) => {
1352
- const cwd = query.cwd ?? process.cwd();
1353
- const isGlobal = query.global ?? false;
1354
- let explicitAgents = normalizeRequestedAgents(query.requested);
1355
- if (query.all) {
1356
- explicitAgents = getMcpAgentTypes();
1322
+ var AgentConfigStore = class {
1323
+ constructor(adapter = new FsConfigStoreAdapter()) {
1324
+ this.adapter = adapter;
1357
1325
  }
1358
- const isDetected = !explicitAgents || explicitAgents.length === 0;
1359
- const detected = isGlobal ? detectGloballyInstalledMcpAgents() : detectProjectInstalledMcpAgents(cwd);
1360
- const candidateAgents = isDetected ? detected : explicitAgents ?? [];
1361
- const allAgents = candidateAgents.filter(
1362
- (type, index) => candidateAgents.indexOf(type) === index
1363
- );
1364
- const incompatible = [];
1365
- const compatibleAgents = [];
1366
- for (const agentType of allAgents) {
1367
- const config = getMcpAgentConfig(agentType);
1368
- if (query.transport && !isMcpTransportSupported(config, query.transport)) {
1369
- incompatible.push({
1370
- agent: agentType,
1371
- reason: config.unsupportedTransportMessage ?? `agent ${agentType} only supports ${config.supportedTransports.join(", ")} transport (attempted ${query.transport})`
1372
- });
1373
- } else {
1374
- compatibleAgents.push(agentType);
1375
- }
1326
+ adapter;
1327
+ getAdapter() {
1328
+ return this.adapter;
1376
1329
  }
1377
- let diagnostic;
1378
- if (compatibleAgents.length === 0) {
1379
- if (isDetected) {
1380
- diagnostic = `No ${isGlobal ? "global" : "project"}-installed MCP agents detected. Pass -a <agent> (e.g. -a cursor) or --all to install.`;
1381
- } else if (allAgents.length > 0 && incompatible.length > 0 && query.transport) {
1382
- const list = incompatible.map((item) => `${item.agent} (${item.reason})`).join(", ");
1383
- diagnostic = `None of the selected agents support ${query.transport} transport: ${list}`;
1384
- } else {
1385
- diagnostic = "No valid target agents specified.";
1386
- }
1330
+ // ---- Single-agent primitives ----
1331
+ resolveTarget(agent, options = {}) {
1332
+ const agentConfig = typeof agent === "string" ? getMcpAgentConfig(agent) : agent;
1333
+ const target = resolveMcpConfigTarget(agentConfig, options);
1334
+ return { agent: agentConfig, target };
1387
1335
  }
1388
- return {
1389
- agents: compatibleAgents,
1390
- compatibleAgents,
1391
- allAgents,
1392
- candidateAgents: allAgents,
1393
- detected,
1394
- isDetected,
1395
- incompatible,
1396
- diagnostic
1397
- };
1398
- };
1399
-
1400
- // src/source-parser.ts
1401
- var REMOTE_URL_REGEX = /^https?:\/\//i;
1402
- var HAS_WHITESPACE_REGEX = /\s/;
1403
- var PACKAGE_NAME_REGEX = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(?:@[^\s]+)?$/;
1404
- var PATH_SEPARATOR_REGEX = /[/\\]/;
1405
- var stripVersionSuffix = (input7) => {
1406
- if (input7.startsWith("@")) {
1407
- const secondAtIndex = input7.indexOf("@", 1);
1408
- if (secondAtIndex > 0) return input7.slice(0, secondAtIndex);
1409
- return input7;
1336
+ resolveDescriptor(agent, options = {}) {
1337
+ const { agent: agentConfig, target } = this.resolveTarget(agent, options);
1338
+ return {
1339
+ filePath: target.configPath,
1340
+ format: agentConfig.format,
1341
+ dottedKey: target.configKey
1342
+ };
1410
1343
  }
1411
- const atIndex = input7.lastIndexOf("@");
1412
- if (atIndex > 0) return input7.slice(0, atIndex);
1413
- return input7;
1414
- };
1415
- var stripScopePrefix = (input7) => {
1416
- if (!input7.startsWith("@") || !input7.includes("/")) return input7;
1417
- const parts = input7.split("/");
1418
- return parts[1] || input7;
1419
- };
1420
- var stripPathPrefix = (input7) => {
1421
- if (!PATH_SEPARATOR_REGEX.test(input7)) return input7;
1422
- const segments = input7.split(PATH_SEPARATOR_REGEX);
1423
- const basename = segments[segments.length - 1];
1424
- return basename || input7;
1425
- };
1426
- var extractPackageName = (input7) => {
1427
- let name = stripVersionSuffix(input7);
1428
- name = stripScopePrefix(name);
1429
- name = stripPathPrefix(name);
1430
- name = name.replace(SCRIPT_EXTENSION_REGEX, "");
1431
- for (const prefix of PACKAGE_NAME_PREFIX_STRIP) {
1432
- if (name.startsWith(prefix)) {
1433
- name = name.slice(prefix.length);
1434
- break;
1344
+ writeServer(agent, serverName, serverConfig, options = {}) {
1345
+ const descriptor = this.resolveDescriptor(agent, options);
1346
+ this.adapter.writeServer(descriptor, serverName, serverConfig);
1347
+ return { path: descriptor.filePath };
1348
+ }
1349
+ removeServer(agent, serverName, options = {}) {
1350
+ const descriptor = this.resolveDescriptor(agent, options);
1351
+ if (!this.adapter.exists(descriptor.filePath)) {
1352
+ return { path: descriptor.filePath, removed: false };
1435
1353
  }
1354
+ const removed = this.adapter.removeServer(descriptor, serverName);
1355
+ return { path: descriptor.filePath, removed };
1436
1356
  }
1437
- for (const suffix of PACKAGE_NAME_SUFFIX_STRIP) {
1438
- if (name.endsWith(suffix)) {
1439
- name = name.slice(0, -suffix.length);
1440
- break;
1357
+ listServers(agent, options = {}) {
1358
+ const descriptor = this.resolveDescriptor(agent, options);
1359
+ if (!this.adapter.exists(descriptor.filePath)) {
1360
+ return { path: descriptor.filePath, exists: false, servers: {} };
1441
1361
  }
1362
+ const servers = this.adapter.listServers(descriptor);
1363
+ return { path: descriptor.filePath, exists: true, servers };
1442
1364
  }
1443
- return name || MCP_DEFAULT_SERVER_NAME;
1444
- };
1445
- var inferNameFromUrl = (input7) => {
1446
- try {
1447
- const url = new URL(input7);
1448
- const host = url.hostname;
1449
- const labels = host.split(".").filter((segment) => segment.length > 0);
1450
- if (labels.length === 0) return MCP_DEFAULT_SERVER_NAME;
1451
- const meaningfulLabels = labels.filter((label) => {
1452
- const lower = label.toLowerCase();
1453
- if (COMMON_TLD_LABELS.has(lower)) return false;
1454
- if (GENERIC_HOST_PREFIXES.has(lower)) return false;
1455
- return true;
1365
+ /**
1366
+ * Batch lists servers for multiple agents, caching adapter reads for co-hosted
1367
+ * agents that share the exact same physical configuration file and dotted key.
1368
+ */
1369
+ listServersForAgents(agents, options = {}) {
1370
+ const readCache = /* @__PURE__ */ new Map();
1371
+ return agents.map((agentType) => {
1372
+ const descriptor = this.resolveDescriptor(agentType, options);
1373
+ const cacheKey = `${descriptor.filePath}::${descriptor.dottedKey ?? ""}`;
1374
+ let cached = readCache.get(cacheKey);
1375
+ if (!cached) {
1376
+ cached = this.listServers(agentType, options);
1377
+ readCache.set(cacheKey, cached);
1378
+ }
1379
+ return {
1380
+ agent: agentType,
1381
+ path: cached.path,
1382
+ exists: cached.exists,
1383
+ servers: cached.servers
1384
+ };
1456
1385
  });
1457
- if (meaningfulLabels.length > 0) return meaningfulLabels[0];
1458
- if (labels.length >= 2) return labels[labels.length - 2];
1459
- return labels[labels.length - 1] || MCP_DEFAULT_SERVER_NAME;
1460
- } catch {
1461
- return MCP_DEFAULT_SERVER_NAME;
1462
1386
  }
1463
- };
1464
- var inferNameFromCommand = (command) => {
1465
- const tokens = command.trim().split(/\s+/);
1466
- const runnerBase = tokens[0]?.split(PATH_SEPARATOR_REGEX).pop() ?? "";
1467
- const startIndex = KNOWN_COMMAND_RUNNERS.has(runnerBase) ? 1 : 0;
1468
- for (let tokenIndex = startIndex; tokenIndex < tokens.length; tokenIndex += 1) {
1469
- const token = tokens[tokenIndex];
1470
- if (!token || token.startsWith("-")) continue;
1471
- return extractPackageName(token);
1387
+ read(agent, options = {}) {
1388
+ const descriptor = this.resolveDescriptor(agent, options);
1389
+ if (!this.adapter.exists(descriptor.filePath)) {
1390
+ return {};
1391
+ }
1392
+ return this.adapter.read(descriptor);
1472
1393
  }
1473
- const firstNonFlag = tokens.find((token) => !token.startsWith("-"));
1474
- return firstNonFlag ? extractPackageName(firstNonFlag) : MCP_DEFAULT_SERVER_NAME;
1475
- };
1476
- var parseMcpSource = (input7) => {
1477
- const trimmed = input7.trim();
1478
- if (trimmed.length === 0) {
1479
- throw new Error(
1480
- "Invalid MCP source: input is empty. Expected a remote URL, an npm package, or a command line."
1481
- );
1394
+ readServer(agent, serverName, options = {}) {
1395
+ const { exists, servers } = this.listServers(agent, options);
1396
+ if (!exists) return void 0;
1397
+ return servers[serverName];
1482
1398
  }
1483
- if (REMOTE_URL_REGEX.test(trimmed)) {
1484
- return {
1485
- type: "remote",
1486
- value: trimmed,
1487
- inferredName: inferNameFromUrl(trimmed)
1488
- };
1399
+ // ---- Cluster & co-hosted awareness ----
1400
+ /**
1401
+ * Returns all other agents sharing the exact same physical configuration target
1402
+ * (same configPath and configKey) for the given scope.
1403
+ */
1404
+ getCoHostedAgents(agentType, options = {}) {
1405
+ const currentAgent = getMcpAgentConfig(agentType);
1406
+ const currentTarget = resolveMcpConfigTarget(currentAgent, options);
1407
+ const candidates = getCandidateAgentsForScope(options);
1408
+ const coHosted = [];
1409
+ for (const candidateType of candidates) {
1410
+ if (candidateType === agentType) continue;
1411
+ const candidateConfig = getMcpAgentConfig(candidateType);
1412
+ const candidateTarget = resolveMcpConfigTarget(candidateConfig, options);
1413
+ if (candidateTarget.configPath === currentTarget.configPath && candidateTarget.configKey === currentTarget.configKey) {
1414
+ coHosted.push(candidateType);
1415
+ }
1416
+ }
1417
+ return coHosted;
1418
+ }
1419
+ /**
1420
+ * Resolves configuration clusters for a given list of requested agents.
1421
+ * Groups requested agents sharing the same physical config path, and tracks
1422
+ * any remaining co-hosted agents sharing the same target that were not in the request.
1423
+ */
1424
+ resolveConfigClusters(agentTypes, options = {}) {
1425
+ const clustersByPath = /* @__PURE__ */ new Map();
1426
+ for (const agentType of agentTypes) {
1427
+ const agentConfig = getMcpAgentConfig(agentType);
1428
+ const target = resolveMcpConfigTarget(agentConfig, options);
1429
+ let keyMap = clustersByPath.get(target.configPath);
1430
+ if (!keyMap) {
1431
+ keyMap = /* @__PURE__ */ new Map();
1432
+ clustersByPath.set(target.configPath, keyMap);
1433
+ }
1434
+ let cluster = keyMap.get(target.configKey);
1435
+ if (!cluster) {
1436
+ const allCoHosted = this.getCoHostedAgents(agentType, options);
1437
+ cluster = {
1438
+ configPath: target.configPath,
1439
+ configKey: target.configKey,
1440
+ targetAgents: [],
1441
+ coHostedAgents: allCoHosted
1442
+ };
1443
+ keyMap.set(target.configKey, cluster);
1444
+ }
1445
+ if (!cluster.targetAgents.includes(agentType)) {
1446
+ cluster.targetAgents.push(agentType);
1447
+ }
1448
+ }
1449
+ const clusters = [];
1450
+ for (const keyMap of clustersByPath.values()) {
1451
+ for (const cluster of keyMap.values()) {
1452
+ cluster.coHostedAgents = cluster.coHostedAgents.filter(
1453
+ (co) => !cluster.targetAgents.includes(co)
1454
+ );
1455
+ clusters.push(cluster);
1456
+ }
1457
+ }
1458
+ return clusters;
1459
+ }
1460
+ /**
1461
+ * Sorts agent types so that agents sharing the same physical config target
1462
+ * appear adjacent to each other in the returned array.
1463
+ */
1464
+ sortAgentsByClusters(agentTypes, options = {}) {
1465
+ const clusters = this.resolveConfigClusters(agentTypes, options);
1466
+ const sorted = [];
1467
+ for (const cluster of clusters) {
1468
+ for (const agent of cluster.targetAgents) {
1469
+ if (!sorted.includes(agent)) {
1470
+ sorted.push(agent);
1471
+ }
1472
+ }
1473
+ }
1474
+ return sorted;
1475
+ }
1476
+ /**
1477
+ * Alias for sortAgentsByClusters for backward compatibility.
1478
+ */
1479
+ sortAgentsWithClusters(agentTypes, options = {}) {
1480
+ return this.sortAgentsByClusters(agentTypes, options);
1481
+ }
1482
+ // ---- Batch operations with automatic clustering & dialect transforms ----
1483
+ /**
1484
+ * Batch write: transforms and writes a server config to multiple agents,
1485
+ * with automatic cluster deduplication, dialect transform, and co-hosted awareness.
1486
+ * Callers pass standard McpServerConfig; the Store applies per-Agent dialect transforms
1487
+ * internally before persisting.
1488
+ */
1489
+ writeServers(agents, serverName, serverConfig, options = {}) {
1490
+ const clusters = this.resolveConfigClusters(agents, options);
1491
+ const resultsByAgent = /* @__PURE__ */ new Map();
1492
+ const isGlobal = options.global ?? false;
1493
+ for (const cluster of clusters) {
1494
+ const primaryAgentType = cluster.targetAgents[0];
1495
+ const primaryAgent = getMcpAgentConfig(primaryAgentType);
1496
+ try {
1497
+ const transformed = transformServerConfigForAgent(primaryAgent, serverName, serverConfig, {
1498
+ global: isGlobal
1499
+ });
1500
+ const descriptor = this.resolveDescriptor(primaryAgent, options);
1501
+ this.adapter.writeServer(descriptor, serverName, transformed);
1502
+ for (const agentType of cluster.targetAgents) {
1503
+ resultsByAgent.set(agentType, {
1504
+ agent: agentType,
1505
+ success: true,
1506
+ path: cluster.configPath,
1507
+ coConfiguredAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
1508
+ });
1509
+ }
1510
+ } catch (error) {
1511
+ const errorMsg = toErrorMessage(error);
1512
+ for (const agentType of cluster.targetAgents) {
1513
+ resultsByAgent.set(agentType, {
1514
+ agent: agentType,
1515
+ success: false,
1516
+ path: cluster.configPath,
1517
+ error: errorMsg
1518
+ });
1519
+ }
1520
+ }
1521
+ }
1522
+ return agents.map((agentType) => resultsByAgent.get(agentType));
1523
+ }
1524
+ /**
1525
+ * Batch remove: removes a server from multiple agents' configs,
1526
+ * with automatic cluster deduplication and co-hosted awareness.
1527
+ */
1528
+ removeServers(agents, serverName, options = {}) {
1529
+ const clusters = this.resolveConfigClusters(agents, options);
1530
+ const resultsByAgent = /* @__PURE__ */ new Map();
1531
+ for (const cluster of clusters) {
1532
+ const primaryAgentType = cluster.targetAgents[0];
1533
+ const primaryAgent = getMcpAgentConfig(primaryAgentType);
1534
+ try {
1535
+ const { removed } = this.removeServer(primaryAgent, serverName, options);
1536
+ for (const agentType of cluster.targetAgents) {
1537
+ resultsByAgent.set(agentType, {
1538
+ agent: agentType,
1539
+ path: cluster.configPath,
1540
+ removed,
1541
+ coAffectedAgents: removed && cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
1542
+ });
1543
+ }
1544
+ } catch (error) {
1545
+ const errorMsg = toErrorMessage(error);
1546
+ for (const agentType of cluster.targetAgents) {
1547
+ resultsByAgent.set(agentType, {
1548
+ agent: agentType,
1549
+ path: cluster.configPath,
1550
+ removed: false,
1551
+ error: errorMsg
1552
+ });
1553
+ }
1554
+ }
1555
+ }
1556
+ return agents.map((agentType) => resultsByAgent.get(agentType));
1489
1557
  }
1490
- if (HAS_WHITESPACE_REGEX.test(trimmed)) {
1491
- return {
1492
- type: "command",
1493
- value: trimmed,
1494
- inferredName: inferNameFromCommand(trimmed)
1495
- };
1558
+ };
1559
+ var agentConfigStore = new AgentConfigStore();
1560
+
1561
+ // src/interactive/utils/build-linked-agent-choices.ts
1562
+ var buildLinkedAgentChoices = (options) => {
1563
+ const { agents, checkedAgents, detectedAgents = [], scopeOptions = {} } = options;
1564
+ const alignedCheckedSet = new Set(checkedAgents);
1565
+ for (const agent of checkedAgents) {
1566
+ const coHosted = agentConfigStore.getCoHostedAgents(agent, scopeOptions);
1567
+ for (const co of coHosted) {
1568
+ if (agents.includes(co)) {
1569
+ alignedCheckedSet.add(co);
1570
+ }
1571
+ }
1496
1572
  }
1497
- if (PACKAGE_NAME_REGEX.test(trimmed)) {
1573
+ return agents.map((agent) => {
1574
+ const config = getMcpAgentConfig(agent);
1575
+ const displayName = config?.displayName ?? agent;
1576
+ const isDetected = detectedAgents.includes(agent);
1577
+ const coHosted = agentConfigStore.getCoHostedAgents(agent, scopeOptions).filter(
1578
+ (co) => agents.includes(co)
1579
+ );
1580
+ const detectedBadge = isDetected ? import_picocolors2.default.green(" [detected]") : "";
1581
+ const sharedBadge = coHosted.length > 0 ? import_picocolors2.default.dim(` [shared: ${coHosted.join(", ")}]`) : "";
1582
+ const label = `${displayName} ${import_picocolors2.default.dim(`(${agent})`)}${detectedBadge}${sharedBadge}`;
1498
1583
  return {
1499
- type: "package",
1500
- value: trimmed,
1501
- inferredName: extractPackageName(trimmed)
1584
+ name: label,
1585
+ value: agent,
1586
+ checked: alignedCheckedSet.has(agent),
1587
+ linkedValues: coHosted,
1588
+ description: coHosted.length > 0 ? `Linked with ${coHosted.map((a) => getMcpAgentConfig(a).displayName).join(", ")} (shared configuration)` : void 0
1502
1589
  };
1503
- }
1504
- return {
1505
- type: "command",
1506
- value: trimmed,
1507
- inferredName: inferNameFromCommand(trimmed)
1508
- };
1590
+ });
1509
1591
  };
1510
- var isRemoteMcpSource = (parsed) => parsed.type === "remote";
1511
1592
 
1512
- // src/install-mcp-server.ts
1513
- var installMcpServer = (options) => {
1514
- const parsed = parseMcpSource(options.source);
1515
- const isGlobal = options.global ?? false;
1593
+ // src/interactive/prompts/scope.ts
1594
+ var import_prompts = require("@inquirer/prompts");
1595
+ var import_picocolors3 = __toESM(require("picocolors"), 1);
1596
+ var promptScope = async (options = {}) => {
1597
+ const initialGlobal = options.defaultGlobal ?? options.global;
1598
+ if (initialGlobal !== void 0) {
1599
+ return initialGlobal;
1600
+ }
1516
1601
  const cwd = options.cwd ?? process.cwd();
1517
- const serverName = options.name ?? parsed.inferredName;
1518
- const serverConfig = buildMcpServerConfig(parsed, {
1519
- transport: options.transport,
1520
- headers: options.headers,
1521
- env: options.env,
1522
- args: options.args
1523
- });
1524
- const requestedTransport = parsed.type === "remote" ? serverConfig.type ?? "http" : "stdio";
1525
- const { allAgents, incompatible } = resolveTargetAgents({
1526
- requested: options.agents,
1527
- global: isGlobal,
1528
- cwd,
1529
- transport: requestedTransport
1530
- });
1531
- const results = installToCompatibleAgents(serverName, serverConfig, {
1532
- allAgents,
1533
- incompatible,
1534
- global: isGlobal,
1535
- cwd
1602
+ return (0, import_prompts.select)({
1603
+ message: options.message ?? "Select MCP scope:",
1604
+ choices: [
1605
+ {
1606
+ name: `Current Project - ${import_picocolors3.default.dim(cwd)}`,
1607
+ value: false
1608
+ },
1609
+ {
1610
+ name: `Global User Config - ${import_picocolors3.default.dim("applies across all projects")}`,
1611
+ value: true
1612
+ }
1613
+ ]
1536
1614
  });
1537
- return { serverName, config: serverConfig, results };
1538
1615
  };
1539
1616
 
1540
- // src/list.ts
1541
- var listInstalledMcpServers = (options = {}) => {
1542
- const agentTypes = options.agents ?? getMcpAgentTypes();
1543
- const collected = [];
1544
- for (const agentType of agentTypes) {
1545
- const agent = getMcpAgentConfig(agentType);
1546
- const { path, exists, servers } = agentConfigStore.listServers(agent, options);
1547
- if (!exists) continue;
1548
- for (const [serverName, rawConfig] of Object.entries(servers)) {
1549
- collected.push({
1550
- serverName,
1551
- agent: agentType,
1552
- path,
1553
- config: rawConfig,
1554
- serverConfig: parseServerConfig(rawConfig)
1555
- });
1617
+ // src/interactive/prompts/agents.ts
1618
+ var import_picocolors5 = __toESM(require("picocolors"), 1);
1619
+
1620
+ // src/server-config.ts
1621
+ var buildMcpServerConfig = (parsed, options = {}) => {
1622
+ if (parsed.type === "remote") {
1623
+ const config2 = {
1624
+ type: options.transport ?? DEFAULT_REMOTE_TRANSPORT,
1625
+ url: parsed.value
1626
+ };
1627
+ if (options.headers && Object.keys(options.headers).length > 0) {
1628
+ config2.headers = options.headers;
1556
1629
  }
1630
+ return config2;
1557
1631
  }
1558
- return collected;
1632
+ if (parsed.type === "command") {
1633
+ const parts = parsed.value.split(/\s+/);
1634
+ const command = parts[0] ?? "";
1635
+ const args = parts.slice(1);
1636
+ if (options.args && options.args.length > 0) {
1637
+ args.push(...options.args);
1638
+ }
1639
+ const config2 = { command, args };
1640
+ if (options.env && Object.keys(options.env).length > 0) {
1641
+ config2.env = options.env;
1642
+ }
1643
+ return config2;
1644
+ }
1645
+ const packageArgs = [NPX_DASH_Y, parsed.value];
1646
+ if (options.args && options.args.length > 0) {
1647
+ packageArgs.push(...options.args);
1648
+ }
1649
+ const config = {
1650
+ command: NPX_COMMAND,
1651
+ args: packageArgs
1652
+ };
1653
+ if (options.env && Object.keys(options.env).length > 0) {
1654
+ config.env = options.env;
1655
+ }
1656
+ return config;
1559
1657
  };
1560
-
1561
- // src/remove.ts
1562
- var removeMcpServerFromAgent = (serverName, agentType, options = {}) => {
1563
- const agent = getMcpAgentConfig(agentType);
1564
- const { target } = agentConfigStore.resolveTarget(agent, options);
1565
- const coHosted = getCoHostedAgents(agentType, options);
1566
- try {
1567
- const { removed } = agentConfigStore.removeServer(agent, serverName, options);
1658
+ var parseServerConfig = (raw) => {
1659
+ if (!raw || typeof raw !== "object") return {};
1660
+ const data = raw;
1661
+ const rawUrl = typeof data.url === "string" && data.url.trim().length > 0 ? data.url.trim() : void 0;
1662
+ const rawHttpUrl = typeof data.httpUrl === "string" && data.httpUrl.trim().length > 0 ? data.httpUrl.trim() : void 0;
1663
+ const remoteUrl = rawHttpUrl ?? rawUrl;
1664
+ if (remoteUrl) {
1665
+ const transport = data.type === "sse" || data.transport === "sse" ? "sse" : "http";
1666
+ const headers = data.headers && typeof data.headers === "object" ? data.headers : void 0;
1568
1667
  return {
1569
- agent: agentType,
1570
- path: target.configPath,
1571
- removed,
1572
- coAffectedAgents: removed && coHosted.length > 0 ? coHosted : void 0
1668
+ type: transport,
1669
+ url: remoteUrl,
1670
+ headers
1573
1671
  };
1574
- } catch (error) {
1672
+ }
1673
+ if (typeof data.command === "string" && data.command.trim().length > 0) {
1674
+ const args = Array.isArray(data.args) ? data.args.filter((item) => typeof item === "string") : void 0;
1675
+ const env = data.env && typeof data.env === "object" ? data.env : void 0;
1575
1676
  return {
1576
- agent: agentType,
1577
- path: target.configPath,
1578
- removed: false,
1579
- error: toErrorMessage(error)
1677
+ command: data.command.trim(),
1678
+ args,
1679
+ env
1580
1680
  };
1581
1681
  }
1682
+ return {};
1582
1683
  };
1583
- var removeMcpServer = (options) => {
1584
- const { allAgents } = resolveTargetAgents({
1585
- requested: options.agents,
1586
- all: !options.agents,
1587
- global: options.global,
1588
- cwd: options.cwd
1589
- });
1590
- const clusters = resolveConfigClusters(allAgents, {
1591
- global: options.global,
1592
- cwd: options.cwd
1593
- });
1594
- const results = [];
1595
- for (const cluster of clusters) {
1596
- const primaryAgentType = cluster.targetAgents[0];
1597
- const primaryAgent = getMcpAgentConfig(primaryAgentType);
1598
- try {
1599
- const { removed } = agentConfigStore.removeServer(primaryAgent, options.name, {
1600
- global: options.global,
1601
- cwd: options.cwd
1602
- });
1603
- if (removed) {
1604
- for (const agentType of cluster.targetAgents) {
1605
- results.push({
1606
- agent: agentType,
1607
- path: cluster.configPath,
1608
- removed: true,
1609
- coAffectedAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
1610
- });
1611
- }
1612
- }
1613
- } catch (error) {
1614
- const errorMsg = toErrorMessage(error);
1615
- for (const agentType of cluster.targetAgents) {
1616
- results.push({
1617
- agent: agentType,
1618
- path: cluster.configPath,
1619
- removed: false,
1620
- error: errorMsg
1621
- });
1622
- }
1623
- }
1624
- }
1625
- return results;
1626
- };
1627
-
1628
- // src/update-mcp-server.ts
1629
1684
  var toRemoteServerConfig = (config, defaultTransport = "http") => {
1630
1685
  const {
1631
1686
  command: _droppedCommand,
@@ -1651,15 +1706,16 @@ var detectUpdateTransition = (incoming, previous) => {
1651
1706
  if (!previous) {
1652
1707
  return incoming.url ? "switch-to-remote" : "switch-to-stdio";
1653
1708
  }
1709
+ const previousIsRemote = Boolean(previous.url && previous.url.length > 0);
1710
+ if (previousIsRemote) {
1711
+ if (incoming.command && !incoming.url) {
1712
+ return "switch-to-stdio";
1713
+ }
1714
+ return "merge-remote";
1715
+ }
1654
1716
  if (incoming.url && !incoming.command) {
1655
1717
  return "switch-to-remote";
1656
1718
  }
1657
- if (incoming.command && !incoming.url) {
1658
- return "switch-to-stdio";
1659
- }
1660
- if (incoming.url || !incoming.command && previous.url) {
1661
- return "merge-remote";
1662
- }
1663
1719
  return "merge-stdio";
1664
1720
  };
1665
1721
  var sanitizeUpdatedServerConfig = (incoming, previous) => {
@@ -1677,40 +1733,263 @@ var sanitizeUpdatedServerConfig = (incoming, previous) => {
1677
1733
  case "merge-remote": {
1678
1734
  return toRemoteServerConfig({ ...previous, ...incoming }, targetTransport);
1679
1735
  }
1680
- case "merge-stdio": {
1736
+ case "merge-stdio":
1737
+ default: {
1681
1738
  return toStdioServerConfig({ ...previous, ...incoming });
1682
1739
  }
1683
1740
  }
1684
1741
  };
1685
- var updateMcpServer = (options) => {
1686
- const isGlobal = options.global ?? false;
1687
- const cwd = options.cwd ?? process.cwd();
1688
- let previousConfig = options.previousConfig;
1689
- if (!previousConfig) {
1690
- const existing = listInstalledMcpServers({
1691
- global: isGlobal,
1692
- cwd,
1693
- agents: options.agents
1694
- });
1695
- const found = existing.find((s) => s.serverName === options.serverName && s.serverConfig);
1696
- if (found) {
1697
- previousConfig = found.serverConfig;
1698
- }
1699
- }
1700
- const serverConfig = sanitizeUpdatedServerConfig(options.config, previousConfig);
1701
- let targetAgents = options.agents;
1702
- if (!targetAgents || targetAgents.length === 0) {
1703
- const existing = listInstalledMcpServers({ global: isGlobal, cwd });
1704
- targetAgents = existing.filter((s) => s.serverName === options.serverName).map((s) => s.agent);
1742
+
1743
+ // src/source-parser.ts
1744
+ var REMOTE_URL_REGEX = /^https?:\/\//i;
1745
+ var HAS_WHITESPACE_REGEX = /\s/;
1746
+ var PACKAGE_NAME_REGEX = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(?:@[^\s]+)?$/;
1747
+ var PATH_SEPARATOR_REGEX = /[/\\]/;
1748
+ var stripVersionSuffix = (input7) => {
1749
+ if (input7.startsWith("@")) {
1750
+ const secondAtIndex = input7.indexOf("@", 1);
1751
+ if (secondAtIndex > 0) return input7.slice(0, secondAtIndex);
1752
+ return input7;
1705
1753
  }
1706
- const requestedTransport = serverConfig.url ? serverConfig.type ?? "http" : "stdio";
1707
- const { allAgents, incompatible } = resolveTargetAgents({
1708
- requested: targetAgents,
1709
- global: isGlobal,
1710
- cwd,
1711
- transport: requestedTransport
1712
- });
1713
- const results = installToCompatibleAgents(options.serverName, serverConfig, {
1754
+ const atIndex = input7.lastIndexOf("@");
1755
+ if (atIndex > 0) return input7.slice(0, atIndex);
1756
+ return input7;
1757
+ };
1758
+ var stripScopePrefix = (input7) => {
1759
+ if (!input7.startsWith("@") || !input7.includes("/")) return input7;
1760
+ const parts = input7.split("/");
1761
+ return parts[1] || input7;
1762
+ };
1763
+ var stripPathPrefix = (input7) => {
1764
+ if (!PATH_SEPARATOR_REGEX.test(input7)) return input7;
1765
+ const segments = input7.split(PATH_SEPARATOR_REGEX);
1766
+ const basename = segments[segments.length - 1];
1767
+ return basename || input7;
1768
+ };
1769
+ var extractPackageName = (input7) => {
1770
+ let name = stripVersionSuffix(input7);
1771
+ name = stripScopePrefix(name);
1772
+ name = stripPathPrefix(name);
1773
+ name = name.replace(SCRIPT_EXTENSION_REGEX, "");
1774
+ for (const prefix of PACKAGE_NAME_PREFIX_STRIP) {
1775
+ if (name.startsWith(prefix)) {
1776
+ name = name.slice(prefix.length);
1777
+ break;
1778
+ }
1779
+ }
1780
+ for (const suffix of PACKAGE_NAME_SUFFIX_STRIP) {
1781
+ if (name.endsWith(suffix)) {
1782
+ name = name.slice(0, -suffix.length);
1783
+ break;
1784
+ }
1785
+ }
1786
+ return name || MCP_DEFAULT_SERVER_NAME;
1787
+ };
1788
+ var inferNameFromUrl = (input7) => {
1789
+ try {
1790
+ const url = new URL(input7);
1791
+ const host = url.hostname;
1792
+ const labels = host.split(".").filter((segment) => segment.length > 0);
1793
+ if (labels.length === 0) return MCP_DEFAULT_SERVER_NAME;
1794
+ const meaningfulLabels = labels.filter((label) => {
1795
+ const lower = label.toLowerCase();
1796
+ if (COMMON_TLD_LABELS.has(lower)) return false;
1797
+ if (GENERIC_HOST_PREFIXES.has(lower)) return false;
1798
+ return true;
1799
+ });
1800
+ if (meaningfulLabels.length > 0) return meaningfulLabels[0];
1801
+ if (labels.length >= 2) return labels[labels.length - 2];
1802
+ return labels[labels.length - 1] || MCP_DEFAULT_SERVER_NAME;
1803
+ } catch {
1804
+ return MCP_DEFAULT_SERVER_NAME;
1805
+ }
1806
+ };
1807
+ var inferNameFromCommand = (command) => {
1808
+ const tokens = command.trim().split(/\s+/);
1809
+ const runnerBase = tokens[0]?.split(PATH_SEPARATOR_REGEX).pop() ?? "";
1810
+ const startIndex = KNOWN_COMMAND_RUNNERS.has(runnerBase) ? 1 : 0;
1811
+ for (let tokenIndex = startIndex; tokenIndex < tokens.length; tokenIndex += 1) {
1812
+ const token = tokens[tokenIndex];
1813
+ if (!token || token.startsWith("-")) continue;
1814
+ return extractPackageName(token);
1815
+ }
1816
+ const firstNonFlag = tokens.find((token) => !token.startsWith("-"));
1817
+ return firstNonFlag ? extractPackageName(firstNonFlag) : MCP_DEFAULT_SERVER_NAME;
1818
+ };
1819
+ var parseMcpSource = (input7) => {
1820
+ const trimmed = input7.trim();
1821
+ if (trimmed.length === 0) {
1822
+ throw new Error(
1823
+ "Invalid MCP source: input is empty. Expected a remote URL, an npm package, or a command line."
1824
+ );
1825
+ }
1826
+ if (REMOTE_URL_REGEX.test(trimmed)) {
1827
+ return {
1828
+ type: "remote",
1829
+ value: trimmed,
1830
+ inferredName: inferNameFromUrl(trimmed)
1831
+ };
1832
+ }
1833
+ if (HAS_WHITESPACE_REGEX.test(trimmed)) {
1834
+ return {
1835
+ type: "command",
1836
+ value: trimmed,
1837
+ inferredName: inferNameFromCommand(trimmed)
1838
+ };
1839
+ }
1840
+ if (PACKAGE_NAME_REGEX.test(trimmed)) {
1841
+ return {
1842
+ type: "package",
1843
+ value: trimmed,
1844
+ inferredName: extractPackageName(trimmed)
1845
+ };
1846
+ }
1847
+ return {
1848
+ type: "command",
1849
+ value: trimmed,
1850
+ inferredName: inferNameFromCommand(trimmed)
1851
+ };
1852
+ };
1853
+
1854
+ // src/install-compat.ts
1855
+ var installToCompatibleAgents = (serverName, serverConfig, options) => {
1856
+ const { allAgents, incompatible = [], global: isGlobal, cwd } = options;
1857
+ const incompatibleMap = new Map(incompatible.map((item) => [item.agent, item.reason]));
1858
+ const compatibleAgents = allAgents.filter((a) => !incompatibleMap.has(a));
1859
+ const installedResults = agentConfigStore.writeServers(
1860
+ compatibleAgents,
1861
+ serverName,
1862
+ serverConfig,
1863
+ {
1864
+ global: isGlobal,
1865
+ cwd
1866
+ }
1867
+ );
1868
+ const installedMap = new Map(installedResults.map((r) => [r.agent, r]));
1869
+ return allAgents.map((agentType) => {
1870
+ const incompatibleReason = incompatibleMap.get(agentType);
1871
+ if (incompatibleReason) {
1872
+ return {
1873
+ agent: agentType,
1874
+ success: false,
1875
+ path: "",
1876
+ error: incompatibleReason
1877
+ };
1878
+ }
1879
+ return installedMap.get(agentType);
1880
+ });
1881
+ };
1882
+
1883
+ // src/install-mcp-server.ts
1884
+ var installMcpServer = (options) => {
1885
+ const parsed = parseMcpSource(options.source);
1886
+ const isGlobal = options.global ?? false;
1887
+ const cwd = options.cwd ?? process.cwd();
1888
+ const serverName = options.name ?? parsed.inferredName;
1889
+ const serverConfig = buildMcpServerConfig(parsed, {
1890
+ transport: options.transport,
1891
+ headers: options.headers,
1892
+ env: options.env,
1893
+ args: options.args
1894
+ });
1895
+ const requestedTransport = parsed.type === "remote" ? serverConfig.type ?? "http" : "stdio";
1896
+ const { allAgents, incompatible } = resolveTargetAgents({
1897
+ requested: options.agents,
1898
+ global: isGlobal,
1899
+ cwd,
1900
+ transport: requestedTransport
1901
+ });
1902
+ const results = installToCompatibleAgents(serverName, serverConfig, {
1903
+ allAgents,
1904
+ incompatible,
1905
+ global: isGlobal,
1906
+ cwd
1907
+ });
1908
+ return { serverName, config: serverConfig, results };
1909
+ };
1910
+
1911
+ // src/list.ts
1912
+ var listInstalledMcpServers = (options = {}) => {
1913
+ const agentTypes = options.agents ?? getMcpAgentTypes();
1914
+ const collected = [];
1915
+ const results = agentConfigStore.listServersForAgents(agentTypes, options);
1916
+ for (const item of results) {
1917
+ if (!item.exists) continue;
1918
+ for (const [serverName, rawConfig] of Object.entries(item.servers)) {
1919
+ collected.push({
1920
+ serverName,
1921
+ agent: item.agent,
1922
+ path: item.path,
1923
+ config: rawConfig,
1924
+ serverConfig: parseServerConfig(rawConfig)
1925
+ });
1926
+ }
1927
+ }
1928
+ return collected;
1929
+ };
1930
+ var groupInstalledServersByName = (installed) => {
1931
+ const grouped = /* @__PURE__ */ new Map();
1932
+ for (const item of installed) {
1933
+ const itemConfig = item.serverConfig ?? parseServerConfig(item.config);
1934
+ let entry = grouped.get(item.serverName);
1935
+ if (!entry) {
1936
+ entry = {
1937
+ serverName: item.serverName,
1938
+ agents: [],
1939
+ paths: [],
1940
+ config: itemConfig,
1941
+ hasDivergence: false
1942
+ };
1943
+ grouped.set(item.serverName, entry);
1944
+ } else if (!entry.hasDivergence) {
1945
+ if (JSON.stringify(entry.config) !== JSON.stringify(itemConfig)) {
1946
+ entry.hasDivergence = true;
1947
+ }
1948
+ }
1949
+ if (!entry.agents.includes(item.agent)) {
1950
+ entry.agents.push(item.agent);
1951
+ }
1952
+ if (!entry.paths.includes(item.path)) {
1953
+ entry.paths.push(item.path);
1954
+ }
1955
+ }
1956
+ return grouped;
1957
+ };
1958
+ var queryGroupedInstalledServers = (options = {}) => {
1959
+ const installed = listInstalledMcpServers(options);
1960
+ return groupInstalledServersByName(installed);
1961
+ };
1962
+
1963
+ // src/update-mcp-server.ts
1964
+ var updateMcpServer = (options) => {
1965
+ const isGlobal = options.global ?? false;
1966
+ const cwd = options.cwd ?? process.cwd();
1967
+ let previousConfig = options.previousConfig;
1968
+ if (!previousConfig) {
1969
+ const existing = listInstalledMcpServers({
1970
+ global: isGlobal,
1971
+ cwd,
1972
+ agents: options.agents
1973
+ });
1974
+ const found = existing.find((s) => s.serverName === options.serverName && s.serverConfig);
1975
+ if (found) {
1976
+ previousConfig = found.serverConfig;
1977
+ }
1978
+ }
1979
+ const serverConfig = sanitizeUpdatedServerConfig(options.config, previousConfig);
1980
+ let targetAgents = options.agents;
1981
+ if (!targetAgents || targetAgents.length === 0) {
1982
+ const existing = listInstalledMcpServers({ global: isGlobal, cwd });
1983
+ targetAgents = existing.filter((s) => s.serverName === options.serverName).map((s) => s.agent);
1984
+ }
1985
+ const requestedTransport = serverConfig.url ? serverConfig.type ?? "http" : "stdio";
1986
+ const { allAgents, incompatible } = resolveTargetAgents({
1987
+ requested: targetAgents,
1988
+ global: isGlobal,
1989
+ cwd,
1990
+ transport: requestedTransport
1991
+ });
1992
+ const results = installToCompatibleAgents(options.serverName, serverConfig, {
1714
1993
  allAgents,
1715
1994
  incompatible,
1716
1995
  global: isGlobal,
@@ -1724,331 +2003,123 @@ var updateMcpServer = (options) => {
1724
2003
  };
1725
2004
  };
1726
2005
 
1727
- // src/interactive/main-menu.ts
1728
- import { select as select8 } from "@inquirer/prompts";
1729
- import pc15 from "picocolors";
1730
-
1731
- // src/interactive/wizard-add.ts
1732
- import { confirm as confirm5, input as input5, select as select5 } from "@inquirer/prompts";
1733
- import pc11 from "picocolors";
1734
-
1735
- // src/utils/co-hosted-feedback.ts
1736
- import pc2 from "picocolors";
2006
+ // src/remove.ts
2007
+ var removeMcpServer = (options) => {
2008
+ const { allAgents } = resolveTargetAgents({
2009
+ requested: options.agents,
2010
+ all: !options.agents,
2011
+ global: options.global,
2012
+ cwd: options.cwd
2013
+ });
2014
+ const storeResults = agentConfigStore.removeServers(allAgents, options.name, {
2015
+ global: options.global,
2016
+ cwd: options.cwd
2017
+ });
2018
+ return storeResults.filter((r) => r.removed || Boolean(r.error));
2019
+ };
1737
2020
 
1738
- // src/utils/logger.ts
1739
- import pc from "picocolors";
1740
- var logger = {
1741
- info: (message) => {
1742
- console.log(pc.cyan("i"), message);
1743
- },
1744
- success: (message) => {
1745
- console.log(pc.green("\u221A"), message);
1746
- },
1747
- warn: (message) => {
1748
- console.log(pc.yellow("!"), message);
1749
- },
1750
- error: (message) => {
1751
- console.error(pc.red("x"), message);
2021
+ // src/utils/mask-secret.ts
2022
+ var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
2023
+ var maskSecretValue = (key, value) => {
2024
+ if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
2025
+ return value;
1752
2026
  }
2027
+ return `${value.slice(0, 2)}***${value.slice(-2)}`;
1753
2028
  };
1754
-
1755
- // src/utils/co-hosted-feedback.ts
1756
- var formatCoHostedBadge = (kind, agents) => {
1757
- if (!agents || agents.length === 0) return "";
1758
- const label = kind === "configured" ? "co-configured" : "co-affected";
1759
- return ` ${pc2.yellow(`(${label}: ${agents.join(", ")})`)}`;
1760
- };
1761
- var logCoHostedNotice = (kind, agents) => {
1762
- if (!agents || agents.length === 0) return;
1763
- const actionText = kind === "configured" ? "Also configured for" : "Also affects";
1764
- logger.info(
1765
- ` ${pc2.dim("Note:")} ${actionText} co-hosted agent(s): ${pc2.yellow(agents.join(", "))}`
1766
- );
2029
+ var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
2030
+ var maskSecretHeader = (key, value) => {
2031
+ if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
2032
+ return value;
2033
+ }
2034
+ return `${value.slice(0, 4)}***${value.slice(-3)}`;
1767
2035
  };
1768
2036
 
1769
- // src/interactive/prompts/agents.ts
1770
- import pc6 from "picocolors";
1771
-
1772
- // src/interactive/utils/build-linked-agent-choices.ts
1773
- import pc3 from "picocolors";
1774
- var buildLinkedAgentChoices = (options) => {
1775
- const { agents, checkedAgents, detectedAgents = [], scopeOptions = {} } = options;
1776
- const alignedCheckedSet = new Set(checkedAgents);
1777
- for (const agent of checkedAgents) {
1778
- const coHosted = getCoHostedAgents(agent, scopeOptions);
1779
- for (const co of coHosted) {
1780
- if (agents.includes(co)) {
1781
- alignedCheckedSet.add(co);
1782
- }
1783
- }
2037
+ // src/utils/parse-mcp-agent-list.ts
2038
+ var parseMcpAgentList = (input7) => {
2039
+ if (!input7 || input7.length === 0) return void 0;
2040
+ if (input7.includes("*")) return getMcpAgentTypes();
2041
+ const resolved = [];
2042
+ for (const value of input7) {
2043
+ const agentType = resolveMcpAgentAlias(value);
2044
+ if (!agentType) throw new Error(`Unknown MCP agent "${value}"`);
2045
+ resolved.push(agentType);
1784
2046
  }
1785
- return agents.map((agent) => {
1786
- const config = getMcpAgentConfig(agent);
1787
- const displayName = config?.displayName ?? agent;
1788
- const isDetected = detectedAgents.includes(agent);
1789
- const coHosted = getCoHostedAgents(agent, scopeOptions).filter(
1790
- (co) => agents.includes(co)
1791
- );
1792
- const detectedBadge = isDetected ? pc3.green(" [detected]") : "";
1793
- const sharedBadge = coHosted.length > 0 ? pc3.dim(` [shared: ${coHosted.join(", ")}]`) : "";
1794
- const label = `${displayName} ${pc3.dim(`(${agent})`)}${detectedBadge}${sharedBadge}`;
1795
- return {
1796
- name: label,
1797
- value: agent,
1798
- checked: alignedCheckedSet.has(agent),
1799
- linkedValues: coHosted,
1800
- description: coHosted.length > 0 ? `Linked with ${coHosted.map((a) => getMcpAgentConfig(a).displayName).join(", ")} (shared configuration)` : void 0
1801
- };
1802
- });
2047
+ return resolved;
1803
2048
  };
1804
2049
 
1805
- // src/interactive/prompts/linked-checkbox.ts
1806
- import {
1807
- Separator,
1808
- ValidationError,
1809
- createPrompt,
1810
- isDownKey,
1811
- isEnterKey,
1812
- isNumberKey,
1813
- isSpaceKey,
1814
- isUpKey,
1815
- makeTheme,
1816
- useKeypress,
1817
- useMemo,
1818
- usePagination,
1819
- usePrefix,
1820
- useState
1821
- } from "@inquirer/core";
1822
- import pc4 from "picocolors";
1823
- var defaultTheme = {
1824
- icon: {
1825
- checked: pc4.green("[x]"),
1826
- unchecked: pc4.dim("[ ]"),
1827
- cursor: pc4.cyan(">"),
1828
- disabledChecked: pc4.dim("[x]"),
1829
- disabledUnchecked: pc4.dim("[-]")
1830
- },
1831
- style: {
1832
- disabled: (text) => pc4.dim(text),
1833
- renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(", "),
1834
- description: (text) => pc4.cyan(text),
1835
- keysHelpTip: (keys) => keys.map(([key, action]) => `${pc4.bold(key)} ${pc4.dim(action)}`).join(pc4.dim(" | ")),
1836
- highlight: (text) => pc4.cyan(text)
1837
- },
1838
- i18n: {
1839
- disabledError: "This option is disabled and cannot be toggled."
2050
+ // src/resolve-target-agents.ts
2051
+ var normalizeRequestedAgents = (input7) => {
2052
+ if (!input7 || input7.length === 0) return void 0;
2053
+ const rawList = [...input7];
2054
+ if (rawList.every((item) => isMcpAgentType(item))) {
2055
+ return rawList;
1840
2056
  }
2057
+ return parseMcpAgentList(rawList);
1841
2058
  };
1842
- function isSelectable(item) {
1843
- return !Separator.isSeparator(item) && !item.disabled;
1844
- }
1845
- function isNavigable(item) {
1846
- return !Separator.isSeparator(item);
1847
- }
1848
- function isChecked(item) {
1849
- return !Separator.isSeparator(item) && item.checked;
1850
- }
1851
- function normalizeChoices(choices) {
1852
- return choices.map((choice) => {
1853
- if (Separator.isSeparator(choice)) {
1854
- return choice;
1855
- }
1856
- if (typeof choice !== "object" || choice === null || !("value" in choice)) {
1857
- const name2 = String(choice);
1858
- return {
1859
- value: choice,
1860
- name: name2,
1861
- short: name2,
1862
- checkedName: name2,
1863
- disabled: false,
1864
- checked: false,
1865
- linkedValues: []
1866
- };
1867
- }
1868
- const name = choice.name ?? String(choice.value);
1869
- return {
1870
- value: choice.value,
1871
- name,
1872
- short: choice.short ?? name,
1873
- checkedName: choice.checkedName ?? name,
1874
- description: choice.description,
1875
- disabled: choice.disabled ?? false,
1876
- checked: choice.checked ?? false,
1877
- linkedValues: choice.linkedValues ?? []
1878
- };
1879
- });
1880
- }
1881
- var linkedCheckbox = createPrompt(
1882
- (config, done) => {
1883
- const { pageSize = 10, loop = true, required, validate = () => true } = config;
1884
- const theme = makeTheme(defaultTheme, config.theme);
1885
- const [status, setStatus] = useState("idle");
1886
- const prefix = usePrefix({ status, theme });
1887
- const [items, setItems] = useState(() => normalizeChoices(config.choices));
1888
- const bounds = useMemo(() => {
1889
- const first = items.findIndex(isNavigable);
1890
- let last = -1;
1891
- for (let i = items.length - 1; i >= 0; i--) {
1892
- if (isNavigable(items[i])) {
1893
- last = i;
1894
- break;
1895
- }
1896
- }
1897
- if (first === -1 || last === -1) {
1898
- throw new ValidationError("[linkedCheckbox prompt] No selectable choices.");
1899
- }
1900
- return { first, last };
1901
- }, [items]);
1902
- const [active, setActive] = useState(bounds.first);
1903
- const [errorMsg, setError] = useState();
1904
- const toggleWithLinked = (targetIndex) => {
1905
- const targetItem = items[targetIndex];
1906
- if (!targetItem || Separator.isSeparator(targetItem) || targetItem.disabled) {
1907
- return;
1908
- }
1909
- const nextChecked = !targetItem.checked;
1910
- const targetValue = targetItem.value;
1911
- const linked = new Set(targetItem.linkedValues);
1912
- setItems(
1913
- (prevItems) => prevItems.map((item) => {
1914
- if (Separator.isSeparator(item) || item.disabled) {
1915
- return item;
1916
- }
1917
- const isTargetOrLinked = item.value === targetValue || linked.has(item.value) || item.linkedValues.includes(targetValue);
1918
- if (isTargetOrLinked) {
1919
- return { ...item, checked: nextChecked };
1920
- }
1921
- return item;
1922
- })
1923
- );
1924
- };
1925
- useKeypress(async (key) => {
1926
- if (isEnterKey(key)) {
1927
- const selection = items.filter(isChecked);
1928
- const isValid = await validate([...selection]);
1929
- if (required && selection.length === 0) {
1930
- setError("At least one choice must be selected");
1931
- } else if (isValid === true) {
1932
- setStatus("done");
1933
- done(selection.map((choice) => choice.value));
1934
- } else {
1935
- setError(typeof isValid === "string" ? isValid : "You must select a valid value");
1936
- }
1937
- } else if (isUpKey(key) || isDownKey(key)) {
1938
- if (errorMsg) setError(void 0);
1939
- if (loop || isUpKey(key) && active !== bounds.first || isDownKey(key) && active !== bounds.last) {
1940
- const offset = isUpKey(key) ? -1 : 1;
1941
- let next = active;
1942
- do {
1943
- next = (next + offset + items.length) % items.length;
1944
- } while (!isNavigable(items[next]));
1945
- setActive(next);
1946
- }
1947
- } else if (isSpaceKey(key)) {
1948
- const activeItem = items[active];
1949
- if (activeItem && !Separator.isSeparator(activeItem)) {
1950
- if (activeItem.disabled) {
1951
- setError(theme.i18n.disabledError);
1952
- } else {
1953
- setError(void 0);
1954
- toggleWithLinked(active);
1955
- }
1956
- }
1957
- } else if (key.name === "a") {
1958
- const hasUnchecked = items.some((choice) => isSelectable(choice) && !choice.checked);
1959
- setItems(
1960
- (prevItems) => prevItems.map((item) => isSelectable(item) ? { ...item, checked: hasUnchecked } : item)
1961
- );
1962
- } else if (isNumberKey(key)) {
1963
- const selectedIndex = Number(key.name) - 1;
1964
- let selectableIndex = -1;
1965
- const position = items.findIndex((item) => {
1966
- if (Separator.isSeparator(item)) return false;
1967
- selectableIndex++;
1968
- return selectableIndex === selectedIndex;
1969
- });
1970
- const selectedItem = items[position];
1971
- if (selectedItem && isSelectable(selectedItem)) {
1972
- setActive(position);
1973
- setError(void 0);
1974
- toggleWithLinked(position);
1975
- }
1976
- }
1977
- });
1978
- const message = theme.style.message(config.message, status);
1979
- let description;
1980
- const page = usePagination({
1981
- items,
1982
- active,
1983
- renderItem({ item, isActive }) {
1984
- if (Separator.isSeparator(item)) {
1985
- return ` ${item.separator}`;
1986
- }
1987
- const cursor = isActive ? theme.icon.cursor : " ";
1988
- if (item.disabled) {
1989
- const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
1990
- const checkbox2 = item.checked ? theme.icon.disabledChecked : theme.icon.disabledUnchecked;
1991
- return theme.style.disabled(`${cursor} ${checkbox2} ${item.name} ${disabledLabel}`);
1992
- }
1993
- if (isActive) {
1994
- description = item.description;
1995
- }
1996
- const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
1997
- const name = item.checked ? item.checkedName : item.name;
1998
- const color = isActive ? theme.style.highlight : (x) => x;
1999
- return color(`${cursor} ${checkbox} ${name}`);
2000
- },
2001
- pageSize,
2002
- loop
2003
- });
2004
- if (status === "done") {
2005
- const selection = items.filter(isChecked);
2006
- const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
2007
- return [prefix, message, answer].filter(Boolean).join(" ");
2008
- }
2009
- const helpLine = theme.style.keysHelpTip([
2010
- ["up/down", "navigate"],
2011
- ["space", "toggle"],
2012
- ["a", "all"],
2013
- ["enter", "submit"]
2014
- ]);
2015
- const lines = [
2016
- [prefix, message].filter(Boolean).join(" "),
2017
- page,
2018
- helpLine
2019
- ];
2020
- if (description) {
2021
- lines.push(theme.style.description(description));
2059
+ var resolveTargetAgents = (query = {}) => {
2060
+ const cwd = query.cwd ?? process.cwd();
2061
+ const isGlobal = query.global ?? false;
2062
+ let explicitAgents = normalizeRequestedAgents(query.requested);
2063
+ if (query.all) {
2064
+ explicitAgents = getMcpAgentTypes();
2065
+ }
2066
+ const isDetected = !explicitAgents || explicitAgents.length === 0;
2067
+ const detected = isGlobal ? detectGloballyInstalledMcpAgents() : detectProjectInstalledMcpAgents(cwd);
2068
+ const candidateAgents = isDetected ? detected : explicitAgents ?? [];
2069
+ const allAgents = candidateAgents.filter(
2070
+ (type, index) => candidateAgents.indexOf(type) === index
2071
+ );
2072
+ const incompatible = [];
2073
+ const compatibleAgents = [];
2074
+ for (const agentType of allAgents) {
2075
+ const config = getMcpAgentConfig(agentType);
2076
+ if (query.transport && !isMcpTransportSupported(config, query.transport)) {
2077
+ incompatible.push({
2078
+ agent: agentType,
2079
+ reason: config.unsupportedTransportMessage ?? `agent ${agentType} only supports ${config.supportedTransports.join(", ")} transport (attempted ${query.transport})`
2080
+ });
2081
+ } else {
2082
+ compatibleAgents.push(agentType);
2022
2083
  }
2023
- if (errorMsg) {
2024
- lines.push(theme.style.error(errorMsg));
2084
+ }
2085
+ let diagnostic;
2086
+ if (compatibleAgents.length === 0) {
2087
+ if (isDetected) {
2088
+ diagnostic = `No ${isGlobal ? "global" : "project"}-installed MCP agents detected. Pass -a <agent> (e.g. -a cursor) or --all to install.`;
2089
+ } else if (allAgents.length > 0 && incompatible.length > 0 && query.transport) {
2090
+ const list = incompatible.map((item) => `${item.agent} (${item.reason})`).join(", ");
2091
+ diagnostic = `None of the selected agents support ${query.transport} transport: ${list}`;
2092
+ } else {
2093
+ diagnostic = "No valid target agents specified.";
2025
2094
  }
2026
- return lines.join("\n");
2027
2095
  }
2028
- );
2096
+ return {
2097
+ agents: compatibleAgents,
2098
+ compatibleAgents,
2099
+ allAgents,
2100
+ candidateAgents: allAgents,
2101
+ detected,
2102
+ isDetected,
2103
+ incompatible,
2104
+ diagnostic
2105
+ };
2106
+ };
2029
2107
 
2030
- // src/interactive/prompts/scope.ts
2031
- import { select } from "@inquirer/prompts";
2032
- import pc5 from "picocolors";
2033
- var promptScope = async (options = {}) => {
2034
- const initialGlobal = options.defaultGlobal ?? options.global;
2035
- if (initialGlobal !== void 0) {
2036
- return initialGlobal;
2108
+ // src/utils/logger.ts
2109
+ var import_picocolors4 = __toESM(require("picocolors"), 1);
2110
+ var logger = {
2111
+ info: (message) => {
2112
+ console.log(import_picocolors4.default.cyan("i"), message);
2113
+ },
2114
+ success: (message) => {
2115
+ console.log(import_picocolors4.default.green("\u221A"), message);
2116
+ },
2117
+ warn: (message) => {
2118
+ console.log(import_picocolors4.default.yellow("!"), message);
2119
+ },
2120
+ error: (message) => {
2121
+ console.error(import_picocolors4.default.red("x"), message);
2037
2122
  }
2038
- const cwd = options.cwd ?? process.cwd();
2039
- return select({
2040
- message: options.message ?? "Select MCP scope:",
2041
- choices: [
2042
- {
2043
- name: `Current Project - ${pc5.dim(cwd)}`,
2044
- value: false
2045
- },
2046
- {
2047
- name: `Global User Config - ${pc5.dim("applies across all projects")}`,
2048
- value: true
2049
- }
2050
- ]
2051
- });
2052
2123
  };
2053
2124
 
2054
2125
  // src/interactive/prompts/agents.ts
@@ -2065,10 +2136,13 @@ var promptScopeAndAgents = async (options = {}) => {
2065
2136
  });
2066
2137
  const detected = resolution.detected;
2067
2138
  const rawAvailable = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
2068
- const availableAgentTypes = sortAgentsWithClusters(rawAvailable, { global: isGlobal, cwd });
2139
+ const availableAgentTypes = agentConfigStore.sortAgentsByClusters(rawAvailable, {
2140
+ global: isGlobal,
2141
+ cwd
2142
+ });
2069
2143
  if (detected.length > 0) {
2070
2144
  logger.info(
2071
- `Detected configured agents: ${pc6.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2145
+ `Detected configured agents: ${import_picocolors5.default.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2072
2146
  );
2073
2147
  } else {
2074
2148
  logger.warn(`No active ${isGlobal ? "global" : "project"} agents detected`);
@@ -2096,86 +2170,25 @@ var promptScopeAndAgents = async (options = {}) => {
2096
2170
  };
2097
2171
  };
2098
2172
 
2099
- // src/interactive/prompts/args.ts
2100
- import { confirm, input } from "@inquirer/prompts";
2101
- var parseArgsString = (rawText) => {
2102
- const matches = rawText.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
2103
- if (!matches) return [];
2104
- return matches.map((arg) => {
2105
- if (arg.startsWith('"') && arg.endsWith('"') || arg.startsWith("'") && arg.endsWith("'")) {
2106
- return arg.slice(1, -1);
2107
- }
2108
- return arg;
2109
- });
2110
- };
2111
- var promptArgsConfig = async (initialArgs = []) => {
2112
- if (initialArgs.length > 0) {
2113
- return initialArgs;
2114
- }
2115
- const needArgs = await confirm({
2116
- message: "Configure command arguments (e.g. file paths, connection strings)?",
2117
- default: false
2118
- });
2119
- if (!needArgs) {
2120
- return [];
2121
- }
2122
- const raw = await input({
2123
- message: "Enter command arguments (space-separated, wrap paths with spaces in quotes):",
2124
- validate: (val) => val.trim() ? true : "Arguments cannot be empty"
2125
- });
2126
- return parseArgsString(raw.trim());
2127
- };
2128
- var formatArgsString = (args) => {
2129
- return args.map((arg) => arg.includes(" ") || arg.includes('"') ? `"${arg.replace(/"/g, '\\"')}"` : arg).join(" ");
2130
- };
2131
- var promptEditArgs = async (currentArgs = []) => {
2132
- const defaultStr = formatArgsString(currentArgs);
2133
- const raw = await input({
2134
- message: "Edit command arguments (space-separated, wrap paths with spaces in quotes, leave empty to clear):",
2135
- default: defaultStr
2136
- });
2137
- const trimmed = raw.trim();
2138
- if (!trimmed) {
2139
- return [];
2140
- }
2141
- return parseArgsString(trimmed);
2142
- };
2143
-
2144
2173
  // src/interactive/prompts/env.ts
2145
- import { input as input3, password as password2, select as select3 } from "@inquirer/prompts";
2146
- import pc9 from "picocolors";
2147
-
2148
- // src/utils/mask-secret.ts
2149
- var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
2150
- var maskSecretValue = (key, value) => {
2151
- if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
2152
- return value;
2153
- }
2154
- return `${value.slice(0, 2)}***${value.slice(-2)}`;
2155
- };
2156
- var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
2157
- var maskSecretHeader = (key, value) => {
2158
- if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
2159
- return value;
2160
- }
2161
- return `${value.slice(0, 4)}***${value.slice(-3)}`;
2162
- };
2174
+ var import_prompts4 = require("@inquirer/prompts");
2175
+ var import_picocolors8 = __toESM(require("picocolors"), 1);
2163
2176
 
2164
2177
  // src/interactive/prompts/kv.ts
2165
- import { confirm as confirm2, input as input2, password, select as select2 } from "@inquirer/prompts";
2166
- import pc8 from "picocolors";
2178
+ var import_prompts3 = require("@inquirer/prompts");
2179
+ var import_picocolors7 = __toESM(require("picocolors"), 1);
2167
2180
 
2168
2181
  // src/interactive/prompts/multiline.ts
2169
- import { createInterface } from "readline";
2170
- import { editor } from "@inquirer/prompts";
2171
- import pc7 from "picocolors";
2182
+ var import_node_readline = require("readline");
2183
+ var import_prompts2 = require("@inquirer/prompts");
2184
+ var import_picocolors6 = __toESM(require("picocolors"), 1);
2172
2185
  var readMultilineTextFromTerminal = async (message, endHint = "When done pasting, enter END on a new line or press Enter twice to finish") => {
2173
- console.log(pc7.cyan(`
2186
+ console.log(import_picocolors6.default.cyan(`
2174
2187
  ${message}`));
2175
- console.log(pc7.dim(` (Hint: ${endHint})
2188
+ console.log(import_picocolors6.default.dim(` (Hint: ${endHint})
2176
2189
  `));
2177
2190
  return new Promise((resolve) => {
2178
- const rl = createInterface({
2191
+ const rl = (0, import_node_readline.createInterface)({
2179
2192
  input: process.stdin,
2180
2193
  output: process.stdout
2181
2194
  });
@@ -2216,7 +2229,7 @@ ${message}`));
2216
2229
  };
2217
2230
  var promptEditorText = async (options) => {
2218
2231
  try {
2219
- return await editor({
2232
+ return await (0, import_prompts2.editor)({
2220
2233
  message: options.message,
2221
2234
  default: options.defaultText ?? "",
2222
2235
  postfix: options.postfix
@@ -2233,16 +2246,16 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
2233
2246
  const keys = Object.keys(items);
2234
2247
  console.log();
2235
2248
  if (keys.length === 0) {
2236
- console.log(pc8.dim(` No ${options.itemsNoun} configured.`));
2249
+ console.log(import_picocolors7.default.dim(` No ${options.itemsNoun} configured.`));
2237
2250
  } else {
2238
- console.log(pc8.cyan(pc8.bold(` Configured ${options.title} (${keys.length}):`)));
2251
+ console.log(import_picocolors7.default.cyan(import_picocolors7.default.bold(` Configured ${options.title} (${keys.length}):`)));
2239
2252
  for (const [k, v] of Object.entries(items)) {
2240
2253
  const sep = options.separator === "=" ? "=" : ": ";
2241
- console.log(` ${pc8.bold(k)}${sep}${pc8.dim(options.maskValue(k, v))}`);
2254
+ console.log(` ${import_picocolors7.default.bold(k)}${sep}${import_picocolors7.default.dim(options.maskValue(k, v))}`);
2242
2255
  }
2243
2256
  }
2244
2257
  console.log();
2245
- const choice = await select2({
2258
+ const choice = await (0, import_prompts3.select)({
2246
2259
  message: `Manage ${options.itemsNoun}:`,
2247
2260
  choices: [
2248
2261
  {
@@ -2289,7 +2302,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
2289
2302
  items = parsed;
2290
2303
  logger.success(`${options.title} updated (${Object.keys(items).length} total)`);
2291
2304
  } else if (choice === "upsert") {
2292
- const key = await input2({
2305
+ const key = await (0, import_prompts3.input)({
2293
2306
  message: options.keyPromptMessage,
2294
2307
  validate: (val) => {
2295
2308
  const trimmed = val.trim();
@@ -2303,7 +2316,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
2303
2316
  const isSecret = options.isSecretKey(trimmedKey);
2304
2317
  let newVal;
2305
2318
  if (isSecret) {
2306
- newVal = await password({
2319
+ newVal = await (0, import_prompts3.password)({
2307
2320
  message: existingVal !== void 0 ? `New value for (${trimmedKey}) [leave empty to keep current]:` : `${options.valuePromptMessage} for (${trimmedKey}) [sensitive content masked]:`,
2308
2321
  mask: "*"
2309
2322
  });
@@ -2311,15 +2324,15 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
2311
2324
  newVal = existingVal;
2312
2325
  }
2313
2326
  } else {
2314
- newVal = await input2({
2327
+ newVal = await (0, import_prompts3.input)({
2315
2328
  message: `${options.valuePromptMessage} for (${trimmedKey}):`,
2316
2329
  default: existingVal
2317
2330
  });
2318
2331
  }
2319
2332
  items[trimmedKey] = newVal;
2320
- logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${pc8.cyan(trimmedKey)}`);
2333
+ logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${import_picocolors7.default.cyan(trimmedKey)}`);
2321
2334
  } else if (choice === "delete") {
2322
- const toDelete = await select2({
2335
+ const toDelete = await (0, import_prompts3.select)({
2323
2336
  message: `Select ${options.itemNoun} to delete:`,
2324
2337
  choices: [
2325
2338
  ...keys.map((k) => ({ name: k, value: k })),
@@ -2328,7 +2341,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
2328
2341
  });
2329
2342
  if (toDelete !== "__cancel__") {
2330
2343
  delete items[toDelete];
2331
- logger.success(`Deleted: ${pc8.cyan(toDelete)}`);
2344
+ logger.success(`Deleted: ${import_picocolors7.default.cyan(toDelete)}`);
2332
2345
  }
2333
2346
  } else if (choice === "paste") {
2334
2347
  const pasted = await readMultilineTextFromTerminal(options.pasteMessage);
@@ -2338,7 +2351,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
2338
2351
  logger.warn(`No valid ${options.itemsNoun} recognized`);
2339
2352
  } else {
2340
2353
  if (keys.length > 0) {
2341
- const pasteMode = await select2({
2354
+ const pasteMode = await (0, import_prompts3.select)({
2342
2355
  message: `How to apply pasted ${options.itemsNoun}?`,
2343
2356
  choices: [
2344
2357
  { name: `Merge with existing ${options.itemsNoun}`, value: "merge" },
@@ -2353,10 +2366,10 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
2353
2366
  } else {
2354
2367
  items = parsed;
2355
2368
  }
2356
- logger.success(`Successfully applied ${pc8.cyan(String(count))} ${options.itemsNoun}`);
2369
+ logger.success(`Successfully applied ${import_picocolors7.default.cyan(String(count))} ${options.itemsNoun}`);
2357
2370
  }
2358
2371
  } else if (choice === "clear") {
2359
- const confirmClear = await confirm2({
2372
+ const confirmClear = await (0, import_prompts3.confirm)({
2360
2373
  message: `Are you sure you want to clear all ${options.itemsNoun}?`,
2361
2374
  default: false
2362
2375
  });
@@ -2402,9 +2415,9 @@ var promptEnvConfig = async (initialEnv = {}) => {
2402
2415
  const env = { ...initialEnv };
2403
2416
  const initialCount = Object.keys(env).length;
2404
2417
  if (initialCount > 0) {
2405
- logger.info(`Includes ${pc9.cyan(String(initialCount))} preset environment variables`);
2418
+ logger.info(`Includes ${import_picocolors8.default.cyan(String(initialCount))} preset environment variables`);
2406
2419
  }
2407
- const mode = await select3({
2420
+ const mode = await (0, import_prompts4.select)({
2408
2421
  message: "Configure environment variables?",
2409
2422
  choices: [
2410
2423
  {
@@ -2440,16 +2453,16 @@ var promptEnvConfig = async (initialEnv = {}) => {
2440
2453
  logger.warn("No valid KEY=VALUE pairs recognized");
2441
2454
  } else {
2442
2455
  Object.assign(env, parsed);
2443
- logger.success(`Successfully parsed ${pc9.cyan(String(count))} environment variables:`);
2456
+ logger.success(`Successfully parsed ${import_picocolors8.default.cyan(String(count))} environment variables:`);
2444
2457
  for (const [k, v] of Object.entries(parsed)) {
2445
- console.log(` ${pc9.bold(k)}=${pc9.dim(maskSecretValue(k, v))}`);
2458
+ console.log(` ${import_picocolors8.default.bold(k)}=${import_picocolors8.default.dim(maskSecretValue(k, v))}`);
2446
2459
  }
2447
2460
  }
2448
2461
  return env;
2449
2462
  }
2450
2463
  logger.info("Entering environment variables (leave key empty and press enter to finish):");
2451
2464
  while (true) {
2452
- const key = await input3({
2465
+ const key = await (0, import_prompts4.input)({
2453
2466
  message: "Variable name (Key, leave empty to finish):",
2454
2467
  validate: (val2) => {
2455
2468
  const trimmed = val2.trim();
@@ -2463,17 +2476,17 @@ var promptEnvConfig = async (initialEnv = {}) => {
2463
2476
  const isSecret = SECRET_KEY_PATTERN.test(trimmedKey);
2464
2477
  let val;
2465
2478
  if (isSecret) {
2466
- val = await password2({
2479
+ val = await (0, import_prompts4.password)({
2467
2480
  message: `Value for (${trimmedKey}) [secret masked]:`,
2468
2481
  mask: "*"
2469
2482
  });
2470
2483
  } else {
2471
- val = await input3({
2484
+ val = await (0, import_prompts4.input)({
2472
2485
  message: `Value for (${trimmedKey}):`
2473
2486
  });
2474
2487
  }
2475
2488
  env[trimmedKey] = val;
2476
- logger.success(`Added: ${pc9.cyan(trimmedKey)}`);
2489
+ logger.success(`Added: ${import_picocolors8.default.cyan(trimmedKey)}`);
2477
2490
  }
2478
2491
  return env;
2479
2492
  };
@@ -2494,8 +2507,8 @@ var promptEditEnvConfig = async (currentEnv = {}) => promptEditKeyValueConfig(cu
2494
2507
  });
2495
2508
 
2496
2509
  // src/interactive/prompts/headers.ts
2497
- import { input as input4, password as password3, select as select4 } from "@inquirer/prompts";
2498
- import pc10 from "picocolors";
2510
+ var import_prompts5 = require("@inquirer/prompts");
2511
+ var import_picocolors9 = __toESM(require("picocolors"), 1);
2499
2512
  var formatHeadersText = (headers) => {
2500
2513
  return Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join("\n");
2501
2514
  };
@@ -2528,7 +2541,7 @@ var parseHeadersText = (rawText) => {
2528
2541
  };
2529
2542
  var promptHeadersConfig = async (initialHeaders = {}) => {
2530
2543
  const headers = { ...initialHeaders };
2531
- const mode = await select4({
2544
+ const mode = await (0, import_prompts5.select)({
2532
2545
  message: "Select HTTP headers configuration method:",
2533
2546
  choices: [
2534
2547
  {
@@ -2565,16 +2578,16 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
2565
2578
  logger.warn("No valid Key: Value pairs recognized");
2566
2579
  } else {
2567
2580
  Object.assign(headers, parsed);
2568
- logger.success(`Successfully parsed ${pc10.cyan(String(count))} headers:`);
2581
+ logger.success(`Successfully parsed ${import_picocolors9.default.cyan(String(count))} headers:`);
2569
2582
  for (const [k, v] of Object.entries(parsed)) {
2570
- console.log(` ${pc10.bold(k)}: ${pc10.dim(maskSecretHeader(k, v))}`);
2583
+ console.log(` ${import_picocolors9.default.bold(k)}: ${import_picocolors9.default.dim(maskSecretHeader(k, v))}`);
2571
2584
  }
2572
2585
  }
2573
2586
  return headers;
2574
2587
  }
2575
2588
  logger.info("Entering HTTP headers (leave header name empty and press enter to finish):");
2576
2589
  while (true) {
2577
- const name = await input4({
2590
+ const name = await (0, import_prompts5.input)({
2578
2591
  message: "Header name (e.g. Authorization, leave empty to finish):",
2579
2592
  validate: (val2) => {
2580
2593
  const trimmed = val2.trim();
@@ -2588,17 +2601,17 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
2588
2601
  const isSecret = SECRET_HEADER_PATTERN.test(trimmedName);
2589
2602
  let val;
2590
2603
  if (isSecret) {
2591
- val = await password3({
2604
+ val = await (0, import_prompts5.password)({
2592
2605
  message: `Header value for (${trimmedName}) [sensitive content masked]:`,
2593
2606
  mask: "*"
2594
2607
  });
2595
2608
  } else {
2596
- val = await input4({
2609
+ val = await (0, import_prompts5.input)({
2597
2610
  message: `Header value for (${trimmedName}):`
2598
2611
  });
2599
2612
  }
2600
2613
  headers[trimmedName] = val;
2601
- logger.success(`Added: ${pc10.cyan(trimmedName)}`);
2614
+ logger.success(`Added: ${import_picocolors9.default.cyan(trimmedName)}`);
2602
2615
  }
2603
2616
  return headers;
2604
2617
  };
@@ -2617,165 +2630,57 @@ var promptEditHeadersConfig = async (currentHeaders = {}) => promptEditKeyValueC
2617
2630
  parseText: parseHeadersText
2618
2631
  });
2619
2632
 
2620
- // src/interactive/wizard-add.ts
2621
- var wizardAdd = async (initial = {}) => {
2622
- const cwd = initial.cwd ?? process.cwd();
2623
- logger.info(pc11.bold("Welcome to the MCP interactive add wizard"));
2624
- let source = initial.source;
2625
- if (!source) {
2626
- const sourceType = await select5({
2627
- message: "Select MCP server type:",
2628
- choices: [
2629
- {
2630
- name: "npm package (run via npx)",
2631
- value: "npm"
2632
- },
2633
- {
2634
- name: "Remote MCP server (via HTTP / SSE URL)",
2635
- value: "remote"
2636
- },
2637
- {
2638
- name: "Local command / script / Docker (stdio)",
2639
- value: "command"
2640
- }
2641
- ]
2642
- });
2643
- if (sourceType === "npm") {
2644
- source = await input5({
2645
- message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres):",
2646
- validate: (val) => val.trim() ? true : "Package name cannot be empty"
2647
- });
2648
- } else if (sourceType === "remote") {
2649
- source = await input5({
2650
- message: "Enter remote server URL (e.g. https://mcp.example.com/sse):",
2651
- validate: (val) => {
2652
- const trimmed = val.trim();
2653
- if (!trimmed) return "URL cannot be empty";
2654
- if (!/^https?:\/\//i.test(trimmed)) return "Please enter a valid URL starting with http:// or https://";
2655
- return true;
2656
- }
2657
- });
2658
- } else {
2659
- source = await input5({
2660
- message: "Enter command and arguments (e.g. python -m my_mcp_server or docker run ...):",
2661
- validate: (val) => val.trim() ? true : "Command cannot be empty"
2662
- });
2663
- }
2664
- }
2665
- source = source.trim();
2666
- const parsed = parseMcpSource(source);
2667
- let serverName = initial.name;
2668
- if (!serverName) {
2669
- serverName = await input5({
2670
- message: "MCP server name:",
2671
- default: parsed.inferredName,
2672
- validate: (val) => val.trim() ? true : "Server name cannot be empty"
2673
- });
2674
- }
2675
- serverName = serverName.trim();
2676
- let transport = initial.transport;
2677
- let headers = initial.headers ?? {};
2678
- if (parsed.type === "remote") {
2679
- if (!transport) {
2680
- const isSseUrl = /\/sse\b/i.test(parsed.value);
2681
- transport = await select5({
2682
- message: "Select remote transport protocol:",
2683
- choices: [
2684
- { name: "HTTP", value: "http" },
2685
- { name: "SSE (Server-Sent Events)", value: "sse" }
2686
- ],
2687
- default: isSseUrl ? "sse" : "http"
2688
- });
2689
- }
2690
- if (Object.keys(headers).length === 0) {
2691
- const needHeader = await confirm5({
2692
- message: "Configure HTTP headers (e.g. Authorization Bearer token)?",
2693
- default: false
2694
- });
2695
- if (needHeader) {
2696
- headers = await promptHeadersConfig();
2697
- }
2633
+ // src/interactive/prompts/args.ts
2634
+ var import_prompts6 = require("@inquirer/prompts");
2635
+ var parseArgsString = (rawText) => {
2636
+ const matches = rawText.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
2637
+ if (!matches) return [];
2638
+ return matches.map((arg) => {
2639
+ if (arg.startsWith('"') && arg.endsWith('"') || arg.startsWith("'") && arg.endsWith("'")) {
2640
+ return arg.slice(1, -1);
2698
2641
  }
2699
- }
2700
- const { global: isGlobal, agents: selectedAgents } = await promptScopeAndAgents({
2701
- cwd,
2702
- defaultGlobal: initial.global,
2703
- defaultAgents: initial.agents
2642
+ return arg;
2704
2643
  });
2705
- let args = initial.args ?? [];
2706
- if (parsed.type !== "remote") {
2707
- args = await promptArgsConfig(args);
2708
- }
2709
- let env = initial.env ?? {};
2710
- if (parsed.type !== "remote") {
2711
- env = await promptEnvConfig(env);
2712
- }
2713
- console.log("\n" + pc11.cyan(pc11.bold("Configuration Preview:")));
2714
- console.log(` ${pc11.bold("Server Name:")} ${pc11.green(serverName)}`);
2715
- console.log(` ${pc11.bold("Server Type:")} ${pc11.magenta(parsed.type)}`);
2716
- console.log(` ${pc11.bold("Source/Command:")} ${pc11.dim(source)}`);
2717
- console.log(` ${pc11.bold("Scope:")} ${isGlobal ? pc11.yellow("Global") : pc11.blue("Project")}`);
2718
- console.log(` ${pc11.bold("Target Agents:")} ${pc11.cyan(selectedAgents.join(", "))}`);
2719
- if (args.length > 0) {
2720
- console.log(` ${pc11.bold("Arguments:")} ${pc11.dim(args.join(" "))}`);
2721
- }
2722
- if (transport) {
2723
- console.log(` ${pc11.bold("Transport:")} ${pc11.magenta(transport)}`);
2724
- }
2725
- const envKeys = Object.keys(env);
2726
- if (envKeys.length > 0) {
2727
- console.log(` ${pc11.bold("Environment Variables:")} ${pc11.dim(envKeys.join(", "))} (${envKeys.length})`);
2728
- }
2729
- const headerKeys = Object.keys(headers);
2730
- if (headerKeys.length > 0) {
2731
- console.log(` ${pc11.bold("Headers:")} ${pc11.dim(headerKeys.join(", "))} (${headerKeys.length})`);
2644
+ };
2645
+ var promptArgsConfig = async (initialArgs = []) => {
2646
+ if (initialArgs.length > 0) {
2647
+ return initialArgs;
2732
2648
  }
2733
- console.log();
2734
- const proceed = await confirm5({
2735
- message: "Confirm installation with this configuration?",
2736
- default: true
2649
+ const needArgs = await (0, import_prompts6.confirm)({
2650
+ message: "Configure command arguments (e.g. file paths, connection strings)?",
2651
+ default: false
2737
2652
  });
2738
- if (!proceed) {
2739
- logger.warn("Operation cancelled");
2740
- return false;
2653
+ if (!needArgs) {
2654
+ return [];
2741
2655
  }
2742
- const result = installMcpServer({
2743
- source,
2744
- name: serverName,
2745
- agents: selectedAgents,
2746
- args,
2747
- global: isGlobal,
2748
- cwd,
2749
- transport,
2750
- headers,
2751
- env
2656
+ const raw = await (0, import_prompts6.input)({
2657
+ message: "Enter command arguments (space-separated, wrap paths with spaces in quotes):",
2658
+ validate: (val) => val.trim() ? true : "Arguments cannot be empty"
2752
2659
  });
2753
- logger.info(
2754
- `Writing ${pc11.bold(result.serverName)} to ${pc11.cyan(String(result.results.length))} agent config files...`
2755
- );
2756
- let allSuccess = true;
2757
- for (const record of result.results) {
2758
- if (record.success) {
2759
- logger.success(
2760
- `${pc11.cyan(record.agent)}: Successfully written to ${pc11.dim(record.path)}${formatCoHostedBadge("configured", record.coConfiguredAgents)}`
2761
- );
2762
- } else {
2763
- allSuccess = false;
2764
- logger.error(`${pc11.cyan(record.agent)}: Failed to write - ${record.error}`);
2765
- }
2766
- }
2767
- if (allSuccess) {
2768
- logger.success(pc11.bold(`MCP server "${serverName}" configured successfully!`));
2660
+ return parseArgsString(raw.trim());
2661
+ };
2662
+ var formatArgsString = (args) => {
2663
+ return args.map((arg) => arg.includes(" ") || arg.includes('"') ? `"${arg.replace(/"/g, '\\"')}"` : arg).join(" ");
2664
+ };
2665
+ var promptEditArgs = async (currentArgs = []) => {
2666
+ const defaultStr = formatArgsString(currentArgs);
2667
+ const raw = await (0, import_prompts6.input)({
2668
+ message: "Edit command arguments (space-separated, wrap paths with spaces in quotes, leave empty to clear):",
2669
+ default: defaultStr
2670
+ });
2671
+ const trimmed = raw.trim();
2672
+ if (!trimmed) {
2673
+ return [];
2769
2674
  }
2770
- return allSuccess;
2675
+ return parseArgsString(trimmed);
2771
2676
  };
2772
2677
 
2773
2678
  // src/interactive/wizard-manage.ts
2774
- import { confirm as confirm6, input as input6, select as select6 } from "@inquirer/prompts";
2775
- import pc13 from "picocolors";
2679
+ var import_prompts7 = require("@inquirer/prompts");
2680
+ var import_picocolors12 = __toESM(require("picocolors"), 1);
2776
2681
 
2777
2682
  // src/utils/display-server-details.ts
2778
- import pc12 from "picocolors";
2683
+ var import_picocolors10 = __toESM(require("picocolors"), 1);
2779
2684
  var displayServerDetails = ({
2780
2685
  serverName,
2781
2686
  config,
@@ -2784,99 +2689,76 @@ var displayServerDetails = ({
2784
2689
  global: isGlobal,
2785
2690
  titlePrefix = "MCP Server Details"
2786
2691
  }) => {
2787
- console.log("\n" + pc12.cyan(pc12.bold(`${titlePrefix}: [${serverName}]`)));
2692
+ console.log("\n" + import_picocolors10.default.cyan(import_picocolors10.default.bold(`${titlePrefix}: [${serverName}]`)));
2788
2693
  if (isGlobal !== void 0) {
2789
- console.log(` ${pc12.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
2694
+ console.log(` ${import_picocolors10.default.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
2790
2695
  }
2791
2696
  if (agents && agents.length > 0) {
2792
2697
  console.log(
2793
- ` ${pc12.bold("Configured Agents:")} ${pc12.green(agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2698
+ ` ${import_picocolors10.default.bold("Configured Agents:")} ${import_picocolors10.default.green(agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2794
2699
  );
2795
2700
  }
2796
2701
  if (hasDivergence) {
2797
2702
  console.log(
2798
- ` ${pc12.yellow(pc12.bold("Notice:"))} ${pc12.yellow("Configurations differ across installed agents. Showing configuration from the first agent.")}`
2703
+ ` ${import_picocolors10.default.yellow(import_picocolors10.default.bold("Notice:"))} ${import_picocolors10.default.yellow("Configurations differ across installed agents. Showing configuration from the first agent.")}`
2799
2704
  );
2800
2705
  }
2801
2706
  const isRemote = Boolean(config.url && config.url.length > 0);
2802
2707
  if (isRemote) {
2803
- console.log(` ${pc12.bold("Transport:")} ${pc12.magenta(config.type ?? "http")}`);
2804
- console.log(` ${pc12.bold("URL:")} ${pc12.dim(config.url ?? "")}`);
2708
+ console.log(` ${import_picocolors10.default.bold("Transport:")} ${import_picocolors10.default.magenta(config.type ?? "http")}`);
2709
+ console.log(` ${import_picocolors10.default.bold("URL:")} ${import_picocolors10.default.dim(config.url ?? "")}`);
2805
2710
  const headerKeys = Object.keys(config.headers ?? {});
2806
2711
  if (headerKeys.length > 0) {
2807
- console.log(` ${pc12.bold("Headers:")} ${pc12.cyan(String(headerKeys.length))}`);
2712
+ console.log(` ${import_picocolors10.default.bold("Headers:")} ${import_picocolors10.default.cyan(String(headerKeys.length))}`);
2808
2713
  for (const [k, v] of Object.entries(config.headers ?? {})) {
2809
- console.log(` ${pc12.bold(k)}: ${pc12.dim(maskSecretHeader(k, v))}`);
2714
+ console.log(` ${import_picocolors10.default.bold(k)}: ${import_picocolors10.default.dim(maskSecretHeader(k, v))}`);
2810
2715
  }
2811
2716
  } else {
2812
- console.log(` ${pc12.bold("Headers:")} ${pc12.dim("(none)")}`);
2717
+ console.log(` ${import_picocolors10.default.bold("Headers:")} ${import_picocolors10.default.dim("(none)")}`);
2813
2718
  }
2814
2719
  } else {
2815
- console.log(` ${pc12.bold("Command:")} ${pc12.magenta(config.command ?? "")}`);
2720
+ console.log(` ${import_picocolors10.default.bold("Command:")} ${import_picocolors10.default.magenta(config.command ?? "")}`);
2816
2721
  const argsStr = config.args && config.args.length > 0 ? config.args.join(" ") : "(none)";
2817
- console.log(` ${pc12.bold("Arguments:")} ${pc12.dim(argsStr)}`);
2722
+ console.log(` ${import_picocolors10.default.bold("Arguments:")} ${import_picocolors10.default.dim(argsStr)}`);
2818
2723
  const envKeys = Object.keys(config.env ?? {});
2819
2724
  if (envKeys.length > 0) {
2820
- console.log(` ${pc12.bold("Environment Variables:")} ${pc12.cyan(String(envKeys.length))}`);
2821
- for (const [k, v] of Object.entries(config.env ?? {})) {
2822
- console.log(` ${pc12.bold(k)}=${pc12.dim(maskSecretValue(k, v))}`);
2823
- }
2824
- } else {
2825
- console.log(` ${pc12.bold("Environment Variables:")} ${pc12.dim("(none)")}`);
2826
- }
2827
- }
2828
- console.log();
2829
- };
2830
-
2831
- // src/interactive/utils/group-installed-servers.ts
2832
- var normalizeServerConfig = parseServerConfig;
2833
- var groupInstalledServersByName = (installed) => {
2834
- const grouped = /* @__PURE__ */ new Map();
2835
- for (const item of installed) {
2836
- const itemConfig = normalizeServerConfig(item.config);
2837
- let entry = grouped.get(item.serverName);
2838
- if (!entry) {
2839
- entry = {
2840
- serverName: item.serverName,
2841
- agents: [],
2842
- paths: [],
2843
- config: itemConfig,
2844
- hasDivergence: false
2845
- };
2846
- grouped.set(item.serverName, entry);
2847
- } else if (!entry.hasDivergence) {
2848
- if (JSON.stringify(entry.config) !== JSON.stringify(itemConfig)) {
2849
- entry.hasDivergence = true;
2725
+ console.log(` ${import_picocolors10.default.bold("Environment Variables:")} ${import_picocolors10.default.cyan(String(envKeys.length))}`);
2726
+ for (const [k, v] of Object.entries(config.env ?? {})) {
2727
+ console.log(` ${import_picocolors10.default.bold(k)}=${import_picocolors10.default.dim(maskSecretValue(k, v))}`);
2850
2728
  }
2851
- }
2852
- if (!entry.agents.includes(item.agent)) {
2853
- entry.agents.push(item.agent);
2854
- }
2855
- if (!entry.paths.includes(item.path)) {
2856
- entry.paths.push(item.path);
2729
+ } else {
2730
+ console.log(` ${import_picocolors10.default.bold("Environment Variables:")} ${import_picocolors10.default.dim("(none)")}`);
2857
2731
  }
2858
2732
  }
2859
- return grouped;
2733
+ console.log();
2734
+ };
2735
+
2736
+ // src/utils/co-hosted-feedback.ts
2737
+ var import_picocolors11 = __toESM(require("picocolors"), 1);
2738
+ var formatCoHostedBadge = (kind, agents) => {
2739
+ if (!agents || agents.length === 0) return "";
2740
+ const label = kind === "configured" ? "co-configured" : "co-affected";
2741
+ return ` ${import_picocolors11.default.yellow(`(${label}: ${agents.join(", ")})`)}`;
2860
2742
  };
2861
2743
 
2862
2744
  // src/interactive/wizard-manage.ts
2863
2745
  var promptSwitchServerType = async (currentConfig, serverName) => {
2864
2746
  const isRemote = Boolean(currentConfig.url && currentConfig.url.length > 0);
2865
2747
  if (isRemote) {
2866
- const newCmd = await input6({
2748
+ const newCmd = await (0, import_prompts7.input)({
2867
2749
  message: "Executable command (e.g. node, npx):",
2868
2750
  validate: (val) => val.trim() ? true : "Command cannot be empty"
2869
2751
  });
2870
2752
  const newArgs = await promptEditArgs([]);
2871
2753
  const newEnv = await promptEditEnvConfig({});
2872
2754
  logger.success(`Switched [${serverName}] configuration to stdio mode`);
2873
- return {
2755
+ return toStdioServerConfig({
2874
2756
  command: newCmd.trim(),
2875
2757
  args: newArgs.length > 0 ? newArgs : void 0,
2876
2758
  env: Object.keys(newEnv).length > 0 ? newEnv : void 0
2877
- };
2759
+ });
2878
2760
  }
2879
- const newUrl = await input6({
2761
+ const newUrl = await (0, import_prompts7.input)({
2880
2762
  message: "Remote server URL:",
2881
2763
  validate: (val) => {
2882
2764
  const trimmed = val.trim();
@@ -2887,7 +2769,7 @@ var promptSwitchServerType = async (currentConfig, serverName) => {
2887
2769
  return true;
2888
2770
  }
2889
2771
  });
2890
- const transport = await select6({
2772
+ const transport = await (0, import_prompts7.select)({
2891
2773
  message: "Select remote transport protocol:",
2892
2774
  choices: [
2893
2775
  { name: "HTTP", value: "http" },
@@ -2897,11 +2779,13 @@ var promptSwitchServerType = async (currentConfig, serverName) => {
2897
2779
  });
2898
2780
  const newHeaders = await promptEditHeadersConfig({});
2899
2781
  logger.success(`Switched [${serverName}] configuration to remote mode`);
2900
- return {
2901
- url: newUrl.trim(),
2902
- type: transport,
2903
- headers: Object.keys(newHeaders).length > 0 ? newHeaders : void 0
2904
- };
2782
+ return toRemoteServerConfig(
2783
+ {
2784
+ url: newUrl.trim(),
2785
+ headers: Object.keys(newHeaders).length > 0 ? newHeaders : void 0
2786
+ },
2787
+ transport
2788
+ );
2905
2789
  };
2906
2790
  var handleEditServerConfig = async (options) => {
2907
2791
  const { targetGroup } = options;
@@ -2938,7 +2822,7 @@ var handleEditServerConfig = async (options) => {
2938
2822
  { name: "Save and apply changes", value: "save" },
2939
2823
  { name: "Cancel (discard changes)", value: "cancel" }
2940
2824
  ];
2941
- const editAction = await select6({
2825
+ const editAction = await (0, import_prompts7.select)({
2942
2826
  message: `What would you like to modify in [${serverName}]?`,
2943
2827
  choices: editChoices
2944
2828
  });
@@ -2965,7 +2849,7 @@ var handleEditServerConfig = async (options) => {
2965
2849
  } else if (editAction === "args") {
2966
2850
  workingConfig.args = await promptEditArgs(workingConfig.args ?? []);
2967
2851
  } else if (editAction === "command") {
2968
- const newCmd = await input6({
2852
+ const newCmd = await (0, import_prompts7.input)({
2969
2853
  message: "Executable command:",
2970
2854
  default: workingConfig.command,
2971
2855
  validate: (val) => val.trim() ? true : "Command cannot be empty"
@@ -2974,7 +2858,7 @@ var handleEditServerConfig = async (options) => {
2974
2858
  } else if (editAction === "headers") {
2975
2859
  workingConfig.headers = await promptEditHeadersConfig(workingConfig.headers ?? {});
2976
2860
  } else if (editAction === "url") {
2977
- const newUrl = await input6({
2861
+ const newUrl = await (0, import_prompts7.input)({
2978
2862
  message: "Remote server URL:",
2979
2863
  default: workingConfig.url,
2980
2864
  validate: (val) => {
@@ -2988,7 +2872,7 @@ var handleEditServerConfig = async (options) => {
2988
2872
  });
2989
2873
  workingConfig.url = newUrl.trim();
2990
2874
  } else if (editAction === "transport") {
2991
- workingConfig.type = await select6({
2875
+ workingConfig.type = await (0, import_prompts7.select)({
2992
2876
  message: "Select remote transport protocol:",
2993
2877
  choices: [
2994
2878
  { name: "HTTP", value: "http" },
@@ -2999,7 +2883,7 @@ var handleEditServerConfig = async (options) => {
2999
2883
  } else if (editAction === "save") {
3000
2884
  let targetAgents = targetGroup.agents;
3001
2885
  if (targetGroup.agents.length > 1) {
3002
- const sortedAgents = sortAgentsWithClusters(targetGroup.agents, { global: isGlobal, cwd });
2886
+ const sortedAgents = agentConfigStore.sortAgentsByClusters(targetGroup.agents, { global: isGlobal, cwd });
3003
2887
  const choices = buildLinkedAgentChoices({
3004
2888
  agents: sortedAgents,
3005
2889
  checkedAgents: sortedAgents,
@@ -3028,7 +2912,7 @@ var handleEditServerConfig = async (options) => {
3028
2912
  });
3029
2913
  if (resolution.incompatible.length > 0) {
3030
2914
  for (const item of resolution.incompatible) {
3031
- logger.warn(`Skipping ${pc13.cyan(item.agent)}: ${item.reason}`);
2915
+ logger.warn(`Skipping ${import_picocolors12.default.cyan(item.agent)}: ${item.reason}`);
3032
2916
  }
3033
2917
  }
3034
2918
  if (resolution.compatibleAgents.length === 0) {
@@ -3038,7 +2922,7 @@ var handleEditServerConfig = async (options) => {
3038
2922
  continue;
3039
2923
  }
3040
2924
  const agentNames = resolution.compatibleAgents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
3041
- const confirmed = await confirm6({
2925
+ const confirmed = await (0, import_prompts7.confirm)({
3042
2926
  message: `Confirm updating configuration for [${serverName}] across: ${agentNames}?`,
3043
2927
  default: true
3044
2928
  });
@@ -3061,10 +2945,10 @@ var handleEditServerConfig = async (options) => {
3061
2945
  updatedAny = true;
3062
2946
  succeededAgents.push(res.agent);
3063
2947
  logger.success(
3064
- `${pc13.cyan(res.agent)}: Successfully updated configuration in ${pc13.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
2948
+ `${import_picocolors12.default.cyan(res.agent)}: Successfully updated configuration in ${import_picocolors12.default.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
3065
2949
  );
3066
2950
  } else {
3067
- logger.error(`${pc13.cyan(res.agent)}: Update failed - ${res.error}`);
2951
+ logger.error(`${import_picocolors12.default.cyan(res.agent)}: Update failed - ${res.error}`);
3068
2952
  }
3069
2953
  }
3070
2954
  if (updatedAny) {
@@ -3082,16 +2966,14 @@ var wizardManage = async (options = {}) => {
3082
2966
  defaultGlobal: options.global,
3083
2967
  message: "Select MCP scope to inspect and manage:"
3084
2968
  });
3085
- const installed = listInstalledMcpServers({ global: isGlobal, cwd });
3086
- if (installed.length === 0) {
2969
+ const grouped = queryGroupedInstalledServers({ global: isGlobal, cwd });
2970
+ if (grouped.size === 0) {
3087
2971
  logger.warn(`No configured MCP servers found in ${isGlobal ? "global" : "project"} scope`);
3088
2972
  return;
3089
2973
  }
3090
- const grouped = groupInstalledServersByName(installed);
3091
2974
  let pendingServerName = options.serverName;
3092
2975
  const refreshGroupedServers = () => {
3093
- const freshInstalled = listInstalledMcpServers({ global: isGlobal, cwd });
3094
- const freshGrouped = groupInstalledServersByName(freshInstalled);
2976
+ const freshGrouped = queryGroupedInstalledServers({ global: isGlobal, cwd });
3095
2977
  grouped.clear();
3096
2978
  for (const [name, grp] of freshGrouped) {
3097
2979
  grouped.set(name, grp);
@@ -3107,7 +2989,7 @@ var wizardManage = async (options = {}) => {
3107
2989
  const choices = Array.from(grouped.values()).map((g) => {
3108
2990
  const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
3109
2991
  return {
3110
- name: `${pc13.bold(g.serverName)} ${pc13.dim(`(configured in: ${agentNames})`)}`,
2992
+ name: `${import_picocolors12.default.bold(g.serverName)} ${import_picocolors12.default.dim(`(configured in: ${agentNames})`)}`,
3111
2993
  value: g.serverName
3112
2994
  };
3113
2995
  });
@@ -3115,7 +2997,7 @@ var wizardManage = async (options = {}) => {
3115
2997
  name: `Back`,
3116
2998
  value: "__back__"
3117
2999
  });
3118
- chosenServerName = await select6({
3000
+ chosenServerName = await (0, import_prompts7.select)({
3119
3001
  message: "Select MCP server to manage or sync:",
3120
3002
  choices
3121
3003
  });
@@ -3132,7 +3014,7 @@ var wizardManage = async (options = {}) => {
3132
3014
  global: isGlobal,
3133
3015
  hasDivergence: targetGroup.hasDivergence
3134
3016
  });
3135
- const action = await select6({
3017
+ const action = await (0, import_prompts7.select)({
3136
3018
  message: `What would you like to do with [${chosenServerName}]?`,
3137
3019
  choices: [
3138
3020
  {
@@ -3168,7 +3050,7 @@ var wizardManage = async (options = {}) => {
3168
3050
  );
3169
3051
  continue;
3170
3052
  }
3171
- const candidateAgents = sortAgentsWithClusters(rawCandidateAgents, { global: isGlobal, cwd });
3053
+ const candidateAgents = agentConfigStore.sortAgentsByClusters(rawCandidateAgents, { global: isGlobal, cwd });
3172
3054
  const choices = buildLinkedAgentChoices({
3173
3055
  agents: candidateAgents,
3174
3056
  checkedAgents: [],
@@ -3180,7 +3062,7 @@ var wizardManage = async (options = {}) => {
3180
3062
  loop: false,
3181
3063
  validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
3182
3064
  });
3183
- const confirmed = await confirm6({
3065
+ const confirmed = await (0, import_prompts7.confirm)({
3184
3066
  message: `Confirm syncing configuration of [${chosenServerName}] to: ${selectedToSync.join(", ")}?`,
3185
3067
  default: true
3186
3068
  });
@@ -3196,7 +3078,7 @@ var wizardManage = async (options = {}) => {
3196
3078
  cwd
3197
3079
  });
3198
3080
  for (const item of syncResult.incompatible) {
3199
- logger.warn(`Skipping ${pc13.cyan(item.agent)}: ${item.reason}`);
3081
+ logger.warn(`Skipping ${import_picocolors12.default.cyan(item.agent)}: ${item.reason}`);
3200
3082
  }
3201
3083
  for (const res of syncResult.results) {
3202
3084
  if (syncResult.incompatible.some((i) => i.agent === res.agent)) {
@@ -3204,11 +3086,11 @@ var wizardManage = async (options = {}) => {
3204
3086
  }
3205
3087
  if (res.success) {
3206
3088
  logger.success(
3207
- `${pc13.cyan(res.agent)}: Successfully synced to ${pc13.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
3089
+ `${import_picocolors12.default.cyan(res.agent)}: Successfully synced to ${import_picocolors12.default.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
3208
3090
  );
3209
3091
  targetGroup.agents.push(res.agent);
3210
3092
  } else {
3211
- logger.error(`${pc13.cyan(res.agent)}: Sync failed - ${res.error}`);
3093
+ logger.error(`${import_picocolors12.default.cyan(res.agent)}: Sync failed - ${res.error}`);
3212
3094
  }
3213
3095
  }
3214
3096
  refreshGroupedServers();
@@ -3216,9 +3098,168 @@ var wizardManage = async (options = {}) => {
3216
3098
  }
3217
3099
  };
3218
3100
 
3101
+ // src/interactive/main-menu.ts
3102
+ var import_prompts10 = require("@inquirer/prompts");
3103
+ var import_picocolors15 = __toESM(require("picocolors"), 1);
3104
+
3105
+ // src/interactive/wizard-add.ts
3106
+ var import_prompts8 = require("@inquirer/prompts");
3107
+ var import_picocolors13 = __toESM(require("picocolors"), 1);
3108
+ var wizardAdd = async (initial = {}) => {
3109
+ const cwd = initial.cwd ?? process.cwd();
3110
+ logger.info(import_picocolors13.default.bold("Welcome to the MCP interactive add wizard"));
3111
+ let source = initial.source;
3112
+ if (!source) {
3113
+ const sourceType = await (0, import_prompts8.select)({
3114
+ message: "Select MCP server type:",
3115
+ choices: [
3116
+ {
3117
+ name: "npm package (run via npx)",
3118
+ value: "npm"
3119
+ },
3120
+ {
3121
+ name: "Remote MCP server (via HTTP / SSE URL)",
3122
+ value: "remote"
3123
+ },
3124
+ {
3125
+ name: "Local command / script / Docker (stdio)",
3126
+ value: "command"
3127
+ }
3128
+ ]
3129
+ });
3130
+ if (sourceType === "npm") {
3131
+ source = await (0, import_prompts8.input)({
3132
+ message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres):",
3133
+ validate: (val) => val.trim() ? true : "Package name cannot be empty"
3134
+ });
3135
+ } else if (sourceType === "remote") {
3136
+ source = await (0, import_prompts8.input)({
3137
+ message: "Enter remote server URL (e.g. https://mcp.example.com/sse):",
3138
+ validate: (val) => {
3139
+ const trimmed = val.trim();
3140
+ if (!trimmed) return "URL cannot be empty";
3141
+ if (!/^https?:\/\//i.test(trimmed)) return "Please enter a valid URL starting with http:// or https://";
3142
+ return true;
3143
+ }
3144
+ });
3145
+ } else {
3146
+ source = await (0, import_prompts8.input)({
3147
+ message: "Enter command and arguments (e.g. python -m my_mcp_server or docker run ...):",
3148
+ validate: (val) => val.trim() ? true : "Command cannot be empty"
3149
+ });
3150
+ }
3151
+ }
3152
+ source = source.trim();
3153
+ const parsed = parseMcpSource(source);
3154
+ let serverName = initial.name;
3155
+ if (!serverName) {
3156
+ serverName = await (0, import_prompts8.input)({
3157
+ message: "MCP server name:",
3158
+ default: parsed.inferredName,
3159
+ validate: (val) => val.trim() ? true : "Server name cannot be empty"
3160
+ });
3161
+ }
3162
+ serverName = serverName.trim();
3163
+ let transport = initial.transport;
3164
+ let headers = initial.headers ?? {};
3165
+ if (parsed.type === "remote") {
3166
+ if (!transport) {
3167
+ const isSseUrl = /\/sse\b/i.test(parsed.value);
3168
+ transport = await (0, import_prompts8.select)({
3169
+ message: "Select remote transport protocol:",
3170
+ choices: [
3171
+ { name: "HTTP", value: "http" },
3172
+ { name: "SSE (Server-Sent Events)", value: "sse" }
3173
+ ],
3174
+ default: isSseUrl ? "sse" : "http"
3175
+ });
3176
+ }
3177
+ if (Object.keys(headers).length === 0) {
3178
+ const needHeader = await (0, import_prompts8.confirm)({
3179
+ message: "Configure HTTP headers (e.g. Authorization Bearer token)?",
3180
+ default: false
3181
+ });
3182
+ if (needHeader) {
3183
+ headers = await promptHeadersConfig();
3184
+ }
3185
+ }
3186
+ }
3187
+ const { global: isGlobal, agents: selectedAgents } = await promptScopeAndAgents({
3188
+ cwd,
3189
+ defaultGlobal: initial.global,
3190
+ defaultAgents: initial.agents
3191
+ });
3192
+ let args = initial.args ?? [];
3193
+ if (parsed.type !== "remote") {
3194
+ args = await promptArgsConfig(args);
3195
+ }
3196
+ let env = initial.env ?? {};
3197
+ if (parsed.type !== "remote") {
3198
+ env = await promptEnvConfig(env);
3199
+ }
3200
+ console.log("\n" + import_picocolors13.default.cyan(import_picocolors13.default.bold("Configuration Preview:")));
3201
+ console.log(` ${import_picocolors13.default.bold("Server Name:")} ${import_picocolors13.default.green(serverName)}`);
3202
+ console.log(` ${import_picocolors13.default.bold("Server Type:")} ${import_picocolors13.default.magenta(parsed.type)}`);
3203
+ console.log(` ${import_picocolors13.default.bold("Source/Command:")} ${import_picocolors13.default.dim(source)}`);
3204
+ console.log(` ${import_picocolors13.default.bold("Scope:")} ${isGlobal ? import_picocolors13.default.yellow("Global") : import_picocolors13.default.blue("Project")}`);
3205
+ console.log(` ${import_picocolors13.default.bold("Target Agents:")} ${import_picocolors13.default.cyan(selectedAgents.join(", "))}`);
3206
+ if (args.length > 0) {
3207
+ console.log(` ${import_picocolors13.default.bold("Arguments:")} ${import_picocolors13.default.dim(args.join(" "))}`);
3208
+ }
3209
+ if (transport) {
3210
+ console.log(` ${import_picocolors13.default.bold("Transport:")} ${import_picocolors13.default.magenta(transport)}`);
3211
+ }
3212
+ const envKeys = Object.keys(env);
3213
+ if (envKeys.length > 0) {
3214
+ console.log(` ${import_picocolors13.default.bold("Environment Variables:")} ${import_picocolors13.default.dim(envKeys.join(", "))} (${envKeys.length})`);
3215
+ }
3216
+ const headerKeys = Object.keys(headers);
3217
+ if (headerKeys.length > 0) {
3218
+ console.log(` ${import_picocolors13.default.bold("Headers:")} ${import_picocolors13.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
3219
+ }
3220
+ console.log();
3221
+ const proceed = await (0, import_prompts8.confirm)({
3222
+ message: "Confirm installation with this configuration?",
3223
+ default: true
3224
+ });
3225
+ if (!proceed) {
3226
+ logger.warn("Operation cancelled");
3227
+ return false;
3228
+ }
3229
+ const result = installMcpServer({
3230
+ source,
3231
+ name: serverName,
3232
+ agents: selectedAgents,
3233
+ args,
3234
+ global: isGlobal,
3235
+ cwd,
3236
+ transport,
3237
+ headers,
3238
+ env
3239
+ });
3240
+ logger.info(
3241
+ `Writing ${import_picocolors13.default.bold(result.serverName)} to ${import_picocolors13.default.cyan(String(result.results.length))} agent config files...`
3242
+ );
3243
+ let allSuccess = true;
3244
+ for (const record of result.results) {
3245
+ if (record.success) {
3246
+ logger.success(
3247
+ `${import_picocolors13.default.cyan(record.agent)}: Successfully written to ${import_picocolors13.default.dim(record.path)}${formatCoHostedBadge("configured", record.coConfiguredAgents)}`
3248
+ );
3249
+ } else {
3250
+ allSuccess = false;
3251
+ logger.error(`${import_picocolors13.default.cyan(record.agent)}: Failed to write - ${record.error}`);
3252
+ }
3253
+ }
3254
+ if (allSuccess) {
3255
+ logger.success(import_picocolors13.default.bold(`MCP server "${serverName}" configured successfully!`));
3256
+ }
3257
+ return allSuccess;
3258
+ };
3259
+
3219
3260
  // src/interactive/wizard-remove.ts
3220
- import { confirm as confirm7, select as select7 } from "@inquirer/prompts";
3221
- import pc14 from "picocolors";
3261
+ var import_prompts9 = require("@inquirer/prompts");
3262
+ var import_picocolors14 = __toESM(require("picocolors"), 1);
3222
3263
  var wizardRemove = async (options = {}) => {
3223
3264
  const cwd = options.cwd ?? process.cwd();
3224
3265
  const isGlobal = await promptScope({
@@ -3226,19 +3267,18 @@ var wizardRemove = async (options = {}) => {
3226
3267
  defaultGlobal: options.global,
3227
3268
  message: "Select scope to remove MCP server from:"
3228
3269
  });
3229
- const installed = listInstalledMcpServers({ global: isGlobal, cwd });
3230
- if (installed.length === 0) {
3270
+ const serverMap = queryGroupedInstalledServers({ global: isGlobal, cwd });
3271
+ if (serverMap.size === 0) {
3231
3272
  logger.warn(`No installed MCP servers found in ${isGlobal ? "global" : "project"} scope`);
3232
3273
  return false;
3233
3274
  }
3234
- const serverMap = groupInstalledServersByName(installed);
3235
3275
  let serverName = options.name;
3236
3276
  if (!serverName) {
3237
3277
  const choices = Array.from(serverMap.values()).map((g) => ({
3238
- name: `${pc14.bold(g.serverName)} ${pc14.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
3278
+ name: `${import_picocolors14.default.bold(g.serverName)} ${import_picocolors14.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
3239
3279
  value: g.serverName
3240
3280
  }));
3241
- serverName = await select7({
3281
+ serverName = await (0, import_prompts9.select)({
3242
3282
  message: "Select MCP server to remove:",
3243
3283
  choices
3244
3284
  });
@@ -3248,7 +3288,7 @@ var wizardRemove = async (options = {}) => {
3248
3288
  logger.warn(`No agents found with [${serverName}] installed`);
3249
3289
  return false;
3250
3290
  }
3251
- const installedAgents = sortAgentsWithClusters(rawInstalledAgents, { global: isGlobal, cwd });
3291
+ const installedAgents = agentConfigStore.sortAgentsByClusters(rawInstalledAgents, { global: isGlobal, cwd });
3252
3292
  let targetAgents = options.agents;
3253
3293
  if (!targetAgents || targetAgents.length === 0) {
3254
3294
  const choices = buildLinkedAgentChoices({
@@ -3269,7 +3309,7 @@ var wizardRemove = async (options = {}) => {
3269
3309
  }
3270
3310
  targetAgents = validAgents;
3271
3311
  }
3272
- const confirmed = await confirm7({
3312
+ const confirmed = await (0, import_prompts9.confirm)({
3273
3313
  message: `Confirm removing MCP server [${serverName}] from ${targetAgents.join(", ")}?`,
3274
3314
  default: true
3275
3315
  });
@@ -3287,11 +3327,11 @@ var wizardRemove = async (options = {}) => {
3287
3327
  for (const res of results) {
3288
3328
  if (res.removed) {
3289
3329
  logger.success(
3290
- `${pc14.cyan(res.agent)}: Successfully removed from ${pc14.dim(res.path)}${formatCoHostedBadge("affected", res.coAffectedAgents)}`
3330
+ `${import_picocolors14.default.cyan(res.agent)}: Successfully removed from ${import_picocolors14.default.dim(res.path)}${formatCoHostedBadge("affected", res.coAffectedAgents)}`
3291
3331
  );
3292
3332
  removedCount++;
3293
3333
  } else if (res.error) {
3294
- logger.error(`${pc14.cyan(res.agent)}: Failed to remove - ${res.error}`);
3334
+ logger.error(`${import_picocolors14.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
3295
3335
  }
3296
3336
  }
3297
3337
  if (removedCount > 0) {
@@ -3305,12 +3345,12 @@ var wizardRemove = async (options = {}) => {
3305
3345
  // src/interactive/main-menu.ts
3306
3346
  var mainMenu = async () => {
3307
3347
  console.log();
3308
- console.log(pc15.bold(pc15.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
3309
- console.log(pc15.dim("Cross-platform MCP server configuration & synchronization tool"));
3348
+ console.log(import_picocolors15.default.bold(import_picocolors15.default.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
3349
+ console.log(import_picocolors15.default.dim("Cross-platform MCP server configuration & synchronization tool"));
3310
3350
  console.log();
3311
3351
  while (true) {
3312
3352
  try {
3313
- const action = await select8({
3353
+ const action = await (0, import_prompts10.select)({
3314
3354
  message: "Select an action:",
3315
3355
  choices: [
3316
3356
  {
@@ -3332,7 +3372,7 @@ var mainMenu = async () => {
3332
3372
  ]
3333
3373
  });
3334
3374
  if (action === "exit") {
3335
- console.log(pc15.dim("Goodbye!"));
3375
+ console.log(import_picocolors15.default.dim("Goodbye!"));
3336
3376
  break;
3337
3377
  }
3338
3378
  if (action === "add") {
@@ -3345,301 +3385,37 @@ var mainMenu = async () => {
3345
3385
  console.log();
3346
3386
  } catch (error) {
3347
3387
  if (error?.name === "ExitPromptError") {
3348
- console.log("\n" + pc15.dim("Exited."));
3388
+ console.log("\n" + import_picocolors15.default.dim("Exited."));
3349
3389
  break;
3350
3390
  }
3351
3391
  throw error;
3352
3392
  }
3353
3393
  }
3354
3394
  };
3355
-
3356
- // src/utils/resolve-transport.ts
3357
- var resolveTransport = (input7) => {
3358
- if (!input7) return void 0;
3359
- if (input7 === "http" || input7 === "sse") return input7;
3360
- throw new Error(`Unsupported transport "${input7}" (expected: http, sse)`);
3361
- };
3362
-
3363
- // src/cli/manage.ts
3364
- import { Command } from "commander";
3365
- import pc16 from "picocolors";
3366
-
3367
- // src/utils/parse-key-value-list.ts
3368
- var parseKeyValueList = (entries, separator) => {
3369
- if (!entries || entries.length === 0) return {};
3370
- const result = {};
3371
- for (const entry of entries) {
3372
- const splitIndex = entry.indexOf(separator);
3373
- if (splitIndex === -1) {
3374
- throw new Error(`Invalid entry "${entry}": expected "${separator}" separator`);
3375
- }
3376
- const key = entry.slice(0, splitIndex).trim();
3377
- const value = entry.slice(splitIndex + separator.length).trim();
3378
- if (!key) throw new Error(`Invalid entry "${entry}": empty key`);
3379
- result[key] = value;
3380
- }
3381
- return result;
3382
- };
3383
-
3384
- // src/cli/manage.ts
3385
- var requireTargetServerGroup = (serverName, scope) => {
3386
- const installed = listInstalledMcpServers(scope);
3387
- const grouped = groupInstalledServersByName(installed);
3388
- const targetGroup = grouped.get(serverName);
3389
- if (!targetGroup) {
3390
- logger.error(
3391
- `MCP server "${serverName}" is not configured in ${scope.global ? "global" : "project"} scope.`
3392
- );
3393
- process.exitCode = 1;
3394
- return void 0;
3395
- }
3396
- return targetGroup;
3397
- };
3398
- var mcpManageCommand = new Command("manage").description("Inspect, modify, and sync installed MCP servers across coding agents").argument("[server-name]", "Optional server name to inspect or manage").option("-a, --agent <agents...>", "Target specific agents for update").option("-g, --global", "Manage global scope servers instead of project").option("-t, --transport <type>", "Transport type for remote servers (http or sse)").option("--header <header...>", "HTTP header (Header: Value), repeatable").option("--clear-headers", "Clear all HTTP headers for remote servers").option("--env <env...>", "Env var for stdio servers (KEY=VALUE), repeatable").option("--clear-env", "Clear all environment variables for stdio servers").option("--args <args...>", "CLI arguments for stdio/package servers").option("--clear-args", "Clear all arguments for stdio/package servers").option("--command <command>", "Executable command for stdio servers").option("--url <url>", "Remote endpoint URL").option("-y, --yes", "Skip interactive prompts").action(async (serverName, options) => {
3399
- try {
3400
- const cwd = process.cwd();
3401
- const isGlobal = Boolean(options.global);
3402
- const hasModifications = options.command !== void 0 || options.args !== void 0 || Boolean(options.clearArgs) || options.env !== void 0 || Boolean(options.clearEnv) || options.header !== void 0 || Boolean(options.clearHeaders) || options.url !== void 0 || options.transport !== void 0;
3403
- const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
3404
- if (hasModifications) {
3405
- if (options.url !== void 0 && options.command !== void 0) {
3406
- logger.error('Cannot specify both "--url" (remote) and "--command" (stdio) simultaneously.');
3407
- process.exitCode = 1;
3408
- return;
3409
- }
3410
- if (!serverName) {
3411
- logger.error('Missing required argument: "server-name" when passing modification flags.');
3412
- process.exitCode = 1;
3413
- return;
3414
- }
3415
- const targetGroup = requireTargetServerGroup(serverName, { global: isGlobal, cwd });
3416
- if (!targetGroup) {
3417
- return;
3418
- }
3419
- const isCurrentRemote = Boolean(targetGroup.config.url && targetGroup.config.url.length > 0);
3420
- const willBeRemote = options.url !== void 0 ? true : options.command !== void 0 ? false : isCurrentRemote;
3421
- if (willBeRemote) {
3422
- const ignoredStdioFlags = [];
3423
- if (options.env !== void 0) ignoredStdioFlags.push("--env");
3424
- if (options.clearEnv) ignoredStdioFlags.push("--clear-env");
3425
- if (options.args !== void 0) ignoredStdioFlags.push("--args");
3426
- if (options.clearArgs) ignoredStdioFlags.push("--clear-args");
3427
- if (ignoredStdioFlags.length > 0) {
3428
- const hint = options.url !== void 0 ? "When configuring a remote server, stdio flags are ignored." : "Use --command to switch to stdio mode.";
3429
- logger.warn(
3430
- `Server "${serverName}" is a remote server. The following stdio flags will be ignored: ${ignoredStdioFlags.join(", ")}. ${hint}`
3431
- );
3432
- }
3433
- } else {
3434
- const ignoredRemoteFlags = [];
3435
- if (options.header !== void 0) ignoredRemoteFlags.push("--header");
3436
- if (options.clearHeaders) ignoredRemoteFlags.push("--clear-headers");
3437
- if (options.transport !== void 0) ignoredRemoteFlags.push("--transport");
3438
- if (ignoredRemoteFlags.length > 0) {
3439
- const hint = options.command !== void 0 ? "When configuring a stdio server, remote flags are ignored." : "Use --url to switch to remote mode.";
3440
- logger.warn(
3441
- `Server "${serverName}" is a stdio server. The following remote flags will be ignored: ${ignoredRemoteFlags.join(", ")}. ${hint}`
3442
- );
3443
- }
3444
- }
3445
- const incomingDelta = {};
3446
- if (options.command !== void 0) {
3447
- incomingDelta.command = options.command;
3448
- }
3449
- if (options.clearArgs) {
3450
- incomingDelta.args = void 0;
3451
- }
3452
- if (options.args !== void 0) {
3453
- incomingDelta.args = options.args;
3454
- }
3455
- if (options.url !== void 0) {
3456
- incomingDelta.url = options.url;
3457
- }
3458
- if (options.transport !== void 0) {
3459
- incomingDelta.type = resolveTransport(options.transport);
3460
- }
3461
- if (options.clearEnv) {
3462
- incomingDelta.env = void 0;
3463
- }
3464
- if (options.env !== void 0) {
3465
- const parsedEnv = parseKeyValueList(options.env, "=");
3466
- const baseEnv = options.clearEnv ? {} : targetGroup.config.env ?? {};
3467
- incomingDelta.env = { ...baseEnv, ...parsedEnv };
3468
- }
3469
- if (options.clearHeaders) {
3470
- incomingDelta.headers = void 0;
3471
- }
3472
- if (options.header !== void 0) {
3473
- const parsedHeaders = parseKeyValueList(options.header, ":");
3474
- const baseHeaders = options.clearHeaders ? {} : targetGroup.config.headers ?? {};
3475
- incomingDelta.headers = { ...baseHeaders, ...parsedHeaders };
3476
- }
3477
- let targetAgents = targetGroup.agents;
3478
- if (options.agent !== void 0) {
3479
- const parsed = parseMcpAgentList(options.agent);
3480
- if (!parsed || parsed.length === 0) {
3481
- logger.error(`No valid agents recognized from: "${options.agent.join(", ")}".`);
3482
- process.exitCode = 1;
3483
- return;
3484
- }
3485
- targetAgents = parsed;
3486
- }
3487
- const updateResult = updateMcpServer({
3488
- serverName,
3489
- config: incomingDelta,
3490
- previousConfig: targetGroup.config,
3491
- agents: targetAgents,
3492
- global: isGlobal,
3493
- cwd
3494
- });
3495
- for (const item of updateResult.incompatible) {
3496
- logger.warn(`Skipping ${pc16.cyan(item.agent)}: ${item.reason}`);
3497
- }
3498
- const attemptedResults = updateResult.results.filter(
3499
- (r) => !updateResult.incompatible.some((i) => i.agent === r.agent)
3500
- );
3501
- if (attemptedResults.length === 0) {
3502
- const requestedTransport = updateResult.config.url ? updateResult.config.type ?? "http" : "stdio";
3503
- logger.error(
3504
- `None of the target agents support ${requestedTransport} transport. Update aborted.`
3505
- );
3506
- process.exitCode = 1;
3507
- return;
3508
- }
3509
- logger.info(
3510
- `Updating ${pc16.bold(serverName)} across ${pc16.cyan(String(attemptedResults.length))} agent(s)...`
3511
- );
3512
- let allSuccess = true;
3513
- for (const res of attemptedResults) {
3514
- if (res.success) {
3515
- logger.success(`${pc16.cyan(res.agent)}: Successfully updated in ${pc16.dim(res.path)}`);
3516
- logCoHostedNotice("configured", res.coConfiguredAgents);
3517
- } else {
3518
- allSuccess = false;
3519
- logger.error(`${pc16.cyan(res.agent)}: Update failed - ${res.error}`);
3520
- }
3521
- }
3522
- if (!allSuccess) {
3523
- process.exitCode = 1;
3524
- }
3525
- return;
3526
- }
3527
- if (!isInteractive) {
3528
- if (!serverName) {
3529
- logger.error(
3530
- 'Missing required argument: "server-name" for non-interactive manage command. Specify a server name or use interactive terminal.'
3531
- );
3532
- process.exitCode = 1;
3533
- return;
3534
- }
3535
- const targetGroup = requireTargetServerGroup(serverName, { global: isGlobal, cwd });
3536
- if (!targetGroup) {
3537
- return;
3538
- }
3539
- displayServerDetails({
3540
- serverName,
3541
- config: targetGroup.config,
3542
- agents: targetGroup.agents,
3543
- global: isGlobal,
3544
- hasDivergence: targetGroup.hasDivergence
3545
- });
3546
- return;
3547
- }
3548
- await wizardManage({
3549
- global: options.global,
3550
- serverName
3551
- });
3552
- } catch (error) {
3553
- if (error && typeof error === "object" && "name" in error && error.name === "ExitPromptError") {
3554
- process.exit(0);
3555
- }
3556
- logger.error(toErrorMessage(error));
3557
- process.exitCode = 1;
3558
- }
3559
- });
3560
-
3561
- export {
3562
- mcpAgents,
3563
- mcpAgentAliases,
3564
- getMcpAgentConfig,
3565
- getMcpAgentTypes,
3566
- isMcpAgentType,
3567
- resolveMcpAgentAlias,
3568
- isMcpTransportSupported,
3569
- detectProjectInstalledMcpAgents,
3570
- detectGloballyInstalledMcpAgents,
3571
- getMcpAgentsSupportingProjectScope,
3572
- DEFAULT_REMOTE_TRANSPORT,
3573
- NPX_COMMAND,
3574
- NPX_DASH_Y,
3575
- buildMcpServerConfig,
3576
- isRemoteServerConfig,
3577
- isStdioServerConfig,
3578
- parseServerConfig,
3579
- readConfigFile,
3580
- writeServerToConfigFile,
3581
- removeServerFromConfigFile,
3582
- listServersInConfigFile,
3583
- resolveMcpConfigTarget,
3584
- AgentConfigStore,
3585
- agentConfigStore,
3586
- toErrorMessage,
3587
- getCandidateAgentsForScope,
3588
- getCoHostedAgents,
3589
- resolveConfigClusters,
3590
- sortAgentsWithClusters,
3591
- transformServerConfig,
3592
- createAgentTransform,
3593
- transformServerConfigForAgent,
3594
- installMcpServerForAgent,
3595
- installMcpServerForAgents,
3596
- installToCompatibleAgents,
3597
- parseMcpAgentList,
3598
- resolveTargetAgents,
3599
- extractPackageName,
3600
- parseMcpSource,
3601
- isRemoteMcpSource,
3602
- installMcpServer,
3603
- listInstalledMcpServers,
3604
- removeMcpServerFromAgent,
3605
- removeMcpServer,
3606
- toRemoteServerConfig,
3607
- toStdioServerConfig,
3608
- detectUpdateTransition,
3609
- sanitizeUpdatedServerConfig,
3610
- updateMcpServer,
3611
- logger,
3612
- logCoHostedNotice,
3395
+ // Annotate the CommonJS export names for ESM import in node:
3396
+ 0 && (module.exports = {
3613
3397
  buildLinkedAgentChoices,
3398
+ formatArgsString,
3399
+ formatEnvText,
3400
+ formatHeadersText,
3614
3401
  linkedCheckbox,
3615
- promptScope,
3616
- promptScopeAndAgents,
3402
+ mainMenu,
3617
3403
  parseArgsString,
3404
+ parseEnvText,
3405
+ parseHeadersText,
3618
3406
  promptArgsConfig,
3619
- formatArgsString,
3620
3407
  promptEditArgs,
3621
- SECRET_KEY_PATTERN,
3622
- maskSecretValue,
3623
- SECRET_HEADER_PATTERN,
3624
- maskSecretHeader,
3408
+ promptEditEnvConfig,
3409
+ promptEditHeadersConfig,
3625
3410
  promptEditKeyValueConfig,
3626
- formatEnvText,
3627
- parseEnvText,
3411
+ promptEditorText,
3628
3412
  promptEnvConfig,
3629
- promptEditEnvConfig,
3630
- formatHeadersText,
3631
- parseHeadersText,
3632
3413
  promptHeadersConfig,
3633
- promptEditHeadersConfig,
3634
- wizardAdd,
3635
- displayServerDetails,
3636
- normalizeServerConfig,
3637
- groupInstalledServersByName,
3414
+ promptScope,
3415
+ promptScopeAndAgents,
3638
3416
  promptSwitchServerType,
3417
+ readMultilineTextFromTerminal,
3418
+ wizardAdd,
3639
3419
  wizardManage,
3640
- wizardRemove,
3641
- mainMenu,
3642
- resolveTransport,
3643
- parseKeyValueList,
3644
- mcpManageCommand
3645
- };
3420
+ wizardRemove
3421
+ });