mcp-aws-manager 0.4.3 → 0.4.4
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/bin/mcp-aws-manager.js +140 -32
- package/package.json +1 -1
package/bin/mcp-aws-manager.js
CHANGED
|
@@ -2375,14 +2375,6 @@ function clientHelpAttempts(cliBin) {
|
|
|
2375
2375
|
return [["mcp", "--help"]];
|
|
2376
2376
|
}
|
|
2377
2377
|
|
|
2378
|
-
function cursorMcpConfigPath() {
|
|
2379
|
-
const explicitPath = envText("CURSOR_MCP_CONFIG_PATH");
|
|
2380
|
-
if (explicitPath) {
|
|
2381
|
-
return path.resolve(explicitPath);
|
|
2382
|
-
}
|
|
2383
|
-
return path.join(os.homedir(), ".cursor", "mcp.json");
|
|
2384
|
-
}
|
|
2385
|
-
|
|
2386
2378
|
function normalizeComparableText(value) {
|
|
2387
2379
|
const text = String(value == null ? "" : value).trim();
|
|
2388
2380
|
return process.platform === "win32" ? text.toLowerCase() : text;
|
|
@@ -2392,37 +2384,128 @@ function normalizeComparableArgs(args) {
|
|
|
2392
2384
|
return Array.isArray(args) ? args.map((arg) => normalizeComparableText(arg)) : [];
|
|
2393
2385
|
}
|
|
2394
2386
|
|
|
2395
|
-
function
|
|
2396
|
-
const
|
|
2397
|
-
|
|
2398
|
-
|
|
2387
|
+
function dedupePaths(paths) {
|
|
2388
|
+
const seen = new Set();
|
|
2389
|
+
const out = [];
|
|
2390
|
+
for (const candidate of paths) {
|
|
2391
|
+
const resolved = path.resolve(String(candidate || ""));
|
|
2392
|
+
const key = normalizeComparableText(resolved);
|
|
2393
|
+
if (!key || seen.has(key)) continue;
|
|
2394
|
+
seen.add(key);
|
|
2395
|
+
out.push(resolved);
|
|
2396
|
+
}
|
|
2397
|
+
return out;
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
function cursorMcpConfigCandidates() {
|
|
2401
|
+
const explicitPath = envText("CURSOR_MCP_CONFIG_PATH");
|
|
2402
|
+
if (explicitPath) {
|
|
2403
|
+
return dedupePaths([path.resolve(explicitPath)]);
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2406
|
+
const home = os.homedir();
|
|
2407
|
+
const candidates = [
|
|
2408
|
+
path.join(home, ".cursor", "mcp.json")
|
|
2409
|
+
];
|
|
2410
|
+
|
|
2411
|
+
if (process.platform === "win32") {
|
|
2412
|
+
const appData = process.env.APPDATA || path.join(home, "AppData", "Roaming");
|
|
2413
|
+
candidates.push(path.join(appData, "Cursor", "User", "mcp.json"));
|
|
2414
|
+
} else if (process.platform === "darwin") {
|
|
2415
|
+
candidates.push(path.join(home, "Library", "Application Support", "Cursor", "User", "mcp.json"));
|
|
2416
|
+
} else {
|
|
2417
|
+
candidates.push(path.join(home, ".config", "Cursor", "User", "mcp.json"));
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
return dedupePaths(candidates);
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
function cursorMcpConfigPath() {
|
|
2424
|
+
const candidates = cursorMcpConfigCandidates();
|
|
2425
|
+
for (const candidate of candidates) {
|
|
2426
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
2427
|
+
}
|
|
2428
|
+
return candidates[0];
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
function parseCursorMcpConfigContent(raw, filePath) {
|
|
2432
|
+
const normalizedRaw = String(raw || "").replace(/^\uFEFF/, "");
|
|
2433
|
+
if (!normalizedRaw.trim()) {
|
|
2434
|
+
return { ok: true, data: { mcpServers: {} } };
|
|
2399
2435
|
}
|
|
2400
2436
|
try {
|
|
2401
|
-
const raw = fs.readFileSync(filePath, "utf8");
|
|
2402
|
-
const normalizedRaw = raw.replace(/^\uFEFF/, "");
|
|
2403
|
-
if (!normalizedRaw.trim()) {
|
|
2404
|
-
return { ok: true, filePath, exists: true, data: { mcpServers: {} } };
|
|
2405
|
-
}
|
|
2406
2437
|
const parsed = JSON.parse(normalizedRaw);
|
|
2407
2438
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2408
|
-
return { ok: false,
|
|
2439
|
+
return { ok: false, error: `Cursor MCP config must be a JSON object. (${filePath})` };
|
|
2409
2440
|
}
|
|
2410
2441
|
const mcpServers = parsed.mcpServers && typeof parsed.mcpServers === "object" && !Array.isArray(parsed.mcpServers)
|
|
2411
2442
|
? parsed.mcpServers
|
|
2412
2443
|
: {};
|
|
2413
|
-
return { ok: true,
|
|
2444
|
+
return { ok: true, data: { ...parsed, mcpServers } };
|
|
2414
2445
|
} catch (error) {
|
|
2415
2446
|
return {
|
|
2416
2447
|
ok: false,
|
|
2417
|
-
filePath
|
|
2418
|
-
|
|
2448
|
+
error: `Failed to parse Cursor MCP config: ${error && error.message ? error.message : String(error)} (${filePath})`
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
function readCursorMcpConfig() {
|
|
2454
|
+
const candidates = cursorMcpConfigCandidates();
|
|
2455
|
+
const errors = [];
|
|
2456
|
+
for (const candidate of candidates) {
|
|
2457
|
+
if (!fs.existsSync(candidate)) continue;
|
|
2458
|
+
try {
|
|
2459
|
+
const raw = fs.readFileSync(candidate, "utf8");
|
|
2460
|
+
const parsed = parseCursorMcpConfigContent(raw, candidate);
|
|
2461
|
+
if (!parsed.ok) {
|
|
2462
|
+
errors.push(parsed.error);
|
|
2463
|
+
continue;
|
|
2464
|
+
}
|
|
2465
|
+
return {
|
|
2466
|
+
ok: true,
|
|
2467
|
+
filePath: candidate,
|
|
2468
|
+
exists: true,
|
|
2469
|
+
data: parsed.data,
|
|
2470
|
+
candidates
|
|
2471
|
+
};
|
|
2472
|
+
} catch (error) {
|
|
2473
|
+
errors.push(`Failed to read Cursor MCP config: ${error && error.message ? error.message : String(error)} (${candidate})`);
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
if (errors.length) {
|
|
2478
|
+
return {
|
|
2479
|
+
ok: false,
|
|
2480
|
+
filePath: candidates[0],
|
|
2481
|
+
error: errors.join("; ")
|
|
2419
2482
|
};
|
|
2420
2483
|
}
|
|
2484
|
+
|
|
2485
|
+
return { ok: true, filePath: candidates[0], exists: false, data: { mcpServers: {} }, candidates };
|
|
2421
2486
|
}
|
|
2422
2487
|
|
|
2423
|
-
function writeCursorMcpConfig(filePath, data) {
|
|
2424
|
-
|
|
2425
|
-
|
|
2488
|
+
function writeCursorMcpConfig(filePath, data, mirrorPaths = []) {
|
|
2489
|
+
const allPaths = dedupePaths([filePath, ...(Array.isArray(mirrorPaths) ? mirrorPaths : [])]);
|
|
2490
|
+
const written = [];
|
|
2491
|
+
const mirrorFailures = [];
|
|
2492
|
+
|
|
2493
|
+
for (let i = 0; i < allPaths.length; i += 1) {
|
|
2494
|
+
const currentPath = allPaths[i];
|
|
2495
|
+
try {
|
|
2496
|
+
fs.mkdirSync(path.dirname(currentPath), { recursive: true });
|
|
2497
|
+
fs.writeFileSync(currentPath, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
2498
|
+
written.push(currentPath);
|
|
2499
|
+
} catch (error) {
|
|
2500
|
+
const message = `${currentPath}: ${error && error.message ? error.message : String(error)}`;
|
|
2501
|
+
if (i === 0) {
|
|
2502
|
+
throw new Error(message);
|
|
2503
|
+
}
|
|
2504
|
+
mirrorFailures.push(message);
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
return { written, mirrorFailures };
|
|
2426
2509
|
}
|
|
2427
2510
|
|
|
2428
2511
|
function cursorRegistrationMatches(entry, mcpCommand, mcpArgs = []) {
|
|
@@ -2455,7 +2538,18 @@ function ensureCursorRegistered(serverName, mcpCommand, mcpArgs = [], force = fa
|
|
|
2455
2538
|
if (force || !cursorRegistrationMatches(current, desiredEntry.command, desiredEntry.args)) {
|
|
2456
2539
|
config.mcpServers[serverName] = desiredEntry;
|
|
2457
2540
|
try {
|
|
2458
|
-
|
|
2541
|
+
const mirrors = (loaded.candidates || []).filter(
|
|
2542
|
+
(candidate) => normalizeComparableText(candidate) !== normalizeComparableText(loaded.filePath)
|
|
2543
|
+
);
|
|
2544
|
+
const writeResult = writeCursorMcpConfig(loaded.filePath, config, mirrors);
|
|
2545
|
+
const detailParts = [`primary=${loaded.filePath}`];
|
|
2546
|
+
if (writeResult.written.length > 1) {
|
|
2547
|
+
detailParts.push(`mirrored=${writeResult.written.slice(1).join(",")}`);
|
|
2548
|
+
}
|
|
2549
|
+
if (writeResult.mirrorFailures.length) {
|
|
2550
|
+
detailParts.push(`mirror_failures=${writeResult.mirrorFailures.join(" | ")}`);
|
|
2551
|
+
}
|
|
2552
|
+
return { ok: true, action: "registered", detail: detailParts.join("; ") };
|
|
2459
2553
|
} catch (error) {
|
|
2460
2554
|
return {
|
|
2461
2555
|
ok: false,
|
|
@@ -2463,9 +2557,8 @@ function ensureCursorRegistered(serverName, mcpCommand, mcpArgs = [], force = fa
|
|
|
2463
2557
|
detail: `${error && error.message ? error.message : String(error)} (${loaded.filePath})`
|
|
2464
2558
|
};
|
|
2465
2559
|
}
|
|
2466
|
-
return { ok: true, action: "registered", detail: loaded.filePath };
|
|
2467
2560
|
}
|
|
2468
|
-
return { ok: true, action: "already registered", detail: loaded.filePath };
|
|
2561
|
+
return { ok: true, action: "already registered", detail: `primary=${loaded.filePath}` };
|
|
2469
2562
|
}
|
|
2470
2563
|
|
|
2471
2564
|
function removeCursorRegistration(serverName) {
|
|
@@ -2474,17 +2567,32 @@ function removeCursorRegistration(serverName) {
|
|
|
2474
2567
|
if (!Object.prototype.hasOwnProperty.call(loaded.data.mcpServers, serverName)) return;
|
|
2475
2568
|
delete loaded.data.mcpServers[serverName];
|
|
2476
2569
|
try {
|
|
2477
|
-
|
|
2570
|
+
const mirrors = (loaded.candidates || []).filter(
|
|
2571
|
+
(candidate) => normalizeComparableText(candidate) !== normalizeComparableText(loaded.filePath)
|
|
2572
|
+
);
|
|
2573
|
+
writeCursorMcpConfig(loaded.filePath, loaded.data, mirrors);
|
|
2478
2574
|
} catch (_) {
|
|
2479
2575
|
// ignore best-effort cleanup
|
|
2480
2576
|
}
|
|
2481
2577
|
}
|
|
2482
2578
|
|
|
2483
2579
|
function isCursorRegistered(serverName, mcpCommand, mcpArgs = []) {
|
|
2484
|
-
const
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2580
|
+
const candidates = cursorMcpConfigCandidates();
|
|
2581
|
+
for (const candidate of candidates) {
|
|
2582
|
+
if (!fs.existsSync(candidate)) continue;
|
|
2583
|
+
try {
|
|
2584
|
+
const raw = fs.readFileSync(candidate, "utf8");
|
|
2585
|
+
const parsed = parseCursorMcpConfigContent(raw, candidate);
|
|
2586
|
+
if (!parsed.ok) continue;
|
|
2587
|
+
const entry = parsed.data && parsed.data.mcpServers ? parsed.data.mcpServers[serverName] : null;
|
|
2588
|
+
if (cursorRegistrationMatches(entry, mcpCommand, mcpArgs)) {
|
|
2589
|
+
return true;
|
|
2590
|
+
}
|
|
2591
|
+
} catch (_) {
|
|
2592
|
+
continue;
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
return false;
|
|
2488
2596
|
}
|
|
2489
2597
|
|
|
2490
2598
|
function clientGetAttempts(cliBin, serverName) {
|
package/package.json
CHANGED