@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.
- package/LICENSE +21 -0
- package/README.md +22 -14
- package/dist/chunk-AWD3VQ3S.js +1624 -0
- package/dist/chunk-O3BRJFEC.js +1898 -0
- package/dist/cli.cjs +1057 -979
- package/dist/cli.js +188 -17
- package/dist/index.cjs +702 -2478
- package/dist/index.d.cts +152 -452
- package/dist/index.d.ts +152 -452
- package/dist/index.js +9 -85
- package/dist/{chunk-BUKA3NPJ.js → interactive.cjs} +1555 -1779
- package/dist/interactive.d.cts +228 -0
- package/dist/interactive.d.ts +228 -0
- package/dist/interactive.js +53 -0
- package/dist/types-lEP3zGvf.d.cts +128 -0
- package/dist/types-lEP3zGvf.d.ts +128 -0
- package/package.json +31 -1
|
@@ -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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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) =>
|
|
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 =
|
|
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 (!
|
|
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
|
-
|
|
727
|
-
|
|
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 (!
|
|
761
|
-
const raw =
|
|
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 =
|
|
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
|
-
|
|
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 (!
|
|
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)
|
|
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
|
-
|
|
785
|
-
|
|
991
|
+
var import_node_fs5 = require("fs");
|
|
992
|
+
var import_yaml = require("yaml");
|
|
786
993
|
var readYamlConfig = (filePath) => {
|
|
787
|
-
if (!
|
|
788
|
-
const raw =
|
|
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 =
|
|
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
|
-
|
|
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 (!
|
|
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)
|
|
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/
|
|
1247
|
-
var
|
|
1248
|
-
|
|
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
|
|
1251
|
-
const
|
|
1252
|
-
|
|
1253
|
-
|
|
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
|
|
1273
|
-
|
|
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
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
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
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
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
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
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
|
|
1352
|
-
|
|
1353
|
-
|
|
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
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
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
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
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
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
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
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
};
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
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
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
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
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
const
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
if (
|
|
1454
|
-
|
|
1455
|
-
|
|
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
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
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
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
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
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
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
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1500
|
-
value:
|
|
1501
|
-
|
|
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/
|
|
1513
|
-
var
|
|
1514
|
-
|
|
1515
|
-
|
|
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
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
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/
|
|
1541
|
-
var
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
const
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1562
|
-
|
|
1563
|
-
const
|
|
1564
|
-
const
|
|
1565
|
-
const
|
|
1566
|
-
|
|
1567
|
-
const
|
|
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
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
coAffectedAgents: removed && coHosted.length > 0 ? coHosted : void 0
|
|
1668
|
+
type: transport,
|
|
1669
|
+
url: remoteUrl,
|
|
1670
|
+
headers
|
|
1573
1671
|
};
|
|
1574
|
-
}
|
|
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
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
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
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
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
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
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/
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
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/
|
|
1739
|
-
|
|
1740
|
-
var
|
|
1741
|
-
|
|
1742
|
-
|
|
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
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
return
|
|
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/
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
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
|
|
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/
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
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
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
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
|
-
|
|
2024
|
-
|
|
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/
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
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 =
|
|
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: ${
|
|
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
|
-
|
|
2146
|
-
|
|
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
|
-
|
|
2166
|
-
|
|
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
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
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(
|
|
2186
|
+
console.log(import_picocolors6.default.cyan(`
|
|
2174
2187
|
${message}`));
|
|
2175
|
-
console.log(
|
|
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(
|
|
2249
|
+
console.log(import_picocolors7.default.dim(` No ${options.itemsNoun} configured.`));
|
|
2237
2250
|
} else {
|
|
2238
|
-
console.log(
|
|
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(` ${
|
|
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
|
|
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
|
|
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
|
|
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"}: ${
|
|
2333
|
+
logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${import_picocolors7.default.cyan(trimmedKey)}`);
|
|
2321
2334
|
} else if (choice === "delete") {
|
|
2322
|
-
const toDelete = await
|
|
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: ${
|
|
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
|
|
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 ${
|
|
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
|
|
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 ${
|
|
2418
|
+
logger.info(`Includes ${import_picocolors8.default.cyan(String(initialCount))} preset environment variables`);
|
|
2406
2419
|
}
|
|
2407
|
-
const mode = await
|
|
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 ${
|
|
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(` ${
|
|
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
|
|
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
|
|
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
|
|
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: ${
|
|
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
|
-
|
|
2498
|
-
|
|
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
|
|
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 ${
|
|
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(` ${
|
|
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
|
|
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
|
|
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
|
|
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: ${
|
|
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/
|
|
2621
|
-
var
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
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
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
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
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
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 (!
|
|
2739
|
-
|
|
2740
|
-
return false;
|
|
2653
|
+
if (!needArgs) {
|
|
2654
|
+
return [];
|
|
2741
2655
|
}
|
|
2742
|
-
const
|
|
2743
|
-
|
|
2744
|
-
|
|
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
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
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
|
|
2675
|
+
return parseArgsString(trimmed);
|
|
2771
2676
|
};
|
|
2772
2677
|
|
|
2773
2678
|
// src/interactive/wizard-manage.ts
|
|
2774
|
-
|
|
2775
|
-
|
|
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
|
-
|
|
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" +
|
|
2692
|
+
console.log("\n" + import_picocolors10.default.cyan(import_picocolors10.default.bold(`${titlePrefix}: [${serverName}]`)));
|
|
2788
2693
|
if (isGlobal !== void 0) {
|
|
2789
|
-
console.log(` ${
|
|
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
|
-
` ${
|
|
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
|
-
` ${
|
|
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(` ${
|
|
2804
|
-
console.log(` ${
|
|
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(` ${
|
|
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(` ${
|
|
2714
|
+
console.log(` ${import_picocolors10.default.bold(k)}: ${import_picocolors10.default.dim(maskSecretHeader(k, v))}`);
|
|
2810
2715
|
}
|
|
2811
2716
|
} else {
|
|
2812
|
-
console.log(` ${
|
|
2717
|
+
console.log(` ${import_picocolors10.default.bold("Headers:")} ${import_picocolors10.default.dim("(none)")}`);
|
|
2813
2718
|
}
|
|
2814
2719
|
} else {
|
|
2815
|
-
console.log(` ${
|
|
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(` ${
|
|
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(` ${
|
|
2821
|
-
for (const [k, v] of Object.entries(config.env ?? {})) {
|
|
2822
|
-
console.log(` ${
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 ${
|
|
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
|
|
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
|
-
`${
|
|
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(`${
|
|
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
|
|
3086
|
-
if (
|
|
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
|
|
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: `${
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 ${
|
|
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
|
-
`${
|
|
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(`${
|
|
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
|
-
|
|
3221
|
-
|
|
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
|
|
3230
|
-
if (
|
|
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: `${
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
`${
|
|
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(`${
|
|
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(
|
|
3309
|
-
console.log(
|
|
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
|
|
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(
|
|
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" +
|
|
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
|
-
|
|
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
|
-
|
|
3616
|
-
promptScopeAndAgents,
|
|
3402
|
+
mainMenu,
|
|
3617
3403
|
parseArgsString,
|
|
3404
|
+
parseEnvText,
|
|
3405
|
+
parseHeadersText,
|
|
3618
3406
|
promptArgsConfig,
|
|
3619
|
-
formatArgsString,
|
|
3620
3407
|
promptEditArgs,
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
SECRET_HEADER_PATTERN,
|
|
3624
|
-
maskSecretHeader,
|
|
3408
|
+
promptEditEnvConfig,
|
|
3409
|
+
promptEditHeadersConfig,
|
|
3625
3410
|
promptEditKeyValueConfig,
|
|
3626
|
-
|
|
3627
|
-
parseEnvText,
|
|
3411
|
+
promptEditorText,
|
|
3628
3412
|
promptEnvConfig,
|
|
3629
|
-
promptEditEnvConfig,
|
|
3630
|
-
formatHeadersText,
|
|
3631
|
-
parseHeadersText,
|
|
3632
3413
|
promptHeadersConfig,
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
displayServerDetails,
|
|
3636
|
-
normalizeServerConfig,
|
|
3637
|
-
groupInstalledServersByName,
|
|
3414
|
+
promptScope,
|
|
3415
|
+
promptScopeAndAgents,
|
|
3638
3416
|
promptSwitchServerType,
|
|
3417
|
+
readMultilineTextFromTerminal,
|
|
3418
|
+
wizardAdd,
|
|
3639
3419
|
wizardManage,
|
|
3640
|
-
wizardRemove
|
|
3641
|
-
|
|
3642
|
-
resolveTransport,
|
|
3643
|
-
parseKeyValueList,
|
|
3644
|
-
mcpManageCommand
|
|
3645
|
-
};
|
|
3420
|
+
wizardRemove
|
|
3421
|
+
});
|