@frontpoint/aws-infra-mcp 0.1.0
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/LICENSE +21 -0
- package/README.md +141 -0
- package/dist/core/aws-analyzer.d.ts +73 -0
- package/dist/core/aws-analyzer.d.ts.map +1 -0
- package/dist/core/aws-analyzer.js +429 -0
- package/dist/core/aws-analyzer.js.map +1 -0
- package/dist/core/cdk-generator.d.ts +26 -0
- package/dist/core/cdk-generator.d.ts.map +1 -0
- package/dist/core/cdk-generator.js +790 -0
- package/dist/core/cdk-generator.js.map +1 -0
- package/dist/core/template-engine.d.ts +32 -0
- package/dist/core/template-engine.d.ts.map +1 -0
- package/dist/core/template-engine.js +131 -0
- package/dist/core/template-engine.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +158 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/aws-add-compute.d.ts +8 -0
- package/dist/tools/aws-add-compute.d.ts.map +1 -0
- package/dist/tools/aws-add-compute.js +269 -0
- package/dist/tools/aws-add-compute.js.map +1 -0
- package/dist/tools/aws-add-database.d.ts +8 -0
- package/dist/tools/aws-add-database.d.ts.map +1 -0
- package/dist/tools/aws-add-database.js +230 -0
- package/dist/tools/aws-add-database.js.map +1 -0
- package/dist/tools/aws-add-network.d.ts +8 -0
- package/dist/tools/aws-add-network.d.ts.map +1 -0
- package/dist/tools/aws-add-network.js +240 -0
- package/dist/tools/aws-add-network.js.map +1 -0
- package/dist/tools/aws-add-storage.d.ts +8 -0
- package/dist/tools/aws-add-storage.d.ts.map +1 -0
- package/dist/tools/aws-add-storage.js +207 -0
- package/dist/tools/aws-add-storage.js.map +1 -0
- package/dist/tools/aws-analyze.d.ts +8 -0
- package/dist/tools/aws-analyze.d.ts.map +1 -0
- package/dist/tools/aws-analyze.js +123 -0
- package/dist/tools/aws-analyze.js.map +1 -0
- package/dist/tools/aws-generate-all.d.ts +8 -0
- package/dist/tools/aws-generate-all.d.ts.map +1 -0
- package/dist/tools/aws-generate-all.js +197 -0
- package/dist/tools/aws-generate-all.js.map +1 -0
- package/dist/tools/aws-init.d.ts +8 -0
- package/dist/tools/aws-init.d.ts.map +1 -0
- package/dist/tools/aws-init.js +114 -0
- package/dist/tools/aws-init.js.map +1 -0
- package/dist/tools/aws-status.d.ts +8 -0
- package/dist/tools/aws-status.d.ts.map +1 -0
- package/dist/tools/aws-status.js +110 -0
- package/dist/tools/aws-status.js.map +1 -0
- package/dist/tools/index.d.ts +51 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +35 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types.d.ts +644 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aws-add-network - Add network resources (VPC, API Gateway)
|
|
3
|
+
*/
|
|
4
|
+
import * as crypto from 'crypto';
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { CONFIG_FILE, } from '../types.js';
|
|
8
|
+
export const awsAddNetworkTool = {
|
|
9
|
+
name: 'aws-add-network',
|
|
10
|
+
description: 'VPC, API Gateway 네트워크 리소스를 설정에 추가합니다.',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
type: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: '추가할 리소스 유형',
|
|
17
|
+
enum: ['vpc', 'api-gateway'],
|
|
18
|
+
},
|
|
19
|
+
name: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
description: '리소스 이름',
|
|
22
|
+
},
|
|
23
|
+
// VPC specific
|
|
24
|
+
cidrBlock: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'VPC CIDR 블록 (예: 10.0.0.0/16)',
|
|
27
|
+
},
|
|
28
|
+
azCount: {
|
|
29
|
+
type: 'number',
|
|
30
|
+
description: '사용할 가용 영역 수 (기본값: 2)',
|
|
31
|
+
},
|
|
32
|
+
natGateways: {
|
|
33
|
+
type: 'number',
|
|
34
|
+
description: 'NAT Gateway 수 (0-3, 기본값: 1)',
|
|
35
|
+
},
|
|
36
|
+
enableDnsSupport: {
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
description: 'DNS 지원 활성화 (기본값: true)',
|
|
39
|
+
},
|
|
40
|
+
// API Gateway specific
|
|
41
|
+
apiType: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
description: 'API Gateway 유형',
|
|
44
|
+
enum: ['REST', 'HTTP', 'WEBSOCKET'],
|
|
45
|
+
},
|
|
46
|
+
cors: {
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
description: 'CORS 활성화',
|
|
49
|
+
},
|
|
50
|
+
corsOrigins: {
|
|
51
|
+
type: 'array',
|
|
52
|
+
items: { type: 'string' },
|
|
53
|
+
description: 'CORS 허용 오리진 목록',
|
|
54
|
+
},
|
|
55
|
+
stageName: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: '기본 스테이지 이름 (기본값: prod)',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
required: ['type', 'name'],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
export async function handleAwsAddNetwork(args, context) {
|
|
64
|
+
const { configRoot, config, state } = context;
|
|
65
|
+
if (!config || !state) {
|
|
66
|
+
return {
|
|
67
|
+
success: false,
|
|
68
|
+
message: 'aws-init을 먼저 실행하세요.',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const resourceType = args.type;
|
|
72
|
+
const name = args.name;
|
|
73
|
+
// Initialize network config if needed
|
|
74
|
+
if (!config.network) {
|
|
75
|
+
config.network = {};
|
|
76
|
+
}
|
|
77
|
+
let message = '';
|
|
78
|
+
const generatedId = crypto.randomUUID().slice(0, 8);
|
|
79
|
+
switch (resourceType) {
|
|
80
|
+
case 'vpc': {
|
|
81
|
+
const cidrBlock = args.cidrBlock || '10.0.0.0/16';
|
|
82
|
+
const azCount = args.azCount || 2;
|
|
83
|
+
const natGateways = Math.min(Math.max(args.natGateways ?? 1, 0), 3);
|
|
84
|
+
const enableDnsSupport = args.enableDnsSupport !== false;
|
|
85
|
+
// Generate subnets based on CIDR and AZ count
|
|
86
|
+
const subnets = generateSubnets(cidrBlock, azCount, generatedId);
|
|
87
|
+
const natGatewayConfigs = generateNatGateways(subnets, natGateways, generatedId);
|
|
88
|
+
const vpcConfig = {
|
|
89
|
+
id: `vpc-${generatedId}`,
|
|
90
|
+
name,
|
|
91
|
+
cidrBlock,
|
|
92
|
+
enableDnsSupport,
|
|
93
|
+
enableDnsHostnames: true,
|
|
94
|
+
subnets,
|
|
95
|
+
internetGateway: true,
|
|
96
|
+
natGateways: natGatewayConfigs,
|
|
97
|
+
securityGroups: [
|
|
98
|
+
{
|
|
99
|
+
id: `sg-default-${generatedId}`,
|
|
100
|
+
name: `${name}-default-sg`,
|
|
101
|
+
description: 'Default security group',
|
|
102
|
+
ingressRules: [
|
|
103
|
+
{
|
|
104
|
+
protocol: 'tcp',
|
|
105
|
+
fromPort: 443,
|
|
106
|
+
toPort: 443,
|
|
107
|
+
cidrBlocks: ['0.0.0.0/0'],
|
|
108
|
+
description: 'HTTPS',
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
egressRules: [
|
|
112
|
+
{
|
|
113
|
+
protocol: '-1',
|
|
114
|
+
fromPort: 0,
|
|
115
|
+
toPort: 0,
|
|
116
|
+
cidrBlocks: ['0.0.0.0/0'],
|
|
117
|
+
description: 'Allow all outbound',
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
if (!config.network.vpcs) {
|
|
124
|
+
config.network.vpcs = [];
|
|
125
|
+
}
|
|
126
|
+
config.network.vpcs.push(vpcConfig);
|
|
127
|
+
const publicSubnets = subnets.filter(s => s.type === 'public').length;
|
|
128
|
+
const privateSubnets = subnets.filter(s => s.type === 'private').length;
|
|
129
|
+
message = `VPC '${name}' (${cidrBlock})가 추가되었습니다. `;
|
|
130
|
+
message += `${publicSubnets} 퍼블릭, ${privateSubnets} 프라이빗 서브넷, ${natGateways} NAT Gateway`;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case 'api-gateway': {
|
|
134
|
+
const apiType = args.apiType || 'HTTP';
|
|
135
|
+
const cors = args.cors === true;
|
|
136
|
+
const corsOrigins = args.corsOrigins || ['*'];
|
|
137
|
+
const stageName = args.stageName || 'prod';
|
|
138
|
+
const apiConfig = {
|
|
139
|
+
id: `apigw-${generatedId}`,
|
|
140
|
+
name,
|
|
141
|
+
type: apiType,
|
|
142
|
+
description: `${name} API Gateway`,
|
|
143
|
+
stages: [
|
|
144
|
+
{
|
|
145
|
+
name: stageName,
|
|
146
|
+
autoDeploy: true,
|
|
147
|
+
throttling: {
|
|
148
|
+
burstLimit: 5000,
|
|
149
|
+
rateLimit: 10000,
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
if (cors) {
|
|
155
|
+
apiConfig.cors = {
|
|
156
|
+
allowOrigins: corsOrigins,
|
|
157
|
+
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
158
|
+
allowHeaders: ['Content-Type', 'Authorization', 'X-Api-Key'],
|
|
159
|
+
maxAge: 86400,
|
|
160
|
+
allowCredentials: corsOrigins[0] !== '*',
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
if (!config.network.apiGateways) {
|
|
164
|
+
config.network.apiGateways = [];
|
|
165
|
+
}
|
|
166
|
+
config.network.apiGateways.push(apiConfig);
|
|
167
|
+
const features = [apiType];
|
|
168
|
+
if (cors)
|
|
169
|
+
features.push('CORS');
|
|
170
|
+
message = `API Gateway '${name}'가 추가되었습니다. (${features.join(', ')}, 스테이지: ${stageName})`;
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
default:
|
|
174
|
+
return {
|
|
175
|
+
success: false,
|
|
176
|
+
message: `알 수 없는 리소스 유형: ${resourceType}`,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// Save config
|
|
180
|
+
config.lastModified = new Date().toISOString();
|
|
181
|
+
fs.writeFileSync(path.join(configRoot, CONFIG_FILE), JSON.stringify(config, null, 2));
|
|
182
|
+
return {
|
|
183
|
+
success: true,
|
|
184
|
+
message,
|
|
185
|
+
data: {
|
|
186
|
+
resourceType,
|
|
187
|
+
name,
|
|
188
|
+
id: `${resourceType}-${generatedId}`,
|
|
189
|
+
},
|
|
190
|
+
nextSteps: [
|
|
191
|
+
'aws-status로 현재 설정을 확인하세요',
|
|
192
|
+
'추가 리소스를 설정하려면 aws-add-* 도구를 사용하세요',
|
|
193
|
+
'설정이 완료되면 aws-generate-all로 CDK 프로젝트를 생성하세요',
|
|
194
|
+
],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function generateSubnets(cidrBlock, azCount, id) {
|
|
198
|
+
const subnets = [];
|
|
199
|
+
const azSuffixes = ['a', 'b', 'c'];
|
|
200
|
+
// Parse CIDR to get base IP
|
|
201
|
+
const [baseIp] = cidrBlock.split('/');
|
|
202
|
+
const octets = baseIp.split('.').map(Number);
|
|
203
|
+
for (let i = 0; i < azCount; i++) {
|
|
204
|
+
const az = azSuffixes[i];
|
|
205
|
+
// Public subnet
|
|
206
|
+
subnets.push({
|
|
207
|
+
id: `subnet-public-${az}-${id}`,
|
|
208
|
+
name: `public-${az}`,
|
|
209
|
+
cidrBlock: `${octets[0]}.${octets[1]}.${i * 16}.0/20`,
|
|
210
|
+
availabilityZone: az,
|
|
211
|
+
type: 'public',
|
|
212
|
+
mapPublicIpOnLaunch: true,
|
|
213
|
+
});
|
|
214
|
+
// Private subnet
|
|
215
|
+
subnets.push({
|
|
216
|
+
id: `subnet-private-${az}-${id}`,
|
|
217
|
+
name: `private-${az}`,
|
|
218
|
+
cidrBlock: `${octets[0]}.${octets[1]}.${128 + i * 16}.0/20`,
|
|
219
|
+
availabilityZone: az,
|
|
220
|
+
type: 'private',
|
|
221
|
+
mapPublicIpOnLaunch: false,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return subnets;
|
|
225
|
+
}
|
|
226
|
+
function generateNatGateways(subnets, count, id) {
|
|
227
|
+
if (count === 0)
|
|
228
|
+
return [];
|
|
229
|
+
const publicSubnets = subnets.filter(s => s.type === 'public');
|
|
230
|
+
const natGateways = [];
|
|
231
|
+
for (let i = 0; i < Math.min(count, publicSubnets.length); i++) {
|
|
232
|
+
natGateways.push({
|
|
233
|
+
id: `nat-${i}-${id}`,
|
|
234
|
+
name: `nat-gateway-${i}`,
|
|
235
|
+
subnetId: publicSubnets[i].id,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
return natGateways;
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=aws-add-network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aws-add-network.js","sourceRoot":"","sources":["../../src/tools/aws-add-network.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aws-add-storage - Add storage resources (S3, EBS, ECR)
|
|
3
|
+
*/
|
|
4
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { type ToolContext, type ToolResponse } from '../types.js';
|
|
6
|
+
export declare const awsAddStorageTool: Tool;
|
|
7
|
+
export declare function handleAwsAddStorage(args: Record<string, unknown>, context: ToolContext): Promise<ToolResponse>;
|
|
8
|
+
//# sourceMappingURL=aws-add-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aws-add-storage.d.ts","sourceRoot":"","sources":["../../src/tools/aws-add-storage.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAI/D,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EAIlB,MAAM,aAAa,CAAC;AAErB,eAAO,MAAM,iBAAiB,EAAE,IAsD/B,CAAC;AAEF,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,CAAC,CAiKvB"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aws-add-storage - Add storage resources (S3, EBS, ECR)
|
|
3
|
+
*/
|
|
4
|
+
import * as crypto from 'crypto';
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { CONFIG_FILE, } from '../types.js';
|
|
8
|
+
export const awsAddStorageTool = {
|
|
9
|
+
name: 'aws-add-storage',
|
|
10
|
+
description: 'S3 버킷, ECR 리포지토리 스토리지 리소스를 설정에 추가합니다.',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
type: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: '추가할 리소스 유형',
|
|
17
|
+
enum: ['s3', 'ecr'],
|
|
18
|
+
},
|
|
19
|
+
name: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
description: '버킷/리포지토리 이름',
|
|
22
|
+
},
|
|
23
|
+
// S3 specific
|
|
24
|
+
versioning: {
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
description: 'S3 버전 관리 활성화',
|
|
27
|
+
},
|
|
28
|
+
encryption: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'S3 암호화 유형',
|
|
31
|
+
enum: ['AES256', 'aws:kms'],
|
|
32
|
+
},
|
|
33
|
+
blockPublicAccess: {
|
|
34
|
+
type: 'boolean',
|
|
35
|
+
description: 'S3 퍼블릭 액세스 차단 (기본값: true)',
|
|
36
|
+
},
|
|
37
|
+
website: {
|
|
38
|
+
type: 'boolean',
|
|
39
|
+
description: 'S3 정적 웹사이트 호스팅 활성화',
|
|
40
|
+
},
|
|
41
|
+
lifecycleDays: {
|
|
42
|
+
type: 'number',
|
|
43
|
+
description: '객체 만료 일수 (선택사항)',
|
|
44
|
+
},
|
|
45
|
+
// ECR specific
|
|
46
|
+
imageScanOnPush: {
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
description: 'ECR 푸시 시 이미지 스캔 활성화 (기본값: true)',
|
|
49
|
+
},
|
|
50
|
+
imageTagMutability: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
description: 'ECR 이미지 태그 변경 가능 여부',
|
|
53
|
+
enum: ['MUTABLE', 'IMMUTABLE'],
|
|
54
|
+
},
|
|
55
|
+
maxImageCount: {
|
|
56
|
+
type: 'number',
|
|
57
|
+
description: 'ECR 이미지 최대 개수 (수명 주기 정책)',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
required: ['type', 'name'],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
export async function handleAwsAddStorage(args, context) {
|
|
64
|
+
const { configRoot, config, state } = context;
|
|
65
|
+
if (!config || !state) {
|
|
66
|
+
return {
|
|
67
|
+
success: false,
|
|
68
|
+
message: 'aws-init을 먼저 실행하세요.',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const resourceType = args.type;
|
|
72
|
+
const name = args.name;
|
|
73
|
+
// Initialize storage config if needed
|
|
74
|
+
if (!config.storage) {
|
|
75
|
+
config.storage = {};
|
|
76
|
+
}
|
|
77
|
+
let message = '';
|
|
78
|
+
const generatedId = crypto.randomUUID().slice(0, 8);
|
|
79
|
+
switch (resourceType) {
|
|
80
|
+
case 's3': {
|
|
81
|
+
const versioning = args.versioning === true;
|
|
82
|
+
const encryption = args.encryption || 'AES256';
|
|
83
|
+
const blockPublicAccess = args.blockPublicAccess !== false;
|
|
84
|
+
const website = args.website === true;
|
|
85
|
+
const lifecycleDays = args.lifecycleDays;
|
|
86
|
+
const s3Config = {
|
|
87
|
+
id: `s3-${generatedId}`,
|
|
88
|
+
name,
|
|
89
|
+
versioning,
|
|
90
|
+
encryption: { type: encryption },
|
|
91
|
+
};
|
|
92
|
+
if (blockPublicAccess) {
|
|
93
|
+
s3Config.publicAccessBlock = {
|
|
94
|
+
blockPublicAcls: true,
|
|
95
|
+
blockPublicPolicy: true,
|
|
96
|
+
ignorePublicAcls: true,
|
|
97
|
+
restrictPublicBuckets: true,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (website) {
|
|
101
|
+
s3Config.websiteConfiguration = {
|
|
102
|
+
indexDocument: 'index.html',
|
|
103
|
+
errorDocument: 'error.html',
|
|
104
|
+
};
|
|
105
|
+
// Disable public access block for website hosting
|
|
106
|
+
s3Config.publicAccessBlock = {
|
|
107
|
+
blockPublicAcls: false,
|
|
108
|
+
blockPublicPolicy: false,
|
|
109
|
+
ignorePublicAcls: false,
|
|
110
|
+
restrictPublicBuckets: false,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (lifecycleDays) {
|
|
114
|
+
s3Config.lifecycleRules = [
|
|
115
|
+
{
|
|
116
|
+
id: 'default-expiration',
|
|
117
|
+
enabled: true,
|
|
118
|
+
expiration: { days: lifecycleDays },
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
if (!config.storage.s3Buckets) {
|
|
123
|
+
config.storage.s3Buckets = [];
|
|
124
|
+
}
|
|
125
|
+
config.storage.s3Buckets.push(s3Config);
|
|
126
|
+
const features = [];
|
|
127
|
+
if (versioning)
|
|
128
|
+
features.push('버전관리');
|
|
129
|
+
if (website)
|
|
130
|
+
features.push('웹사이트');
|
|
131
|
+
if (lifecycleDays)
|
|
132
|
+
features.push(`${lifecycleDays}일 만료`);
|
|
133
|
+
message = `S3 버킷 '${name}'가 추가되었습니다.`;
|
|
134
|
+
if (features.length > 0) {
|
|
135
|
+
message += ` (${features.join(', ')})`;
|
|
136
|
+
}
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case 'ecr': {
|
|
140
|
+
const imageScanOnPush = args.imageScanOnPush !== false;
|
|
141
|
+
const imageTagMutability = args.imageTagMutability || 'MUTABLE';
|
|
142
|
+
const maxImageCount = args.maxImageCount;
|
|
143
|
+
const ecrConfig = {
|
|
144
|
+
id: `ecr-${generatedId}`,
|
|
145
|
+
name,
|
|
146
|
+
imageScanningEnabled: imageScanOnPush,
|
|
147
|
+
imageTagMutability,
|
|
148
|
+
encryptionType: 'AES256',
|
|
149
|
+
};
|
|
150
|
+
if (maxImageCount) {
|
|
151
|
+
ecrConfig.lifecyclePolicy = {
|
|
152
|
+
rules: [
|
|
153
|
+
{
|
|
154
|
+
rulePriority: 1,
|
|
155
|
+
description: 'Keep only recent images',
|
|
156
|
+
selection: {
|
|
157
|
+
tagStatus: 'any',
|
|
158
|
+
countType: 'imageCountMoreThan',
|
|
159
|
+
countNumber: maxImageCount,
|
|
160
|
+
},
|
|
161
|
+
action: { type: 'expire' },
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (!config.storage.ecrRepositories) {
|
|
167
|
+
config.storage.ecrRepositories = [];
|
|
168
|
+
}
|
|
169
|
+
config.storage.ecrRepositories.push(ecrConfig);
|
|
170
|
+
const features = [];
|
|
171
|
+
if (imageScanOnPush)
|
|
172
|
+
features.push('이미지스캔');
|
|
173
|
+
if (imageTagMutability === 'IMMUTABLE')
|
|
174
|
+
features.push('불변태그');
|
|
175
|
+
if (maxImageCount)
|
|
176
|
+
features.push(`최대 ${maxImageCount}개`);
|
|
177
|
+
message = `ECR 리포지토리 '${name}'가 추가되었습니다.`;
|
|
178
|
+
if (features.length > 0) {
|
|
179
|
+
message += ` (${features.join(', ')})`;
|
|
180
|
+
}
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
default:
|
|
184
|
+
return {
|
|
185
|
+
success: false,
|
|
186
|
+
message: `알 수 없는 리소스 유형: ${resourceType}`,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
// Save config
|
|
190
|
+
config.lastModified = new Date().toISOString();
|
|
191
|
+
fs.writeFileSync(path.join(configRoot, CONFIG_FILE), JSON.stringify(config, null, 2));
|
|
192
|
+
return {
|
|
193
|
+
success: true,
|
|
194
|
+
message,
|
|
195
|
+
data: {
|
|
196
|
+
resourceType,
|
|
197
|
+
name,
|
|
198
|
+
id: `${resourceType}-${generatedId}`,
|
|
199
|
+
},
|
|
200
|
+
nextSteps: [
|
|
201
|
+
'aws-status로 현재 설정을 확인하세요',
|
|
202
|
+
'추가 리소스를 설정하려면 aws-add-* 도구를 사용하세요',
|
|
203
|
+
'설정이 완료되면 aws-generate-all로 CDK 프로젝트를 생성하세요',
|
|
204
|
+
],
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=aws-add-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aws-add-storage.js","sourceRoot":"","sources":["../../src/tools/aws-add-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aws-analyze - Analyze existing AWS resources
|
|
3
|
+
*/
|
|
4
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { type ToolContext, type ToolResponse } from '../types.js';
|
|
6
|
+
export declare const awsAnalyzeTool: Tool;
|
|
7
|
+
export declare function handleAwsAnalyze(args: Record<string, unknown>, context: ToolContext): Promise<ToolResponse>;
|
|
8
|
+
//# sourceMappingURL=aws-analyze.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aws-analyze.d.ts","sourceRoot":"","sources":["../../src/tools/aws-analyze.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAG/D,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EAGlB,MAAM,aAAa,CAAC;AAGrB,eAAO,MAAM,cAAc,EAAE,IAoB5B,CAAC;AAEF,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,CAAC,CA+FvB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aws-analyze - Analyze existing AWS resources
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { ANALYSIS_CACHE_FILE, STATE_FILE, } from '../types.js';
|
|
7
|
+
import { AWSAnalyzer } from '../core/aws-analyzer.js';
|
|
8
|
+
export const awsAnalyzeTool = {
|
|
9
|
+
name: 'aws-analyze',
|
|
10
|
+
description: 'AWS 계정의 기존 리소스를 분석합니다. EC2, RDS, Lambda, S3, DynamoDB, ECS, EKS, ECR, VPC, API Gateway를 스캔합니다.',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
services: {
|
|
15
|
+
type: 'array',
|
|
16
|
+
items: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
enum: ['ec2', 'rds', 'lambda', 's3', 'dynamodb', 'ecs', 'eks', 'ecr', 'vpc', 'apigateway', 'all'],
|
|
19
|
+
},
|
|
20
|
+
description: '분석할 서비스 목록 (기본값: all)',
|
|
21
|
+
},
|
|
22
|
+
refresh: {
|
|
23
|
+
type: 'boolean',
|
|
24
|
+
description: '캐시를 무시하고 새로 분석 (기본값: false)',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
export async function handleAwsAnalyze(args, context) {
|
|
30
|
+
const { configRoot, config, state } = context;
|
|
31
|
+
if (!config || !state) {
|
|
32
|
+
return {
|
|
33
|
+
success: false,
|
|
34
|
+
message: 'aws-init을 먼저 실행하세요.',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const services = args.services || ['all'];
|
|
38
|
+
const refresh = args.refresh === true;
|
|
39
|
+
// Note: service filtering not yet implemented, analyzes all by default
|
|
40
|
+
const _analyzeAll = services.includes('all');
|
|
41
|
+
void _analyzeAll;
|
|
42
|
+
// Check cache
|
|
43
|
+
const cachePath = path.join(configRoot, ANALYSIS_CACHE_FILE);
|
|
44
|
+
if (!refresh && fs.existsSync(cachePath)) {
|
|
45
|
+
try {
|
|
46
|
+
const cached = JSON.parse(fs.readFileSync(cachePath, 'utf-8'));
|
|
47
|
+
const cacheAge = Date.now() - new Date(cached.analyzedAt).getTime();
|
|
48
|
+
const oneHour = 60 * 60 * 1000;
|
|
49
|
+
if (cacheAge < oneHour) {
|
|
50
|
+
return {
|
|
51
|
+
success: true,
|
|
52
|
+
message: `캐시된 분석 결과를 사용합니다 (${Math.round(cacheAge / 60000)}분 전)`,
|
|
53
|
+
data: {
|
|
54
|
+
cached: true,
|
|
55
|
+
analysis: cached,
|
|
56
|
+
summary: buildSummary(cached.resources),
|
|
57
|
+
},
|
|
58
|
+
nextSteps: [
|
|
59
|
+
'새로운 분석을 원하면 refresh: true 옵션을 사용하세요',
|
|
60
|
+
'특정 리소스를 설정에 추가하려면 aws-add-* 도구를 사용하세요',
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Cache invalid, proceed with fresh analysis
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Run analysis
|
|
70
|
+
try {
|
|
71
|
+
const analyzer = new AWSAnalyzer({
|
|
72
|
+
region: config.region,
|
|
73
|
+
profile: config.awsProfile,
|
|
74
|
+
});
|
|
75
|
+
const analysis = await analyzer.analyzeAll();
|
|
76
|
+
// Save to cache
|
|
77
|
+
fs.writeFileSync(cachePath, JSON.stringify(analysis, null, 2));
|
|
78
|
+
// Update state
|
|
79
|
+
state.analyzedAt = analysis.analyzedAt;
|
|
80
|
+
state.analysisCache = analysis;
|
|
81
|
+
state.lastModified = new Date().toISOString();
|
|
82
|
+
fs.writeFileSync(path.join(configRoot, STATE_FILE), JSON.stringify(state, null, 2));
|
|
83
|
+
const summary = buildSummary(analysis.resources);
|
|
84
|
+
return {
|
|
85
|
+
success: true,
|
|
86
|
+
message: `AWS 리소스 분석이 완료되었습니다. ${analysis.importableResources.length}개의 가져오기 가능한 리소스를 발견했습니다.`,
|
|
87
|
+
data: {
|
|
88
|
+
cached: false,
|
|
89
|
+
region: analysis.region,
|
|
90
|
+
account: analysis.account,
|
|
91
|
+
summary,
|
|
92
|
+
importableResources: analysis.importableResources.slice(0, 20), // First 20
|
|
93
|
+
totalImportable: analysis.importableResources.length,
|
|
94
|
+
},
|
|
95
|
+
nextSteps: [
|
|
96
|
+
'발견된 리소스를 CDK로 가져오려면 import 명령을 사용하세요',
|
|
97
|
+
'aws-add-* 도구로 새 리소스를 설정에 추가하세요',
|
|
98
|
+
'aws-generate-all로 CDK 프로젝트를 생성하세요',
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
104
|
+
return {
|
|
105
|
+
success: false,
|
|
106
|
+
message: `AWS 리소스 분석 실패: ${message}`,
|
|
107
|
+
nextSteps: [
|
|
108
|
+
'AWS 자격증명이 올바른지 확인하세요',
|
|
109
|
+
'필요한 IAM 권한이 있는지 확인하세요 (ec2:Describe*, rds:Describe*, lambda:List*, s3:List*, 등)',
|
|
110
|
+
],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function buildSummary(resources) {
|
|
115
|
+
const summary = {};
|
|
116
|
+
for (const [service, items] of Object.entries(resources)) {
|
|
117
|
+
if (Array.isArray(items) && items.length > 0) {
|
|
118
|
+
summary[service] = items.length;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return summary;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=aws-analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aws-analyze.js","sourceRoot":"","sources":["../../src/tools/aws-analyze.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aws-generate-all - Generate complete CDK project from configuration
|
|
3
|
+
*/
|
|
4
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { type ToolContext, type ToolResponse } from '../types.js';
|
|
6
|
+
export declare const awsGenerateAllTool: Tool;
|
|
7
|
+
export declare function handleAwsGenerateAll(args: Record<string, unknown>, context: ToolContext): Promise<ToolResponse>;
|
|
8
|
+
//# sourceMappingURL=aws-generate-all.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aws-generate-all.d.ts","sourceRoot":"","sources":["../../src/tools/aws-generate-all.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAI/D,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EASlB,MAAM,aAAa,CAAC;AAGrB,eAAO,MAAM,kBAAkB,EAAE,IAgBhC,CAAC;AAEF,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,CAAC,CA8HvB"}
|