mcpcm 1.0.3

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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +356 -0
  3. package/dist/cli.js +1383 -0
  4. package/package.json +63 -0
package/dist/cli.js ADDED
@@ -0,0 +1,1383 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import { readFileSync as readFileSync5 } from "fs";
5
+ import { dirname as dirname2, join as join5 } from "path";
6
+ import { fileURLToPath } from "url";
7
+
8
+ // src/commands/add.ts
9
+ import { readFileSync as readFileSync3 } from "fs";
10
+
11
+ // src/agents.ts
12
+ import { homedir, platform } from "os";
13
+ import { join } from "path";
14
+ import { existsSync } from "fs";
15
+ var home = homedir();
16
+ var isMac = platform() === "darwin";
17
+ var isWindows = platform() === "win32";
18
+ function getVscodeGlobalPath() {
19
+ if (isMac) {
20
+ return join(home, "Library/Application Support/Code/User/mcp.json");
21
+ } else if (isWindows) {
22
+ return join(home, "AppData/Roaming/Code/User/mcp.json");
23
+ } else {
24
+ return join(home, ".config/Code/User/mcp.json");
25
+ }
26
+ }
27
+ var agents = {
28
+ cursor: {
29
+ name: "cursor",
30
+ displayName: "Cursor",
31
+ projectConfigPath: ".cursor/mcp.json",
32
+ globalConfigPath: join(home, ".cursor/mcp.json"),
33
+ configFormat: "json",
34
+ mcpConfigKey: "mcpServers",
35
+ detectInstalled: async () => existsSync(join(home, ".cursor"))
36
+ },
37
+ "claude-code": {
38
+ name: "claude-code",
39
+ displayName: "Claude Code",
40
+ projectConfigPath: ".mcp.json",
41
+ globalConfigPath: join(home, ".claude.json"),
42
+ configFormat: "json",
43
+ mcpConfigKey: "mcpServers",
44
+ detectInstalled: async () => existsSync(join(home, ".claude.json"))
45
+ },
46
+ antigravity: {
47
+ name: "antigravity",
48
+ displayName: "Antigravity",
49
+ projectConfigPath: ".gemini/mcp_config.json",
50
+ globalConfigPath: join(home, ".gemini/antigravity/mcp_config.json"),
51
+ configFormat: "json",
52
+ mcpConfigKey: "mcpServers",
53
+ detectInstalled: async () => existsSync(join(home, ".gemini/antigravity")) || existsSync(join(home, ".gemini"))
54
+ },
55
+ windsurf: {
56
+ name: "windsurf",
57
+ displayName: "Windsurf",
58
+ projectConfigPath: ".windsurf/mcp_config.json",
59
+ globalConfigPath: join(home, ".codeium/windsurf/mcp_config.json"),
60
+ configFormat: "json",
61
+ mcpConfigKey: "mcpServers",
62
+ detectInstalled: async () => existsSync(join(home, ".codeium/windsurf"))
63
+ },
64
+ vscode: {
65
+ name: "vscode",
66
+ displayName: "VS Code / GitHub Copilot",
67
+ projectConfigPath: ".vscode/mcp.json",
68
+ globalConfigPath: getVscodeGlobalPath(),
69
+ configFormat: "json",
70
+ mcpConfigKey: "servers",
71
+ detectInstalled: async () => {
72
+ if (isMac) {
73
+ return existsSync(join(home, "Library/Application Support/Code"));
74
+ } else if (isWindows) {
75
+ return existsSync(join(home, "AppData/Roaming/Code"));
76
+ }
77
+ return existsSync(join(home, ".config/Code"));
78
+ }
79
+ },
80
+ codex: {
81
+ name: "codex",
82
+ displayName: "Codex",
83
+ projectConfigPath: ".codex/config.toml",
84
+ globalConfigPath: join(home, ".codex/config.toml"),
85
+ configFormat: "toml",
86
+ mcpConfigKey: "mcp_servers",
87
+ detectInstalled: async () => existsSync(join(home, ".codex"))
88
+ },
89
+ opencode: {
90
+ name: "opencode",
91
+ displayName: "OpenCode",
92
+ projectConfigPath: null,
93
+ globalConfigPath: join(home, ".config/opencode/opencode.json"),
94
+ configFormat: "json",
95
+ mcpConfigKey: "mcpServers",
96
+ detectInstalled: async () => existsSync(join(home, ".config/opencode"))
97
+ },
98
+ "gemini-cli": {
99
+ name: "gemini-cli",
100
+ displayName: "Gemini CLI",
101
+ projectConfigPath: ".gemini/settings.json",
102
+ globalConfigPath: join(home, ".gemini/settings.json"),
103
+ configFormat: "json",
104
+ mcpConfigKey: "mcpServers",
105
+ detectInstalled: async () => existsSync(join(home, ".gemini"))
106
+ },
107
+ qoder: {
108
+ name: "qoder",
109
+ displayName: "Qoder",
110
+ projectConfigPath: null,
111
+ globalConfigPath: null,
112
+ // Managed via qodercli
113
+ configFormat: "json",
114
+ mcpConfigKey: null,
115
+ detectInstalled: async () => false
116
+ // Cannot detect programmatically
117
+ },
118
+ "qwen-code": {
119
+ name: "qwen-code",
120
+ displayName: "Qwen Code",
121
+ projectConfigPath: ".qwen/settings.json",
122
+ globalConfigPath: join(home, ".qwen/settings.json"),
123
+ configFormat: "json",
124
+ mcpConfigKey: "mcpServers",
125
+ detectInstalled: async () => existsSync(join(home, ".qwen"))
126
+ },
127
+ trae: {
128
+ name: "trae",
129
+ displayName: "Trae",
130
+ projectConfigPath: ".trae/mcp.json",
131
+ globalConfigPath: null,
132
+ configFormat: "json",
133
+ mcpConfigKey: "mcpServers",
134
+ detectInstalled: async () => existsSync(join(process.cwd(), ".trae"))
135
+ }
136
+ };
137
+ function getAllAgentTypes() {
138
+ return Object.keys(agents);
139
+ }
140
+ async function detectInstalledAgents() {
141
+ const installed = [];
142
+ for (const [type, config] of Object.entries(agents)) {
143
+ if (await config.detectInstalled()) {
144
+ installed.push(type);
145
+ }
146
+ }
147
+ return installed;
148
+ }
149
+ function getAgentConfig(type) {
150
+ return agents[type];
151
+ }
152
+ function isValidAgentType(type) {
153
+ return type in agents;
154
+ }
155
+
156
+ // src/config-reader.ts
157
+ import { readFileSync, existsSync as existsSync3 } from "fs";
158
+ import { join as join3 } from "path";
159
+ import { parse as parseToml } from "@iarna/toml";
160
+
161
+ // src/utils.ts
162
+ import { homedir as homedir2 } from "os";
163
+ import { join as join2, dirname } from "path";
164
+ import { existsSync as existsSync2, mkdirSync } from "fs";
165
+ var RESET = "\x1B[0m";
166
+ var BOLD = "\x1B[1m";
167
+ var DIM = "\x1B[38;5;102m";
168
+ var TEXT = "\x1B[38;5;145m";
169
+ var GREEN = "\x1B[38;5;78m";
170
+ var YELLOW = "\x1B[38;5;220m";
171
+ var RED = "\x1B[38;5;196m";
172
+ var CYAN = "\x1B[38;5;87m";
173
+ function expandPath(path) {
174
+ if (path.startsWith("~")) {
175
+ return join2(homedir2(), path.slice(1));
176
+ }
177
+ return path;
178
+ }
179
+ function ensureDir(filePath) {
180
+ const dir = dirname(filePath);
181
+ if (!existsSync2(dir)) {
182
+ mkdirSync(dir, { recursive: true });
183
+ }
184
+ }
185
+ function safeParseJson(content) {
186
+ try {
187
+ return JSON.parse(content);
188
+ } catch {
189
+ return null;
190
+ }
191
+ }
192
+ function formatServerConfig(name, config) {
193
+ const command = config["command"] || "unknown";
194
+ const args = config["args"] || [];
195
+ const argsStr = args.length > 0 ? ` ${args.join(" ")}` : "";
196
+ return `${CYAN}${name}${RESET}: ${DIM}${command}${argsStr}${RESET}`;
197
+ }
198
+ function success(message) {
199
+ console.log(`${GREEN}\u2713${RESET} ${message}`);
200
+ }
201
+ function error(message) {
202
+ console.log(`${RED}\u2717${RESET} ${message}`);
203
+ }
204
+ function warn(message) {
205
+ console.log(`${YELLOW}!${RESET} ${message}`);
206
+ }
207
+ function info(message) {
208
+ console.log(`${DIM}${message}${RESET}`);
209
+ }
210
+ function verbose(message, isVerbose) {
211
+ if (isVerbose) {
212
+ console.log(`${DIM}[verbose] ${message}${RESET}`);
213
+ }
214
+ }
215
+
216
+ // src/config-reader.ts
217
+ function readConfigFile(filePath, format, mcpConfigKey, verboseMode = false) {
218
+ const expandedPath = expandPath(filePath);
219
+ if (!existsSync3(expandedPath)) {
220
+ verbose(`Config file not found: ${expandedPath}`, verboseMode);
221
+ return { config: null, rawContent: null, path: expandedPath, exists: false };
222
+ }
223
+ try {
224
+ const content = readFileSync(expandedPath, "utf-8");
225
+ let parsed;
226
+ if (format === "toml") {
227
+ parsed = parseToml(content);
228
+ } else {
229
+ const jsonParsed = safeParseJson(content);
230
+ if (!jsonParsed) {
231
+ return {
232
+ config: null,
233
+ rawContent: null,
234
+ path: expandedPath,
235
+ exists: true,
236
+ error: "Invalid JSON"
237
+ };
238
+ }
239
+ parsed = jsonParsed;
240
+ }
241
+ let mcpServers = {};
242
+ if (mcpConfigKey) {
243
+ const servers = parsed[mcpConfigKey];
244
+ if (servers && typeof servers === "object") {
245
+ mcpServers = servers;
246
+ }
247
+ } else {
248
+ if (parsed["mcpServers"] && typeof parsed["mcpServers"] === "object") {
249
+ mcpServers = parsed["mcpServers"];
250
+ }
251
+ }
252
+ verbose(`Read config from ${expandedPath}: ${Object.keys(mcpServers).length} servers`, verboseMode);
253
+ return {
254
+ config: { mcpServers },
255
+ rawContent: parsed,
256
+ path: expandedPath,
257
+ exists: true
258
+ };
259
+ } catch (err) {
260
+ return {
261
+ config: null,
262
+ rawContent: null,
263
+ path: expandedPath,
264
+ exists: true,
265
+ error: err instanceof Error ? err.message : "Unknown error"
266
+ };
267
+ }
268
+ }
269
+ function readGlobalConfig(agentType, verboseMode = false) {
270
+ const agent = getAgentConfig(agentType);
271
+ if (!agent.globalConfigPath) {
272
+ return {
273
+ config: null,
274
+ rawContent: null,
275
+ path: "",
276
+ exists: false,
277
+ error: "No global config path"
278
+ };
279
+ }
280
+ return readConfigFile(
281
+ agent.globalConfigPath,
282
+ agent.configFormat,
283
+ agent.mcpConfigKey,
284
+ verboseMode
285
+ );
286
+ }
287
+ function readProjectConfig(agentType, projectDir = process.cwd(), verboseMode = false) {
288
+ const agent = getAgentConfig(agentType);
289
+ if (!agent.projectConfigPath) {
290
+ return {
291
+ config: null,
292
+ rawContent: null,
293
+ path: "",
294
+ exists: false,
295
+ error: "No project config path"
296
+ };
297
+ }
298
+ const fullPath = join3(projectDir, agent.projectConfigPath);
299
+ return readConfigFile(fullPath, agent.configFormat, agent.mcpConfigKey, verboseMode);
300
+ }
301
+ function parseMcpConfigString(jsonString) {
302
+ const parsed = safeParseJson(jsonString);
303
+ if (!parsed) return null;
304
+ if (parsed["mcpServers"] && typeof parsed["mcpServers"] === "object") {
305
+ return { mcpServers: parsed["mcpServers"] };
306
+ }
307
+ const firstValue = Object.values(parsed)[0];
308
+ if (firstValue && typeof firstValue === "object" && "command" in firstValue) {
309
+ return { mcpServers: parsed };
310
+ }
311
+ return null;
312
+ }
313
+
314
+ // src/config-writer.ts
315
+ import { writeFileSync, readFileSync as readFileSync2, existsSync as existsSync4 } from "fs";
316
+ import { join as join4 } from "path";
317
+ import { parse as parseToml2, stringify as stringifyToml } from "@iarna/toml";
318
+ function mergeMcpConfigs(existing, incoming, replace = false) {
319
+ if (replace) {
320
+ return {
321
+ mcpServers: {
322
+ ...existing.mcpServers,
323
+ ...incoming.mcpServers
324
+ }
325
+ };
326
+ }
327
+ const merged = { ...existing.mcpServers };
328
+ for (const [name, config] of Object.entries(incoming.mcpServers)) {
329
+ if (merged[name]) {
330
+ merged[name] = { ...merged[name], ...config };
331
+ } else {
332
+ merged[name] = config;
333
+ }
334
+ }
335
+ return { mcpServers: merged };
336
+ }
337
+ function removeServersFromConfig(config, serverNames) {
338
+ const filtered = { ...config.mcpServers };
339
+ for (const name of serverNames) {
340
+ delete filtered[name];
341
+ }
342
+ return { mcpServers: filtered };
343
+ }
344
+ function writeConfigFile(filePath, config, format, mcpConfigKey, existingContent = null, verboseMode = false) {
345
+ const expandedPath = expandPath(filePath);
346
+ try {
347
+ ensureDir(expandedPath);
348
+ let content;
349
+ if (existingContent) {
350
+ content = { ...existingContent };
351
+ } else if (existsSync4(expandedPath)) {
352
+ const existing = readFileSync2(expandedPath, "utf-8");
353
+ if (format === "toml") {
354
+ content = parseToml2(existing);
355
+ } else {
356
+ content = safeParseJson(existing) || {};
357
+ }
358
+ } else {
359
+ content = {};
360
+ }
361
+ const key = mcpConfigKey || "mcpServers";
362
+ content[key] = config.mcpServers;
363
+ let output;
364
+ if (format === "toml") {
365
+ output = stringifyToml(content);
366
+ } else {
367
+ output = JSON.stringify(content, null, 2);
368
+ }
369
+ writeFileSync(expandedPath, output, "utf-8");
370
+ verbose(`Wrote config to ${expandedPath}`, verboseMode);
371
+ return { success: true, path: expandedPath };
372
+ } catch (err) {
373
+ return {
374
+ success: false,
375
+ path: expandedPath,
376
+ error: err instanceof Error ? err.message : "Unknown error"
377
+ };
378
+ }
379
+ }
380
+ function writeGlobalConfig(agentType, config, existingContent = null, verboseMode = false) {
381
+ const agent = getAgentConfig(agentType);
382
+ if (!agent.globalConfigPath) {
383
+ return { success: false, path: "", error: "No global config path" };
384
+ }
385
+ return writeConfigFile(
386
+ agent.globalConfigPath,
387
+ config,
388
+ agent.configFormat,
389
+ agent.mcpConfigKey,
390
+ existingContent,
391
+ verboseMode
392
+ );
393
+ }
394
+ function writeProjectConfig(agentType, config, existingContent = null, projectDir = process.cwd(), verboseMode = false) {
395
+ const agent = getAgentConfig(agentType);
396
+ if (!agent.projectConfigPath) {
397
+ return { success: false, path: "", error: "No project config path" };
398
+ }
399
+ const fullPath = join4(projectDir, agent.projectConfigPath);
400
+ return writeConfigFile(
401
+ fullPath,
402
+ config,
403
+ agent.configFormat,
404
+ agent.mcpConfigKey,
405
+ existingContent,
406
+ verboseMode
407
+ );
408
+ }
409
+
410
+ // src/commands/add.ts
411
+ function parseAddOptions(args) {
412
+ const options = {};
413
+ let input = null;
414
+ for (let i = 0; i < args.length; i++) {
415
+ const arg = args[i];
416
+ if (arg === "--agent" || arg === "-a") {
417
+ options.agents = [];
418
+ while (i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
419
+ i++;
420
+ const agentName = args[i];
421
+ if (agentName && isValidAgentType(agentName)) {
422
+ options.agents.push(agentName);
423
+ } else if (agentName) {
424
+ warn(`Unknown agent: ${agentName}`);
425
+ }
426
+ }
427
+ } else if (arg === "--global" || arg === "-g") {
428
+ options.global = true;
429
+ } else if (arg === "--workspace" || arg === "-w") {
430
+ options.workspace = true;
431
+ } else if (arg === "--replace" || arg === "-r") {
432
+ options.replace = true;
433
+ } else if (arg === "--file" || arg === "-f") {
434
+ options.file = args[++i];
435
+ } else if (arg === "--verbose" || arg === "-v") {
436
+ options.verbose = true;
437
+ } else if (!arg?.startsWith("-") && !input) {
438
+ input = arg ?? null;
439
+ }
440
+ }
441
+ return { input, options };
442
+ }
443
+ async function runAdd(input, options) {
444
+ verbose("Running add command", options.verbose ?? false);
445
+ let mcpConfig = null;
446
+ if (options.file) {
447
+ try {
448
+ const content = readFileSync3(options.file, "utf-8");
449
+ mcpConfig = parseMcpConfigString(content);
450
+ if (!mcpConfig) {
451
+ error(`Invalid MCP config in file: ${options.file}`);
452
+ return;
453
+ }
454
+ verbose(`Read config from file: ${options.file}`, options.verbose ?? false);
455
+ } catch (err) {
456
+ error(`Failed to read file: ${options.file}`);
457
+ return;
458
+ }
459
+ } else if (input) {
460
+ mcpConfig = parseMcpConfigString(input);
461
+ if (!mcpConfig) {
462
+ error("Invalid MCP config JSON");
463
+ return;
464
+ }
465
+ } else {
466
+ error("No MCP config provided. Use JSON string or --file option.");
467
+ console.log(`
468
+ ${DIM}Example:${RESET}`);
469
+ console.log(
470
+ ` mcpcm add '{"mcpServers":{"my-server":{"command":"node","args":["/path/to/server.js"]}}}' --agent cursor`
471
+ );
472
+ console.log(` mcpcm add --file mcp.json --global`);
473
+ return;
474
+ }
475
+ const serverNames = Object.keys(mcpConfig.mcpServers);
476
+ info(`Adding ${serverNames.length} MCP server(s): ${serverNames.join(", ")}`);
477
+ let targetAgents = [];
478
+ if (options.agents && options.agents.length > 0) {
479
+ targetAgents = options.agents;
480
+ } else if (options.global) {
481
+ targetAgents = await detectInstalledAgents();
482
+ if (targetAgents.length === 0) {
483
+ warn("No installed agents detected. Specify agents with --agent.");
484
+ return;
485
+ }
486
+ } else if (options.workspace) {
487
+ targetAgents = getAllAgentTypes().filter((t) => agents[t].projectConfigPath !== null);
488
+ } else {
489
+ error("Specify target with --agent, --global, or --workspace");
490
+ return;
491
+ }
492
+ verbose(`Target agents: ${targetAgents.join(", ")}`, options.verbose ?? false);
493
+ let successCount = 0;
494
+ let failCount = 0;
495
+ const allSkippedServers = /* @__PURE__ */ new Map();
496
+ for (const agentType of targetAgents) {
497
+ const agent = agents[agentType];
498
+ if (options.workspace) {
499
+ if (!agent.projectConfigPath) {
500
+ verbose(`${agent.displayName} doesn't support project config`, options.verbose ?? false);
501
+ continue;
502
+ }
503
+ const existing = readProjectConfig(agentType, process.cwd(), options.verbose);
504
+ const existingServers = Object.keys(existing.config?.mcpServers || {});
505
+ const incomingServers = Object.keys(mcpConfig.mcpServers);
506
+ const duplicates = incomingServers.filter((s) => existingServers.includes(s));
507
+ const newServers = incomingServers.filter((s) => !existingServers.includes(s));
508
+ for (const dup of duplicates) {
509
+ const agents2 = allSkippedServers.get(dup) || [];
510
+ agents2.push(agent.displayName);
511
+ allSkippedServers.set(dup, agents2);
512
+ }
513
+ if (newServers.length === 0) {
514
+ warn(`${agent.displayName}: all servers already exist (skipped)`);
515
+ continue;
516
+ }
517
+ const filteredConfig = {
518
+ mcpServers: Object.fromEntries(
519
+ Object.entries(mcpConfig.mcpServers).filter(([name]) => newServers.includes(name))
520
+ )
521
+ };
522
+ const merged = mergeMcpConfigs(
523
+ existing.config || { mcpServers: {} },
524
+ filteredConfig,
525
+ options.replace
526
+ );
527
+ const result = writeProjectConfig(
528
+ agentType,
529
+ merged,
530
+ existing.rawContent,
531
+ process.cwd(),
532
+ options.verbose
533
+ );
534
+ if (result.success) {
535
+ if (duplicates.length > 0) {
536
+ success(
537
+ `${agent.displayName}: added ${newServers.join(", ")} (skipped: ${duplicates.join(", ")})`
538
+ );
539
+ } else {
540
+ success(`${agent.displayName}: ${result.path}`);
541
+ }
542
+ successCount++;
543
+ } else {
544
+ error(`${agent.displayName}: ${result.error}`);
545
+ failCount++;
546
+ }
547
+ } else {
548
+ if (!agent.globalConfigPath) {
549
+ verbose(`${agent.displayName} doesn't support global config`, options.verbose ?? false);
550
+ continue;
551
+ }
552
+ const existing = readGlobalConfig(agentType, options.verbose);
553
+ const existingServers = Object.keys(existing.config?.mcpServers || {});
554
+ const incomingServers = Object.keys(mcpConfig.mcpServers);
555
+ const duplicates = incomingServers.filter((s) => existingServers.includes(s));
556
+ const newServers = incomingServers.filter((s) => !existingServers.includes(s));
557
+ for (const dup of duplicates) {
558
+ const agents2 = allSkippedServers.get(dup) || [];
559
+ agents2.push(agent.displayName);
560
+ allSkippedServers.set(dup, agents2);
561
+ }
562
+ if (newServers.length === 0) {
563
+ warn(`${agent.displayName}: all servers already exist (skipped)`);
564
+ continue;
565
+ }
566
+ const filteredConfig = {
567
+ mcpServers: Object.fromEntries(
568
+ Object.entries(mcpConfig.mcpServers).filter(([name]) => newServers.includes(name))
569
+ )
570
+ };
571
+ const merged = mergeMcpConfigs(
572
+ existing.config || { mcpServers: {} },
573
+ filteredConfig,
574
+ options.replace
575
+ );
576
+ const result = writeGlobalConfig(agentType, merged, existing.rawContent, options.verbose);
577
+ if (result.success) {
578
+ if (duplicates.length > 0) {
579
+ success(
580
+ `${agent.displayName}: added ${newServers.join(", ")} (skipped: ${duplicates.join(", ")})`
581
+ );
582
+ } else {
583
+ success(`${agent.displayName}: ${result.path}`);
584
+ }
585
+ successCount++;
586
+ } else {
587
+ error(`${agent.displayName}: ${result.error}`);
588
+ failCount++;
589
+ }
590
+ }
591
+ }
592
+ console.log();
593
+ if (successCount > 0) {
594
+ success(`Added to ${successCount} agent(s)`);
595
+ }
596
+ if (failCount > 0) {
597
+ error(`Failed for ${failCount} agent(s)`);
598
+ }
599
+ if (allSkippedServers.size > 0) {
600
+ console.log();
601
+ warn(`Skipped ${allSkippedServers.size} existing server(s):`);
602
+ for (const [serverName, agentNames] of allSkippedServers) {
603
+ console.log(` ${DIM}${serverName}${RESET} \u2192 ${agentNames.join(", ")}`);
604
+ }
605
+ console.log(`
606
+ ${DIM}Use 'mcpcm update' to modify existing servers.${RESET}`);
607
+ }
608
+ }
609
+
610
+ // src/commands/del.ts
611
+ function parseDelOptions(args) {
612
+ const options = {};
613
+ const serverNames = [];
614
+ for (let i = 0; i < args.length; i++) {
615
+ const arg = args[i];
616
+ if (arg === "--agent" || arg === "-a") {
617
+ options.agents = [];
618
+ while (i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
619
+ i++;
620
+ const agentName = args[i];
621
+ if (agentName && isValidAgentType(agentName)) {
622
+ options.agents.push(agentName);
623
+ } else if (agentName) {
624
+ warn(`Unknown agent: ${agentName}`);
625
+ }
626
+ }
627
+ } else if (arg === "--global" || arg === "-g") {
628
+ options.global = true;
629
+ } else if (arg === "--workspace" || arg === "-w") {
630
+ options.workspace = true;
631
+ } else if (arg === "--verbose" || arg === "-v") {
632
+ options.verbose = true;
633
+ } else if (!arg?.startsWith("-")) {
634
+ if (typeof arg === "string") {
635
+ serverNames.push(arg);
636
+ }
637
+ }
638
+ }
639
+ return { serverNames, options };
640
+ }
641
+ async function runDel(serverNames, options) {
642
+ verbose("Running del command", options.verbose ?? false);
643
+ if (serverNames.length === 0) {
644
+ error("No server name provided");
645
+ console.log(`
646
+ ${DIM}Example:${RESET}`);
647
+ console.log(` mcpcm del my-server --agent cursor`);
648
+ console.log(` mcpcm del my-server --global`);
649
+ return;
650
+ }
651
+ info(`Deleting MCP server(s): ${serverNames.join(", ")}`);
652
+ let targetAgents = [];
653
+ if (options.agents && options.agents.length > 0) {
654
+ targetAgents = options.agents;
655
+ } else if (options.global) {
656
+ targetAgents = await detectInstalledAgents();
657
+ if (targetAgents.length === 0) {
658
+ warn("No installed agents detected.");
659
+ return;
660
+ }
661
+ } else if (options.workspace) {
662
+ targetAgents = getAllAgentTypes().filter((t) => agents[t].projectConfigPath !== null);
663
+ } else {
664
+ error("Specify target with --agent, --global, or --workspace");
665
+ return;
666
+ }
667
+ let successCount = 0;
668
+ let failCount = 0;
669
+ const allNotFoundServers = /* @__PURE__ */ new Map();
670
+ for (const agentType of targetAgents) {
671
+ const agent = agents[agentType];
672
+ if (options.workspace) {
673
+ if (!agent.projectConfigPath) continue;
674
+ const existing = readProjectConfig(agentType, process.cwd(), options.verbose);
675
+ if (!existing.config) continue;
676
+ const existingServers = Object.keys(existing.config.mcpServers || {});
677
+ const toDelete = serverNames.filter((s) => existingServers.includes(s));
678
+ const notFound = serverNames.filter((s) => !existingServers.includes(s));
679
+ for (const nf of notFound) {
680
+ const agents2 = allNotFoundServers.get(nf) || [];
681
+ agents2.push(agent.displayName);
682
+ allNotFoundServers.set(nf, agents2);
683
+ }
684
+ if (toDelete.length === 0) {
685
+ warn(`${agent.displayName}: no matching servers found (skipped)`);
686
+ continue;
687
+ }
688
+ const updated = removeServersFromConfig(existing.config, toDelete);
689
+ const result = writeProjectConfig(
690
+ agentType,
691
+ updated,
692
+ existing.rawContent,
693
+ process.cwd(),
694
+ options.verbose
695
+ );
696
+ if (result.success) {
697
+ if (notFound.length > 0) {
698
+ success(
699
+ `${agent.displayName}: deleted ${toDelete.join(", ")} (not found: ${notFound.join(", ")})`
700
+ );
701
+ } else {
702
+ success(`${agent.displayName}: deleted ${toDelete.join(", ")}`);
703
+ }
704
+ successCount++;
705
+ } else {
706
+ error(`${agent.displayName}: ${result.error}`);
707
+ failCount++;
708
+ }
709
+ } else {
710
+ if (!agent.globalConfigPath) continue;
711
+ const existing = readGlobalConfig(agentType, options.verbose);
712
+ if (!existing.config) continue;
713
+ const existingServers = Object.keys(existing.config.mcpServers || {});
714
+ const toDelete = serverNames.filter((s) => existingServers.includes(s));
715
+ const notFound = serverNames.filter((s) => !existingServers.includes(s));
716
+ for (const nf of notFound) {
717
+ const agents2 = allNotFoundServers.get(nf) || [];
718
+ agents2.push(agent.displayName);
719
+ allNotFoundServers.set(nf, agents2);
720
+ }
721
+ if (toDelete.length === 0) {
722
+ warn(`${agent.displayName}: no matching servers found (skipped)`);
723
+ continue;
724
+ }
725
+ const updated = removeServersFromConfig(existing.config, toDelete);
726
+ const result = writeGlobalConfig(agentType, updated, existing.rawContent, options.verbose);
727
+ if (result.success) {
728
+ if (notFound.length > 0) {
729
+ success(
730
+ `${agent.displayName}: deleted ${toDelete.join(", ")} (not found: ${notFound.join(", ")})`
731
+ );
732
+ } else {
733
+ success(`${agent.displayName}: deleted ${toDelete.join(", ")}`);
734
+ }
735
+ successCount++;
736
+ } else {
737
+ error(`${agent.displayName}: ${result.error}`);
738
+ failCount++;
739
+ }
740
+ }
741
+ }
742
+ console.log();
743
+ if (successCount > 0) {
744
+ success(`Deleted from ${successCount} agent(s)`);
745
+ }
746
+ if (failCount > 0) {
747
+ error(`Failed for ${failCount} agent(s)`);
748
+ }
749
+ if (allNotFoundServers.size > 0) {
750
+ console.log();
751
+ warn(`${allNotFoundServers.size} server(s) not found:`);
752
+ for (const [serverName, agentNames] of allNotFoundServers) {
753
+ console.log(` ${DIM}${serverName}${RESET} \u2192 ${agentNames.join(", ")}`);
754
+ }
755
+ }
756
+ }
757
+
758
+ // src/commands/list.ts
759
+ function parseListOptions(args) {
760
+ const options = {};
761
+ for (let i = 0; i < args.length; i++) {
762
+ const arg = args[i];
763
+ if (arg === "--agent" || arg === "-a") {
764
+ options.agents = [];
765
+ while (i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
766
+ i++;
767
+ const agentName = args[i];
768
+ if (agentName && isValidAgentType(agentName)) {
769
+ options.agents.push(agentName);
770
+ } else if (agentName) {
771
+ warn(`Unknown agent: ${agentName}`);
772
+ }
773
+ }
774
+ } else if (arg === "--global" || arg === "-g") {
775
+ options.global = true;
776
+ } else if (arg === "--workspace" || arg === "-w") {
777
+ options.workspace = true;
778
+ } else if (arg === "--verbose" || arg === "-v") {
779
+ options.verbose = true;
780
+ }
781
+ }
782
+ return options;
783
+ }
784
+ async function runList(options) {
785
+ let targetAgents = [];
786
+ if (options.agents && options.agents.length > 0) {
787
+ targetAgents = options.agents;
788
+ } else {
789
+ targetAgents = await detectInstalledAgents();
790
+ if (targetAgents.length === 0) {
791
+ info("No installed agents detected.");
792
+ console.log(`
793
+ ${DIM}Supported agents:${RESET}`);
794
+ for (const type of getAllAgentTypes()) {
795
+ console.log(` ${agents[type].displayName} (--agent ${type})`);
796
+ }
797
+ return;
798
+ }
799
+ }
800
+ let totalServers = 0;
801
+ for (const agentType of targetAgents) {
802
+ const agent = agents[agentType];
803
+ let hasOutput = false;
804
+ if (!options.workspace) {
805
+ const globalConfig = readGlobalConfig(agentType, options.verbose);
806
+ if (globalConfig.config && Object.keys(globalConfig.config.mcpServers).length > 0) {
807
+ if (!hasOutput) {
808
+ console.log(`
809
+ ${BOLD}${agent.displayName}${RESET}`);
810
+ hasOutput = true;
811
+ }
812
+ console.log(` ${DIM}Global:${RESET} ${globalConfig.path}`);
813
+ for (const [name, config] of Object.entries(globalConfig.config.mcpServers)) {
814
+ console.log(` ${formatServerConfig(name, config)}`);
815
+ totalServers++;
816
+ }
817
+ }
818
+ }
819
+ if (!options.global) {
820
+ const projectConfig = readProjectConfig(agentType, process.cwd(), options.verbose);
821
+ if (projectConfig.config && Object.keys(projectConfig.config.mcpServers).length > 0) {
822
+ if (!hasOutput) {
823
+ console.log(`
824
+ ${BOLD}${agent.displayName}${RESET}`);
825
+ hasOutput = true;
826
+ }
827
+ console.log(` ${DIM}Project:${RESET} ${projectConfig.path}`);
828
+ for (const [name, config] of Object.entries(projectConfig.config.mcpServers)) {
829
+ console.log(` ${formatServerConfig(name, config)}`);
830
+ totalServers++;
831
+ }
832
+ }
833
+ }
834
+ }
835
+ console.log();
836
+ if (totalServers > 0) {
837
+ console.log(`${GREEN}Total:${RESET} ${totalServers} MCP server(s)`);
838
+ } else {
839
+ info("No MCP servers configured");
840
+ }
841
+ }
842
+
843
+ // src/commands/find.ts
844
+ async function runFind(args) {
845
+ const serverName = args[0];
846
+ const verbose2 = args.includes("--verbose") || args.includes("-v");
847
+ if (!serverName) {
848
+ info("Usage: mcpcm find <server-name>");
849
+ console.log(`
850
+ ${DIM}Example:${RESET}`);
851
+ console.log(` mcpcm find easeim`);
852
+ return;
853
+ }
854
+ console.log(`
855
+ ${DIM}Searching for "${serverName}"...${RESET}
856
+ `);
857
+ const results = [];
858
+ for (const agentType of getAllAgentTypes()) {
859
+ const agent = agents[agentType];
860
+ if (agent.globalConfigPath) {
861
+ const globalConfig = readGlobalConfig(agentType, verbose2);
862
+ if (globalConfig.config?.mcpServers[serverName]) {
863
+ results.push({
864
+ agent: agentType,
865
+ scope: "global",
866
+ path: globalConfig.path,
867
+ config: globalConfig.config.mcpServers[serverName]
868
+ });
869
+ }
870
+ }
871
+ if (agent.projectConfigPath) {
872
+ const projectConfig = readProjectConfig(agentType, process.cwd(), verbose2);
873
+ if (projectConfig.config?.mcpServers[serverName]) {
874
+ results.push({
875
+ agent: agentType,
876
+ scope: "project",
877
+ path: projectConfig.path,
878
+ config: projectConfig.config.mcpServers[serverName]
879
+ });
880
+ }
881
+ }
882
+ }
883
+ if (results.length === 0) {
884
+ info(`"${serverName}" not found in any MCP configuration`);
885
+ return;
886
+ }
887
+ console.log(`${GREEN}\u2713${RESET} ${BOLD}${serverName}${RESET} found in:
888
+ `);
889
+ for (const result of results) {
890
+ const agent = agents[result.agent];
891
+ const scopeLabel = result.scope === "global" ? "global" : "project";
892
+ console.log(
893
+ ` ${CYAN}${agent.displayName}${RESET} (${scopeLabel}): ${DIM}${result.path}${RESET}`
894
+ );
895
+ if (verbose2) {
896
+ const config = result.config;
897
+ console.log(` ${DIM}command:${RESET} ${config.command}`);
898
+ if (config.args && config.args.length > 0) {
899
+ console.log(` ${DIM}args:${RESET} ${config.args.join(" ")}`);
900
+ }
901
+ if (config.env) {
902
+ console.log(` ${DIM}env:${RESET} ${JSON.stringify(config.env)}`);
903
+ }
904
+ }
905
+ }
906
+ console.log();
907
+ }
908
+
909
+ // src/commands/sync.ts
910
+ function parseSyncOptions(args) {
911
+ let from = null;
912
+ const to = [];
913
+ let toAll = false;
914
+ let verboseMode = false;
915
+ for (let i = 0; i < args.length; i++) {
916
+ const arg = args[i];
917
+ if (arg === "--from" || arg === "-f") {
918
+ const agentName = args[++i];
919
+ if (agentName && isValidAgentType(agentName)) {
920
+ from = agentName;
921
+ } else {
922
+ warn(`Unknown agent: ${agentName}`);
923
+ }
924
+ } else if (arg === "--to" || arg === "-t") {
925
+ while (i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
926
+ i++;
927
+ const agentName = args[i];
928
+ if (agentName && isValidAgentType(agentName)) {
929
+ to.push(agentName);
930
+ } else if (agentName) {
931
+ warn(`Unknown agent: ${agentName}`);
932
+ }
933
+ }
934
+ } else if (arg === "--to-all") {
935
+ toAll = true;
936
+ } else if (arg === "--verbose" || arg === "-v") {
937
+ verboseMode = true;
938
+ }
939
+ }
940
+ if (!from) {
941
+ error("Missing --from agent");
942
+ return null;
943
+ }
944
+ return { from, to: to.length > 0 ? to : void 0, toAll, verbose: verboseMode };
945
+ }
946
+ async function runSync(options) {
947
+ verbose("Running sync command", options.verbose ?? false);
948
+ const sourceConfig = readGlobalConfig(options.from, options.verbose);
949
+ if (!sourceConfig.config || Object.keys(sourceConfig.config.mcpServers).length === 0) {
950
+ error(`No MCP servers found in ${agents[options.from].displayName}'s global config`);
951
+ return;
952
+ }
953
+ info(
954
+ `Syncing ${Object.keys(sourceConfig.config.mcpServers).length} server(s) from ${agents[options.from].displayName}`
955
+ );
956
+ let targetAgents = [];
957
+ if (options.toAll) {
958
+ targetAgents = await detectInstalledAgents();
959
+ targetAgents = targetAgents.filter((a) => a !== options.from);
960
+ } else if (options.to && options.to.length > 0) {
961
+ targetAgents = options.to.filter((a) => a !== options.from);
962
+ } else {
963
+ error("Specify target with --to or --to-all");
964
+ return;
965
+ }
966
+ if (targetAgents.length === 0) {
967
+ warn("No target agents to sync to");
968
+ return;
969
+ }
970
+ let successCount = 0;
971
+ let failCount = 0;
972
+ for (const agentType of targetAgents) {
973
+ const agent = agents[agentType];
974
+ if (!agent.globalConfigPath) {
975
+ verbose(`${agent.displayName} doesn't support global config`, options.verbose ?? false);
976
+ continue;
977
+ }
978
+ const existing = readGlobalConfig(agentType, options.verbose);
979
+ const merged = mergeMcpConfigs(
980
+ existing.config || { mcpServers: {} },
981
+ sourceConfig.config,
982
+ false
983
+ // Always merge, don't replace
984
+ );
985
+ const result = writeGlobalConfig(agentType, merged, existing.rawContent, options.verbose);
986
+ if (result.success) {
987
+ success(`${agent.displayName}: ${result.path}`);
988
+ successCount++;
989
+ } else {
990
+ error(`${agent.displayName}: ${result.error}`);
991
+ failCount++;
992
+ }
993
+ }
994
+ console.log();
995
+ if (successCount > 0) {
996
+ success(`Synced to ${successCount} agent(s)`);
997
+ }
998
+ if (failCount > 0) {
999
+ error(`Failed for ${failCount} agent(s)`);
1000
+ }
1001
+ }
1002
+
1003
+ // src/commands/update.ts
1004
+ import { readFileSync as readFileSync4 } from "fs";
1005
+ function parseUpdateOptions(args) {
1006
+ const options = {};
1007
+ let input = null;
1008
+ for (let i = 0; i < args.length; i++) {
1009
+ const arg = args[i];
1010
+ if (arg === "--agent" || arg === "-a") {
1011
+ options.agents = [];
1012
+ while (i + 1 < args.length && !args[i + 1]?.startsWith("-")) {
1013
+ i++;
1014
+ const agentName = args[i];
1015
+ if (agentName && isValidAgentType(agentName)) {
1016
+ options.agents.push(agentName);
1017
+ } else if (agentName) {
1018
+ warn(`Unknown agent: ${agentName}`);
1019
+ }
1020
+ }
1021
+ } else if (arg === "--global" || arg === "-g") {
1022
+ options.global = true;
1023
+ } else if (arg === "--workspace" || arg === "-w") {
1024
+ options.workspace = true;
1025
+ } else if (arg === "--replace" || arg === "-r") {
1026
+ options.replace = true;
1027
+ } else if (arg === "--file" || arg === "-f") {
1028
+ options.file = args[++i];
1029
+ } else if (arg === "--verbose" || arg === "-v") {
1030
+ options.verbose = true;
1031
+ } else if (!arg?.startsWith("-") && !input) {
1032
+ input = arg ?? null;
1033
+ }
1034
+ }
1035
+ return { input, options };
1036
+ }
1037
+ async function runUpdate(input, options) {
1038
+ verbose("Running update command", options.verbose ?? false);
1039
+ let mcpConfig = null;
1040
+ if (options.file) {
1041
+ try {
1042
+ const content = readFileSync4(options.file, "utf-8");
1043
+ mcpConfig = parseMcpConfigString(content);
1044
+ if (!mcpConfig) {
1045
+ error(`Invalid MCP config in file: ${options.file}`);
1046
+ return;
1047
+ }
1048
+ verbose(`Read config from file: ${options.file}`, options.verbose ?? false);
1049
+ } catch (err) {
1050
+ error(`Failed to read file: ${options.file}`);
1051
+ return;
1052
+ }
1053
+ } else if (input) {
1054
+ mcpConfig = parseMcpConfigString(input);
1055
+ if (!mcpConfig) {
1056
+ error("Invalid MCP config JSON");
1057
+ return;
1058
+ }
1059
+ } else {
1060
+ error("No MCP config provided. Use JSON string or --file option.");
1061
+ console.log(`
1062
+ ${DIM}Example:${RESET}`);
1063
+ console.log(
1064
+ ` mcpcm update '{"mcpServers":{"my-server":{"command":"node","args":["/path/to/server.js"]}}}' --agent cursor`
1065
+ );
1066
+ console.log(` mcpcm update --file mcp.json --global`);
1067
+ return;
1068
+ }
1069
+ const serverNames = Object.keys(mcpConfig.mcpServers);
1070
+ info(`Updating ${serverNames.length} MCP server(s): ${serverNames.join(", ")}`);
1071
+ let targetAgents = [];
1072
+ if (options.agents && options.agents.length > 0) {
1073
+ targetAgents = options.agents;
1074
+ } else if (options.global) {
1075
+ targetAgents = await detectInstalledAgents();
1076
+ if (targetAgents.length === 0) {
1077
+ warn("No installed agents detected. Specify agents with --agent.");
1078
+ return;
1079
+ }
1080
+ } else if (options.workspace) {
1081
+ targetAgents = getAllAgentTypes().filter((t) => agents[t].projectConfigPath !== null);
1082
+ } else {
1083
+ error("Specify target with --agent, --global, or --workspace");
1084
+ return;
1085
+ }
1086
+ verbose(`Target agents: ${targetAgents.join(", ")}`, options.verbose ?? false);
1087
+ let successCount = 0;
1088
+ let failCount = 0;
1089
+ const allSkippedServers = /* @__PURE__ */ new Map();
1090
+ for (const agentType of targetAgents) {
1091
+ const agent = agents[agentType];
1092
+ if (options.workspace) {
1093
+ if (!agent.projectConfigPath) {
1094
+ verbose(`${agent.displayName} doesn't support project config`, options.verbose ?? false);
1095
+ continue;
1096
+ }
1097
+ const existing = readProjectConfig(agentType, process.cwd(), options.verbose);
1098
+ const existingServers = Object.keys(existing.config?.mcpServers || {});
1099
+ const incomingServers = Object.keys(mcpConfig.mcpServers);
1100
+ const toUpdate = incomingServers.filter((s) => existingServers.includes(s));
1101
+ const notFound = incomingServers.filter((s) => !existingServers.includes(s));
1102
+ for (const nf of notFound) {
1103
+ const agents2 = allSkippedServers.get(nf) || [];
1104
+ agents2.push(agent.displayName);
1105
+ allSkippedServers.set(nf, agents2);
1106
+ }
1107
+ if (toUpdate.length === 0) {
1108
+ warn(`${agent.displayName}: no matching servers found (skipped)`);
1109
+ continue;
1110
+ }
1111
+ const filteredConfig = {
1112
+ mcpServers: Object.fromEntries(
1113
+ Object.entries(mcpConfig.mcpServers).filter(([name]) => toUpdate.includes(name))
1114
+ )
1115
+ };
1116
+ const merged = mergeMcpConfigs(
1117
+ existing.config || { mcpServers: {} },
1118
+ filteredConfig,
1119
+ true
1120
+ // Always replace for update
1121
+ );
1122
+ const result = writeProjectConfig(
1123
+ agentType,
1124
+ merged,
1125
+ existing.rawContent,
1126
+ process.cwd(),
1127
+ options.verbose
1128
+ );
1129
+ if (result.success) {
1130
+ if (notFound.length > 0) {
1131
+ success(
1132
+ `${agent.displayName}: updated ${toUpdate.join(", ")} (skipped: ${notFound.join(", ")})`
1133
+ );
1134
+ } else {
1135
+ success(`${agent.displayName}: updated ${toUpdate.join(", ")}`);
1136
+ }
1137
+ successCount++;
1138
+ } else {
1139
+ error(`${agent.displayName}: ${result.error}`);
1140
+ failCount++;
1141
+ }
1142
+ } else {
1143
+ if (!agent.globalConfigPath) {
1144
+ verbose(`${agent.displayName} doesn't support global config`, options.verbose ?? false);
1145
+ continue;
1146
+ }
1147
+ const existing = readGlobalConfig(agentType, options.verbose);
1148
+ const existingServers = Object.keys(existing.config?.mcpServers || {});
1149
+ const incomingServers = Object.keys(mcpConfig.mcpServers);
1150
+ const toUpdate = incomingServers.filter((s) => existingServers.includes(s));
1151
+ const notFound = incomingServers.filter((s) => !existingServers.includes(s));
1152
+ for (const nf of notFound) {
1153
+ const agents2 = allSkippedServers.get(nf) || [];
1154
+ agents2.push(agent.displayName);
1155
+ allSkippedServers.set(nf, agents2);
1156
+ }
1157
+ if (toUpdate.length === 0) {
1158
+ warn(`${agent.displayName}: no matching servers found (skipped)`);
1159
+ continue;
1160
+ }
1161
+ const filteredConfig = {
1162
+ mcpServers: Object.fromEntries(
1163
+ Object.entries(mcpConfig.mcpServers).filter(([name]) => toUpdate.includes(name))
1164
+ )
1165
+ };
1166
+ const merged = mergeMcpConfigs(
1167
+ existing.config || { mcpServers: {} },
1168
+ filteredConfig,
1169
+ true
1170
+ // Always replace for update
1171
+ );
1172
+ const result = writeGlobalConfig(agentType, merged, existing.rawContent, options.verbose);
1173
+ if (result.success) {
1174
+ if (notFound.length > 0) {
1175
+ success(
1176
+ `${agent.displayName}: updated ${toUpdate.join(", ")} (skipped: ${notFound.join(", ")})`
1177
+ );
1178
+ } else {
1179
+ success(`${agent.displayName}: updated ${toUpdate.join(", ")}`);
1180
+ }
1181
+ successCount++;
1182
+ } else {
1183
+ error(`${agent.displayName}: ${result.error}`);
1184
+ failCount++;
1185
+ }
1186
+ }
1187
+ }
1188
+ console.log();
1189
+ if (successCount > 0) {
1190
+ success(`Updated ${successCount} agent(s)`);
1191
+ }
1192
+ if (failCount > 0) {
1193
+ error(`Failed for ${failCount} agent(s)`);
1194
+ }
1195
+ if (allSkippedServers.size > 0) {
1196
+ console.log();
1197
+ warn(`Skipped ${allSkippedServers.size} server(s) not found:`);
1198
+ for (const [serverName, agentNames] of allSkippedServers) {
1199
+ console.log(` ${DIM}${serverName}${RESET} \u2192 ${agentNames.join(", ")}`);
1200
+ }
1201
+ console.log(`
1202
+ ${DIM}Use 'mcpcm add' to add new servers.${RESET}`);
1203
+ }
1204
+ }
1205
+
1206
+ // src/cli.ts
1207
+ var __dirname = dirname2(fileURLToPath(import.meta.url));
1208
+ function getVersion() {
1209
+ try {
1210
+ const pkgPath = join5(__dirname, "..", "package.json");
1211
+ const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
1212
+ return pkg.version;
1213
+ } catch {
1214
+ return "1.0.0";
1215
+ }
1216
+ }
1217
+ var VERSION = getVersion();
1218
+ var LOGO_LINES = [
1219
+ "\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557",
1220
+ "\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551",
1221
+ "\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551",
1222
+ "\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551",
1223
+ "\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551",
1224
+ "\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D"
1225
+ ];
1226
+ var GRAYS = [
1227
+ "\x1B[38;5;250m",
1228
+ "\x1B[38;5;248m",
1229
+ "\x1B[38;5;245m",
1230
+ "\x1B[38;5;243m",
1231
+ "\x1B[38;5;240m",
1232
+ "\x1B[38;5;238m"
1233
+ ];
1234
+ function showLogo() {
1235
+ console.log();
1236
+ LOGO_LINES.forEach((line, i) => {
1237
+ console.log(`${GRAYS[i]}${line}${RESET}`);
1238
+ });
1239
+ }
1240
+ function showBanner() {
1241
+ showLogo();
1242
+ console.log();
1243
+ console.log(
1244
+ `${DIM}MCP Configuration Manager - Manage MCP server configuration across AI Agents${RESET}`
1245
+ );
1246
+ console.log();
1247
+ console.log(` ${DIM}$${RESET} ${TEXT}mcpcm add${RESET} ${DIM}Add MCP server config${RESET}`);
1248
+ console.log(
1249
+ ` ${DIM}$${RESET} ${TEXT}mcpcm del${RESET} ${DIM}Delete MCP server config${RESET}`
1250
+ );
1251
+ console.log(` ${DIM}$${RESET} ${TEXT}mcpcm list${RESET} ${DIM}List all MCP configs${RESET}`);
1252
+ console.log(` ${DIM}$${RESET} ${TEXT}mcpcm find${RESET} ${DIM}Find MCP server${RESET}`);
1253
+ console.log(
1254
+ ` ${DIM}$${RESET} ${TEXT}mcpcm sync${RESET} ${DIM}Sync configs between agents${RESET}`
1255
+ );
1256
+ console.log();
1257
+ console.log(`${DIM}Run${RESET} mcpcm --help ${DIM}for more info${RESET}`);
1258
+ console.log();
1259
+ }
1260
+ function showHelp() {
1261
+ const agentList = getAllAgentTypes().join(", ");
1262
+ console.log(`
1263
+ ${BOLD}Usage:${RESET} mcpcm <command> [options]
1264
+
1265
+ ${BOLD}Commands:${RESET}
1266
+ add <json> Add MCP server config from JSON string
1267
+ add --file <path> Add MCP server config from file
1268
+ update Update MCP server config (same as add)
1269
+ del <name> Delete MCP server by name
1270
+ list List all MCP configurations
1271
+ find <name> Find where an MCP server is configured
1272
+ sync Sync configs from one agent to others
1273
+
1274
+ ${BOLD}Target Options:${RESET}
1275
+ -a, --agent <name> Target specific agent(s)
1276
+ -g, --global Target all installed agents (global configs)
1277
+ -w, --workspace Target project-level configs
1278
+
1279
+ ${BOLD}Add/Update Options:${RESET}
1280
+ -f, --file <path> Read config from JSON/TOML file
1281
+ -r, --replace Replace configs instead of merging
1282
+
1283
+ ${BOLD}Sync Options:${RESET}
1284
+ --from <agent> Source agent to sync from
1285
+ --to <agent> Target agent(s) to sync to
1286
+ --to-all Sync to all installed agents
1287
+
1288
+ ${BOLD}Other Options:${RESET}
1289
+ -v, --verbose Show detailed output
1290
+ -h, --help Show this help message
1291
+ --version Show version number
1292
+
1293
+ ${BOLD}Supported Agents:${RESET}
1294
+ ${DIM}${agentList}${RESET}
1295
+
1296
+ ${BOLD}Examples:${RESET}
1297
+ ${DIM}$${RESET} mcpcm add '{"mcpServers":{"my-server":{"command":"node","args":["/path/to/server"]}}}' --agent cursor
1298
+ ${DIM}$${RESET} mcpcm add --file mcp.json --global
1299
+ ${DIM}$${RESET} mcpcm del my-server --agent cursor
1300
+ ${DIM}$${RESET} mcpcm list --global
1301
+ ${DIM}$${RESET} mcpcm find my-server
1302
+ ${DIM}$${RESET} mcpcm sync --from cursor --to antigravity claude-code
1303
+ ${DIM}$${RESET} mcpcm sync --from cursor --to-all
1304
+ `);
1305
+ }
1306
+ async function main() {
1307
+ const args = process.argv.slice(2);
1308
+ if (args.length === 0) {
1309
+ showBanner();
1310
+ return;
1311
+ }
1312
+ const command = args[0];
1313
+ const restArgs = args.slice(1);
1314
+ switch (command) {
1315
+ case "add":
1316
+ case "a": {
1317
+ showLogo();
1318
+ console.log();
1319
+ const { input, options } = parseAddOptions(restArgs);
1320
+ await runAdd(input, options);
1321
+ break;
1322
+ }
1323
+ case "update":
1324
+ case "u": {
1325
+ showLogo();
1326
+ console.log();
1327
+ const { input, options } = parseUpdateOptions(restArgs);
1328
+ await runUpdate(input, options);
1329
+ break;
1330
+ }
1331
+ case "del":
1332
+ case "delete":
1333
+ case "d": {
1334
+ showLogo();
1335
+ console.log();
1336
+ const { serverNames, options } = parseDelOptions(restArgs);
1337
+ await runDel(serverNames, options);
1338
+ break;
1339
+ }
1340
+ case "list":
1341
+ case "ls":
1342
+ case "l": {
1343
+ showLogo();
1344
+ console.log();
1345
+ const options = parseListOptions(restArgs);
1346
+ await runList(options);
1347
+ break;
1348
+ }
1349
+ case "find":
1350
+ case "search":
1351
+ case "f": {
1352
+ showLogo();
1353
+ await runFind(restArgs);
1354
+ break;
1355
+ }
1356
+ case "sync":
1357
+ case "s": {
1358
+ showLogo();
1359
+ console.log();
1360
+ const options = parseSyncOptions(restArgs);
1361
+ if (options) {
1362
+ await runSync(options);
1363
+ }
1364
+ break;
1365
+ }
1366
+ case "--help":
1367
+ case "-h":
1368
+ case "help":
1369
+ showHelp();
1370
+ break;
1371
+ case "--version":
1372
+ case "-v":
1373
+ console.log(VERSION);
1374
+ break;
1375
+ default:
1376
+ console.log(`Unknown command: ${command}`);
1377
+ console.log(`Run ${BOLD}mcpcm --help${RESET} for usage.`);
1378
+ }
1379
+ }
1380
+ main().catch((err) => {
1381
+ console.error("Error:", err.message);
1382
+ process.exit(1);
1383
+ });