mcp-aws-manager 0.3.6 → 0.3.8
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/README.md +11 -4
- package/README_KO.md +6 -4
- package/bin/mcp-aws-manager-mcp.js +1 -1
- package/bin/mcp-aws-manager.js +102 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -91,10 +91,16 @@ If AWS auth is not available, use manual fallback:
|
|
|
91
91
|
mcp-aws-manager discover --manual-server-list ./servers.csv --pem-paths C:\keys\prod.pem --no-progress
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
GUI report is generated by default (auto path: workspace/home `aws-inventory.html`):
|
|
95
95
|
|
|
96
96
|
```bash
|
|
97
|
-
mcp-aws-manager discover --profiles default --
|
|
97
|
+
mcp-aws-manager discover --profiles default --no-progress
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Custom path / open behavior:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
mcp-aws-manager discover --profiles default --html-out ./inventory.html --open-html --no-progress
|
|
98
104
|
```
|
|
99
105
|
|
|
100
106
|
## User Confirmation Required
|
|
@@ -228,8 +234,9 @@ aws sts get-caller-identity --profile default
|
|
|
228
234
|
- `--ssh-user <name>`
|
|
229
235
|
- `--ssh-port <port>`
|
|
230
236
|
- `--ssh-connect-timeout <seconds>`
|
|
231
|
-
- `--html-out <path>`
|
|
232
|
-
- `--open-html`
|
|
237
|
+
- `--html-out <path>` (default: auto path, workspace/home `aws-inventory.html`)
|
|
238
|
+
- `--open-html` (force open)
|
|
239
|
+
- `--no-open-html` (disable auto-open)
|
|
233
240
|
- `--auto-sso-login` / `--no-auto-sso-login`
|
|
234
241
|
- `--format <json|csv>`
|
|
235
242
|
- `--out <path>`
|
package/README_KO.md
CHANGED
|
@@ -19,7 +19,7 @@ mcp-aws-manager discover --profiles default --no-progress
|
|
|
19
19
|
- SSM 상태 확인: managed/online
|
|
20
20
|
- 런타임 스냅샷(선택), SSM 완화(선택)
|
|
21
21
|
- AWS 인증이 안 될 때 수동 모드: JSON/CSV 서버 목록 + PEM SSH
|
|
22
|
-
- GUI 리포트 생성:
|
|
22
|
+
- GUI 리포트 기본 생성: 워크스페이스/홈 자동 경로 `aws-inventory.html` (검색/필터/CSV 다운로드 버튼 포함)
|
|
23
23
|
- 사람이 개입해야 할 상황을 `ACTION_REQUIRED`로 표준화
|
|
24
24
|
|
|
25
25
|
## 바이너리
|
|
@@ -70,11 +70,13 @@ mcp-aws-manager discover --manual-server-list ./servers.csv --pem-paths C:\keys\
|
|
|
70
70
|
## GUI 리포트
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
mcp-aws-manager discover --profiles default --
|
|
73
|
+
mcp-aws-manager discover --profiles default --no-progress
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
-
|
|
77
|
-
- `--
|
|
76
|
+
- 기본 경로: 워크스페이스/홈 자동 선택(`aws-inventory.html`)
|
|
77
|
+
- `--html-out <path>`: 리포트 경로 변경
|
|
78
|
+
- `--open-html`: 생성 후 브라우저 오픈 강제
|
|
79
|
+
- `--no-open-html`: 자동 오픈 비활성화
|
|
78
80
|
- GUI에서 현재 뷰 기준 CSV 다운로드 가능
|
|
79
81
|
|
|
80
82
|
## MCP 도구
|
package/bin/mcp-aws-manager.js
CHANGED
|
@@ -11,6 +11,7 @@ const DEFAULT_SNAPSHOT_CONCURRENCY = 3;
|
|
|
11
11
|
const MAX_SSM_FILTER_IDS = 50;
|
|
12
12
|
const DEFAULT_SERVER_NAME = "mcp-aws-manager";
|
|
13
13
|
const DEFAULT_MCP_COMMAND = "mcp-aws-manager-mcp";
|
|
14
|
+
const DEFAULT_HTML_REPORT_NAME = "aws-inventory.html";
|
|
14
15
|
const SUPPORTED_CLIENTS = new Set(["codex", "claude", "cursor", "windsurf", "antigravity"]);
|
|
15
16
|
const INTERNAL_BACKEND_ID = "internal";
|
|
16
17
|
|
|
@@ -206,6 +207,64 @@ function expandHome(input) {
|
|
|
206
207
|
return value;
|
|
207
208
|
}
|
|
208
209
|
|
|
210
|
+
function isWritableDirectory(dirPath) {
|
|
211
|
+
try {
|
|
212
|
+
const resolved = path.resolve(String(dirPath || ""));
|
|
213
|
+
fs.mkdirSync(resolved, { recursive: true });
|
|
214
|
+
fs.accessSync(resolved, fs.constants.W_OK);
|
|
215
|
+
return true;
|
|
216
|
+
} catch (_error) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function isLikelyProtectedInstallDir(dirPath) {
|
|
222
|
+
const resolved = path.resolve(String(dirPath || ""));
|
|
223
|
+
if (!resolved) return false;
|
|
224
|
+
const normalized = resolved.replace(/\//g, "\\").toLowerCase();
|
|
225
|
+
if (process.platform === "win32") {
|
|
226
|
+
if (normalized.includes("\\program files\\")) return true;
|
|
227
|
+
if (/^[a-z]:\\windows(\\|$)/.test(normalized)) return true;
|
|
228
|
+
} else {
|
|
229
|
+
if (normalized === "\\usr" || normalized.startsWith("\\usr\\")) return true;
|
|
230
|
+
if (normalized === "\\opt" || normalized.startsWith("\\opt\\")) return true;
|
|
231
|
+
if (normalized === "\\system" || normalized.startsWith("\\system\\")) return true;
|
|
232
|
+
}
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function resolveDefaultHtmlOutPath() {
|
|
237
|
+
const explicit = envText("MCP_AWS_WORKSPACE_DIR");
|
|
238
|
+
if (explicit) {
|
|
239
|
+
const dir = path.resolve(expandHome(explicit));
|
|
240
|
+
if (isWritableDirectory(dir)) {
|
|
241
|
+
return path.join(dir, DEFAULT_HTML_REPORT_NAME);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const candidates = [
|
|
246
|
+
envText("PWD"),
|
|
247
|
+
envText("INIT_CWD"),
|
|
248
|
+
envText("WORKSPACE_DIR"),
|
|
249
|
+
envText("PROJECT_ROOT")
|
|
250
|
+
];
|
|
251
|
+
for (const raw of candidates) {
|
|
252
|
+
if (!raw) continue;
|
|
253
|
+
const dir = path.resolve(expandHome(raw));
|
|
254
|
+
if (isLikelyProtectedInstallDir(dir)) continue;
|
|
255
|
+
if (isWritableDirectory(dir)) {
|
|
256
|
+
return path.join(dir, DEFAULT_HTML_REPORT_NAME);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const home = os.homedir();
|
|
261
|
+
if (isWritableDirectory(home)) {
|
|
262
|
+
return path.join(home, DEFAULT_HTML_REPORT_NAME);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return path.resolve(process.cwd(), DEFAULT_HTML_REPORT_NAME);
|
|
266
|
+
}
|
|
267
|
+
|
|
209
268
|
function usageText() {
|
|
210
269
|
const clientList = Array.from(SUPPORTED_CLIENTS).join(",");
|
|
211
270
|
return [
|
|
@@ -266,8 +325,9 @@ function usageText() {
|
|
|
266
325
|
" --ssh-user <name> (default: ec2-user)",
|
|
267
326
|
" --ssh-port <port> (default: 22)",
|
|
268
327
|
" --ssh-connect-timeout <seconds> (default: 8)",
|
|
269
|
-
" --html-out <path> (
|
|
270
|
-
" --open-html (
|
|
328
|
+
" --html-out <path> (default: auto -> workspace/home aws-inventory.html)",
|
|
329
|
+
" --open-html (force opening HTML report after write)",
|
|
330
|
+
" --no-open-html (disable auto-open of HTML report)",
|
|
271
331
|
" --auto-sso-login / --no-auto-sso-login",
|
|
272
332
|
" --format <json|csv> (default: json)",
|
|
273
333
|
" --out <path>",
|
|
@@ -285,7 +345,7 @@ function usageText() {
|
|
|
285
345
|
" MCP_AWS_SNAPSHOT_MAX_KB, MCP_AWS_AUTO_SSO_LOGIN",
|
|
286
346
|
" MCP_AWS_MANUAL_SERVER_LIST, MCP_AWS_PEM_PATHS, MCP_AWS_SSH_USER, MCP_AWS_SSH_PORT",
|
|
287
347
|
" MCP_AWS_SSH_CONNECT_TIMEOUT",
|
|
288
|
-
" MCP_AWS_HTML_OUT, MCP_AWS_OPEN_HTML",
|
|
348
|
+
" MCP_AWS_HTML_OUT, MCP_AWS_OPEN_HTML, MCP_AWS_HEADLESS, MCP_AWS_WORKSPACE_DIR",
|
|
289
349
|
" MCP_AWS_FORMAT, MCP_AWS_OUT, MCP_AWS_NO_PROGRESS",
|
|
290
350
|
""
|
|
291
351
|
].join("\n");
|
|
@@ -502,6 +562,7 @@ function parseDiscoverArgs(argv) {
|
|
|
502
562
|
if (arg === "--auto-sso-login") { options.autoSsoLogin = true; continue; }
|
|
503
563
|
if (arg === "--no-auto-sso-login") { options.autoSsoLogin = false; continue; }
|
|
504
564
|
if (arg === "--open-html") { options.openHtml = true; continue; }
|
|
565
|
+
if (arg === "--no-open-html") { options.openHtml = false; continue; }
|
|
505
566
|
if (arg === "--progress") { options.noProgress = false; continue; }
|
|
506
567
|
if (arg === "--no-progress") { options.noProgress = true; continue; }
|
|
507
568
|
if (!arg.startsWith("--")) throw new Error(`Unexpected argument: ${arg}`);
|
|
@@ -529,6 +590,8 @@ function parseDiscoverArgs(argv) {
|
|
|
529
590
|
|
|
530
591
|
const envNoProgress = envText("MCP_AWS_NO_PROGRESS");
|
|
531
592
|
|
|
593
|
+
const envOpenHtml = envText("MCP_AWS_OPEN_HTML");
|
|
594
|
+
|
|
532
595
|
return {
|
|
533
596
|
help: false,
|
|
534
597
|
profiles: parseCsv(options.profiles) || parseCsv(envText("MCP_AWS_PROFILES")),
|
|
@@ -561,8 +624,8 @@ function parseDiscoverArgs(argv) {
|
|
|
561
624
|
sshConnectTimeoutSec: Math.round(toPosNum(options.sshConnectTimeoutSec || envText("MCP_AWS_SSH_CONNECT_TIMEOUT") || "8", "--ssh-connect-timeout", 8)),
|
|
562
625
|
htmlOutPath: options.htmlOutPath
|
|
563
626
|
? path.resolve(expandHome(options.htmlOutPath))
|
|
564
|
-
: (envText("MCP_AWS_HTML_OUT") ? path.resolve(expandHome(envText("MCP_AWS_HTML_OUT"))) :
|
|
565
|
-
openHtml: options.openHtml != null ? options.openHtml : envBool("MCP_AWS_OPEN_HTML"),
|
|
627
|
+
: (envText("MCP_AWS_HTML_OUT") ? path.resolve(expandHome(envText("MCP_AWS_HTML_OUT"))) : resolveDefaultHtmlOutPath()),
|
|
628
|
+
openHtml: options.openHtml != null ? options.openHtml : (envOpenHtml != null ? envBool("MCP_AWS_OPEN_HTML") : null),
|
|
566
629
|
autoSsoLogin: options.autoSsoLogin != null ? options.autoSsoLogin : (envText("MCP_AWS_AUTO_SSO_LOGIN") != null ? envBool("MCP_AWS_AUTO_SSO_LOGIN") : true),
|
|
567
630
|
format,
|
|
568
631
|
outPath: options.outPath ? path.resolve(expandHome(options.outPath)) : (envText("MCP_AWS_OUT") ? path.resolve(expandHome(envText("MCP_AWS_OUT"))) : null),
|
|
@@ -2934,9 +2997,25 @@ function renderHtmlReport(records) {
|
|
|
2934
2997
|
function writeHtmlReport(config, records) {
|
|
2935
2998
|
if (!config.htmlOutPath) return null;
|
|
2936
2999
|
const html = renderHtmlReport(records);
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
3000
|
+
try {
|
|
3001
|
+
fs.writeFileSync(config.htmlOutPath, html, "utf8");
|
|
3002
|
+
eprint(`Wrote HTML report to ${config.htmlOutPath}`);
|
|
3003
|
+
return config.htmlOutPath;
|
|
3004
|
+
} catch (error) {
|
|
3005
|
+
const code = String(error && error.code ? error.code : "");
|
|
3006
|
+
if (!["EACCES", "EPERM", "EROFS"].includes(code)) {
|
|
3007
|
+
throw error;
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
const fallbackPath = path.join(os.homedir(), path.basename(config.htmlOutPath) || DEFAULT_HTML_REPORT_NAME);
|
|
3011
|
+
if (path.resolve(fallbackPath) === path.resolve(config.htmlOutPath)) {
|
|
3012
|
+
throw error;
|
|
3013
|
+
}
|
|
3014
|
+
fs.mkdirSync(path.dirname(fallbackPath), { recursive: true });
|
|
3015
|
+
fs.writeFileSync(fallbackPath, html, "utf8");
|
|
3016
|
+
eprint(`WARNING: failed to write HTML report to ${config.htmlOutPath} (${code}); wrote fallback to ${fallbackPath}`);
|
|
3017
|
+
return fallbackPath;
|
|
3018
|
+
}
|
|
2940
3019
|
}
|
|
2941
3020
|
|
|
2942
3021
|
function tryOpenFile(targetPath) {
|
|
@@ -2961,6 +3040,19 @@ function tryOpenFile(targetPath) {
|
|
|
2961
3040
|
}
|
|
2962
3041
|
}
|
|
2963
3042
|
|
|
3043
|
+
function shouldAutoOpenHtml(config) {
|
|
3044
|
+
if (config.openHtml === true) return true;
|
|
3045
|
+
if (config.openHtml === false) return false;
|
|
3046
|
+
|
|
3047
|
+
// Auto mode: only try in likely local desktop sessions.
|
|
3048
|
+
if (envBool("MCP_AWS_HEADLESS")) return false;
|
|
3049
|
+
if (envBool("CI")) return false;
|
|
3050
|
+
if (envText("SSH_CONNECTION") || envText("SSH_CLIENT") || envText("SSH_TTY")) return false;
|
|
3051
|
+
if (!(process.stdout && process.stdout.isTTY)) return false;
|
|
3052
|
+
if (process.platform === "linux" && !envText("DISPLAY") && !envText("WAYLAND_DISPLAY")) return false;
|
|
3053
|
+
return true;
|
|
3054
|
+
}
|
|
3055
|
+
|
|
2964
3056
|
function writeOutput(config, content) {
|
|
2965
3057
|
if (config.outPath) {
|
|
2966
3058
|
fs.writeFileSync(config.outPath, content, "utf8");
|
|
@@ -2976,7 +3068,7 @@ async function runWorkflow(config) {
|
|
|
2976
3068
|
const requiredActions = [];
|
|
2977
3069
|
|
|
2978
3070
|
progress(config, 1, "orchestrator: parse user request and operation scope");
|
|
2979
|
-
eprint(`Inputs: execution_mode=${INTERNAL_BACKEND_ID}, profiles=${config.profiles ? config.profiles.join(",") : "auto"}, regions=${config.regions ? config.regions.join(",") : "auto"}, include_ec2=${config.includeEc2 ? "on" : "off"}, include_lambda=${config.includeLambda ? "on" : "off"}, include_alb=${config.includeAlb ? "on" : "off"}, include_asg=${config.includeAsg ? "on" : "off"}, include_rds=${config.includeRds ? "on" : "off"}, include_elasticache=${config.includeElastiCache ? "on" : "off"}, include_route53=${config.includeRoute53 ? "on" : "off"}, public_only=${config.publicOnly ? "on" : "off"}, managed_only=${config.managedOnly ? "on" : "off"}, auto_remediate_ssm=${config.autoRemediateSsm ? "on" : "off"}, runtime_snapshot=${config.runtimeSnapshot ? "on" : "off"}, manual_server_list=${config.manualServerListPath || "off"}, pem_paths=${config.pemPaths && config.pemPaths.length ? config.pemPaths.length : 0}, ssh_user=${config.sshUser}, ssh_port=${config.sshPort}, html_out=${config.htmlOutPath || "off"}, open_html=${config.openHtml ? "on" : "off"}, auto_sso_login=${config.autoSsoLogin ? "on" : "off"}`);
|
|
3071
|
+
eprint(`Inputs: execution_mode=${INTERNAL_BACKEND_ID}, profiles=${config.profiles ? config.profiles.join(",") : "auto"}, regions=${config.regions ? config.regions.join(",") : "auto"}, include_ec2=${config.includeEc2 ? "on" : "off"}, include_lambda=${config.includeLambda ? "on" : "off"}, include_alb=${config.includeAlb ? "on" : "off"}, include_asg=${config.includeAsg ? "on" : "off"}, include_rds=${config.includeRds ? "on" : "off"}, include_elasticache=${config.includeElastiCache ? "on" : "off"}, include_route53=${config.includeRoute53 ? "on" : "off"}, public_only=${config.publicOnly ? "on" : "off"}, managed_only=${config.managedOnly ? "on" : "off"}, auto_remediate_ssm=${config.autoRemediateSsm ? "on" : "off"}, runtime_snapshot=${config.runtimeSnapshot ? "on" : "off"}, manual_server_list=${config.manualServerListPath || "off"}, pem_paths=${config.pemPaths && config.pemPaths.length ? config.pemPaths.length : 0}, ssh_user=${config.sshUser}, ssh_port=${config.sshPort}, html_out=${config.htmlOutPath || "off"}, open_html=${config.openHtml == null ? "auto" : (config.openHtml ? "on" : "off")}, auto_sso_login=${config.autoSsoLogin ? "on" : "off"}`);
|
|
2980
3072
|
|
|
2981
3073
|
progress(config, 2, "config_validator: validate settings and output path");
|
|
2982
3074
|
validateConfig(config, warnings, requiredActions);
|
|
@@ -3039,7 +3131,7 @@ async function runWorkflow(config) {
|
|
|
3039
3131
|
progress(config, 8, "cli_output_formatter: render JSON/CSV and guidance payload");
|
|
3040
3132
|
writeOutput(config, renderOutput(config, outputRecords));
|
|
3041
3133
|
const htmlPath = writeHtmlReport(config, outputRecords);
|
|
3042
|
-
if (htmlPath && config
|
|
3134
|
+
if (htmlPath && shouldAutoOpenHtml(config)) {
|
|
3043
3135
|
const opened = tryOpenFile(htmlPath);
|
|
3044
3136
|
if (!opened.ok) {
|
|
3045
3137
|
warnings.push(`Failed to auto-open HTML report: ${opened.detail}`);
|
package/package.json
CHANGED