mcp-aws-manager 0.3.0 → 0.3.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.
@@ -0,0 +1,52 @@
1
+ # Agent Guidance Loop Template (KO)
2
+
3
+ 아래 규칙은 `discover_ec2_with_ssm` 또는 호환 alias 호출 결과를 바탕으로 사용자 개입을 최소화하기 위한 시스템 프롬프트 템플릿입니다.
4
+
5
+ ## 목적
6
+
7
+ - 가능한 범위는 자동으로 끝까지 처리한다.
8
+ - 수동 개입이 필요한 순간에만 사용자를 안내한다.
9
+ - 사용자가 조치를 완료하면 같은 입력으로 자동 재시도한다.
10
+
11
+ ## 입력 가정
12
+
13
+ MCP 응답 JSON에는 아래 필드가 포함된다.
14
+
15
+ - `requiresUserAction: boolean`
16
+ - `requiredActions: [{ code, message, hint }]`
17
+ - `guidance: { assistantMessageTemplate, retryTool, retryArgs, userChecklist, completionTrigger }`
18
+
19
+ ## 실행 규칙
20
+
21
+ 1. 먼저 도구를 실행한다.
22
+ 2. `requiresUserAction=false`이면 결과를 요약하고 종료한다.
23
+ 3. `requiresUserAction=true`이면 `guidance.assistantMessageTemplate`을 사용자에게 그대로 전달한다.
24
+ 4. 사용자의 답변이 `완료` 또는 완료 의사표시이면, `guidance.retryTool` + `guidance.retryArgs`로 동일 요청을 즉시 재실행한다.
25
+ 5. 여전히 `requiresUserAction=true`이면 다음 액션을 다시 안내한다.
26
+ 6. 성공(`requiresUserAction=false`)할 때까지 반복한다.
27
+
28
+ ## 사용자 안내 스타일
29
+
30
+ - 한 번에 하나의 액션만 안내한다.
31
+ - 필요한 명령어는 복붙 가능한 한 줄로 제시한다.
32
+ - 사용자의 AWS 지식 수준을 가정하지 않는다.
33
+ - 매 단계 끝에 반드시 재시도 트리거 문구를 넣는다.
34
+
35
+ 예시 트리거 문구:
36
+
37
+ - `조치가 끝나면 "완료"라고 답해주세요. 제가 바로 같은 요청으로 다시 확인하겠습니다.`
38
+
39
+ ## 금지 사항
40
+
41
+ - 사용자가 요청하지 않은 파괴적 작업을 임의 실행하지 않는다.
42
+ - 여러 개의 복잡한 선택지를 한 번에 던지지 않는다.
43
+ - 내부 오류 로그를 장황하게 그대로 노출하지 않는다.
44
+
45
+ ## 최종 완료 응답
46
+
47
+ 완료 시 아래를 간단히 보고한다.
48
+
49
+ 1. 전체 인스턴스 수
50
+ 2. SSM 관리/온라인 수
51
+ 3. 주요 경고 유무
52
+ 4. 다음 선택 사항(예: 런타임 스냅샷 확장)
@@ -93,5 +93,5 @@ Use only when automatic registration is unavailable in your environment.
93
93
 
94
94
  - Discovery is SSM-only; PEM path arguments are no longer required.
95
95
  - Keep AWS credentials/profiles available on the host running MCP.
96
- - When `requiresUserAction=true` is returned, surface `requiredActions` to the user and retry after intervention.
96
+ - When `requiresUserAction=true` is returned, use `guidance.assistantMessageTemplate` to prompt the user, then retry with `guidance.retryTool` + `guidance.retryArgs` after user confirmation.
97
97
  - For auto remediation, pass `autoRemediateSsm` and an instance profile name/arn.
package/README.md CHANGED
@@ -122,7 +122,11 @@ When fully automatic execution is not possible, the CLI/MCP returns actionable g
122
122
  - `ACTION_REQUIRED: [SSM_ROLE_OR_AGENT_REQUIRED] ...`
123
123
  - `ACTION_REQUIRED: [IAM_PROFILE_ASSOCIATION_FAILED] ...`
124
124
 
125
- The MCP wrapper surfaces these in a structured `requiredActions` list.
125
+ The MCP wrapper surfaces these in a structured `requiredActions` list and a `guidance` object (`assistantMessageTemplate`, `retryTool`, `retryArgs`).
126
+
127
+ For agent orchestration, see:
128
+
129
+ - `AGENT_GUIDANCE_LOOP_TEMPLATE_KO.md`
126
130
 
127
131
  ## Security Notes
128
132
 
@@ -248,6 +248,157 @@ function summarizeRecords(records) {
248
248
  return summary;
249
249
  }
250
250
 
251
+ function firstProfileArg(args) {
252
+ if (args && Array.isArray(args.profiles) && args.profiles.length > 0) {
253
+ return String(args.profiles[0]);
254
+ }
255
+ return "default";
256
+ }
257
+
258
+ function inferSsoLoginCommand(action, args) {
259
+ const hint = action && action.hint ? String(action.hint) : "";
260
+ const matched = /aws sso login --profile\s+[^\s'"]+/i.exec(hint);
261
+ if (matched) {
262
+ return matched[0];
263
+ }
264
+ return `aws sso login --profile ${firstProfileArg(args)}`;
265
+ }
266
+
267
+ function guidanceForAction(action, args) {
268
+ const code = action && action.code ? String(action.code) : "UNKNOWN";
269
+ const defaultItem = {
270
+ code,
271
+ title: "Manual action required",
272
+ steps: [
273
+ action && action.message ? action.message : "A manual action is required.",
274
+ action && action.hint ? action.hint : "After completing the action, reply '완료' to continue."
275
+ ],
276
+ confirmText: "조치가 완료되면 '완료'라고 답해주세요. 같은 요청으로 자동 재시도하겠습니다."
277
+ };
278
+
279
+ switch (code) {
280
+ case "SSO_LOGIN_NEEDED":
281
+ case "SSO_REAUTH_REQUIRED": {
282
+ const cmd = inferSsoLoginCommand(action, args);
283
+ return {
284
+ code,
285
+ title: "AWS SSO login required",
286
+ steps: [
287
+ `터미널에서 다음 명령을 실행하세요: ${cmd}`,
288
+ "브라우저 인증/MFA를 완료하세요.",
289
+ "완료 후 '완료'라고 답해주세요."
290
+ ],
291
+ confirmText: "SSO 로그인이 끝났다면 '완료'라고 답해주세요."
292
+ };
293
+ }
294
+ case "AWS_CREDENTIALS_REQUIRED":
295
+ return {
296
+ code,
297
+ title: "AWS credentials required",
298
+ steps: [
299
+ "사용할 프로필의 자격증명을 설정하세요 (SSO 또는 access key).",
300
+ "SSO라면 'aws configure sso --profile <profile>' 후 로그인하세요.",
301
+ "완료 후 '완료'라고 답해주세요."
302
+ ],
303
+ confirmText: "자격증명 설정/로그인이 끝났다면 '완료'라고 답해주세요."
304
+ };
305
+ case "SET_SSM_INSTANCE_PROFILE":
306
+ return {
307
+ code,
308
+ title: "SSM remediation target missing",
309
+ steps: [
310
+ "자동 복구를 사용하려면 instance profile 이름 또는 ARN을 지정해야 합니다.",
311
+ "다음 옵션 중 하나를 함께 전달하세요: --ssm-instance-profile-name 또는 --ssm-instance-profile-arn",
312
+ "완료 후 '완료'라고 답해주세요."
313
+ ],
314
+ confirmText: "프로파일 대상을 지정했다면 '완료'라고 답해주세요."
315
+ };
316
+ case "SSM_ROLE_OR_AGENT_REQUIRED":
317
+ return {
318
+ code,
319
+ title: "Instance is not SSM managed",
320
+ steps: [
321
+ "인스턴스 역할에 AmazonSSMManagedInstanceCore를 포함하세요.",
322
+ "SSM Agent와 네트워크(SSM endpoint/인터넷 경로)가 정상인지 확인하세요.",
323
+ "완료 후 '완료'라고 답해주세요."
324
+ ],
325
+ confirmText: "SSM 관리 상태를 조치했다면 '완료'라고 답해주세요."
326
+ };
327
+ case "INSTANCE_HAS_PROFILE":
328
+ return {
329
+ code,
330
+ title: "Existing instance profile detected",
331
+ steps: [
332
+ "기존 인스턴스 프로파일이 있습니다.",
333
+ "선택 1: 기존 역할 정책에 SSM 권한을 추가합니다.",
334
+ "선택 2: 자동 교체를 원하면 allowReplaceProfile=true 로 재시도합니다."
335
+ ],
336
+ confirmText: "적용할 방법을 정했다면 '완료'라고 답해주세요."
337
+ };
338
+ case "IAM_PROFILE_ASSOCIATION_FAILED":
339
+ case "IAM_PROFILE_REPLACE_FAILED":
340
+ return {
341
+ code,
342
+ title: "Missing IAM permission for remediation",
343
+ steps: [
344
+ "실행 주체에 EC2 인스턴스 프로파일 연결/교체 권한을 부여하세요.",
345
+ "필요 권한: ec2:AssociateIamInstanceProfile, ec2:ReplaceIamInstanceProfileAssociation(교체 시), iam:PassRole",
346
+ "완료 후 '완료'라고 답해주세요."
347
+ ],
348
+ confirmText: "IAM 권한 반영이 끝났다면 '완료'라고 답해주세요."
349
+ };
350
+ case "SSM_RUNCOMMAND_PERMISSION_REQUIRED":
351
+ return {
352
+ code,
353
+ title: "Missing SSM RunCommand permission",
354
+ steps: [
355
+ "실행 주체에 SSM 명령 권한을 부여하세요.",
356
+ "필요 권한: ssm:SendCommand, ssm:GetCommandInvocation",
357
+ "완료 후 '완료'라고 답해주세요."
358
+ ],
359
+ confirmText: "SSM 권한 반영이 끝났다면 '완료'라고 답해주세요."
360
+ };
361
+ default:
362
+ return defaultItem;
363
+ }
364
+ }
365
+
366
+ function buildAgentGuidance(requiredActions, toolName, args) {
367
+ const items = Array.isArray(requiredActions)
368
+ ? requiredActions.map((action) => guidanceForAction(action, args))
369
+ : [];
370
+
371
+ if (!items.length) {
372
+ return {
373
+ mode: "none",
374
+ autoRetryRecommended: false,
375
+ retryTool: toolName,
376
+ retryArgs: args,
377
+ userChecklist: [],
378
+ assistantMessageTemplate: "상태 조회가 완료되었습니다."
379
+ };
380
+ }
381
+
382
+ const firstItem = items[0];
383
+ const lines = [];
384
+ lines.push("AWS 상태 조회를 계속하려면 아래 조치가 필요합니다.");
385
+ lines.push(`1. [${firstItem.code}] ${firstItem.title}`);
386
+ for (let i = 0; i < firstItem.steps.length; i += 1) {
387
+ lines.push(`${i + 1}. ${firstItem.steps[i]}`);
388
+ }
389
+ lines.push(firstItem.confirmText);
390
+
391
+ return {
392
+ mode: "human_in_the_loop",
393
+ autoRetryRecommended: true,
394
+ retryTool: toolName,
395
+ retryArgs: args,
396
+ completionTrigger: "사용자가 '완료' 또는 조치 완료를 확인하면 같은 입력으로 도구를 재실행",
397
+ userChecklist: items,
398
+ assistantMessageTemplate: lines.join("\n")
399
+ };
400
+ }
401
+
251
402
  function buildToolTextResponse(payload) {
252
403
  return truncateText(JSON.stringify(payload, null, 2), DEFAULT_JSON_TEXT_LIMIT);
253
404
  }
@@ -353,6 +504,7 @@ function registerDiscoverTool(server, name, title, description) {
353
504
 
354
505
  const acceptedExitCodes = new Set([0, 2, 3]);
355
506
  const requiresUserAction = logInfo.requiredActions.length > 0 || cliResult.exitCode === 3;
507
+ const guidance = buildAgentGuidance(logInfo.requiredActions, name, args);
356
508
 
357
509
  const response = {
358
510
  ok: acceptedExitCodes.has(cliResult.exitCode),
@@ -362,6 +514,7 @@ function registerDiscoverTool(server, name, title, description) {
362
514
  signal: cliResult.signal,
363
515
  requiresUserAction,
364
516
  requiredActions: logInfo.requiredActions,
517
+ guidance,
365
518
  summary: {
366
519
  ...summarizeRecords(allRecords),
367
520
  returnedRecords: records.length,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-aws-manager",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "AWS operations CLI and MCP server (SSM-only) for EC2 inventory, remediation, and runtime snapshots",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -23,7 +23,8 @@
23
23
  },
24
24
  "files": [
25
25
  "bin",
26
- "MCP_CLIENT_SETUP.md"
26
+ "MCP_CLIENT_SETUP.md",
27
+ "AGENT_GUIDANCE_LOOP_TEMPLATE_KO.md"
27
28
  ],
28
29
  "engines": {
29
30
  "node": ">=18"