@wuyax/mcps 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs ADDED
@@ -0,0 +1,2534 @@
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 __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+
25
+ // src/cli.ts
26
+ var import_commander4 = require("commander");
27
+
28
+ // src/cli/add.ts
29
+ var import_commander = require("commander");
30
+ var import_picocolors11 = __toESM(require("picocolors"), 1);
31
+
32
+ // src/agents.ts
33
+ var import_node_fs = require("fs");
34
+ var import_node_os = require("os");
35
+ var import_node_path = require("path");
36
+ var home = (0, import_node_os.homedir)();
37
+ var getPlatformPaths = () => {
38
+ const currentPlatform = (0, import_node_os.platform)();
39
+ if (currentPlatform === "win32") {
40
+ const appData = process.env.APPDATA || (0, import_node_path.join)(home, "AppData", "Roaming");
41
+ return {
42
+ appSupport: appData,
43
+ vscodePath: (0, import_node_path.join)(appData, "Code", "User"),
44
+ traePath: (0, import_node_path.join)(appData, "Trae", "User"),
45
+ gooseConfigPath: (0, import_node_path.join)(appData, "Block", "goose", "config", "config.yaml"),
46
+ zedConfigPath: (0, import_node_path.join)(appData, "Zed", "settings.json")
47
+ };
48
+ }
49
+ if (currentPlatform === "darwin") {
50
+ return {
51
+ appSupport: (0, import_node_path.join)(home, "Library", "Application Support"),
52
+ vscodePath: (0, import_node_path.join)(home, "Library", "Application Support", "Code", "User"),
53
+ traePath: (0, import_node_path.join)(home, "Library", "Application Support", "Trae", "User"),
54
+ gooseConfigPath: (0, import_node_path.join)(home, ".config", "goose", "config.yaml"),
55
+ zedConfigPath: (0, import_node_path.join)(home, ".config", "zed", "settings.json")
56
+ };
57
+ }
58
+ const configDir = process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config");
59
+ return {
60
+ appSupport: configDir,
61
+ vscodePath: (0, import_node_path.join)(configDir, "Code", "User"),
62
+ traePath: (0, import_node_path.join)(configDir, "Trae", "User"),
63
+ gooseConfigPath: (0, import_node_path.join)(configDir, "goose", "config.yaml"),
64
+ zedConfigPath: (0, import_node_path.join)(configDir, "zed", "settings.json")
65
+ };
66
+ };
67
+ var { appSupport, vscodePath, traePath, gooseConfigPath, zedConfigPath } = getPlatformPaths();
68
+ 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");
69
+ 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");
70
+ var antigravityMcpConfigPath = (0, import_node_path.join)(home, ".gemini", "config", "mcp_config.json");
71
+ var augmentConfigDir = process.env.AUGMENT_HOME?.trim() || (0, import_node_path.join)(home, ".augment");
72
+ 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");
73
+ var clineDir = process.env.CLINE_DIR || (0, import_node_path.join)(home, ".cline");
74
+ var clineCliConfigPath = (0, import_node_path.join)(clineDir, "mcp.json");
75
+ var clineExtensionConfigPath = (0, import_node_path.join)(
76
+ vscodePath,
77
+ "globalStorage",
78
+ "saoudrizwan.claude-dev",
79
+ "settings",
80
+ "cline_mcp_settings.json"
81
+ );
82
+ var copilotConfigPath = (0, import_node_path.join)(
83
+ process.env.COPILOT_HOME?.trim() || (0, import_node_path.join)(home, ".copilot"),
84
+ "mcp-config.json"
85
+ );
86
+ var grokConfigPath = (0, import_node_path.join)(
87
+ process.env.GROK_HOME?.trim() || (0, import_node_path.join)(home, ".grok"),
88
+ "config.toml"
89
+ );
90
+ var kimiCodeConfigPath = (0, import_node_path.join)(
91
+ process.env.KIMI_CODE_HOME?.trim() || (0, import_node_path.join)(home, ".kimi-code"),
92
+ "mcp.json"
93
+ );
94
+ var kiroConfigPath = (0, import_node_path.join)(
95
+ process.env.KIRO_HOME?.trim() || (0, import_node_path.join)(home, ".kiro"),
96
+ "settings",
97
+ "mcp.json"
98
+ );
99
+ var qoderConfigPath = (0, import_node_path.join)(
100
+ process.env.QODER_HOME?.trim() || (0, import_node_path.join)(home, ".qoder"),
101
+ "settings.json"
102
+ );
103
+ var qwenCodeConfigPath = (0, import_node_path.join)(
104
+ process.env.QWEN_CODE_HOME?.trim() || process.env.QWEN_HOME?.trim() || (0, import_node_path.join)(home, ".qwen"),
105
+ "settings.json"
106
+ );
107
+ 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");
108
+ var ALL_TRANSPORTS = ["stdio", "http", "sse"];
109
+ var mcpAgents = {
110
+ // https://ampcode.com/docs/markdown/customize/mcp
111
+ amp: {
112
+ name: "amp",
113
+ displayName: "Amp",
114
+ globalConfigPath: ampGlobalConfigPath,
115
+ projectConfigPath: ".amp/settings.json",
116
+ configKey: "amp.mcpServers",
117
+ format: "jsonc",
118
+ supportedTransports: ALL_TRANSPORTS,
119
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(ampConfigDir) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".amp")),
120
+ 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")),
121
+ resolveConfigPath: ({ global: isGlobal, cwd }) => {
122
+ if (isGlobal) {
123
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(ampConfigDir, "settings.jsonc"))) {
124
+ return (0, import_node_path.join)(ampConfigDir, "settings.jsonc");
125
+ }
126
+ return ampGlobalConfigPath;
127
+ }
128
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".amp", "settings.jsonc"))) {
129
+ return (0, import_node_path.join)(cwd, ".amp", "settings.jsonc");
130
+ }
131
+ return (0, import_node_path.join)(cwd, ".amp", "settings.json");
132
+ },
133
+ transformDialect: "amp"
134
+ },
135
+ antigravity: {
136
+ name: "antigravity",
137
+ displayName: "Antigravity",
138
+ globalConfigPath: antigravityMcpConfigPath,
139
+ projectConfigPath: ".agents/mcp_config.json",
140
+ configKey: "mcpServers",
141
+ format: "jsonc",
142
+ supportedTransports: ALL_TRANSPORTS,
143
+ 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")),
144
+ 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"))
145
+ },
146
+ // https://antigravity.google/docs/cli/mcp/
147
+ "antigravity-cli": {
148
+ name: "antigravity-cli",
149
+ displayName: "Antigravity CLI",
150
+ globalConfigPath: antigravityMcpConfigPath,
151
+ projectConfigPath: ".agents/mcp_config.json",
152
+ configKey: "mcpServers",
153
+ format: "jsonc",
154
+ supportedTransports: ALL_TRANSPORTS,
155
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".gemini", "antigravity-cli")),
156
+ 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"))
157
+ },
158
+ // https://docs.augmentcode.com/cli/integrations.md
159
+ augment: {
160
+ name: "augment",
161
+ displayName: "Augment",
162
+ globalConfigPath: augmentGlobalConfigPath,
163
+ projectConfigPath: ".augment/settings.json",
164
+ configKey: "mcpServers",
165
+ format: "jsonc",
166
+ supportedTransports: ALL_TRANSPORTS,
167
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(augmentConfigDir) || (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".augment")),
168
+ 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")),
169
+ resolveConfigPath: ({ global: isGlobal, cwd }) => {
170
+ if (isGlobal) {
171
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(augmentConfigDir, "settings.jsonc"))) {
172
+ return (0, import_node_path.join)(augmentConfigDir, "settings.jsonc");
173
+ }
174
+ return augmentGlobalConfigPath;
175
+ }
176
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".augment", "settings.jsonc"))) {
177
+ return (0, import_node_path.join)(cwd, ".augment", "settings.jsonc");
178
+ }
179
+ return (0, import_node_path.join)(cwd, ".augment", "settings.json");
180
+ },
181
+ transformDialect: "augment"
182
+ },
183
+ cline: {
184
+ name: "cline",
185
+ displayName: "Cline (VSCode extension)",
186
+ globalConfigPath: clineExtensionConfigPath,
187
+ projectConfigPath: ".cline/mcp.json",
188
+ configKey: "mcpServers",
189
+ format: "jsonc",
190
+ supportedTransports: ALL_TRANSPORTS,
191
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(clineExtensionConfigPath),
192
+ 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")),
193
+ resolveConfigPath: ({ global: isGlobal, cwd }) => {
194
+ if (isGlobal) {
195
+ return clineExtensionConfigPath;
196
+ }
197
+ return (0, import_node_path.join)(cwd, ".cline", "mcp.json");
198
+ },
199
+ transformDialect: "cline"
200
+ },
201
+ // https://docs.cline.bot/mcp/mcp-overview.md
202
+ "cline-cli": {
203
+ name: "cline-cli",
204
+ displayName: "Cline CLI",
205
+ globalConfigPath: clineCliConfigPath,
206
+ projectConfigPath: ".cline/mcp.json",
207
+ configKey: "mcpServers",
208
+ format: "jsonc",
209
+ supportedTransports: ALL_TRANSPORTS,
210
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(clineDir),
211
+ 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")),
212
+ resolveConfigPath: ({ global: isGlobal, cwd }) => {
213
+ if (isGlobal) {
214
+ return clineCliConfigPath;
215
+ }
216
+ return (0, import_node_path.join)(cwd, ".cline", "mcp.json");
217
+ },
218
+ transformDialect: "cline"
219
+ },
220
+ // https://code.claude.com/docs/en/mcp-quickstart#edit-mcp-json-directly
221
+ "claude-code": {
222
+ name: "claude-code",
223
+ displayName: "Claude Code",
224
+ globalConfigPath: (0, import_node_path.join)(home, ".claude.json"),
225
+ projectConfigPath: ".mcp.json",
226
+ configKey: "mcpServers",
227
+ format: "jsonc",
228
+ supportedTransports: ALL_TRANSPORTS,
229
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".claude.json")),
230
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".mcp.json"))
231
+ },
232
+ "claude-desktop": {
233
+ name: "claude-desktop",
234
+ displayName: "Claude Desktop",
235
+ globalConfigPath: (0, import_node_path.join)(appSupport, "Claude", "claude_desktop_config.json"),
236
+ configKey: "mcpServers",
237
+ format: "jsonc",
238
+ supportedTransports: ["stdio"],
239
+ unsupportedTransportMessage: "Claude Desktop currently supports only stdio MCP servers. Use a package name or command instead of a URL.",
240
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(appSupport, "Claude", "claude_desktop_config.json"))
241
+ },
242
+ // https://learn.chatgpt.com/docs/extend/mcp?surface=app
243
+ codex: {
244
+ name: "codex",
245
+ displayName: "Codex",
246
+ globalConfigPath: (0, import_node_path.join)(process.env.CODEX_HOME?.trim() || (0, import_node_path.join)(home, ".codex"), "config.toml"),
247
+ projectConfigPath: ".codex/config.toml",
248
+ configKey: "mcp_servers",
249
+ format: "toml",
250
+ supportedTransports: ALL_TRANSPORTS,
251
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(process.env.CODEX_HOME?.trim() || (0, import_node_path.join)(home, ".codex")),
252
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".codex", "config.toml")),
253
+ transformDialect: "augment"
254
+ },
255
+ // https://cursor.com/help/customization/mcp
256
+ cursor: {
257
+ name: "cursor",
258
+ displayName: "Cursor",
259
+ globalConfigPath: (0, import_node_path.join)(home, ".cursor", "mcp.json"),
260
+ projectConfigPath: ".cursor/mcp.json",
261
+ configKey: "mcpServers",
262
+ format: "jsonc",
263
+ supportedTransports: ALL_TRANSPORTS,
264
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".cursor")),
265
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".cursor", "mcp.json"))
266
+ },
267
+ "gemini-cli": {
268
+ name: "gemini-cli",
269
+ displayName: "Gemini CLI",
270
+ globalConfigPath: (0, import_node_path.join)(home, ".gemini", "settings.json"),
271
+ projectConfigPath: ".gemini/settings.json",
272
+ configKey: "mcpServers",
273
+ format: "jsonc",
274
+ supportedTransports: ALL_TRANSPORTS,
275
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".gemini")),
276
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".gemini", "settings.json"))
277
+ },
278
+ // https://docs.x.ai/build/features/mcp-servers.md
279
+ grok: {
280
+ name: "grok",
281
+ displayName: "Grok",
282
+ globalConfigPath: grokConfigPath,
283
+ projectConfigPath: ".grok/config.toml",
284
+ configKey: "mcp_servers",
285
+ format: "toml",
286
+ supportedTransports: ALL_TRANSPORTS,
287
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(grokConfigPath) || (0, import_node_fs.existsSync)(process.env.GROK_HOME?.trim() || (0, import_node_path.join)(home, ".grok")),
288
+ 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")),
289
+ transformDialect: "grok"
290
+ },
291
+ // https://goose-docs.ai/docs/guides/config-files/
292
+ goose: {
293
+ name: "goose",
294
+ displayName: "Goose",
295
+ globalConfigPath: gooseConfigPath,
296
+ projectConfigPath: ".goose/config.yaml",
297
+ configKey: "extensions",
298
+ format: "yaml",
299
+ supportedTransports: ALL_TRANSPORTS,
300
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(gooseConfigPath),
301
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".goose", "config.yaml")),
302
+ transformDialect: "goose"
303
+ },
304
+ "github-copilot-cli": {
305
+ name: "github-copilot-cli",
306
+ displayName: "GitHub Copilot CLI",
307
+ globalConfigPath: copilotConfigPath,
308
+ projectConfigPath: ".mcp.json",
309
+ configKey: "mcpServers",
310
+ format: "jsonc",
311
+ supportedTransports: ALL_TRANSPORTS,
312
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(copilotConfigPath) || (0, import_node_fs.existsSync)(process.env.COPILOT_HOME?.trim() || (0, import_node_path.join)(home, ".copilot")),
313
+ 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")),
314
+ transformDialect: "vscode"
315
+ },
316
+ // https://www.kimi.com/code/docs/en/kimi-code-cli/customization/mcp.html
317
+ "kimi-code-cli": {
318
+ name: "kimi-code-cli",
319
+ displayName: "Kimi Code CLI",
320
+ globalConfigPath: kimiCodeConfigPath,
321
+ projectConfigPath: ".kimi-code/mcp.json",
322
+ configKey: "mcpServers",
323
+ format: "jsonc",
324
+ supportedTransports: ALL_TRANSPORTS,
325
+ 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")),
326
+ 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")),
327
+ transformDialect: "kimi-code"
328
+ },
329
+ // https://kiro.dev/docs/mcp/configuration.md
330
+ kiro: {
331
+ name: "kiro",
332
+ displayName: "Kiro",
333
+ globalConfigPath: kiroConfigPath,
334
+ projectConfigPath: ".kiro/settings/mcp.json",
335
+ configKey: "mcpServers",
336
+ format: "jsonc",
337
+ supportedTransports: ALL_TRANSPORTS,
338
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(kiroConfigPath) || (0, import_node_fs.existsSync)(process.env.KIRO_HOME?.trim() || (0, import_node_path.join)(home, ".kiro")),
339
+ 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")),
340
+ transformDialect: "kiro"
341
+ },
342
+ // https://opencode.ai/docs/config/
343
+ opencode: {
344
+ name: "opencode",
345
+ displayName: "OpenCode",
346
+ globalConfigPath: (0, import_node_path.join)(
347
+ process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config"),
348
+ "opencode",
349
+ "opencode.json"
350
+ ),
351
+ projectConfigPath: "opencode.json",
352
+ configKey: "mcp",
353
+ format: "jsonc",
354
+ supportedTransports: ALL_TRANSPORTS,
355
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(process.env.XDG_CONFIG_HOME || (0, import_node_path.join)(home, ".config"), "opencode")),
356
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, "opencode.json")),
357
+ transformDialect: "opencode"
358
+ },
359
+ // https://pi.dev/packages/pi-mcp-extension
360
+ pi: {
361
+ name: "pi",
362
+ displayName: "Pi",
363
+ globalConfigPath: (0, import_node_path.join)(home, ".pi", "agent", "mcp.json"),
364
+ projectConfigPath: ".pi/mcp.json",
365
+ configKey: "mcpServers",
366
+ format: "jsonc",
367
+ supportedTransports: ALL_TRANSPORTS,
368
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".pi")),
369
+ 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")),
370
+ transformDialect: "pi"
371
+ },
372
+ // https://docs.qoder.com/zh/cli/mcp-servers.md
373
+ qoder: {
374
+ name: "qoder",
375
+ displayName: "Qoder",
376
+ globalConfigPath: qoderConfigPath,
377
+ projectConfigPath: ".mcp.json",
378
+ configKey: "mcpServers",
379
+ format: "jsonc",
380
+ supportedTransports: ALL_TRANSPORTS,
381
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(qoderConfigPath) || (0, import_node_fs.existsSync)(process.env.QODER_HOME?.trim() || (0, import_node_path.join)(home, ".qoder")),
382
+ 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")),
383
+ resolveConfigPath: ({ global: isGlobal, cwd }) => {
384
+ if (isGlobal) return qoderConfigPath;
385
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".qoder", "settings.json"))) {
386
+ return (0, import_node_path.join)(cwd, ".qoder", "settings.json");
387
+ }
388
+ return (0, import_node_path.join)(cwd, ".mcp.json");
389
+ }
390
+ },
391
+ // https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/
392
+ "qwen-code": {
393
+ name: "qwen-code",
394
+ displayName: "Qwen Code",
395
+ globalConfigPath: qwenCodeConfigPath,
396
+ projectConfigPath: ".qwen/settings.json",
397
+ configKey: "mcpServers",
398
+ format: "jsonc",
399
+ supportedTransports: ALL_TRANSPORTS,
400
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)(qwenCodeConfigPath) || (0, import_node_fs.existsSync)(
401
+ process.env.QWEN_CODE_HOME?.trim() || process.env.QWEN_HOME?.trim() || (0, import_node_path.join)(home, ".qwen")
402
+ ),
403
+ 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")),
404
+ transformDialect: "qwen-code"
405
+ },
406
+ // https://docs.trae.ai/ide/add-mcp-servers?_lang=en
407
+ trae: {
408
+ name: "trae",
409
+ displayName: "Trae",
410
+ globalConfigPath: traeConfigPath,
411
+ projectConfigPath: ".trae/mcp.json",
412
+ configKey: "mcpServers",
413
+ format: "jsonc",
414
+ supportedTransports: ALL_TRANSPORTS,
415
+ 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")),
416
+ 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")),
417
+ resolveConfigPath: ({ global: isGlobal, cwd }) => {
418
+ if (isGlobal) {
419
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(home, ".trae", "mcp.json"))) {
420
+ return (0, import_node_path.join)(home, ".trae", "mcp.json");
421
+ }
422
+ return traeConfigPath;
423
+ }
424
+ return (0, import_node_path.join)(cwd, ".trae", "mcp.json");
425
+ },
426
+ transformDialect: "trae"
427
+ },
428
+ // https://code.visualstudio.com/raw/docs/agents/reference/mcp-configuration.md
429
+ vscode: {
430
+ name: "vscode",
431
+ displayName: "VS Code",
432
+ globalConfigPath: (0, import_node_path.join)(vscodePath, "mcp.json"),
433
+ projectConfigPath: ".vscode/mcp.json",
434
+ configKey: "servers",
435
+ format: "jsonc",
436
+ supportedTransports: ALL_TRANSPORTS,
437
+ detectGlobalInstall: () => (0, import_node_fs.existsSync)((0, import_node_path.join)(vscodePath, "mcp.json")) || (0, import_node_fs.existsSync)(vscodePath),
438
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".vscode", "mcp.json")),
439
+ transformDialect: "vscode"
440
+ },
441
+ // https://zed.dev/docs/ai/mcp.md
442
+ zed: {
443
+ name: "zed",
444
+ displayName: "Zed",
445
+ globalConfigPath: zedConfigPath,
446
+ projectConfigPath: ".zed/settings.json",
447
+ configKey: "context_servers",
448
+ format: "jsonc",
449
+ supportedTransports: ALL_TRANSPORTS,
450
+ 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")),
451
+ detectProjectInstall: (cwd) => (0, import_node_fs.existsSync)((0, import_node_path.join)(cwd, ".zed", "settings.json")),
452
+ transformDialect: "zed"
453
+ }
454
+ };
455
+ var mcpAgentAliases = {
456
+ agy: "antigravity-cli",
457
+ "amp-cli": "amp",
458
+ "amp-code": "amp",
459
+ ampcode: "amp",
460
+ auggie: "augment",
461
+ "augment-code": "augment",
462
+ augmentcode: "augment",
463
+ "cline-vscode": "cline",
464
+ gemini: "gemini-cli",
465
+ "github-copilot": "vscode",
466
+ "grok-cli": "grok",
467
+ kimi: "kimi-code-cli",
468
+ "kimi-cli": "kimi-code-cli",
469
+ "kimi-code": "kimi-code-cli",
470
+ "kiro-cli": "kiro",
471
+ "kiro-ide": "kiro",
472
+ "pi-agent": "pi",
473
+ "qoder-cli": "qoder",
474
+ qwen: "qwen-code",
475
+ "qwen-cli": "qwen-code",
476
+ qwencode: "qwen-code",
477
+ "trae-code": "trae",
478
+ traecode: "trae",
479
+ "trae-ide": "trae",
480
+ xai: "grok",
481
+ "xai-grok": "grok"
482
+ };
483
+ var getMcpAgentConfig = (agentType) => mcpAgents[agentType];
484
+ var getMcpAgentTypes = () => Object.values(mcpAgents).map((config) => config.name);
485
+ var isMcpAgentType = (value) => value in mcpAgents;
486
+ var resolveMcpAgentAlias = (input5) => {
487
+ if (isMcpAgentType(input5)) return input5;
488
+ return mcpAgentAliases[input5] ?? null;
489
+ };
490
+ var isMcpTransportSupported = (agent, transport) => agent.supportedTransports.includes(transport);
491
+ var detectProjectInstalledMcpAgents = (cwd) => getMcpAgentTypes().filter(
492
+ (type) => mcpAgents[type].detectProjectInstall ? mcpAgents[type].detectProjectInstall(cwd) : false
493
+ );
494
+ var detectGloballyInstalledMcpAgents = () => getMcpAgentTypes().filter((type) => mcpAgents[type].detectGlobalInstall());
495
+ var getMcpAgentsSupportingProjectScope = () => getMcpAgentTypes().filter((type) => Boolean(mcpAgents[type].projectConfigPath));
496
+
497
+ // src/constants.ts
498
+ var DEFAULT_REMOTE_TRANSPORT = "http";
499
+ var NPX_COMMAND = "npx";
500
+ var NPX_DASH_Y = "-y";
501
+ var GOOSE_TIMEOUT_SECONDS = 300;
502
+ var DEFAULT_JSON_INDENT_SPACES = 2;
503
+ var MCP_DEFAULT_SERVER_NAME = "mcp-server";
504
+ var GENERIC_HOST_PREFIXES = /* @__PURE__ */ new Set([
505
+ "mcp",
506
+ "api",
507
+ "app",
508
+ "www",
509
+ "server",
510
+ "servers",
511
+ "remote"
512
+ ]);
513
+ var COMMON_TLD_LABELS = /* @__PURE__ */ new Set([
514
+ "com",
515
+ "org",
516
+ "net",
517
+ "io",
518
+ "dev",
519
+ "ai",
520
+ "tech",
521
+ "co",
522
+ "app",
523
+ "cloud",
524
+ "sh",
525
+ "run"
526
+ ]);
527
+ var PACKAGE_NAME_PREFIX_STRIP = ["mcp-server-", "server-"];
528
+ var PACKAGE_NAME_SUFFIX_STRIP = ["-mcp-server", "-mcp"];
529
+ var KNOWN_COMMAND_RUNNERS = /* @__PURE__ */ new Set([
530
+ "npx",
531
+ "node",
532
+ "python",
533
+ "python3",
534
+ "uvx",
535
+ "bunx",
536
+ "deno"
537
+ ]);
538
+ var SCRIPT_EXTENSION_REGEX = /\.(?:js|ts|mjs|cjs|py|sh|rb|go)$/i;
539
+
540
+ // src/build-server-config.ts
541
+ var buildMcpServerConfig = (parsed, options = {}) => {
542
+ if (parsed.type === "remote") {
543
+ const config2 = {
544
+ type: options.transport ?? DEFAULT_REMOTE_TRANSPORT,
545
+ url: parsed.value
546
+ };
547
+ if (options.headers && Object.keys(options.headers).length > 0) {
548
+ config2.headers = options.headers;
549
+ }
550
+ return config2;
551
+ }
552
+ if (parsed.type === "command") {
553
+ const parts = parsed.value.split(/\s+/);
554
+ const command = parts[0] ?? "";
555
+ const args = parts.slice(1);
556
+ if (options.args && options.args.length > 0) {
557
+ args.push(...options.args);
558
+ }
559
+ const config2 = { command, args };
560
+ if (options.env && Object.keys(options.env).length > 0) {
561
+ config2.env = options.env;
562
+ }
563
+ return config2;
564
+ }
565
+ const packageArgs = [NPX_DASH_Y, parsed.value];
566
+ if (options.args && options.args.length > 0) {
567
+ packageArgs.push(...options.args);
568
+ }
569
+ const config = {
570
+ command: NPX_COMMAND,
571
+ args: packageArgs
572
+ };
573
+ if (options.env && Object.keys(options.env).length > 0) {
574
+ config.env = options.env;
575
+ }
576
+ return config;
577
+ };
578
+
579
+ // src/parse-server-config.ts
580
+ var isRemoteServerConfig = (config) => typeof config.url === "string" && config.url.length > 0;
581
+ var isStdioServerConfig = (config) => typeof config.command === "string" && config.command.length > 0;
582
+ var parseServerConfig = (raw) => {
583
+ if (!raw || typeof raw !== "object") return {};
584
+ const data = raw;
585
+ const rawUrl = typeof data.url === "string" && data.url.trim().length > 0 ? data.url.trim() : void 0;
586
+ const rawHttpUrl = typeof data.httpUrl === "string" && data.httpUrl.trim().length > 0 ? data.httpUrl.trim() : void 0;
587
+ const remoteUrl = rawHttpUrl ?? rawUrl;
588
+ if (remoteUrl) {
589
+ const transport = data.type === "sse" || data.transport === "sse" ? "sse" : "http";
590
+ const headers = data.headers && typeof data.headers === "object" ? data.headers : void 0;
591
+ return {
592
+ type: transport,
593
+ url: remoteUrl,
594
+ headers
595
+ };
596
+ }
597
+ if (typeof data.command === "string" && data.command.trim().length > 0) {
598
+ const args = Array.isArray(data.args) ? data.args.filter((item) => typeof item === "string") : void 0;
599
+ const env = data.env && typeof data.env === "object" ? data.env : void 0;
600
+ return {
601
+ command: data.command.trim(),
602
+ args,
603
+ env
604
+ };
605
+ }
606
+ return {};
607
+ };
608
+
609
+ // src/utils/is-plain-object.ts
610
+ var isPlainObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
611
+
612
+ // src/utils/get-nested-value.ts
613
+ var getNestedValue = (source, dottedKey) => {
614
+ if (!source) return void 0;
615
+ if (dottedKey in source) return source[dottedKey];
616
+ const segments = dottedKey.split(".");
617
+ let cursor = source;
618
+ for (const segment of segments) {
619
+ if (!isPlainObject(cursor)) return void 0;
620
+ cursor = cursor[segment];
621
+ }
622
+ return cursor;
623
+ };
624
+
625
+ // src/formats/json.ts
626
+ var import_node_fs3 = require("fs");
627
+ var import_jsonc_parser = require("jsonc-parser");
628
+
629
+ // src/utils/ensure-parent-dir.ts
630
+ var import_node_fs2 = require("fs");
631
+ var import_node_path2 = require("path");
632
+ var ensureParentDir = (filePath) => {
633
+ const parentDir = (0, import_node_path2.dirname)(filePath);
634
+ if (!(0, import_node_fs2.existsSync)(parentDir)) (0, import_node_fs2.mkdirSync)(parentDir, { recursive: true });
635
+ };
636
+
637
+ // src/utils/set-nested-value.ts
638
+ var DANGEROUS_KEY_SEGMENTS = /* @__PURE__ */ new Set([
639
+ "__proto__",
640
+ "prototype",
641
+ "constructor"
642
+ ]);
643
+ var assertSafeSegment = (segment) => {
644
+ if (DANGEROUS_KEY_SEGMENTS.has(segment)) {
645
+ throw new Error(`Refusing to write to unsafe key segment "${segment}"`);
646
+ }
647
+ };
648
+ var setNestedValue = (target, dottedKey, value) => {
649
+ if (dottedKey in target) {
650
+ assertSafeSegment(dottedKey);
651
+ target[dottedKey] = value;
652
+ return;
653
+ }
654
+ const segments = dottedKey.split(".");
655
+ let cursor = target;
656
+ for (let segmentIndex = 0; segmentIndex < segments.length - 1; segmentIndex += 1) {
657
+ const segment = segments[segmentIndex];
658
+ assertSafeSegment(segment);
659
+ const existing = cursor[segment];
660
+ if (isPlainObject(existing)) {
661
+ cursor = existing;
662
+ continue;
663
+ }
664
+ const next = {};
665
+ cursor[segment] = next;
666
+ cursor = next;
667
+ }
668
+ const finalSegment = segments[segments.length - 1];
669
+ assertSafeSegment(finalSegment);
670
+ cursor[finalSegment] = value;
671
+ };
672
+
673
+ // src/utils/walk-nested-object.ts
674
+ var walkNestedObject = (root, segments) => {
675
+ let cursor = root;
676
+ for (const segment of segments) {
677
+ if (!isPlainObject(cursor)) return void 0;
678
+ cursor = cursor[segment];
679
+ }
680
+ return isPlainObject(cursor) ? cursor : void 0;
681
+ };
682
+
683
+ // src/formats/json.ts
684
+ var JSONC_FORMATTING = {
685
+ insertSpaces: true,
686
+ tabSize: DEFAULT_JSON_INDENT_SPACES,
687
+ eol: "\n"
688
+ };
689
+ var readFileOrEmpty = (filePath) => (0, import_node_fs3.existsSync)(filePath) ? (0, import_node_fs3.readFileSync)(filePath, "utf-8") : "";
690
+ var writeWithTrailingNewline = (filePath, contents) => {
691
+ (0, import_node_fs3.writeFileSync)(filePath, contents.endsWith("\n") ? contents : `${contents}
692
+ `, "utf-8");
693
+ };
694
+ var readJsoncConfig = (filePath) => {
695
+ const raw = readFileOrEmpty(filePath);
696
+ if (!raw.trim()) return {};
697
+ const parsed = (0, import_jsonc_parser.parse)(raw);
698
+ return isPlainObject(parsed) ? parsed : {};
699
+ };
700
+ var resolvePathPrefix = (root, dottedKey) => {
701
+ if (dottedKey in root) return [dottedKey];
702
+ const segments = dottedKey.split(".");
703
+ if (segments.length > 1 && walkNestedObject(root, segments)) {
704
+ return segments;
705
+ }
706
+ return [dottedKey];
707
+ };
708
+ var setJsoncNestedValue = (filePath, dottedKey, serverName, serverConfig) => {
709
+ ensureParentDir(filePath);
710
+ const existingText = readFileOrEmpty(filePath);
711
+ const sourceText = existingText.trim() ? existingText : "{}";
712
+ const existing = readJsoncConfig(filePath);
713
+ const pathPrefix = resolvePathPrefix(existing, dottedKey);
714
+ const path = [...pathPrefix, serverName];
715
+ const edits = (0, import_jsonc_parser.modify)(sourceText, path, serverConfig, {
716
+ formattingOptions: JSONC_FORMATTING
717
+ });
718
+ writeWithTrailingNewline(filePath, (0, import_jsonc_parser.applyEdits)(sourceText, edits));
719
+ };
720
+ var writeJsonConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
721
+ ensureParentDir(filePath);
722
+ const existing = readJsoncConfig(filePath);
723
+ const pathPrefix = resolvePathPrefix(existing, dottedKey);
724
+ const existingServers = walkNestedObject(existing, pathPrefix);
725
+ const servers = existingServers ? { ...existingServers } : {};
726
+ servers[serverName] = serverConfig;
727
+ if (pathPrefix.length === 1) {
728
+ existing[pathPrefix[0]] = servers;
729
+ } else {
730
+ setNestedValue(existing, dottedKey, servers);
731
+ }
732
+ (0, import_node_fs3.writeFileSync)(
733
+ filePath,
734
+ `${JSON.stringify(existing, null, DEFAULT_JSON_INDENT_SPACES)}
735
+ `,
736
+ "utf-8"
737
+ );
738
+ };
739
+ var removeJsoncConfigKey = (filePath, dottedKey, serverName) => {
740
+ if (!(0, import_node_fs3.existsSync)(filePath)) return false;
741
+ const sourceText = (0, import_node_fs3.readFileSync)(filePath, "utf-8");
742
+ if (!sourceText.trim()) return false;
743
+ const existing = readJsoncConfig(filePath);
744
+ const pathPrefix = resolvePathPrefix(existing, dottedKey);
745
+ const parentObject = walkNestedObject(existing, pathPrefix);
746
+ if (!parentObject || !(serverName in parentObject)) return false;
747
+ const path = [...pathPrefix, serverName];
748
+ const edits = (0, import_jsonc_parser.modify)(sourceText, path, void 0, {
749
+ formattingOptions: JSONC_FORMATTING
750
+ });
751
+ if (edits.length === 0) return false;
752
+ writeWithTrailingNewline(filePath, (0, import_jsonc_parser.applyEdits)(sourceText, edits));
753
+ return true;
754
+ };
755
+
756
+ // src/formats/toml.ts
757
+ var import_node_fs4 = require("fs");
758
+ var import_toml = __toESM(require("@iarna/toml"), 1);
759
+
760
+ // src/utils/delete-nested-value.ts
761
+ var DANGEROUS_KEY_SEGMENTS2 = /* @__PURE__ */ new Set([
762
+ "__proto__",
763
+ "prototype",
764
+ "constructor"
765
+ ]);
766
+ var deleteNestedValue = (target, dottedKey) => {
767
+ if (!target) return false;
768
+ if (dottedKey in target) {
769
+ if (DANGEROUS_KEY_SEGMENTS2.has(dottedKey)) return false;
770
+ delete target[dottedKey];
771
+ return true;
772
+ }
773
+ const segments = dottedKey.split(".");
774
+ if (segments.some((segment) => DANGEROUS_KEY_SEGMENTS2.has(segment))) return false;
775
+ let cursor = target;
776
+ for (let segmentIndex = 0; segmentIndex < segments.length - 1; segmentIndex += 1) {
777
+ const segment = segments[segmentIndex];
778
+ const existing = cursor[segment];
779
+ if (!isPlainObject(existing)) return false;
780
+ cursor = existing;
781
+ }
782
+ const lastSegment = segments[segments.length - 1];
783
+ if (!(lastSegment in cursor)) return false;
784
+ delete cursor[lastSegment];
785
+ return true;
786
+ };
787
+
788
+ // src/formats/toml.ts
789
+ var toTomlJsonMap = (value) => JSON.parse(JSON.stringify(value));
790
+ var readTomlConfig = (filePath) => {
791
+ if (!(0, import_node_fs4.existsSync)(filePath)) return {};
792
+ const raw = (0, import_node_fs4.readFileSync)(filePath, "utf-8");
793
+ if (!raw.trim()) return {};
794
+ const parsed = import_toml.default.parse(raw);
795
+ return isPlainObject(parsed) ? parsed : {};
796
+ };
797
+ var writeTomlConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
798
+ ensureParentDir(filePath);
799
+ const existing = readTomlConfig(filePath);
800
+ const existingServers = walkNestedObject(existing, dottedKey.split("."));
801
+ const servers = existingServers ? { ...existingServers } : {};
802
+ servers[serverName] = serverConfig;
803
+ setNestedValue(existing, dottedKey, servers);
804
+ (0, import_node_fs4.writeFileSync)(filePath, import_toml.default.stringify(toTomlJsonMap(existing)), "utf-8");
805
+ };
806
+ var removeTomlConfigKey = (filePath, dottedKey, serverName) => {
807
+ if (!(0, import_node_fs4.existsSync)(filePath)) return false;
808
+ const existing = readTomlConfig(filePath);
809
+ const didRemove = deleteNestedValue(existing, `${dottedKey}.${serverName}`);
810
+ if (didRemove) (0, import_node_fs4.writeFileSync)(filePath, import_toml.default.stringify(toTomlJsonMap(existing)), "utf-8");
811
+ return didRemove;
812
+ };
813
+
814
+ // src/formats/yaml.ts
815
+ var import_node_fs5 = require("fs");
816
+ var import_yaml = require("yaml");
817
+ var readYamlConfig = (filePath) => {
818
+ if (!(0, import_node_fs5.existsSync)(filePath)) return {};
819
+ const raw = (0, import_node_fs5.readFileSync)(filePath, "utf-8");
820
+ if (!raw.trim()) return {};
821
+ const parsed = (0, import_yaml.parse)(raw);
822
+ return isPlainObject(parsed) ? parsed : {};
823
+ };
824
+ var writeYamlConfigAtKey = (filePath, dottedKey, serverName, serverConfig) => {
825
+ ensureParentDir(filePath);
826
+ const existing = readYamlConfig(filePath);
827
+ const existingServers = walkNestedObject(existing, dottedKey.split("."));
828
+ const servers = existingServers ? { ...existingServers } : {};
829
+ servers[serverName] = serverConfig;
830
+ setNestedValue(existing, dottedKey, servers);
831
+ (0, import_node_fs5.writeFileSync)(filePath, (0, import_yaml.stringify)(existing), "utf-8");
832
+ };
833
+ var removeYamlConfigKey = (filePath, dottedKey, serverName) => {
834
+ if (!(0, import_node_fs5.existsSync)(filePath)) return false;
835
+ const existing = readYamlConfig(filePath);
836
+ const didRemove = deleteNestedValue(existing, `${dottedKey}.${serverName}`);
837
+ if (didRemove) (0, import_node_fs5.writeFileSync)(filePath, (0, import_yaml.stringify)(existing), "utf-8");
838
+ return didRemove;
839
+ };
840
+
841
+ // src/formats/index.ts
842
+ var readConfigFile = (filePath, format) => {
843
+ switch (format) {
844
+ case "json":
845
+ case "jsonc":
846
+ return readJsoncConfig(filePath);
847
+ case "yaml":
848
+ return readYamlConfig(filePath);
849
+ case "toml":
850
+ return readTomlConfig(filePath);
851
+ default:
852
+ throw new Error(`Unsupported config format: ${format}`);
853
+ }
854
+ };
855
+ var writeServerToConfigFile = (filePath, format, dottedKey, serverName, serverConfig) => {
856
+ switch (format) {
857
+ case "jsonc":
858
+ setJsoncNestedValue(filePath, dottedKey, serverName, serverConfig);
859
+ return;
860
+ case "json":
861
+ writeJsonConfigAtKey(filePath, dottedKey, serverName, serverConfig);
862
+ return;
863
+ case "yaml":
864
+ writeYamlConfigAtKey(filePath, dottedKey, serverName, serverConfig);
865
+ return;
866
+ case "toml":
867
+ writeTomlConfigAtKey(filePath, dottedKey, serverName, serverConfig);
868
+ return;
869
+ default:
870
+ throw new Error(`Unsupported config format: ${format}`);
871
+ }
872
+ };
873
+ var removeServerFromConfigFile = (filePath, format, dottedKey, serverName) => {
874
+ switch (format) {
875
+ case "json":
876
+ case "jsonc":
877
+ return removeJsoncConfigKey(filePath, dottedKey, serverName);
878
+ case "yaml":
879
+ return removeYamlConfigKey(filePath, dottedKey, serverName);
880
+ case "toml":
881
+ return removeTomlConfigKey(filePath, dottedKey, serverName);
882
+ default:
883
+ throw new Error(`Unsupported config format: ${format}`);
884
+ }
885
+ };
886
+ var listServersInConfigFile = (filePath, format, dottedKey) => {
887
+ const config = readConfigFile(filePath, format);
888
+ const entries = getNestedValue(config, dottedKey);
889
+ return isPlainObject(entries) ? entries : {};
890
+ };
891
+
892
+ // src/config-store.ts
893
+ var import_node_fs6 = require("fs");
894
+
895
+ // src/resolve-config-target.ts
896
+ var import_node_path3 = require("path");
897
+ var resolveMcpConfigTarget = (agent, options = {}) => {
898
+ const isGlobal = options.global ?? false;
899
+ const cwd = options.cwd ?? process.cwd();
900
+ const configPath = agent.resolveConfigPath ? agent.resolveConfigPath({ global: isGlobal, cwd }) : !isGlobal && agent.projectConfigPath ? (0, import_node_path3.join)(cwd, agent.projectConfigPath) : agent.globalConfigPath;
901
+ const configKey = !isGlobal && agent.projectConfigKey ? agent.projectConfigKey : agent.configKey;
902
+ return { configPath, configKey };
903
+ };
904
+
905
+ // src/config-store.ts
906
+ var FsConfigStoreAdapter = class {
907
+ exists(filePath) {
908
+ return (0, import_node_fs6.existsSync)(filePath);
909
+ }
910
+ read(target) {
911
+ return readConfigFile(target.filePath, target.format);
912
+ }
913
+ writeServer(target, serverName, serverConfig) {
914
+ if (!target.dottedKey) {
915
+ throw new Error(`Cannot write server: missing dottedKey for ${target.filePath}`);
916
+ }
917
+ writeServerToConfigFile(
918
+ target.filePath,
919
+ target.format,
920
+ target.dottedKey,
921
+ serverName,
922
+ serverConfig
923
+ );
924
+ }
925
+ removeServer(target, serverName) {
926
+ if (!target.dottedKey) return false;
927
+ return removeServerFromConfigFile(
928
+ target.filePath,
929
+ target.format,
930
+ target.dottedKey,
931
+ serverName
932
+ );
933
+ }
934
+ listServers(target) {
935
+ if (!target.dottedKey) return {};
936
+ return listServersInConfigFile(target.filePath, target.format, target.dottedKey);
937
+ }
938
+ };
939
+ var AgentConfigStore = class {
940
+ constructor(adapter = new FsConfigStoreAdapter()) {
941
+ this.adapter = adapter;
942
+ }
943
+ adapter;
944
+ getAdapter() {
945
+ return this.adapter;
946
+ }
947
+ resolveTarget(agent, options = {}) {
948
+ const agentConfig = typeof agent === "string" ? getMcpAgentConfig(agent) : agent;
949
+ const target = resolveMcpConfigTarget(agentConfig, options);
950
+ return { agent: agentConfig, target };
951
+ }
952
+ resolveDescriptor(agent, options = {}) {
953
+ const { agent: agentConfig, target } = this.resolveTarget(agent, options);
954
+ return {
955
+ filePath: target.configPath,
956
+ format: agentConfig.format,
957
+ dottedKey: target.configKey
958
+ };
959
+ }
960
+ writeServer(agent, serverName, serverConfig, options = {}) {
961
+ const descriptor = this.resolveDescriptor(agent, options);
962
+ this.adapter.writeServer(descriptor, serverName, serverConfig);
963
+ return { path: descriptor.filePath };
964
+ }
965
+ removeServer(agent, serverName, options = {}) {
966
+ const descriptor = this.resolveDescriptor(agent, options);
967
+ if (!this.adapter.exists(descriptor.filePath)) {
968
+ return { path: descriptor.filePath, removed: false };
969
+ }
970
+ const removed = this.adapter.removeServer(descriptor, serverName);
971
+ return { path: descriptor.filePath, removed };
972
+ }
973
+ listServers(agent, options = {}) {
974
+ const descriptor = this.resolveDescriptor(agent, options);
975
+ if (!this.adapter.exists(descriptor.filePath)) {
976
+ return { path: descriptor.filePath, exists: false, servers: {} };
977
+ }
978
+ const servers = this.adapter.listServers(descriptor);
979
+ return { path: descriptor.filePath, exists: true, servers };
980
+ }
981
+ read(agent, options = {}) {
982
+ const descriptor = this.resolveDescriptor(agent, options);
983
+ if (!this.adapter.exists(descriptor.filePath)) {
984
+ return {};
985
+ }
986
+ return this.adapter.read(descriptor);
987
+ }
988
+ readServer(agent, serverName, options = {}) {
989
+ const { exists, servers } = this.listServers(agent, options);
990
+ if (!exists) return void 0;
991
+ return servers[serverName];
992
+ }
993
+ };
994
+ var agentConfigStore = new AgentConfigStore();
995
+
996
+ // src/utils/to-error-message.ts
997
+ var toErrorMessage = (error, fallback = "Unknown error") => error instanceof Error ? error.message : fallback;
998
+
999
+ // src/transforms/index.ts
1000
+ var DIALECT_PRESETS = {
1001
+ vscode: {
1002
+ stdioTransport: "type-stdio",
1003
+ remoteTransport: "type-http-sse"
1004
+ },
1005
+ augment: {
1006
+ stdioTransport: "none",
1007
+ remoteTransport: "type-http-sse"
1008
+ },
1009
+ amp: {
1010
+ stdioTransport: "none",
1011
+ remoteTransport: "none"
1012
+ },
1013
+ trae: {
1014
+ stdioTransport: "none",
1015
+ remoteTransport: "sse-only-type"
1016
+ },
1017
+ grok: {
1018
+ stdioTransport: "none",
1019
+ remoteTransport: "sse-only-type"
1020
+ },
1021
+ cline: {
1022
+ stdioTransport: "none",
1023
+ remoteTransport: "streamableHttp"
1024
+ },
1025
+ goose: {
1026
+ stdioTransport: "type-stdio",
1027
+ remoteTransport: "streamable_http",
1028
+ commandField: "cmd",
1029
+ envField: "envs",
1030
+ urlField: "uri",
1031
+ defaultEnvEmpty: true,
1032
+ defaultHeadersEmpty: true,
1033
+ includeServerName: true,
1034
+ timeoutSeconds: GOOSE_TIMEOUT_SECONDS,
1035
+ extraFields: {
1036
+ description: "",
1037
+ enabled: true
1038
+ }
1039
+ },
1040
+ "kimi-code": {
1041
+ stdioTransport: "none",
1042
+ remoteTransport: "sse-only-transport"
1043
+ },
1044
+ kiro: {
1045
+ stdioTransport: "none",
1046
+ remoteTransport: "none"
1047
+ },
1048
+ opencode: {
1049
+ stdioTransport: "type-local",
1050
+ remoteTransport: "remote-type",
1051
+ commandArray: true,
1052
+ envField: "environment",
1053
+ defaultEnvEmpty: true,
1054
+ extraFields: {
1055
+ enabled: true
1056
+ }
1057
+ },
1058
+ pi: {
1059
+ stdioTransport: "transport-stdio",
1060
+ remoteTransport: "streamable-http"
1061
+ },
1062
+ "qwen-code": {
1063
+ stdioTransport: "none",
1064
+ remoteTransport: "qwen"
1065
+ },
1066
+ zed: {
1067
+ stdioTransport: "none",
1068
+ remoteTransport: "none",
1069
+ defaultEnvEmpty: true
1070
+ }
1071
+ };
1072
+ var resolveDialectOptions = (dialect) => {
1073
+ if (typeof dialect === "string") {
1074
+ const preset = DIALECT_PRESETS[dialect];
1075
+ if (!preset) {
1076
+ throw new Error(`Unknown server config dialect: "${dialect}"`);
1077
+ }
1078
+ return preset;
1079
+ }
1080
+ return dialect;
1081
+ };
1082
+ var transformRemoteConfig = (serverName, config, options) => {
1083
+ const result = {};
1084
+ if (options.includeServerName) {
1085
+ result.name = serverName;
1086
+ }
1087
+ if (options.extraFields) {
1088
+ Object.assign(result, options.extraFields);
1089
+ }
1090
+ const remoteTransport = options.remoteTransport ?? "type-http-sse";
1091
+ const urlField = options.urlField ?? "url";
1092
+ switch (remoteTransport) {
1093
+ case "type-http-sse":
1094
+ result.type = config.type || "http";
1095
+ result[urlField] = config.url;
1096
+ break;
1097
+ case "sse-only-type":
1098
+ result[urlField] = config.url;
1099
+ if (config.type === "sse") {
1100
+ result.type = "sse";
1101
+ }
1102
+ break;
1103
+ case "sse-only-transport":
1104
+ result[urlField] = config.url;
1105
+ if (config.type === "sse") {
1106
+ result.transport = "sse";
1107
+ }
1108
+ break;
1109
+ case "none":
1110
+ result[urlField] = config.url;
1111
+ break;
1112
+ case "streamableHttp":
1113
+ result.type = config.type === "sse" ? "sse" : "streamableHttp";
1114
+ result[urlField] = config.url;
1115
+ break;
1116
+ case "streamable-http":
1117
+ result.transport = config.type === "sse" ? "sse" : "streamable-http";
1118
+ result[urlField] = config.url;
1119
+ break;
1120
+ case "streamable_http":
1121
+ result.type = config.type === "sse" ? "sse" : "streamable_http";
1122
+ result[urlField] = config.url;
1123
+ break;
1124
+ case "remote-type":
1125
+ result.type = "remote";
1126
+ result[urlField] = config.url;
1127
+ break;
1128
+ case "qwen":
1129
+ if (config.type === "sse") {
1130
+ result.url = config.url;
1131
+ } else {
1132
+ result.httpUrl = config.url;
1133
+ }
1134
+ break;
1135
+ }
1136
+ const hasHeaders = config.headers && Object.keys(config.headers).length > 0;
1137
+ if (hasHeaders) {
1138
+ result.headers = config.headers;
1139
+ } else if (options.defaultHeadersEmpty) {
1140
+ result.headers = {};
1141
+ }
1142
+ if (options.timeoutSeconds !== void 0) {
1143
+ result.timeout = options.timeoutSeconds;
1144
+ }
1145
+ return result;
1146
+ };
1147
+ var transformStdioConfig = (serverName, config, options) => {
1148
+ const result = {};
1149
+ if (options.includeServerName) {
1150
+ result.name = serverName;
1151
+ }
1152
+ if (options.extraFields) {
1153
+ Object.assign(result, options.extraFields);
1154
+ }
1155
+ const stdioTransport = options.stdioTransport ?? "none";
1156
+ const commandField = options.commandField ?? "command";
1157
+ const argsField = options.argsField ?? "args";
1158
+ const envField = options.envField ?? "env";
1159
+ switch (stdioTransport) {
1160
+ case "type-stdio":
1161
+ result.type = "stdio";
1162
+ break;
1163
+ case "transport-stdio":
1164
+ result.transport = "stdio";
1165
+ break;
1166
+ case "type-local":
1167
+ result.type = "local";
1168
+ break;
1169
+ case "none":
1170
+ break;
1171
+ }
1172
+ if (options.commandArray) {
1173
+ result[commandField] = [config.command, ...config.args || []];
1174
+ } else {
1175
+ result[commandField] = config.command;
1176
+ result[argsField] = config.args || [];
1177
+ }
1178
+ const hasEnv = config.env && Object.keys(config.env).length > 0;
1179
+ if (hasEnv) {
1180
+ result[envField] = config.env;
1181
+ } else if (options.defaultEnvEmpty) {
1182
+ result[envField] = {};
1183
+ }
1184
+ if (options.timeoutSeconds !== void 0) {
1185
+ result.timeout = options.timeoutSeconds;
1186
+ }
1187
+ return result;
1188
+ };
1189
+ var transformServerConfig = (serverName, config, dialect, _context) => {
1190
+ const options = resolveDialectOptions(dialect);
1191
+ if (config.url) {
1192
+ return transformRemoteConfig(serverName, config, options);
1193
+ }
1194
+ return transformStdioConfig(serverName, config, options);
1195
+ };
1196
+ var transformServerConfigForAgent = (agent, serverName, config, context = { global: false }) => {
1197
+ if (agent.transformConfig) {
1198
+ return agent.transformConfig(serverName, config, context);
1199
+ }
1200
+ if (agent.transformDialect) {
1201
+ return transformServerConfig(serverName, config, agent.transformDialect, context);
1202
+ }
1203
+ return config;
1204
+ };
1205
+
1206
+ // src/installer.ts
1207
+ var installMcpServerForAgent = (serverName, serverConfig, agentType, options = {}) => {
1208
+ const agent = getMcpAgentConfig(agentType);
1209
+ const isGlobal = options.global ?? false;
1210
+ const { target } = agentConfigStore.resolveTarget(agent, options);
1211
+ try {
1212
+ const transformed = transformServerConfigForAgent(agent, serverName, serverConfig, {
1213
+ global: isGlobal
1214
+ });
1215
+ agentConfigStore.writeServer(agent, serverName, transformed, options);
1216
+ return { agent: agentType, success: true, path: target.configPath };
1217
+ } catch (error) {
1218
+ return {
1219
+ agent: agentType,
1220
+ success: false,
1221
+ path: target.configPath,
1222
+ error: toErrorMessage(error)
1223
+ };
1224
+ }
1225
+ };
1226
+
1227
+ // src/utils/parse-mcp-agent-list.ts
1228
+ var parseMcpAgentList = (input5) => {
1229
+ if (!input5 || input5.length === 0) return void 0;
1230
+ if (input5.includes("*")) return getMcpAgentTypes();
1231
+ const resolved = [];
1232
+ for (const value of input5) {
1233
+ const agentType = resolveMcpAgentAlias(value);
1234
+ if (!agentType) throw new Error(`Unknown MCP agent "${value}"`);
1235
+ resolved.push(agentType);
1236
+ }
1237
+ return resolved;
1238
+ };
1239
+
1240
+ // src/resolve-target-agents.ts
1241
+ var normalizeRequestedAgents = (input5) => {
1242
+ if (!input5 || input5.length === 0) return void 0;
1243
+ const rawList = [...input5];
1244
+ if (rawList.every((item) => isMcpAgentType(item))) {
1245
+ return rawList;
1246
+ }
1247
+ return parseMcpAgentList(rawList);
1248
+ };
1249
+ var resolveTargetAgents = (query = {}) => {
1250
+ const cwd = query.cwd ?? process.cwd();
1251
+ const isGlobal = query.global ?? false;
1252
+ let explicitAgents = normalizeRequestedAgents(query.requested);
1253
+ if (query.all) {
1254
+ explicitAgents = getMcpAgentTypes();
1255
+ }
1256
+ const isDetected = !explicitAgents || explicitAgents.length === 0;
1257
+ const detected = isGlobal ? detectGloballyInstalledMcpAgents() : detectProjectInstalledMcpAgents(cwd);
1258
+ const candidateAgents = isDetected ? detected : explicitAgents ?? [];
1259
+ const allAgents = candidateAgents.filter(
1260
+ (type, index) => candidateAgents.indexOf(type) === index
1261
+ );
1262
+ const incompatible = [];
1263
+ const compatibleAgents = [];
1264
+ for (const agentType of allAgents) {
1265
+ const config = getMcpAgentConfig(agentType);
1266
+ if (query.transport && !isMcpTransportSupported(config, query.transport)) {
1267
+ incompatible.push({
1268
+ agent: agentType,
1269
+ reason: config.unsupportedTransportMessage ?? `agent ${agentType} only supports ${config.supportedTransports.join(", ")} transport (attempted ${query.transport})`
1270
+ });
1271
+ } else {
1272
+ compatibleAgents.push(agentType);
1273
+ }
1274
+ }
1275
+ let diagnostic;
1276
+ if (compatibleAgents.length === 0) {
1277
+ if (isDetected) {
1278
+ diagnostic = `No ${isGlobal ? "global" : "project"}-installed MCP agents detected. Pass -a <agent> (e.g. -a cursor) or --all to install.`;
1279
+ } else if (allAgents.length > 0 && incompatible.length > 0 && query.transport) {
1280
+ const list = incompatible.map((item) => `${item.agent} (${item.reason})`).join(", ");
1281
+ diagnostic = `None of the selected agents support ${query.transport} transport: ${list}`;
1282
+ } else {
1283
+ diagnostic = "No valid target agents specified.";
1284
+ }
1285
+ }
1286
+ return {
1287
+ agents: compatibleAgents,
1288
+ compatibleAgents,
1289
+ allAgents,
1290
+ candidateAgents: allAgents,
1291
+ detected,
1292
+ isDetected,
1293
+ incompatible,
1294
+ diagnostic
1295
+ };
1296
+ };
1297
+
1298
+ // src/source-parser.ts
1299
+ var REMOTE_URL_REGEX = /^https?:\/\//i;
1300
+ var HAS_WHITESPACE_REGEX = /\s/;
1301
+ var PACKAGE_NAME_REGEX = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(?:@[^\s]+)?$/;
1302
+ var PATH_SEPARATOR_REGEX = /[/\\]/;
1303
+ var stripVersionSuffix = (input5) => {
1304
+ if (input5.startsWith("@")) {
1305
+ const secondAtIndex = input5.indexOf("@", 1);
1306
+ if (secondAtIndex > 0) return input5.slice(0, secondAtIndex);
1307
+ return input5;
1308
+ }
1309
+ const atIndex = input5.lastIndexOf("@");
1310
+ if (atIndex > 0) return input5.slice(0, atIndex);
1311
+ return input5;
1312
+ };
1313
+ var stripScopePrefix = (input5) => {
1314
+ if (!input5.startsWith("@") || !input5.includes("/")) return input5;
1315
+ const parts = input5.split("/");
1316
+ return parts[1] || input5;
1317
+ };
1318
+ var stripPathPrefix = (input5) => {
1319
+ if (!PATH_SEPARATOR_REGEX.test(input5)) return input5;
1320
+ const segments = input5.split(PATH_SEPARATOR_REGEX);
1321
+ const basename = segments[segments.length - 1];
1322
+ return basename || input5;
1323
+ };
1324
+ var extractPackageName = (input5) => {
1325
+ let name = stripVersionSuffix(input5);
1326
+ name = stripScopePrefix(name);
1327
+ name = stripPathPrefix(name);
1328
+ name = name.replace(SCRIPT_EXTENSION_REGEX, "");
1329
+ for (const prefix of PACKAGE_NAME_PREFIX_STRIP) {
1330
+ if (name.startsWith(prefix)) {
1331
+ name = name.slice(prefix.length);
1332
+ break;
1333
+ }
1334
+ }
1335
+ for (const suffix of PACKAGE_NAME_SUFFIX_STRIP) {
1336
+ if (name.endsWith(suffix)) {
1337
+ name = name.slice(0, -suffix.length);
1338
+ break;
1339
+ }
1340
+ }
1341
+ return name || MCP_DEFAULT_SERVER_NAME;
1342
+ };
1343
+ var inferNameFromUrl = (input5) => {
1344
+ try {
1345
+ const url = new URL(input5);
1346
+ const host = url.hostname;
1347
+ const labels = host.split(".").filter((segment) => segment.length > 0);
1348
+ if (labels.length === 0) return MCP_DEFAULT_SERVER_NAME;
1349
+ const meaningfulLabels = labels.filter((label) => {
1350
+ const lower = label.toLowerCase();
1351
+ if (COMMON_TLD_LABELS.has(lower)) return false;
1352
+ if (GENERIC_HOST_PREFIXES.has(lower)) return false;
1353
+ return true;
1354
+ });
1355
+ if (meaningfulLabels.length > 0) return meaningfulLabels[0];
1356
+ if (labels.length >= 2) return labels[labels.length - 2];
1357
+ return labels[labels.length - 1] || MCP_DEFAULT_SERVER_NAME;
1358
+ } catch {
1359
+ return MCP_DEFAULT_SERVER_NAME;
1360
+ }
1361
+ };
1362
+ var inferNameFromCommand = (command) => {
1363
+ const tokens = command.trim().split(/\s+/);
1364
+ const runnerBase = tokens[0]?.split(PATH_SEPARATOR_REGEX).pop() ?? "";
1365
+ const startIndex = KNOWN_COMMAND_RUNNERS.has(runnerBase) ? 1 : 0;
1366
+ for (let tokenIndex = startIndex; tokenIndex < tokens.length; tokenIndex += 1) {
1367
+ const token = tokens[tokenIndex];
1368
+ if (!token || token.startsWith("-")) continue;
1369
+ return extractPackageName(token);
1370
+ }
1371
+ const firstNonFlag = tokens.find((token) => !token.startsWith("-"));
1372
+ return firstNonFlag ? extractPackageName(firstNonFlag) : MCP_DEFAULT_SERVER_NAME;
1373
+ };
1374
+ var parseMcpSource = (input5) => {
1375
+ const trimmed = input5.trim();
1376
+ if (trimmed.length === 0) {
1377
+ throw new Error(
1378
+ "Invalid MCP source: input is empty. Expected a remote URL, an npm package, or a command line."
1379
+ );
1380
+ }
1381
+ if (REMOTE_URL_REGEX.test(trimmed)) {
1382
+ return {
1383
+ type: "remote",
1384
+ value: trimmed,
1385
+ inferredName: inferNameFromUrl(trimmed)
1386
+ };
1387
+ }
1388
+ if (HAS_WHITESPACE_REGEX.test(trimmed)) {
1389
+ return {
1390
+ type: "command",
1391
+ value: trimmed,
1392
+ inferredName: inferNameFromCommand(trimmed)
1393
+ };
1394
+ }
1395
+ if (PACKAGE_NAME_REGEX.test(trimmed)) {
1396
+ return {
1397
+ type: "package",
1398
+ value: trimmed,
1399
+ inferredName: extractPackageName(trimmed)
1400
+ };
1401
+ }
1402
+ return {
1403
+ type: "command",
1404
+ value: trimmed,
1405
+ inferredName: inferNameFromCommand(trimmed)
1406
+ };
1407
+ };
1408
+
1409
+ // src/install-mcp-server.ts
1410
+ var installMcpServer = (options) => {
1411
+ const parsed = parseMcpSource(options.source);
1412
+ const isGlobal = options.global ?? false;
1413
+ const cwd = options.cwd ?? process.cwd();
1414
+ const serverName = options.name ?? parsed.inferredName;
1415
+ const serverConfig = buildMcpServerConfig(parsed, {
1416
+ transport: options.transport,
1417
+ headers: options.headers,
1418
+ env: options.env,
1419
+ args: options.args
1420
+ });
1421
+ const requestedTransport = parsed.type === "remote" ? serverConfig.type ?? "http" : "stdio";
1422
+ const { allAgents, incompatible } = resolveTargetAgents({
1423
+ requested: options.agents,
1424
+ global: isGlobal,
1425
+ cwd,
1426
+ transport: requestedTransport
1427
+ });
1428
+ const incompatibleMap = new Map(incompatible.map((item) => [item.agent, item.reason]));
1429
+ const results = allAgents.map((agentType) => {
1430
+ const incompatibleReason = incompatibleMap.get(agentType);
1431
+ if (incompatibleReason) {
1432
+ return {
1433
+ agent: agentType,
1434
+ success: false,
1435
+ path: "",
1436
+ error: incompatibleReason
1437
+ };
1438
+ }
1439
+ return installMcpServerForAgent(serverName, serverConfig, agentType, { global: isGlobal, cwd });
1440
+ });
1441
+ return { serverName, config: serverConfig, results };
1442
+ };
1443
+
1444
+ // src/list.ts
1445
+ var listInstalledMcpServers = (options = {}) => {
1446
+ const agentTypes = options.agents ?? getMcpAgentTypes();
1447
+ const collected = [];
1448
+ for (const agentType of agentTypes) {
1449
+ const agent = getMcpAgentConfig(agentType);
1450
+ const { path, exists, servers } = agentConfigStore.listServers(agent, options);
1451
+ if (!exists) continue;
1452
+ for (const [serverName, rawConfig] of Object.entries(servers)) {
1453
+ collected.push({
1454
+ serverName,
1455
+ agent: agentType,
1456
+ path,
1457
+ config: rawConfig,
1458
+ serverConfig: parseServerConfig(rawConfig)
1459
+ });
1460
+ }
1461
+ }
1462
+ return collected;
1463
+ };
1464
+
1465
+ // src/remove.ts
1466
+ var removeMcpServerFromAgent = (serverName, agentType, options = {}) => {
1467
+ const agent = getMcpAgentConfig(agentType);
1468
+ const { target } = agentConfigStore.resolveTarget(agent, options);
1469
+ try {
1470
+ const { removed } = agentConfigStore.removeServer(agent, serverName, options);
1471
+ return { agent: agentType, path: target.configPath, removed };
1472
+ } catch (error) {
1473
+ return {
1474
+ agent: agentType,
1475
+ path: target.configPath,
1476
+ removed: false,
1477
+ error: toErrorMessage(error)
1478
+ };
1479
+ }
1480
+ };
1481
+ var removeMcpServer = (options) => {
1482
+ const { allAgents } = resolveTargetAgents({
1483
+ requested: options.agents,
1484
+ all: !options.agents,
1485
+ global: options.global,
1486
+ cwd: options.cwd
1487
+ });
1488
+ const results = [];
1489
+ for (const agentType of allAgents) {
1490
+ const result = removeMcpServerFromAgent(options.name, agentType, {
1491
+ global: options.global,
1492
+ cwd: options.cwd
1493
+ });
1494
+ if (result.removed || result.error) results.push(result);
1495
+ }
1496
+ return results;
1497
+ };
1498
+
1499
+ // src/interactive/main-menu.ts
1500
+ var import_prompts10 = require("@inquirer/prompts");
1501
+ var import_picocolors10 = __toESM(require("picocolors"), 1);
1502
+
1503
+ // src/interactive/wizard-add.ts
1504
+ var import_prompts7 = require("@inquirer/prompts");
1505
+ var import_picocolors7 = __toESM(require("picocolors"), 1);
1506
+
1507
+ // src/utils/logger.ts
1508
+ var import_picocolors = __toESM(require("picocolors"), 1);
1509
+ var logger = {
1510
+ info: (message) => {
1511
+ console.log(import_picocolors.default.cyan("i"), message);
1512
+ },
1513
+ success: (message) => {
1514
+ console.log(import_picocolors.default.green("\u221A"), message);
1515
+ },
1516
+ warn: (message) => {
1517
+ console.log(import_picocolors.default.yellow("!"), message);
1518
+ },
1519
+ error: (message) => {
1520
+ console.error(import_picocolors.default.red("x"), message);
1521
+ }
1522
+ };
1523
+
1524
+ // src/interactive/prompts/agents.ts
1525
+ var import_prompts2 = require("@inquirer/prompts");
1526
+ var import_picocolors3 = __toESM(require("picocolors"), 1);
1527
+
1528
+ // src/interactive/prompts/scope.ts
1529
+ var import_prompts = require("@inquirer/prompts");
1530
+ var import_picocolors2 = __toESM(require("picocolors"), 1);
1531
+ var promptScope = async (options = {}) => {
1532
+ const initialGlobal = options.defaultGlobal ?? options.global;
1533
+ if (initialGlobal !== void 0) {
1534
+ return initialGlobal;
1535
+ }
1536
+ const cwd = options.cwd ?? process.cwd();
1537
+ return (0, import_prompts.select)({
1538
+ message: options.message ?? "Select MCP scope:",
1539
+ choices: [
1540
+ {
1541
+ name: `Current Project - ${import_picocolors2.default.dim(cwd)}`,
1542
+ value: false
1543
+ },
1544
+ {
1545
+ name: `Global User Config - ${import_picocolors2.default.dim("applies across all projects")}`,
1546
+ value: true
1547
+ }
1548
+ ]
1549
+ });
1550
+ };
1551
+
1552
+ // src/interactive/prompts/agents.ts
1553
+ var promptScopeAndAgents = async (options = {}) => {
1554
+ const cwd = options.cwd ?? process.cwd();
1555
+ const isGlobal = await promptScope({
1556
+ cwd,
1557
+ defaultGlobal: options.defaultGlobal,
1558
+ message: "Select MCP installation scope:"
1559
+ });
1560
+ const resolution = resolveTargetAgents({
1561
+ global: isGlobal,
1562
+ cwd
1563
+ });
1564
+ const detected = resolution.detected;
1565
+ const availableAgentTypes = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
1566
+ if (detected.length > 0) {
1567
+ logger.info(
1568
+ `Detected configured agents: ${import_picocolors3.default.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
1569
+ );
1570
+ } else {
1571
+ logger.warn(`No active ${isGlobal ? "global" : "project"} agents detected`);
1572
+ }
1573
+ const defaultChecked = options.defaultAgents && options.defaultAgents.length > 0 ? options.defaultAgents : detected;
1574
+ const choices = availableAgentTypes.map((agentType) => {
1575
+ const config = getMcpAgentConfig(agentType);
1576
+ const isDetected = detected.includes(agentType);
1577
+ const label = `${config.displayName} ${import_picocolors3.default.dim(`(${agentType})`)}${isDetected ? import_picocolors3.default.green(" [detected]") : ""}`;
1578
+ return {
1579
+ name: label,
1580
+ value: agentType,
1581
+ checked: defaultChecked.includes(agentType)
1582
+ };
1583
+ });
1584
+ const selectedAgents = await (0, import_prompts2.checkbox)({
1585
+ message: "Select target agents (Space to select, Enter to confirm):",
1586
+ choices,
1587
+ validate: (chosen) => {
1588
+ if (chosen.length === 0) {
1589
+ return "Please select at least one agent";
1590
+ }
1591
+ return true;
1592
+ }
1593
+ });
1594
+ return {
1595
+ global: isGlobal,
1596
+ agents: selectedAgents
1597
+ };
1598
+ };
1599
+
1600
+ // src/interactive/prompts/args.ts
1601
+ var import_prompts3 = require("@inquirer/prompts");
1602
+ var parseArgsString = (rawText) => {
1603
+ const matches = rawText.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
1604
+ if (!matches) return [];
1605
+ return matches.map((arg) => {
1606
+ if (arg.startsWith('"') && arg.endsWith('"') || arg.startsWith("'") && arg.endsWith("'")) {
1607
+ return arg.slice(1, -1);
1608
+ }
1609
+ return arg;
1610
+ });
1611
+ };
1612
+ var promptArgsConfig = async (initialArgs = []) => {
1613
+ if (initialArgs.length > 0) {
1614
+ return initialArgs;
1615
+ }
1616
+ const needArgs = await (0, import_prompts3.confirm)({
1617
+ message: "Configure command arguments (e.g. file paths, connection strings)?",
1618
+ default: false
1619
+ });
1620
+ if (!needArgs) {
1621
+ return [];
1622
+ }
1623
+ const raw = await (0, import_prompts3.input)({
1624
+ message: "Enter command arguments (space-separated, wrap paths with spaces in quotes):",
1625
+ validate: (val) => val.trim() ? true : "Arguments cannot be empty"
1626
+ });
1627
+ return parseArgsString(raw.trim());
1628
+ };
1629
+
1630
+ // src/interactive/prompts/env.ts
1631
+ var import_prompts5 = require("@inquirer/prompts");
1632
+ var import_picocolors5 = __toESM(require("picocolors"), 1);
1633
+
1634
+ // src/interactive/prompts/multiline.ts
1635
+ var import_node_readline = require("readline");
1636
+ var import_prompts4 = require("@inquirer/prompts");
1637
+ var import_picocolors4 = __toESM(require("picocolors"), 1);
1638
+ var readMultilineTextFromTerminal = async (message, endHint = "When done pasting, enter END on a new line or press Enter twice to finish") => {
1639
+ console.log(import_picocolors4.default.cyan(`
1640
+ ${message}`));
1641
+ console.log(import_picocolors4.default.dim(` (Hint: ${endHint})
1642
+ `));
1643
+ return new Promise((resolve) => {
1644
+ const rl = (0, import_node_readline.createInterface)({
1645
+ input: process.stdin,
1646
+ output: process.stdout
1647
+ });
1648
+ const lines = [];
1649
+ let consecutiveEmpty = 0;
1650
+ const cleanup = () => {
1651
+ rl.removeAllListeners();
1652
+ rl.close();
1653
+ };
1654
+ rl.on("line", (line) => {
1655
+ const trimmed = line.trim();
1656
+ if (trimmed === "END") {
1657
+ cleanup();
1658
+ resolve(lines.join("\n"));
1659
+ return;
1660
+ }
1661
+ if (line === "") {
1662
+ consecutiveEmpty++;
1663
+ if (lines.length > 0) {
1664
+ cleanup();
1665
+ resolve(lines.join("\n"));
1666
+ return;
1667
+ }
1668
+ if (consecutiveEmpty >= 2) {
1669
+ cleanup();
1670
+ resolve("");
1671
+ return;
1672
+ }
1673
+ } else {
1674
+ consecutiveEmpty = 0;
1675
+ lines.push(line);
1676
+ }
1677
+ });
1678
+ rl.on("close", () => {
1679
+ resolve(lines.join("\n"));
1680
+ });
1681
+ });
1682
+ };
1683
+ var promptEditorText = async (options) => {
1684
+ try {
1685
+ return await (0, import_prompts4.editor)({
1686
+ message: options.message,
1687
+ default: options.defaultText ?? "",
1688
+ postfix: options.postfix
1689
+ });
1690
+ } catch {
1691
+ return readMultilineTextFromTerminal(options.message);
1692
+ }
1693
+ };
1694
+
1695
+ // src/interactive/prompts/env.ts
1696
+ var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
1697
+ var parseEnvText = (rawText) => {
1698
+ const result = {};
1699
+ const lines = rawText.split(/\r?\n/);
1700
+ for (const rawLine of lines) {
1701
+ let line = rawLine.trim();
1702
+ if (!line || line.startsWith("#")) continue;
1703
+ if (line.startsWith("export ")) {
1704
+ line = line.slice(7).trim();
1705
+ }
1706
+ const eqIndex = line.indexOf("=");
1707
+ if (eqIndex === -1) continue;
1708
+ const key = line.slice(0, eqIndex).trim();
1709
+ let value = line.slice(eqIndex + 1).trim();
1710
+ if (!key) continue;
1711
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
1712
+ value = value.slice(1, -1);
1713
+ }
1714
+ result[key] = value;
1715
+ }
1716
+ return result;
1717
+ };
1718
+ var promptEnvConfig = async (initialEnv = {}) => {
1719
+ const env = { ...initialEnv };
1720
+ const initialCount = Object.keys(env).length;
1721
+ if (initialCount > 0) {
1722
+ logger.info(`Includes ${import_picocolors5.default.cyan(String(initialCount))} preset environment variables`);
1723
+ }
1724
+ const mode = await (0, import_prompts5.select)({
1725
+ message: "Configure environment variables?",
1726
+ choices: [
1727
+ {
1728
+ name: "Skip / None",
1729
+ value: "skip"
1730
+ },
1731
+ {
1732
+ name: "Paste multiline .env text into terminal",
1733
+ value: "paste"
1734
+ },
1735
+ {
1736
+ name: "Open in system default editor ($EDITOR)",
1737
+ value: "editor"
1738
+ },
1739
+ {
1740
+ name: "Enter key-value pairs one by one",
1741
+ value: "manual"
1742
+ }
1743
+ ]
1744
+ });
1745
+ if (mode === "skip") {
1746
+ return env;
1747
+ }
1748
+ if (mode === "paste" || mode === "editor") {
1749
+ const pasted = mode === "editor" ? await promptEditorText({
1750
+ message: "Paste or edit environment variables in editor, then save and exit:",
1751
+ postfix: ".env"
1752
+ }) : await readMultilineTextFromTerminal("Paste .env formatted content (multiline supported):");
1753
+ const parsed = parseEnvText(pasted);
1754
+ const count = Object.keys(parsed).length;
1755
+ if (count === 0) {
1756
+ logger.warn("No valid KEY=VALUE pairs recognized");
1757
+ } else {
1758
+ Object.assign(env, parsed);
1759
+ logger.success(`Successfully parsed ${import_picocolors5.default.cyan(String(count))} environment variables:`);
1760
+ for (const [k, v] of Object.entries(parsed)) {
1761
+ const masked = SECRET_KEY_PATTERN.test(k) && v.length > 4 ? `${v.slice(0, 2)}***${v.slice(-2)}` : v;
1762
+ console.log(` ${import_picocolors5.default.bold(k)}=${import_picocolors5.default.dim(masked)}`);
1763
+ }
1764
+ }
1765
+ return env;
1766
+ }
1767
+ logger.info("Entering environment variables (leave key empty and press enter to finish):");
1768
+ while (true) {
1769
+ const key = await (0, import_prompts5.input)({
1770
+ message: "Variable name (Key, leave empty to finish):",
1771
+ validate: (val2) => {
1772
+ const trimmed = val2.trim();
1773
+ if (!trimmed) return true;
1774
+ if (/\s/.test(trimmed)) return "Variable name cannot contain spaces";
1775
+ return true;
1776
+ }
1777
+ });
1778
+ const trimmedKey = key.trim();
1779
+ if (!trimmedKey) break;
1780
+ const isSecret = SECRET_KEY_PATTERN.test(trimmedKey);
1781
+ let val;
1782
+ if (isSecret) {
1783
+ val = await (0, import_prompts5.password)({
1784
+ message: `Value for (${trimmedKey}) [secret masked]:`,
1785
+ mask: "*"
1786
+ });
1787
+ } else {
1788
+ val = await (0, import_prompts5.input)({
1789
+ message: `Value for (${trimmedKey}):`
1790
+ });
1791
+ }
1792
+ env[trimmedKey] = val;
1793
+ logger.success(`Added: ${import_picocolors5.default.cyan(trimmedKey)}`);
1794
+ }
1795
+ return env;
1796
+ };
1797
+
1798
+ // src/interactive/prompts/headers.ts
1799
+ var import_prompts6 = require("@inquirer/prompts");
1800
+ var import_picocolors6 = __toESM(require("picocolors"), 1);
1801
+ var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
1802
+ var parseHeadersText = (rawText) => {
1803
+ const result = {};
1804
+ const lines = rawText.split(/\r?\n/);
1805
+ for (const rawLine of lines) {
1806
+ const line = rawLine.trim();
1807
+ if (!line || line.startsWith("#")) continue;
1808
+ const colonIndex = line.indexOf(":");
1809
+ const equalIndex = line.indexOf("=");
1810
+ let splitIndex = -1;
1811
+ if (colonIndex !== -1 && equalIndex !== -1) {
1812
+ splitIndex = Math.min(colonIndex, equalIndex);
1813
+ } else if (colonIndex !== -1) {
1814
+ splitIndex = colonIndex;
1815
+ } else {
1816
+ splitIndex = equalIndex;
1817
+ }
1818
+ if (splitIndex === -1) continue;
1819
+ const key = line.slice(0, splitIndex).trim();
1820
+ let value = line.slice(splitIndex + 1).trim();
1821
+ if (!key) continue;
1822
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
1823
+ value = value.slice(1, -1);
1824
+ }
1825
+ result[key] = value;
1826
+ }
1827
+ return result;
1828
+ };
1829
+ var promptHeadersConfig = async (initialHeaders = {}) => {
1830
+ const headers = { ...initialHeaders };
1831
+ const mode = await (0, import_prompts6.select)({
1832
+ message: "Select HTTP headers configuration method:",
1833
+ choices: [
1834
+ {
1835
+ name: "Paste multiline headers into terminal (Key: Value format)",
1836
+ value: "paste"
1837
+ },
1838
+ {
1839
+ name: "Open in system default editor ($EDITOR)",
1840
+ value: "editor"
1841
+ },
1842
+ {
1843
+ name: "Enter headers one by one (e.g. Authorization: Bearer ...)",
1844
+ value: "manual"
1845
+ },
1846
+ {
1847
+ name: "Skip / None",
1848
+ value: "skip"
1849
+ }
1850
+ ]
1851
+ });
1852
+ if (mode === "skip") {
1853
+ return headers;
1854
+ }
1855
+ if (mode === "paste" || mode === "editor") {
1856
+ const pasted = mode === "editor" ? await promptEditorText({
1857
+ message: "Paste or edit HTTP headers in editor, then save and exit:"
1858
+ }) : await readMultilineTextFromTerminal(
1859
+ "Paste HTTP headers content (multiline supported, e.g. Authorization: Bearer ...):"
1860
+ );
1861
+ const parsed = parseHeadersText(pasted);
1862
+ const count = Object.keys(parsed).length;
1863
+ if (count === 0) {
1864
+ logger.warn("No valid Key: Value pairs recognized");
1865
+ } else {
1866
+ Object.assign(headers, parsed);
1867
+ logger.success(`Successfully parsed ${import_picocolors6.default.cyan(String(count))} headers:`);
1868
+ for (const [k, v] of Object.entries(parsed)) {
1869
+ const masked = SECRET_HEADER_PATTERN.test(k) && v.length > 8 ? `${v.slice(0, 4)}***${v.slice(-3)}` : v;
1870
+ console.log(` ${import_picocolors6.default.bold(k)}: ${import_picocolors6.default.dim(masked)}`);
1871
+ }
1872
+ }
1873
+ return headers;
1874
+ }
1875
+ logger.info("Entering HTTP headers (leave header name empty and press enter to finish):");
1876
+ while (true) {
1877
+ const name = await (0, import_prompts6.input)({
1878
+ message: "Header name (e.g. Authorization, leave empty to finish):",
1879
+ validate: (val2) => {
1880
+ const trimmed = val2.trim();
1881
+ if (!trimmed) return true;
1882
+ if (/\s/.test(trimmed)) return "Header name cannot contain spaces";
1883
+ return true;
1884
+ }
1885
+ });
1886
+ const trimmedName = name.trim();
1887
+ if (!trimmedName) break;
1888
+ const isSecret = SECRET_HEADER_PATTERN.test(trimmedName);
1889
+ let val;
1890
+ if (isSecret) {
1891
+ val = await (0, import_prompts6.password)({
1892
+ message: `Header value for (${trimmedName}) [sensitive content masked]:`,
1893
+ mask: "*"
1894
+ });
1895
+ } else {
1896
+ val = await (0, import_prompts6.input)({
1897
+ message: `Header value for (${trimmedName}):`
1898
+ });
1899
+ }
1900
+ headers[trimmedName] = val;
1901
+ logger.success(`Added: ${import_picocolors6.default.cyan(trimmedName)}`);
1902
+ }
1903
+ return headers;
1904
+ };
1905
+
1906
+ // src/interactive/wizard-add.ts
1907
+ var wizardAdd = async (initial = {}) => {
1908
+ const cwd = initial.cwd ?? process.cwd();
1909
+ logger.info(import_picocolors7.default.bold("Welcome to the MCP interactive add wizard"));
1910
+ let source = initial.source;
1911
+ if (!source) {
1912
+ const sourceType = await (0, import_prompts7.select)({
1913
+ message: "Select MCP server type:",
1914
+ choices: [
1915
+ {
1916
+ name: "npm package (run via npx)",
1917
+ value: "npm"
1918
+ },
1919
+ {
1920
+ name: "Remote MCP server (via HTTP / SSE URL)",
1921
+ value: "remote"
1922
+ },
1923
+ {
1924
+ name: "Local command / script / Docker (stdio)",
1925
+ value: "command"
1926
+ }
1927
+ ]
1928
+ });
1929
+ if (sourceType === "npm") {
1930
+ source = await (0, import_prompts7.input)({
1931
+ message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres or mcp-server-git):",
1932
+ validate: (val) => val.trim() ? true : "Package name cannot be empty"
1933
+ });
1934
+ } else if (sourceType === "remote") {
1935
+ source = await (0, import_prompts7.input)({
1936
+ message: "Enter remote server URL (e.g. https://mcp.example.com/sse):",
1937
+ validate: (val) => {
1938
+ const trimmed = val.trim();
1939
+ if (!trimmed) return "URL cannot be empty";
1940
+ if (!/^https?:\/\//i.test(trimmed)) return "Please enter a valid URL starting with http:// or https://";
1941
+ return true;
1942
+ }
1943
+ });
1944
+ } else {
1945
+ source = await (0, import_prompts7.input)({
1946
+ message: "Enter command and arguments (e.g. python -m my_mcp_server or docker run ...):",
1947
+ validate: (val) => val.trim() ? true : "Command cannot be empty"
1948
+ });
1949
+ }
1950
+ }
1951
+ source = source.trim();
1952
+ const parsed = parseMcpSource(source);
1953
+ let serverName = initial.name;
1954
+ if (!serverName) {
1955
+ serverName = await (0, import_prompts7.input)({
1956
+ message: "MCP server name:",
1957
+ default: parsed.inferredName,
1958
+ validate: (val) => val.trim() ? true : "Server name cannot be empty"
1959
+ });
1960
+ }
1961
+ serverName = serverName.trim();
1962
+ let transport = initial.transport;
1963
+ let headers = initial.headers ?? {};
1964
+ if (parsed.type === "remote") {
1965
+ if (!transport) {
1966
+ const isSseUrl = /\/sse\b/i.test(parsed.value);
1967
+ transport = await (0, import_prompts7.select)({
1968
+ message: "Select remote transport protocol:",
1969
+ choices: [
1970
+ { name: "HTTP", value: "http" },
1971
+ { name: "SSE (Server-Sent Events)", value: "sse" }
1972
+ ],
1973
+ default: isSseUrl ? "sse" : "http"
1974
+ });
1975
+ }
1976
+ if (Object.keys(headers).length === 0) {
1977
+ const needHeader = await (0, import_prompts7.confirm)({
1978
+ message: "Configure HTTP headers (e.g. Authorization Bearer token)?",
1979
+ default: false
1980
+ });
1981
+ if (needHeader) {
1982
+ headers = await promptHeadersConfig();
1983
+ }
1984
+ }
1985
+ }
1986
+ const { global: isGlobal, agents: selectedAgents } = await promptScopeAndAgents({
1987
+ cwd,
1988
+ defaultGlobal: initial.global,
1989
+ defaultAgents: initial.agents
1990
+ });
1991
+ let args = initial.args ?? [];
1992
+ if (parsed.type !== "remote") {
1993
+ args = await promptArgsConfig(args);
1994
+ }
1995
+ let env = initial.env ?? {};
1996
+ if (parsed.type !== "remote") {
1997
+ env = await promptEnvConfig(env);
1998
+ }
1999
+ console.log("\n" + import_picocolors7.default.cyan(import_picocolors7.default.bold("Configuration Preview:")));
2000
+ console.log(` ${import_picocolors7.default.bold("Server Name:")} ${import_picocolors7.default.green(serverName)}`);
2001
+ console.log(` ${import_picocolors7.default.bold("Server Type:")} ${import_picocolors7.default.magenta(parsed.type)}`);
2002
+ console.log(` ${import_picocolors7.default.bold("Source/Command:")} ${import_picocolors7.default.dim(source)}`);
2003
+ console.log(` ${import_picocolors7.default.bold("Scope:")} ${isGlobal ? import_picocolors7.default.yellow("Global") : import_picocolors7.default.blue("Project")}`);
2004
+ console.log(` ${import_picocolors7.default.bold("Target Agents:")} ${import_picocolors7.default.cyan(selectedAgents.join(", "))}`);
2005
+ if (args.length > 0) {
2006
+ console.log(` ${import_picocolors7.default.bold("Arguments:")} ${import_picocolors7.default.dim(args.join(" "))}`);
2007
+ }
2008
+ if (transport) {
2009
+ console.log(` ${import_picocolors7.default.bold("Transport:")} ${import_picocolors7.default.magenta(transport)}`);
2010
+ }
2011
+ const envKeys = Object.keys(env);
2012
+ if (envKeys.length > 0) {
2013
+ console.log(` ${import_picocolors7.default.bold("Environment Variables:")} ${import_picocolors7.default.dim(envKeys.join(", "))} (${envKeys.length})`);
2014
+ }
2015
+ const headerKeys = Object.keys(headers);
2016
+ if (headerKeys.length > 0) {
2017
+ console.log(` ${import_picocolors7.default.bold("Headers:")} ${import_picocolors7.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
2018
+ }
2019
+ console.log();
2020
+ const proceed = await (0, import_prompts7.confirm)({
2021
+ message: "Confirm installation with this configuration?",
2022
+ default: true
2023
+ });
2024
+ if (!proceed) {
2025
+ logger.warn("Operation cancelled");
2026
+ return false;
2027
+ }
2028
+ const result = installMcpServer({
2029
+ source,
2030
+ name: serverName,
2031
+ agents: selectedAgents,
2032
+ args,
2033
+ global: isGlobal,
2034
+ cwd,
2035
+ transport,
2036
+ headers,
2037
+ env
2038
+ });
2039
+ logger.info(
2040
+ `Writing ${import_picocolors7.default.bold(result.serverName)} to ${import_picocolors7.default.cyan(String(result.results.length))} agent config files...`
2041
+ );
2042
+ let allSuccess = true;
2043
+ for (const record of result.results) {
2044
+ if (record.success) {
2045
+ logger.success(`${import_picocolors7.default.cyan(record.agent)}: Successfully written to ${import_picocolors7.default.dim(record.path)}`);
2046
+ } else {
2047
+ allSuccess = false;
2048
+ logger.error(`${import_picocolors7.default.cyan(record.agent)}: Failed to write - ${record.error}`);
2049
+ }
2050
+ }
2051
+ if (allSuccess) {
2052
+ logger.success(import_picocolors7.default.bold(`MCP server "${serverName}" configured successfully!`));
2053
+ }
2054
+ return allSuccess;
2055
+ };
2056
+
2057
+ // src/interactive/wizard-manage.ts
2058
+ var import_prompts8 = require("@inquirer/prompts");
2059
+ var import_picocolors8 = __toESM(require("picocolors"), 1);
2060
+
2061
+ // src/interactive/utils/group-installed-servers.ts
2062
+ var normalizeServerConfig = parseServerConfig;
2063
+ var groupInstalledServersByName = (installed) => {
2064
+ const grouped = /* @__PURE__ */ new Map();
2065
+ for (const item of installed) {
2066
+ let entry = grouped.get(item.serverName);
2067
+ if (!entry) {
2068
+ entry = {
2069
+ serverName: item.serverName,
2070
+ agents: [],
2071
+ paths: [],
2072
+ config: normalizeServerConfig(item.config)
2073
+ };
2074
+ grouped.set(item.serverName, entry);
2075
+ }
2076
+ if (!entry.agents.includes(item.agent)) {
2077
+ entry.agents.push(item.agent);
2078
+ }
2079
+ if (!entry.paths.includes(item.path)) {
2080
+ entry.paths.push(item.path);
2081
+ }
2082
+ }
2083
+ return grouped;
2084
+ };
2085
+
2086
+ // src/interactive/wizard-manage.ts
2087
+ var wizardManage = async (options = {}) => {
2088
+ const cwd = options.cwd ?? process.cwd();
2089
+ const isGlobal = await promptScope({
2090
+ cwd,
2091
+ defaultGlobal: options.global,
2092
+ message: "Select MCP scope to inspect and manage:"
2093
+ });
2094
+ const installed = listInstalledMcpServers({ global: isGlobal, cwd });
2095
+ if (installed.length === 0) {
2096
+ logger.warn(`No configured MCP servers found in ${isGlobal ? "global" : "project"} scope`);
2097
+ return;
2098
+ }
2099
+ const grouped = groupInstalledServersByName(installed);
2100
+ while (true) {
2101
+ const choices = Array.from(grouped.values()).map((g) => {
2102
+ const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2103
+ return {
2104
+ name: `${import_picocolors8.default.bold(g.serverName)} ${import_picocolors8.default.dim(`(configured in: ${agentNames})`)}`,
2105
+ value: g.serverName
2106
+ };
2107
+ });
2108
+ choices.push({
2109
+ name: `Back`,
2110
+ value: "__back__"
2111
+ });
2112
+ const chosenServerName = await (0, import_prompts8.select)({
2113
+ message: "Select MCP server to manage or sync:",
2114
+ choices
2115
+ });
2116
+ if (chosenServerName === "__back__") {
2117
+ return;
2118
+ }
2119
+ const targetGroup = grouped.get(chosenServerName);
2120
+ if (!targetGroup) continue;
2121
+ console.log("\n" + import_picocolors8.default.cyan(import_picocolors8.default.bold(`MCP Server Details: [${chosenServerName}]`)));
2122
+ console.log(` ${import_picocolors8.default.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
2123
+ console.log(
2124
+ ` ${import_picocolors8.default.bold("Configured Agents:")} ${import_picocolors8.default.green(targetGroup.agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2125
+ );
2126
+ const cfg = targetGroup.config;
2127
+ if (isRemoteServerConfig(cfg)) {
2128
+ console.log(` ${import_picocolors8.default.bold("URL:")} ${import_picocolors8.default.dim(cfg.url)} (${cfg.type})`);
2129
+ if (cfg.headers && Object.keys(cfg.headers).length > 0) {
2130
+ console.log(` ${import_picocolors8.default.bold("Headers:")} ${Object.keys(cfg.headers).join(", ")}`);
2131
+ }
2132
+ } else if (isStdioServerConfig(cfg)) {
2133
+ console.log(` ${import_picocolors8.default.bold("Command:")} ${import_picocolors8.default.magenta(cfg.command)}`);
2134
+ if (cfg.args && cfg.args.length > 0) {
2135
+ console.log(` ${import_picocolors8.default.bold("Arguments:")} ${import_picocolors8.default.dim(cfg.args.join(" "))}`);
2136
+ }
2137
+ if (cfg.env && Object.keys(cfg.env).length > 0) {
2138
+ console.log(` ${import_picocolors8.default.bold("Environment Variables:")} ${import_picocolors8.default.dim(Object.keys(cfg.env).join(", "))}`);
2139
+ }
2140
+ }
2141
+ console.log();
2142
+ const action = await (0, import_prompts8.select)({
2143
+ message: `What would you like to do with [${chosenServerName}]?`,
2144
+ choices: [
2145
+ {
2146
+ name: "Sync / clone to other agents",
2147
+ value: "sync"
2148
+ },
2149
+ {
2150
+ name: "Back to list",
2151
+ value: "back"
2152
+ }
2153
+ ]
2154
+ });
2155
+ if (action === "back") continue;
2156
+ if (action === "sync") {
2157
+ const allAllowedAgents = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
2158
+ const candidateAgents = allAllowedAgents.filter((a) => !targetGroup.agents.includes(a));
2159
+ if (candidateAgents.length === 0) {
2160
+ logger.info("All supported agents in this scope already have this MCP server configured; no sync needed");
2161
+ continue;
2162
+ }
2163
+ const selectedToSync = await (0, import_prompts8.checkbox)({
2164
+ message: "Select target agents to sync to (Space to select):",
2165
+ choices: candidateAgents.map((a) => ({
2166
+ name: `${getMcpAgentConfig(a).displayName} (${a})`,
2167
+ value: a,
2168
+ checked: false
2169
+ })),
2170
+ validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2171
+ });
2172
+ const confirmed = await (0, import_prompts8.confirm)({
2173
+ message: `Confirm syncing configuration of [${chosenServerName}] to: ${selectedToSync.join(", ")}?`,
2174
+ default: true
2175
+ });
2176
+ if (!confirmed) {
2177
+ logger.warn("Sync cancelled");
2178
+ continue;
2179
+ }
2180
+ for (const targetAgent of selectedToSync) {
2181
+ const res = installMcpServerForAgent(chosenServerName, targetGroup.config, targetAgent, {
2182
+ global: isGlobal,
2183
+ cwd
2184
+ });
2185
+ if (res.success) {
2186
+ logger.success(`${import_picocolors8.default.cyan(targetAgent)}: Successfully synced to ${import_picocolors8.default.dim(res.path)}`);
2187
+ targetGroup.agents.push(targetAgent);
2188
+ } else {
2189
+ logger.error(`${import_picocolors8.default.cyan(targetAgent)}: Sync failed - ${res.error}`);
2190
+ }
2191
+ }
2192
+ }
2193
+ }
2194
+ };
2195
+
2196
+ // src/interactive/wizard-remove.ts
2197
+ var import_prompts9 = require("@inquirer/prompts");
2198
+ var import_picocolors9 = __toESM(require("picocolors"), 1);
2199
+ var wizardRemove = async (options = {}) => {
2200
+ const cwd = options.cwd ?? process.cwd();
2201
+ const isGlobal = await promptScope({
2202
+ cwd,
2203
+ defaultGlobal: options.global,
2204
+ message: "Select scope to remove MCP server from:"
2205
+ });
2206
+ const installed = listInstalledMcpServers({ global: isGlobal, cwd });
2207
+ if (installed.length === 0) {
2208
+ logger.warn(`No installed MCP servers found in ${isGlobal ? "global" : "project"} scope`);
2209
+ return false;
2210
+ }
2211
+ const serverMap = groupInstalledServersByName(installed);
2212
+ let serverName = options.name;
2213
+ if (!serverName) {
2214
+ const choices = Array.from(serverMap.values()).map((g) => ({
2215
+ name: `${import_picocolors9.default.bold(g.serverName)} ${import_picocolors9.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
2216
+ value: g.serverName
2217
+ }));
2218
+ serverName = await (0, import_prompts9.select)({
2219
+ message: "Select MCP server to remove:",
2220
+ choices
2221
+ });
2222
+ }
2223
+ const installedAgents = serverMap.get(serverName)?.agents || [];
2224
+ if (installedAgents.length === 0) {
2225
+ logger.warn(`No agents found with [${serverName}] installed`);
2226
+ return false;
2227
+ }
2228
+ let targetAgents = options.agents;
2229
+ if (!targetAgents || targetAgents.length === 0) {
2230
+ targetAgents = await (0, import_prompts9.checkbox)({
2231
+ message: `Select agents to remove [${serverName}] from:`,
2232
+ choices: installedAgents.map((agent) => ({
2233
+ name: `${getMcpAgentConfig(agent)?.displayName ?? agent} (${agent})`,
2234
+ value: agent,
2235
+ checked: true
2236
+ })),
2237
+ validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2238
+ });
2239
+ } else {
2240
+ const validAgents = targetAgents.filter((agent) => installedAgents.includes(agent));
2241
+ if (validAgents.length === 0) {
2242
+ logger.warn(`None of the specified agents (${targetAgents.join(", ")}) have [${serverName}] installed`);
2243
+ return false;
2244
+ }
2245
+ targetAgents = validAgents;
2246
+ }
2247
+ const confirmed = await (0, import_prompts9.confirm)({
2248
+ message: `Confirm removing MCP server [${serverName}] from ${targetAgents.join(", ")}?`,
2249
+ default: true
2250
+ });
2251
+ if (!confirmed) {
2252
+ logger.warn("Operation cancelled");
2253
+ return false;
2254
+ }
2255
+ const results = removeMcpServer({
2256
+ name: serverName,
2257
+ agents: targetAgents,
2258
+ global: isGlobal,
2259
+ cwd
2260
+ });
2261
+ let removedCount = 0;
2262
+ for (const res of results) {
2263
+ if (res.removed) {
2264
+ logger.success(`${import_picocolors9.default.cyan(res.agent)}: Successfully removed from ${import_picocolors9.default.dim(res.path)}`);
2265
+ removedCount++;
2266
+ } else if (res.error) {
2267
+ logger.error(`${import_picocolors9.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
2268
+ }
2269
+ }
2270
+ if (removedCount > 0) {
2271
+ logger.success(`Successfully removed [${serverName}] from ${removedCount} agent(s)`);
2272
+ return true;
2273
+ }
2274
+ logger.warn(`Failed to remove [${serverName}] from specified agents`);
2275
+ return false;
2276
+ };
2277
+
2278
+ // src/interactive/main-menu.ts
2279
+ var mainMenu = async () => {
2280
+ console.log();
2281
+ console.log(import_picocolors10.default.bold(import_picocolors10.default.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
2282
+ console.log(import_picocolors10.default.dim("Cross-platform MCP server configuration & synchronization tool"));
2283
+ console.log();
2284
+ while (true) {
2285
+ try {
2286
+ const action = await (0, import_prompts10.select)({
2287
+ message: "Select an action:",
2288
+ choices: [
2289
+ {
2290
+ name: "Add MCP Server",
2291
+ value: "add"
2292
+ },
2293
+ {
2294
+ name: "Manage & Sync Installed MCP Servers",
2295
+ value: "manage"
2296
+ },
2297
+ {
2298
+ name: "Remove MCP Server",
2299
+ value: "remove"
2300
+ },
2301
+ {
2302
+ name: "Exit",
2303
+ value: "exit"
2304
+ }
2305
+ ]
2306
+ });
2307
+ if (action === "exit") {
2308
+ console.log(import_picocolors10.default.dim("Goodbye!"));
2309
+ break;
2310
+ }
2311
+ if (action === "add") {
2312
+ await wizardAdd();
2313
+ } else if (action === "manage") {
2314
+ await wizardManage();
2315
+ } else if (action === "remove") {
2316
+ await wizardRemove();
2317
+ }
2318
+ console.log();
2319
+ } catch (error) {
2320
+ if (error?.name === "ExitPromptError") {
2321
+ console.log("\n" + import_picocolors10.default.dim("Exited."));
2322
+ break;
2323
+ }
2324
+ throw error;
2325
+ }
2326
+ }
2327
+ };
2328
+
2329
+ // src/utils/format-agent-list.ts
2330
+ var formatAgentList = (agentList, emptyLabel = "(none)") => agentList.length === 0 ? emptyLabel : agentList.join(", ");
2331
+
2332
+ // src/cli/add.ts
2333
+ var parseKeyValueList = (entries, separator) => {
2334
+ if (!entries || entries.length === 0) return {};
2335
+ const result = {};
2336
+ for (const entry of entries) {
2337
+ const splitIndex = entry.indexOf(separator);
2338
+ if (splitIndex === -1) {
2339
+ throw new Error(`Invalid entry "${entry}": expected "${separator}" separator`);
2340
+ }
2341
+ const key = entry.slice(0, splitIndex).trim();
2342
+ const value = entry.slice(splitIndex + separator.length).trim();
2343
+ if (!key) throw new Error(`Invalid entry "${entry}": empty key`);
2344
+ result[key] = value;
2345
+ }
2346
+ return result;
2347
+ };
2348
+ var resolveTransport = (input5) => {
2349
+ if (!input5) return void 0;
2350
+ if (input5 === "http" || input5 === "sse") return input5;
2351
+ throw new Error(`Unsupported transport "${input5}" (expected: http, sse)`);
2352
+ };
2353
+ var mcpAddCommand = new import_commander.Command("add").description("Add an MCP server to coding agents").argument("[source]", "Remote URL, npm package, or command line").option("-a, --agent <agents...>", "Target specific agents (use '*' for all)").option("-g, --global", "Install to user-level config instead of project").option("-t, --transport <type>", "Transport type for remote servers (http or sse)").option("--header <header...>", "HTTP header (Key: Value), repeatable").option("--env <env...>", "Env var for stdio servers (KEY=VALUE), repeatable").option("--args <args...>", "CLI arguments for stdio/package servers").option("-n, --name <name>", "Server name override").option("-y, --yes", "Skip all prompts").option("--all", "Install to all supported agents").action(async (source, options) => {
2354
+ try {
2355
+ const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
2356
+ if (!source) {
2357
+ if (isInteractive) {
2358
+ const success = await wizardAdd({
2359
+ name: options.name,
2360
+ global: options.global,
2361
+ args: options.args,
2362
+ transport: resolveTransport(options.transport),
2363
+ headers: parseKeyValueList(options.header, ":"),
2364
+ env: parseKeyValueList(options.env, "="),
2365
+ agents: options.all ? getMcpAgentTypes() : parseMcpAgentList(options.agent)
2366
+ });
2367
+ if (!success) process.exitCode = 1;
2368
+ return;
2369
+ }
2370
+ logger.error('Missing required argument: "source" (e.g. mcps add @modelcontextprotocol/server-filesystem)');
2371
+ process.exitCode = 1;
2372
+ return;
2373
+ }
2374
+ const parsed = parseMcpSource(source);
2375
+ const cwd = process.cwd();
2376
+ const isGlobal = Boolean(options.global);
2377
+ const explicitTransport = resolveTransport(options.transport);
2378
+ const transport = explicitTransport ?? (parsed.type === "remote" ? "http" : "stdio");
2379
+ const resolvedTargets = resolveTargetAgents({
2380
+ requested: options.agent,
2381
+ all: options.all,
2382
+ global: isGlobal,
2383
+ cwd,
2384
+ transport
2385
+ });
2386
+ if (resolvedTargets.agents.length === 0) {
2387
+ const message = resolvedTargets.diagnostic ?? `No ${isGlobal ? "global" : "project"}-installed MCP agents detected. Pass ${import_picocolors11.default.cyan("-a <agent>")} (e.g. ${import_picocolors11.default.cyan("-a cursor")}) or ${import_picocolors11.default.cyan("--all")} to install.`;
2388
+ logger.warn(message);
2389
+ process.exitCode = 1;
2390
+ return;
2391
+ }
2392
+ if (resolvedTargets.isDetected) {
2393
+ logger.info(
2394
+ `Detected ${isGlobal ? "global" : "project"} agents: ${import_picocolors11.default.cyan(formatAgentList(resolvedTargets.detected, "(none detected)"))}`
2395
+ );
2396
+ if (resolvedTargets.incompatible.length > 0) {
2397
+ const skippedList = resolvedTargets.incompatible.map((item) => `${item.agent} (${item.reason})`).join(", ");
2398
+ logger.info(
2399
+ `Skipping detected agents incompatible with ${transport}: ${import_picocolors11.default.yellow(skippedList)}`
2400
+ );
2401
+ }
2402
+ }
2403
+ const targetAgents = resolvedTargets.isDetected ? resolvedTargets.agents : resolvedTargets.allAgents;
2404
+ const result = installMcpServer({
2405
+ source,
2406
+ name: options.name,
2407
+ agents: targetAgents,
2408
+ args: options.args,
2409
+ global: isGlobal,
2410
+ cwd,
2411
+ transport: explicitTransport,
2412
+ headers: parseKeyValueList(options.header, ":"),
2413
+ env: parseKeyValueList(options.env, "=")
2414
+ });
2415
+ logger.info(
2416
+ `Installing ${import_picocolors11.default.bold(result.serverName)} (${import_picocolors11.default.cyan(parsed.type)}) to ${import_picocolors11.default.cyan(String(result.results.length))} agent(s)`
2417
+ );
2418
+ for (const record of result.results) {
2419
+ if (record.success) {
2420
+ logger.success(`${import_picocolors11.default.cyan(record.agent)} ${import_picocolors11.default.dim(record.path)}`);
2421
+ } else {
2422
+ logger.error(`${import_picocolors11.default.cyan(record.agent)}: ${record.error}`);
2423
+ }
2424
+ }
2425
+ if (result.results.some((record) => !record.success)) process.exitCode = 1;
2426
+ } catch (error) {
2427
+ logger.error(toErrorMessage(error));
2428
+ process.exitCode = 1;
2429
+ }
2430
+ });
2431
+
2432
+ // src/cli/list.ts
2433
+ var import_commander2 = require("commander");
2434
+ var import_picocolors12 = __toESM(require("picocolors"), 1);
2435
+ var mcpListCommand = new import_commander2.Command("list").alias("ls").description("List installed MCP servers across agents").option("-g, --global", "List global configs instead of project").option("-a, --agent <agents...>", "Filter by specific agents").option("--json", "Output as JSON").action((options) => {
2436
+ try {
2437
+ const entries = listInstalledMcpServers({
2438
+ global: Boolean(options.global),
2439
+ cwd: process.cwd(),
2440
+ agents: parseMcpAgentList(options.agent)
2441
+ });
2442
+ if (options.json) {
2443
+ console.log(JSON.stringify(entries, null, 2));
2444
+ return;
2445
+ }
2446
+ if (entries.length === 0) {
2447
+ logger.warn("No MCP servers installed");
2448
+ return;
2449
+ }
2450
+ const grouped = /* @__PURE__ */ new Map();
2451
+ for (const entry of entries) {
2452
+ const existing = grouped.get(entry.serverName) ?? [];
2453
+ existing.push(entry);
2454
+ grouped.set(entry.serverName, existing);
2455
+ }
2456
+ for (const [serverName, group] of grouped) {
2457
+ const agentLabels = group.map((record) => record.agent).join(", ");
2458
+ console.log(` ${import_picocolors12.default.bold(serverName)} ${import_picocolors12.default.dim(`[${agentLabels}]`)}`);
2459
+ const firstPath = group[0]?.path;
2460
+ if (firstPath) console.log(` ${import_picocolors12.default.dim(firstPath)}`);
2461
+ }
2462
+ } catch (error) {
2463
+ logger.error(toErrorMessage(error));
2464
+ process.exitCode = 1;
2465
+ }
2466
+ });
2467
+
2468
+ // src/cli/remove.ts
2469
+ var import_commander3 = require("commander");
2470
+ var import_picocolors13 = __toESM(require("picocolors"), 1);
2471
+ var mcpRemoveCommand = new import_commander3.Command("remove").alias("rm").description("Remove an MCP server from agent configs").argument("[name]", "Server name").option("-g, --global", "Remove from global scope").option("-a, --agent <agents...>", "Filter by specific agents (use '*' for all)").option("-y, --yes", "Skip confirmation prompts").action(async (name, options) => {
2472
+ try {
2473
+ const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
2474
+ if (!name) {
2475
+ if (isInteractive) {
2476
+ const success = await wizardRemove({
2477
+ global: options.global,
2478
+ agents: parseMcpAgentList(options.agent)
2479
+ });
2480
+ if (!success) process.exitCode = 1;
2481
+ return;
2482
+ }
2483
+ logger.error('Missing required argument: "name" (e.g. mcps remove server-filesystem)');
2484
+ process.exitCode = 1;
2485
+ return;
2486
+ }
2487
+ const results = removeMcpServer({
2488
+ name,
2489
+ agents: parseMcpAgentList(options.agent),
2490
+ global: Boolean(options.global),
2491
+ cwd: process.cwd()
2492
+ });
2493
+ if (results.length === 0) {
2494
+ logger.warn(`No agent config contained ${import_picocolors13.default.bold(name)}`);
2495
+ return;
2496
+ }
2497
+ for (const record of results) {
2498
+ if (record.removed) {
2499
+ logger.success(
2500
+ `${import_picocolors13.default.cyan(record.agent)} removed ${import_picocolors13.default.bold(name)} ${import_picocolors13.default.dim(record.path)}`
2501
+ );
2502
+ } else {
2503
+ logger.error(`${import_picocolors13.default.cyan(record.agent)}: ${record.error ?? "not found"}`);
2504
+ }
2505
+ }
2506
+ } catch (error) {
2507
+ logger.error(toErrorMessage(error));
2508
+ process.exitCode = 1;
2509
+ }
2510
+ });
2511
+
2512
+ // src/cli.ts
2513
+ var VERSION = "0.1.0-beta.1";
2514
+ process.on("SIGINT", () => process.exit(0));
2515
+ process.on("SIGTERM", () => process.exit(0));
2516
+ var program = new import_commander4.Command().name("mcps").description("Install, list, and remove MCP servers across AI coding agents").version(VERSION, "-v, --version", "display the version number");
2517
+ program.addCommand(mcpAddCommand);
2518
+ program.addCommand(mcpListCommand);
2519
+ program.addCommand(mcpRemoveCommand);
2520
+ var main = async () => {
2521
+ if (process.argv.length <= 2 && process.stdin.isTTY) {
2522
+ try {
2523
+ await mainMenu();
2524
+ return;
2525
+ } catch (error) {
2526
+ if (error?.name === "ExitPromptError") {
2527
+ process.exit(0);
2528
+ }
2529
+ throw error;
2530
+ }
2531
+ }
2532
+ await program.parseAsync();
2533
+ };
2534
+ main();