awslabs.cfn-mcp-server 1.0.1__py3-none-any.whl → 1.0.3__py3-none-any.whl

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.
@@ -11,4 +11,4 @@
11
11
 
12
12
  """awslabs.cfn-mcp-server"""
13
13
 
14
- __version__ = '0.0.0'
14
+ __version__ = '1.0.3'
@@ -0,0 +1,200 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
4
+ # with the License. A copy of the License is located at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
9
+ # OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
10
+ # and limitations under the License.
11
+
12
+ """CloudFormation IaC Generator tool implementation."""
13
+
14
+ import os
15
+ from awslabs.cfn_mcp_server.aws_client import get_aws_client
16
+ from awslabs.cfn_mcp_server.errors import ClientError, handle_aws_api_error
17
+ from typing import Dict, List, Optional
18
+
19
+
20
+ async def create_template(
21
+ template_name: Optional[str] = None,
22
+ resources: Optional[List[Dict[str, str]]] = None,
23
+ output_format: str = 'YAML',
24
+ deletion_policy: str = 'RETAIN',
25
+ update_replace_policy: str = 'RETAIN',
26
+ template_id: Optional[str] = None,
27
+ save_to_file: Optional[str] = None,
28
+ region_name: Optional[str] = None,
29
+ ) -> Dict:
30
+ """Create a CloudFormation template from existing resources using the IaC Generator API.
31
+
32
+ This function handles three main scenarios:
33
+ 1. Starting a new template generation process
34
+ 2. Checking the status of an existing template generation process
35
+ 3. Retrieving a generated template
36
+
37
+ Args:
38
+ template_name: Name for the generated template
39
+ resources: List of resources to include in the template, each with 'ResourceType' and 'ResourceIdentifier'
40
+ output_format: Output format for the template (JSON or YAML)
41
+ deletion_policy: Default DeletionPolicy for resources in the template (RETAIN, DELETE, or SNAPSHOT)
42
+ update_replace_policy: Default UpdateReplacePolicy for resources in the template (RETAIN, DELETE, or SNAPSHOT)
43
+ template_id: ID of an existing template generation process to check status or retrieve template
44
+ save_to_file: Path to save the generated template to a file
45
+ region_name: AWS region name
46
+
47
+ Returns:
48
+ A dictionary containing information about the template generation process or the generated template
49
+ """
50
+ # Validate parameters
51
+ if not template_id and not template_name:
52
+ raise ClientError('Either template_name or template_id must be provided')
53
+
54
+ if output_format not in ['JSON', 'YAML']:
55
+ raise ClientError("output_format must be either 'JSON' or 'YAML'")
56
+
57
+ if deletion_policy not in ['RETAIN', 'DELETE', 'SNAPSHOT']:
58
+ raise ClientError("deletion_policy must be one of 'RETAIN', 'DELETE', or 'SNAPSHOT'")
59
+
60
+ if update_replace_policy not in ['RETAIN', 'DELETE', 'SNAPSHOT']:
61
+ raise ClientError("update_replace_policy must be one of 'RETAIN', 'DELETE', or 'SNAPSHOT'")
62
+
63
+ # Get CloudFormation client
64
+ cfn_client = get_aws_client('cloudformation', region_name)
65
+
66
+ # Case 1: Check status or retrieve template for an existing template generation process
67
+ if template_id:
68
+ return await _handle_existing_template(
69
+ cfn_client, template_id, save_to_file, output_format
70
+ )
71
+
72
+ # Case 2: Start a new template generation process
73
+ return await _start_template_generation(
74
+ cfn_client, template_name, resources, deletion_policy, update_replace_policy
75
+ )
76
+
77
+
78
+ async def _start_template_generation(
79
+ cfn_client,
80
+ template_name: str | None,
81
+ resources: Optional[List[Dict[str, str]]],
82
+ deletion_policy: str,
83
+ update_replace_policy: str,
84
+ ) -> Dict:
85
+ """Start a new template generation process.
86
+
87
+ Args:
88
+ cfn_client: Boto3 CloudFormation client
89
+ template_name: Name for the generated template
90
+ resources: List of resources to include in the template
91
+ output_format: Output format for the template (JSON or YAML)
92
+ deletion_policy: DeletionPolicy for resources in the template
93
+ update_replace_policy: UpdateReplacePolicy for resources in the template
94
+
95
+ Returns:
96
+ A dictionary containing information about the template generation process
97
+ """
98
+ # Prepare parameters for the API call
99
+ params = {
100
+ 'GeneratedTemplateName': template_name,
101
+ 'TemplateConfiguration': {
102
+ 'DeletionPolicy': deletion_policy,
103
+ 'UpdateReplacePolicy': update_replace_policy,
104
+ },
105
+ }
106
+
107
+ # Add resources if provided
108
+ if resources:
109
+ resource_identifiers = []
110
+ for resource in resources:
111
+ if 'ResourceType' not in resource or 'ResourceIdentifier' not in resource:
112
+ raise ClientError(
113
+ "Each resource must have 'ResourceType' and 'ResourceIdentifier'"
114
+ )
115
+ resource_identifiers.append(
116
+ {
117
+ 'ResourceType': resource['ResourceType'],
118
+ 'ResourceIdentifier': resource['ResourceIdentifier'],
119
+ }
120
+ )
121
+ params['Resources'] = resource_identifiers
122
+
123
+ # Call the API
124
+ try:
125
+ response = cfn_client.create_generated_template(**params)
126
+ return {
127
+ 'status': 'INITIATED',
128
+ 'template_id': response['GeneratedTemplateId'],
129
+ 'message': 'Template generation initiated. Use the template_id to check status.',
130
+ }
131
+ except Exception as e:
132
+ raise handle_aws_api_error(e)
133
+
134
+
135
+ async def _handle_existing_template(
136
+ cfn_client, template_id: str, save_to_file: Optional[str], output_format: str = 'YAML'
137
+ ) -> Dict:
138
+ """Handle an existing template generation process - check status or retrieve template.
139
+
140
+ Args:
141
+ cfn_client: Boto3 CloudFormation client
142
+ template_id: ID of the template generation process
143
+ save_to_file: Path to save the generated template to a file
144
+ output_format: Format of generated template. Either JSON or YAML
145
+
146
+ Returns:
147
+ A dictionary containing information about the template generation process or the generated template
148
+ """
149
+ # Check the status of the template generation process
150
+ try:
151
+ status_response = cfn_client.describe_generated_template(GeneratedTemplateName=template_id)
152
+
153
+ status = status_response['Status']
154
+
155
+ # Return status information if the template is not yet complete
156
+ if status != 'COMPLETE':
157
+ return {
158
+ 'status': status,
159
+ 'template_id': template_id,
160
+ 'message': f'Template generation {status.lower()}.',
161
+ }
162
+
163
+ # If the template is complete, retrieve it
164
+ template_response = cfn_client.get_generated_template(
165
+ GeneratedTemplateName=template_id, Format=output_format
166
+ )
167
+
168
+ template_content = template_response['TemplateBody']
169
+ resources = status_response.get('ResourceIdentifiers', [])
170
+
171
+ # Save the template to a file if requested
172
+ file_path = None
173
+ if save_to_file:
174
+ try:
175
+ # Ensure the directory exists
176
+ os.makedirs(os.path.dirname(os.path.abspath(save_to_file)), exist_ok=True)
177
+
178
+ # Write the template to the file
179
+ with open(save_to_file, 'w') as f:
180
+ f.write(template_content)
181
+ file_path = save_to_file
182
+ except Exception as e:
183
+ raise ClientError(f'Failed to save template to file: {str(e)}')
184
+
185
+ # Return the template and related information
186
+ result = {
187
+ 'status': 'COMPLETED',
188
+ 'template_id': template_id,
189
+ 'template': template_content,
190
+ 'resources': resources,
191
+ 'message': 'Template generation completed.',
192
+ }
193
+
194
+ if file_path:
195
+ result['file_path'] = file_path
196
+
197
+ return result
198
+
199
+ except Exception as e:
200
+ raise handle_aws_api_error(e)
@@ -17,6 +17,7 @@ from awslabs.cfn_mcp_server.aws_client import get_aws_client
17
17
  from awslabs.cfn_mcp_server.cloud_control_utils import progress_event, validate_patch
18
18
  from awslabs.cfn_mcp_server.context import Context
19
19
  from awslabs.cfn_mcp_server.errors import ClientError, handle_aws_api_error
20
+ from awslabs.cfn_mcp_server.iac_generator import create_template as create_template_impl
20
21
  from awslabs.cfn_mcp_server.schema_manager import schema_manager
21
22
  from mcp.server.fastmcp import FastMCP
22
23
  from pydantic import Field
@@ -169,7 +170,7 @@ async def update_resource(
169
170
  "identifier": The resource identifier
170
171
  "is_complete": Boolean indicating whether the operation is complete
171
172
  "status_message": Human-readable message describing the result
172
- "request_token": A token that allows you to track long running operations via the get_request_status tool
173
+ "request_token": A token that allows you to track long running operations via the get_resource_request_status tool
173
174
  "resource_info": Optional information about the resource properties
174
175
  }
175
176
  """
@@ -229,7 +230,7 @@ async def create_resource(
229
230
  "identifier": The resource identifier
230
231
  "is_complete": Boolean indicating whether the operation is complete
231
232
  "status_message": Human-readable message describing the result
232
- "request_token": A token that allows you to track long running operations via the get_request_status tool
233
+ "request_token": A token that allows you to track long running operations via the get_resource_request_status tool
233
234
  "resource_info": Optional information about the resource properties
234
235
  }
235
236
  """
@@ -282,7 +283,7 @@ async def delete_resource(
282
283
  "identifier": The resource identifier
283
284
  "is_complete": Boolean indicating whether the operation is complete
284
285
  "status_message": Human-readable message describing the result
285
- "request_token": A token that allows you to track long running operations via the get_request_status tool
286
+ "request_token": A token that allows you to track long running operations via the get_resource_request_status tool
286
287
  }
287
288
  """
288
289
  if not resource_type:
@@ -308,7 +309,7 @@ async def delete_resource(
308
309
 
309
310
 
310
311
  @mcp.tool()
311
- async def get_request_status(
312
+ async def get_resource_request_status(
312
313
  request_token: str = Field(
313
314
  description='The request_token returned from the long running operation'
314
315
  ),
@@ -330,7 +331,7 @@ async def get_request_status(
330
331
  "identifier": The resource identifier
331
332
  "is_complete": Boolean indicating whether the operation is complete
332
333
  "status_message": Human-readable message describing the result
333
- "request_token": A token that allows you to track long running operations via the get_request_status tool
334
+ "request_token": A token that allows you to track long running operations via the get_resource_request_status tool
334
335
  "error_code": A code associated with any errors if the request failed
335
336
  "retry_after": A duration to wait before retrying the request
336
337
  }
@@ -349,6 +350,73 @@ async def get_request_status(
349
350
  return progress_event(response['ProgressEvent'])
350
351
 
351
352
 
353
+ @mcp.tool()
354
+ async def create_template(
355
+ template_name: str | None = Field(None, description='Name for the generated template'),
356
+ resources: list | None = Field(
357
+ None,
358
+ description="List of resources to include in the template, each with 'ResourceType' and 'ResourceIdentifier'",
359
+ ),
360
+ output_format: str = Field(
361
+ 'YAML', description='Output format for the template (JSON or YAML)'
362
+ ),
363
+ deletion_policy: str = Field(
364
+ 'RETAIN',
365
+ description='Default DeletionPolicy for resources in the template (RETAIN, DELETE, or SNAPSHOT)',
366
+ ),
367
+ update_replace_policy: str = Field(
368
+ 'RETAIN',
369
+ description='Default UpdateReplacePolicy for resources in the template (RETAIN, DELETE, or SNAPSHOT)',
370
+ ),
371
+ template_id: str | None = Field(
372
+ None,
373
+ description='ID of an existing template generation process to check status or retrieve template',
374
+ ),
375
+ save_to_file: str | None = Field(
376
+ None, description='Path to save the generated template to a file'
377
+ ),
378
+ region: str | None = Field(
379
+ description='The AWS region that the operation should be performed in', default=None
380
+ ),
381
+ ) -> dict:
382
+ """Create a CloudFormation template from existing resources using the IaC Generator API.
383
+
384
+ This tool allows you to generate CloudFormation templates from existing AWS resources
385
+ that are not already managed by CloudFormation. The template generation process is
386
+ asynchronous, so you can check the status of the process and retrieve the template
387
+ once it's complete. You can pass up to 500 resources at a time.
388
+
389
+ Examples:
390
+ 1. Start template generation for an S3 bucket:
391
+ create_template(
392
+ template_name="my-template",
393
+ resources=[{"ResourceType": "AWS::S3::Bucket", "ResourceIdentifier": {"BucketName": "my-bucket"}}],
394
+ deletion_policy="RETAIN",
395
+ update_replace_policy="RETAIN"
396
+ )
397
+
398
+ 2. Check status of template generation:
399
+ create_template(template_id="arn:aws:cloudformation:us-east-1:123456789012:generatedtemplate/abcdef12-3456-7890-abcd-ef1234567890")
400
+
401
+ 3. Retrieve and save generated template:
402
+ create_template(
403
+ template_id="arn:aws:cloudformation:us-east-1:123456789012:generatedtemplate/abcdef12-3456-7890-abcd-ef1234567890",
404
+ save_to_file="/path/to/template.yaml",
405
+ output_format="YAML"
406
+ )
407
+ """
408
+ return await create_template_impl(
409
+ template_name=template_name,
410
+ resources=resources,
411
+ output_format=output_format,
412
+ deletion_policy=deletion_policy,
413
+ update_replace_policy=update_replace_policy,
414
+ template_id=template_id,
415
+ save_to_file=save_to_file,
416
+ region_name=region,
417
+ )
418
+
419
+
352
420
  def main():
353
421
  """Run the MCP server with CLI argument support."""
354
422
  parser = argparse.ArgumentParser(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: awslabs.cfn-mcp-server
3
- Version: 1.0.1
3
+ Version: 1.0.3
4
4
  Summary: An AWS Labs Model Context Protocol (MCP) server for doing common cloudformation tasks and for managing your resources in your AWS account
5
5
  Project-URL: homepage, https://awslabs.github.io/mcp/
6
6
  Project-URL: docs, https://awslabs.github.io/mcp/servers/cfn-mcp-server/
@@ -30,7 +30,7 @@ Description-Content-Type: text/markdown
30
30
 
31
31
  # CloudFormation MCP Server
32
32
 
33
- Model Context Protocol (MCP) server that enables LLMs to directly create and manage over 1,100 AWS resources through natural language using AWS Cloud Control API with Infrastructure as Code best practices.
33
+ Model Context Protocol (MCP) server that enables LLMs to directly create and manage over 1,100 AWS resources through natural language using AWS Cloud Control API and Iac Generator with Infrastructure as Code best practices.
34
34
 
35
35
  ## Features
36
36
 
@@ -42,6 +42,7 @@ Model Context Protocol (MCP) server that enables LLMs to directly create and man
42
42
  - **Schema Information**: Returns detailed CloudFormation schema for any resource to enable more effective operations
43
43
  - **Natural Language Interface**: Transform infrastructure-as-code from static authoring to dynamic conversations
44
44
  - **Partner Resource Support**: Works with both AWS-native and partner-defined resources
45
+ - **Template Generation**: Generates a template on created/existing resources for a [subset of resource types](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resource-import-supported-resources.html)
45
46
 
46
47
  ## Prerequisites
47
48
 
@@ -153,8 +154,12 @@ Get schema information for an AWS CloudFormation resource.
153
154
  **Example**: Get the schema for AWS::S3::Bucket to understand all available properties.
154
155
 
155
156
  ### get_request_status
156
- Get the status of a mutation that was initiated by create/update/delete resource
157
- **Example**: Give me the status of the last request I made
157
+ Get the status of a mutation that was initiated by create/update/delete resource.
158
+ **Example**: Give me the status of the last request I made.
159
+
160
+ ### create_tempalte
161
+ Create a Cloudformation template from created or listed resources.
162
+ **Example**: Create a YAML template for those resources.
158
163
 
159
164
  ## Basic Usage
160
165
 
@@ -169,6 +174,7 @@ Examples of how to use the AWS Infrastructure as Code MCP Server:
169
174
  - "Configure CloudWatch alarms for all production resources"
170
175
  - "Implement cross-region replication for critical S3 buckets"
171
176
  - "Show me the schema for AWS::Lambda::Function"
177
+ - "Create a template for all the resources we created and modified"
172
178
 
173
179
  ## Resource Type support
174
180
  Resources which are supported by this MCP and the supported operations can be found here: https://docs.aws.amazon.com/cloudcontrolapi/latest/userguide/supported-resources.html
@@ -199,7 +205,10 @@ Ensure your AWS credentials have the following minimum permissions:
199
205
  "cloudcontrol:GetResource",
200
206
  "cloudcontrol:CreateResource",
201
207
  "cloudcontrol:DeleteResource",
202
- "cloudcontrol:UpdateResource"
208
+ "cloudcontrol:UpdateResource",
209
+ "cloudformation:CreateGeneratedTemplate",
210
+ "cloudformation:DescribeGeneratedTemplate",
211
+ "cloudformation:GetGeneratedTemplate"
203
212
  ],
204
213
  "Resource": "*"
205
214
  }
@@ -209,10 +218,11 @@ Ensure your AWS credentials have the following minimum permissions:
209
218
 
210
219
  ## Limitations
211
220
 
212
- - Operations are limited to resources supported by AWS Cloud Control API
221
+ - Operations are limited to resources supported by AWS Cloud Control API and Iac Generator
213
222
  - Performance depends on the underlying AWS services' response times
214
223
  - Some complex resource relationships may require multiple operations
215
- - This MCP server can only manage resources in the AWS regions where Cloud Control API is available
224
+ - This MCP server can only manage resources in the AWS regions where Cloud Control API and/or Iac Generator is available
216
225
  - Resource modification operations may be limited by service-specific constraints
217
226
  - Rate limiting may affect operations when managing many resources simultaneously
218
227
  - Some resource types might not support all operations (create, read, update, delete)
228
+ - Generated templates are primarily intended for importing existing resources into a CloudFormation stack and may not always work for creating new resources (in another account or region)
@@ -1,14 +1,15 @@
1
1
  awslabs/__init__.py,sha256=47wJeKcStxEJwX7SVVV2pnAWYR8FxcaYoT3YTmZ5Plg,674
2
- awslabs/cfn_mcp_server/__init__.py,sha256=0iDzkNDzH_VHat2joZdYA_i2NeOiAWYlorKpKaW1vpE,611
2
+ awslabs/cfn_mcp_server/__init__.py,sha256=83bE3XbvOF6sigHPxEk0J9k7lNU9bzTwoCLde-IKQNA,611
3
3
  awslabs/cfn_mcp_server/aws_client.py,sha256=w0cwuQq7b34IUaABEwZYpEols1QoMjO2gd3T98K5FcE,2783
4
4
  awslabs/cfn_mcp_server/cloud_control_utils.py,sha256=wUDT-J9iEAOYnqZAG2vDtBsXUp0EUZ__jQzJ4RJ6AvM,2973
5
5
  awslabs/cfn_mcp_server/context.py,sha256=YpJZPjyzHW7df9O-lyj2j8yuenZI-yPxLuVuyvmnAnE,777
6
6
  awslabs/cfn_mcp_server/errors.py,sha256=0ADg9EesPyvjNZD-J89QLQ5OFcD6aSKDaMfW_4RQjfo,4481
7
+ awslabs/cfn_mcp_server/iac_generator.py,sha256=iTZ6tM92m430GHM60lH1qR5nlRdhSbx2m0_WTbkU1f8,7881
7
8
  awslabs/cfn_mcp_server/schema_manager.py,sha256=7dw2W2hgdn1ODRU5PrUmOG9_rvnKUhGD51q8Wz4Ksks,6775
8
- awslabs/cfn_mcp_server/server.py,sha256=A_t60rwFRDJ8KopbS_zo5aYr7aqh6KiE5IWyZrLrh1U,13839
9
- awslabs_cfn_mcp_server-1.0.1.dist-info/METADATA,sha256=umJjb2U5Yx0-oyjbCpu815RMJrNIlT6ednWO-EGZ61c,8272
10
- awslabs_cfn_mcp_server-1.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
- awslabs_cfn_mcp_server-1.0.1.dist-info/entry_points.txt,sha256=Hartc24s_fYgi3o2m2tBHahod0pqXYwpebQy2_tXL7s,78
12
- awslabs_cfn_mcp_server-1.0.1.dist-info/licenses/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
13
- awslabs_cfn_mcp_server-1.0.1.dist-info/licenses/NOTICE,sha256=bcw4NZAgn5eQZzrtuDiwOe23BRSm_JiRzn0gxBLDzlg,90
14
- awslabs_cfn_mcp_server-1.0.1.dist-info/RECORD,,
9
+ awslabs/cfn_mcp_server/server.py,sha256=Fw7vMYfzxGCTaJD_MHj1EmGVlTO_CmtOKjzicGj8uYw,16737
10
+ awslabs_cfn_mcp_server-1.0.3.dist-info/METADATA,sha256=rnKRPLiaG5-n1zVWpwJ5WtbUL_41ChoqlCqsdjjnd64,9121
11
+ awslabs_cfn_mcp_server-1.0.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
12
+ awslabs_cfn_mcp_server-1.0.3.dist-info/entry_points.txt,sha256=Hartc24s_fYgi3o2m2tBHahod0pqXYwpebQy2_tXL7s,78
13
+ awslabs_cfn_mcp_server-1.0.3.dist-info/licenses/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
14
+ awslabs_cfn_mcp_server-1.0.3.dist-info/licenses/NOTICE,sha256=bcw4NZAgn5eQZzrtuDiwOe23BRSm_JiRzn0gxBLDzlg,90
15
+ awslabs_cfn_mcp_server-1.0.3.dist-info/RECORD,,