awslabs.terraform-mcp-server 0.0.11__py3-none-any.whl → 0.0.12__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.

Potentially problematic release.


This version of awslabs.terraform-mcp-server might be problematic. Click here for more details.

@@ -2,6 +2,7 @@
2
2
 
3
3
  from .search_user_provided_module import search_user_provided_module_impl
4
4
  from .execute_terraform_command import execute_terraform_command_impl
5
+ from .execute_terragrunt_command import execute_terragrunt_command_impl
5
6
  from .search_aws_provider_docs import search_aws_provider_docs_impl
6
7
  from .search_awscc_provider_docs import search_awscc_provider_docs_impl
7
8
  from .search_specific_aws_ia_modules import search_specific_aws_ia_modules_impl
@@ -10,6 +11,7 @@ from .run_checkov_scan import run_checkov_scan_impl
10
11
  __all__ = [
11
12
  'search_user_provided_module_impl',
12
13
  'execute_terraform_command_impl',
14
+ 'execute_terragrunt_command_impl',
13
15
  'search_aws_provider_docs_impl',
14
16
  'search_awscc_provider_docs_impl',
15
17
  'search_specific_aws_ia_modules_impl',
@@ -0,0 +1,303 @@
1
+ """Implementation of Terragrunt command execution tool."""
2
+
3
+ import json
4
+ import os
5
+ import re
6
+ import subprocess
7
+ from awslabs.terraform_mcp_server.impl.tools.utils import get_dangerous_patterns
8
+ from awslabs.terraform_mcp_server.models import (
9
+ TerragruntExecutionRequest,
10
+ TerragruntExecutionResult,
11
+ )
12
+ from loguru import logger
13
+
14
+
15
+ async def execute_terragrunt_command_impl(
16
+ request: TerragruntExecutionRequest,
17
+ ) -> TerragruntExecutionResult:
18
+ """Execute Terragrunt workflow commands against an AWS account.
19
+
20
+ This tool runs Terragrunt commands (init, plan, validate, apply, destroy, run-all) in the
21
+ specified working directory, with optional variables and region settings.
22
+
23
+ Parameters:
24
+ request: Details about the Terragrunt command to execute
25
+
26
+ Returns:
27
+ A TerragruntExecutionResult object containing command output and status
28
+ """
29
+ logger.info(f"Executing 'terragrunt {request.command}' in {request.working_directory}")
30
+
31
+ # Helper function to clean output text
32
+ def clean_output_text(text: str) -> str:
33
+ """Clean output text by removing or replacing problematic Unicode characters.
34
+
35
+ Args:
36
+ text: The text to clean
37
+
38
+ Returns:
39
+ Cleaned text with ASCII-friendly replacements
40
+ """
41
+ if not text:
42
+ return text
43
+
44
+ # First remove ANSI escape sequences (color codes, cursor movement)
45
+ ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
46
+ text = ansi_escape.sub('', text)
47
+
48
+ # Remove C0 and C1 control characters (except common whitespace)
49
+ control_chars = re.compile(r'[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F]')
50
+ text = control_chars.sub('', text)
51
+
52
+ # Replace HTML entities
53
+ html_entities = {
54
+ '->': '->', # Replace HTML arrow
55
+ '&lt;': '<', # Less than
56
+ '&gt;': '>', # Greater than
57
+ '&amp;': '&', # Ampersand
58
+ }
59
+ for entity, replacement in html_entities.items():
60
+ text = text.replace(entity, replacement)
61
+
62
+ # Replace box-drawing and other special Unicode characters with ASCII equivalents
63
+ unicode_chars = {
64
+ '\u2500': '-', # Horizontal line
65
+ '\u2502': '|', # Vertical line
66
+ '\u2514': '+', # Up and right
67
+ '\u2518': '+', # Up and left
68
+ '\u2551': '|', # Double vertical
69
+ '\u2550': '-', # Double horizontal
70
+ '\u2554': '+', # Double down and right
71
+ '\u2557': '+', # Double down and left
72
+ '\u255a': '+', # Double up and right
73
+ '\u255d': '+', # Double up and left
74
+ '\u256c': '+', # Double cross
75
+ '\u2588': '#', # Full block
76
+ '\u25cf': '*', # Black circle
77
+ '\u2574': '-', # Left box drawing
78
+ '\u2576': '-', # Right box drawing
79
+ '\u2577': '|', # Down box drawing
80
+ '\u2575': '|', # Up box drawing
81
+ }
82
+ for char, replacement in unicode_chars.items():
83
+ text = text.replace(char, replacement)
84
+
85
+ return text
86
+
87
+ # Set environment variables for AWS region if provided
88
+ env = os.environ.copy()
89
+ if request.aws_region:
90
+ env['AWS_REGION'] = request.aws_region
91
+
92
+ # Security check for command injection
93
+ allowed_commands = ['init', 'plan', 'validate', 'apply', 'destroy', 'output', 'run-all']
94
+ if request.command not in allowed_commands:
95
+ logger.error(f'Invalid Terragrunt command: {request.command}')
96
+ return TerragruntExecutionResult(
97
+ command=f'terragrunt {request.command}',
98
+ status='error',
99
+ error_message=f'Invalid Terragrunt command: {request.command}. Allowed commands are: {", ".join(allowed_commands)}',
100
+ working_directory=request.working_directory,
101
+ outputs=None,
102
+ affected_dirs=None,
103
+ )
104
+
105
+ # Validate that terragrunt_config is not used with run-all
106
+ if request.terragrunt_config and request.command == 'run-all':
107
+ logger.error('terragrunt_config cannot be used with run-all command')
108
+ return TerragruntExecutionResult(
109
+ command=f'terragrunt {request.command}',
110
+ status='error',
111
+ error_message='Invalid configuration: --terragrunt-config cannot be used with run-all command',
112
+ working_directory=request.working_directory,
113
+ outputs=None,
114
+ affected_dirs=None,
115
+ )
116
+
117
+ # Check for potentially dangerous characters or command injection attempts
118
+ dangerous_patterns = get_dangerous_patterns()
119
+ logger.debug(f'Checking for {len(dangerous_patterns)} dangerous patterns')
120
+
121
+ for pattern in dangerous_patterns:
122
+ if request.variables:
123
+ # Check if the pattern is in any of the variable values
124
+ for var_name, var_value in request.variables.items():
125
+ if pattern in str(var_value) or pattern in str(var_name):
126
+ logger.error(
127
+ f'Potentially dangerous pattern detected in variable {var_name}: {pattern}'
128
+ )
129
+ return TerragruntExecutionResult(
130
+ command=f'terragrunt {request.command}',
131
+ status='error',
132
+ error_message=f"Security violation: Potentially dangerous pattern '{pattern}' detected in variable '{var_name}'",
133
+ working_directory=request.working_directory,
134
+ outputs=None,
135
+ affected_dirs=None,
136
+ )
137
+
138
+ # Check terragrunt_config for dangerous patterns
139
+ if request.terragrunt_config and pattern in str(request.terragrunt_config):
140
+ logger.error(f'Potentially dangerous pattern detected in terragrunt_config: {pattern}')
141
+ return TerragruntExecutionResult(
142
+ command=f'terragrunt {request.command}',
143
+ status='error',
144
+ error_message=f"Security violation: Potentially dangerous pattern '{pattern}' detected in terragrunt_config",
145
+ working_directory=request.working_directory,
146
+ outputs=None,
147
+ affected_dirs=None,
148
+ )
149
+
150
+ # Also check include_dirs and exclude_dirs for dangerous patterns
151
+ if request.include_dirs:
152
+ for dir_path in request.include_dirs:
153
+ if pattern in str(dir_path):
154
+ logger.error(
155
+ f'Potentially dangerous pattern detected in include_dirs: {pattern}'
156
+ )
157
+ return TerragruntExecutionResult(
158
+ command=f'terragrunt {request.command}',
159
+ status='error',
160
+ error_message=f"Security violation: Potentially dangerous pattern '{pattern}' detected in include_dirs",
161
+ working_directory=request.working_directory,
162
+ outputs=None,
163
+ affected_dirs=None,
164
+ )
165
+
166
+ if request.exclude_dirs:
167
+ for dir_path in request.exclude_dirs:
168
+ if pattern in str(dir_path):
169
+ logger.error(
170
+ f'Potentially dangerous pattern detected in exclude_dirs: {pattern}'
171
+ )
172
+ return TerragruntExecutionResult(
173
+ command=f'terragrunt {request.command}',
174
+ status='error',
175
+ error_message=f"Security violation: Potentially dangerous pattern '{pattern}' detected in exclude_dirs",
176
+ working_directory=request.working_directory,
177
+ outputs=None,
178
+ affected_dirs=None,
179
+ )
180
+
181
+ # Build the command
182
+ base_cmd = ['terragrunt']
183
+
184
+ # Handle run-all command differently
185
+ if request.command == 'run-all':
186
+ base_cmd.append('run-all')
187
+ # The actual terraform command becomes the first argument
188
+ # Default to 'apply' if not specified in the command
189
+ base_cmd.append('apply')
190
+ else:
191
+ base_cmd.append(request.command)
192
+
193
+ # Add auto-approve flag for apply and destroy commands to make them non-interactive
194
+ if request.command in ['apply', 'destroy'] or (request.command == 'run-all'):
195
+ logger.info(f'Adding -auto-approve flag to {request.command} command')
196
+ base_cmd.append('-auto-approve')
197
+
198
+ # Add terragrunt_config if specified and not using run-all
199
+ if request.terragrunt_config:
200
+ logger.info(f'Using custom terragrunt config file: {request.terragrunt_config}')
201
+ base_cmd.append(f'--terragrunt-config={request.terragrunt_config}')
202
+
203
+ # Add variables only for commands that accept them (plan, apply, destroy, output)
204
+ if request.command in ['plan', 'apply', 'destroy', 'output', 'run-all'] and request.variables:
205
+ logger.info(f'Adding {len(request.variables)} variables to {request.command} command')
206
+ for key, value in request.variables.items():
207
+ base_cmd.append(f'-var={key}={value}')
208
+
209
+ # Add include-dirs if specified
210
+ if request.include_dirs and request.command == 'run-all':
211
+ for dir_path in request.include_dirs:
212
+ base_cmd.append(f'--queue-include-dir={dir_path}')
213
+
214
+ # Add exclude-dirs if specified
215
+ if request.exclude_dirs and request.command == 'run-all':
216
+ for dir_path in request.exclude_dirs:
217
+ base_cmd.append(f'--queue-exclude-dir={dir_path}')
218
+
219
+ # Execute command
220
+ try:
221
+ process = subprocess.run(
222
+ base_cmd, cwd=request.working_directory, capture_output=True, text=True, env=env
223
+ )
224
+
225
+ # Prepare the result
226
+ stdout = process.stdout
227
+ stderr = process.stderr if process.stderr else ''
228
+
229
+ # Clean output text if requested
230
+ if request.strip_ansi:
231
+ logger.debug('Cleaning command output text (ANSI codes and control characters)')
232
+ stdout = clean_output_text(stdout)
233
+ stderr = clean_output_text(stderr)
234
+
235
+ # Extract affected directories for run-all command
236
+ affected_dirs = None
237
+ if request.command == 'run-all':
238
+ affected_dirs = []
239
+ # Look for directory paths in the output
240
+ dir_pattern = re.compile(r'Module at\s+"([^"]+)"')
241
+ for match in dir_pattern.finditer(stdout):
242
+ affected_dirs.append(match.group(1))
243
+
244
+ result = {
245
+ 'command': f'terragrunt {request.command}',
246
+ 'status': 'success' if process.returncode == 0 else 'error',
247
+ 'return_code': process.returncode,
248
+ 'stdout': stdout,
249
+ 'stderr': stderr,
250
+ 'working_directory': request.working_directory,
251
+ 'outputs': None,
252
+ 'affected_dirs': affected_dirs,
253
+ }
254
+
255
+ # Get outputs if this was a successful apply or output command
256
+ if (
257
+ request.command in ['apply', 'output'] or (request.command == 'run-all')
258
+ ) and process.returncode == 0:
259
+ try:
260
+ logger.info('Getting Terragrunt outputs')
261
+ output_process = subprocess.run(
262
+ ['terragrunt', 'output', '-json'],
263
+ cwd=request.working_directory,
264
+ capture_output=True,
265
+ text=True,
266
+ env=env,
267
+ )
268
+
269
+ if output_process.returncode == 0 and output_process.stdout:
270
+ # Get output and clean it if needed
271
+ output_stdout = output_process.stdout
272
+ if request.strip_ansi:
273
+ output_stdout = clean_output_text(output_stdout)
274
+
275
+ # Parse the JSON output
276
+ raw_outputs = json.loads(output_stdout)
277
+
278
+ # Process outputs to extract values from complex structure
279
+ processed_outputs = {}
280
+ for key, value in raw_outputs.items():
281
+ # Terraform outputs in JSON format have a nested structure
282
+ # with 'value', 'type', and sometimes 'sensitive'
283
+ if isinstance(value, dict) and 'value' in value:
284
+ processed_outputs[key] = value['value']
285
+ else:
286
+ processed_outputs[key] = value
287
+
288
+ result['outputs'] = processed_outputs
289
+ logger.info(f'Extracted {len(processed_outputs)} Terragrunt outputs')
290
+ except Exception as e:
291
+ logger.warning(f'Failed to get Terragrunt outputs: {e}')
292
+
293
+ # Return the output
294
+ return TerragruntExecutionResult(**result)
295
+ except Exception as e:
296
+ return TerragruntExecutionResult(
297
+ command=f'terragrunt {request.command}',
298
+ status='error',
299
+ error_message=str(e),
300
+ working_directory=request.working_directory,
301
+ outputs=None,
302
+ affected_dirs=None,
303
+ )
@@ -5,6 +5,8 @@ from .models import (
5
5
  SubmoduleInfo,
6
6
  TerraformExecutionRequest,
7
7
  TerraformExecutionResult,
8
+ TerragruntExecutionRequest,
9
+ TerragruntExecutionResult,
8
10
  CheckovVulnerability,
9
11
  CheckovScanRequest,
10
12
  CheckovScanResult,
@@ -21,6 +23,8 @@ __all__ = [
21
23
  'SubmoduleInfo',
22
24
  'TerraformExecutionRequest',
23
25
  'TerraformExecutionResult',
26
+ 'TerragruntExecutionRequest',
27
+ 'TerragruntExecutionResult',
24
28
  'CheckovVulnerability',
25
29
  'CheckovScanRequest',
26
30
  'CheckovScanResult',
@@ -302,3 +302,66 @@ class SearchUserProvidedModuleResult(BaseModel):
302
302
  outputs: List[TerraformOutput] = Field([], description='Outputs provided by the module')
303
303
  readme_content: Optional[str] = Field(None, description='README content of the module')
304
304
  error_message: Optional[str] = Field(None, description='Error message if execution failed')
305
+
306
+
307
+ class TerragruntExecutionRequest(BaseModel):
308
+ """Request model for Terragrunt command execution with parameters.
309
+
310
+ Attributes:
311
+ command: The Terragrunt command to execute (init, plan, validate, apply, destroy, etc.).
312
+ working_directory: Directory containing Terragrunt configuration files.
313
+ variables: Optional dictionary of Terraform variables to pass.
314
+ aws_region: Optional AWS region to use.
315
+ strip_ansi: Whether to strip ANSI color codes from command output.
316
+ include_dirs: Optional list of directories to include in a multi-module run.
317
+ exclude_dirs: Optional list of directories to exclude from a multi-module run.
318
+ run_all: Whether to run the command in all subdirectories with terragrunt.hcl files.
319
+ """
320
+
321
+ command: Literal['init', 'plan', 'validate', 'apply', 'destroy', 'output', 'run-all'] = Field(
322
+ ..., description='Terragrunt command to execute'
323
+ )
324
+ working_directory: str = Field(..., description='Directory containing Terragrunt files')
325
+ variables: Optional[Dict[str, str]] = Field(None, description='Terraform variables to pass')
326
+ aws_region: Optional[str] = Field(None, description='AWS region to use')
327
+ strip_ansi: bool = Field(True, description='Whether to strip ANSI color codes from output')
328
+ include_dirs: Optional[List[str]] = Field(
329
+ None, description='Directories to include in a multi-module run'
330
+ )
331
+ exclude_dirs: Optional[List[str]] = Field(
332
+ None, description='Directories to exclude from a multi-module run'
333
+ )
334
+ run_all: bool = Field(False, description='Run command on all modules in subdirectories')
335
+ terragrunt_config: Optional[str] = Field(
336
+ None, description='Path to a custom terragrunt config file (not valid with run-all)'
337
+ )
338
+
339
+
340
+ class TerragruntExecutionResult(BaseModel):
341
+ """Result model for Terragrunt command execution.
342
+
343
+ Attributes:
344
+ command: The Terragrunt command that was executed.
345
+ status: Execution status (success/error).
346
+ return_code: The command's return code (0 for success).
347
+ stdout: Standard output from the Terragrunt command.
348
+ stderr: Standard error output from the Terragrunt command.
349
+ working_directory: Directory where the command was executed.
350
+ error_message: Optional error message if execution failed.
351
+ outputs: Dictionary of output values from Terragrunt (for apply command).
352
+ affected_dirs: List of directories affected by a run-all command.
353
+ """
354
+
355
+ command: str
356
+ status: Literal['success', 'error']
357
+ return_code: Optional[int] = None
358
+ stdout: Optional[str] = None
359
+ stderr: str = ''
360
+ working_directory: str
361
+ error_message: Optional[str] = None
362
+ outputs: Optional[Dict[str, Any]] = Field(
363
+ None, description='Terragrunt outputs (for apply or output command)'
364
+ )
365
+ affected_dirs: Optional[List[str]] = Field(
366
+ None, description='Directories affected by a run-all command'
367
+ )
@@ -8,6 +8,7 @@ from awslabs.terraform_mcp_server.impl.resources import (
8
8
  )
9
9
  from awslabs.terraform_mcp_server.impl.tools import (
10
10
  execute_terraform_command_impl,
11
+ execute_terragrunt_command_impl,
11
12
  run_checkov_scan_impl,
12
13
  search_aws_provider_docs_impl,
13
14
  search_awscc_provider_docs_impl,
@@ -24,6 +25,8 @@ from awslabs.terraform_mcp_server.models import (
24
25
  TerraformAWSProviderDocsResult,
25
26
  TerraformExecutionRequest,
26
27
  TerraformExecutionResult,
28
+ TerragruntExecutionRequest,
29
+ TerragruntExecutionResult,
27
30
  )
28
31
  from awslabs.terraform_mcp_server.static import (
29
32
  AWS_TERRAFORM_BEST_PRACTICES,
@@ -84,6 +87,61 @@ async def execute_terraform_command(
84
87
  return await execute_terraform_command_impl(request)
85
88
 
86
89
 
90
+ @mcp.tool(name='ExecuteTerragruntCommand')
91
+ async def execute_terragrunt_command(
92
+ command: Literal['init', 'plan', 'validate', 'apply', 'destroy', 'output', 'run-all'] = Field(
93
+ ..., description='Terragrunt command to execute'
94
+ ),
95
+ working_directory: str = Field(..., description='Directory containing Terragrunt files'),
96
+ variables: Optional[Dict[str, str]] = Field(None, description='Terraform variables to pass'),
97
+ aws_region: Optional[str] = Field(None, description='AWS region to use'),
98
+ strip_ansi: bool = Field(True, description='Whether to strip ANSI color codes from output'),
99
+ include_dirs: Optional[List[str]] = Field(
100
+ None, description='Directories to include in a multi-module run'
101
+ ),
102
+ exclude_dirs: Optional[List[str]] = Field(
103
+ None, description='Directories to exclude from a multi-module run'
104
+ ),
105
+ run_all: bool = Field(False, description='Run command on all modules in subdirectories'),
106
+ terragrunt_config: Optional[str] = Field(
107
+ None, description='Path to a custom terragrunt config file (not valid with run-all)'
108
+ ),
109
+ ) -> TerragruntExecutionResult:
110
+ """Execute Terragrunt workflow commands against an AWS account.
111
+
112
+ This tool runs Terragrunt commands (init, plan, validate, apply, destroy, run-all) in the
113
+ specified working directory, with optional variables and region settings. Terragrunt extends
114
+ Terraform's functionality by providing features like remote state management, dependencies
115
+ between modules, and the ability to execute Terraform commands on multiple modules at once.
116
+
117
+ Parameters:
118
+ command: Terragrunt command to execute
119
+ working_directory: Directory containing Terragrunt files
120
+ variables: Terraform variables to pass
121
+ aws_region: AWS region to use
122
+ strip_ansi: Whether to strip ANSI color codes from output
123
+ include_dirs: Directories to include in a multi-module run
124
+ exclude_dirs: Directories to exclude from a multi-module run
125
+ run_all: Run command on all modules in subdirectories
126
+ terragrunt_config: Path to a custom terragrunt config file (not valid with run-all)
127
+
128
+ Returns:
129
+ A TerragruntExecutionResult object containing command output and status
130
+ """
131
+ request = TerragruntExecutionRequest(
132
+ command=command,
133
+ working_directory=working_directory,
134
+ variables=variables,
135
+ aws_region=aws_region,
136
+ strip_ansi=strip_ansi,
137
+ include_dirs=include_dirs,
138
+ exclude_dirs=exclude_dirs,
139
+ run_all=run_all,
140
+ terragrunt_config=terragrunt_config,
141
+ )
142
+ return await execute_terragrunt_command_impl(request)
143
+
144
+
87
145
  @mcp.tool(name='SearchAwsProviderDocs')
88
146
  async def search_aws_provider_docs(
89
147
  asset_name: str = Field(
@@ -1,8 +1,6 @@
1
1
  # Terraform MCP Server Instructions
2
2
 
3
- ## Overview
4
-
5
- MCP server specialized in AWS cloud infrastructure provided through Terraform. I help you create, understand, optimize, and execute Terraform configurations for AWS using security-focused development practices.
3
+ MCP server specialized in AWS cloud infrastructure provided through Terraform. I help you create, understand, optimize, and execute Terraform Or Terragrunt configurations for AWS using security-focused development practices.
6
4
 
7
5
  ## How to Use This Server (Required Workflow)
8
6
 
@@ -80,7 +78,10 @@ When implementing specific AWS resources (only after confirming no suitable AWS-
80
78
  1. `ExecuteTerraformCommand`
81
79
  * Execute Terraform commands in the sequence specified by the workflow
82
80
  * Supports: validate, init, plan, apply, destroy
83
- 2. `RunCheckovScan`
81
+ 2. `ExecuteTerragruntCommand`
82
+ * Execute Terragrunt commands in the sequence specified by the workflow
83
+ * Supports: validate, init, plan, apply, destroy, output, run-all
84
+ 3. `RunCheckovScan`
84
85
  * Run after validation passes, before initialization
85
86
  * Identifies security and compliance issues
86
87
 
@@ -103,6 +104,8 @@ The AWSCC provider (Cloud Control API-based) offers:
103
104
  - "Find documentation for awscc_lambda_function resource" (specifically AWSCC)
104
105
  - "Find documentation for aws_lambda_function resource" (specifically AWS)
105
106
  - "Execute terraform plan in my ./infrastructure directory"
107
+ - "Execute terragrunt plan in my ./infrastructure directory"
108
+ - "Execute terragrunt run-all plan in my ./infrastructure directory"
106
109
  - "How can I use the AWS Bedrock module to create a RAG application?"
107
110
  - "Show me details about the AWS-IA Bedrock Terraform module"
108
111
  - "Compare the four specific AWS-IA modules for generative AI applications"
@@ -115,6 +118,10 @@ The AWSCC provider (Cloud Control API-based) offers:
115
118
  - "Use the terraform-aws-modules/vpc/aws module to implement a VPC"
116
119
  - "Search for the hashicorp/consul/aws module and explain how to use it"
117
120
  - "What variables are required for the terraform-aws-modules/eks/aws module?"
121
+ - "I have a multi-environment Terragrunt project. How can I run apply on all modules at once?"
122
+ - "Execute terragrunt run-all apply in my ./infrastructure directory"
123
+ - "How to construct a well-formed terragrunt hierarchy folder structure"
124
+ - "Generate common inputs for all environments using generate in Terragrunt"
118
125
 
119
126
  ## Best Practices
120
127
 
@@ -129,5 +136,7 @@ When interacting with this server:
129
136
  7. **Be specific** about your requirements and constraints
130
137
  8. **Specify AWS region** when relevant to your infrastructure needs
131
138
  9. **Provide context** about your architecture and use case
132
- 10. **For Terraform execution**, ensure the working directory exists and contains valid Terraform files
139
+ 10. **For Terraform/Terragrunt execution**, ensure the working directory exists and contains valid Terraform/Terragrunt files
133
140
  11. **Review generated code** carefully before applying changes to your infrastructure
141
+ 12. When using **Terragrunt**, leverage DRY features—locals, dependencies, and generate blocks—to compose multi-env stacks.
142
+ 13. **Organize repos with clear folder hierarchies** (e.g. live/, modules/) and consistent naming so both Terraform and Terragrunt code is discoverable.
@@ -10,6 +10,7 @@ You have access to specialized tools and resources through this MCP server that
10
10
  1. Reference this workflow consistently throughout your interactions
11
11
  2. Leverage this MCP server's capabilities rather than relying solely on your general knowledge
12
12
  3. Explain the workflow steps to users as you assist them
13
+ 4. Choose the appropriate path—Terraform or Terragrunt—based on the user's project structure and tooling preferences
13
14
 
14
15
  ## Benefits to Emphasize
15
16
  When following this workflow and using these tools, you provide several advantages to users:
@@ -18,6 +19,7 @@ When following this workflow and using these tools, you provide several advantag
18
19
  - Identification of security vulnerabilities before deployment
19
20
  - Adherence to AWS best practices
20
21
  - Validation that code will work correctly when deployed
22
+ - Support for layered, DRY configurations through Terragrunt when modularization and environment inheritance are needed
21
23
 
22
24
  By following this workflow guide and leveraging the provided tools and resources, you'll deliver consistent, high-quality assistance for Terraform development on AWS, helping users create infrastructure code that is syntactically valid, secure, and ready for review before deployment.
23
25
 
@@ -25,32 +27,33 @@ By following this workflow guide and leveraging the provided tools and resources
25
27
 
26
28
  ``` mermaid
27
29
  flowchart TD
28
- start([Start Development]) --> edit[Edit Terraform Code]
30
+ start([Start Development]) --> detectConfig[Identify Project Type:\nTerraform or Terragrunt]
31
+
32
+ detectConfig --> edit[Edit Code]
29
33
 
30
34
  %% Initial Code Validation
31
- edit --> tfValidate[Run terraform validate\nvia ExecuteTerraformCommand]
35
+ edit --> validate[Run Validation:\nterraform validate or terragrunt validate\nvia ExecuteTerraformCommand]
32
36
 
33
37
  %% Validation Flow
34
- tfValidate -->|Passes| checkovScan[Run Security Scan\nvia RunCheckovScan]
35
- tfValidate -->|Fails| fixValidation[Fix Configuration\nIssues]
38
+ validate -->|Passes| checkovScan[Run Security Scan\nvia RunCheckovScan]
39
+ validate -->|Fails| fixValidation[Fix Configuration\nIssues]
36
40
  fixValidation --> edit
37
41
 
38
42
  %% Checkov Flow
39
- checkovScan -->|No Issues| tfInit[Run terraform init\nvia ExecuteTerraformCommand]
43
+ checkovScan -->|No Issues| initCmd[Run Init Command:\nterraform init or terragrunt init\nvia ExecuteTerraformCommand]
40
44
  checkovScan -->|Finds Issues| reviewIssues[Review Security\nIssues]
41
45
 
42
46
  reviewIssues --> manualFix[Fix Security Issues]
43
-
44
47
  manualFix --> edit
45
48
 
46
- %% Terraform Init & Plan (No Apply)
47
- tfInit -->|Success| tfPlan[Run terraform plan\nvia ExecuteTerraformCommand]
48
- tfInit -->|Fails| fixInit[Fix Provider/Module\nIssues]
49
+ %% Init & Plan (No Apply)
50
+ initCmd -->|Success| planCmd[Run Plan Command:\nterraform plan or terragrunt plan\nvia ExecuteTerraformCommand]
51
+ initCmd -->|Fails| fixInit[Fix Provider/Module\nIssues]
49
52
  fixInit --> edit
50
53
 
51
54
  %% Final Review & Handoff to Developer
52
- tfPlan -->|Plan Generated| reviewPlan[Review Planned Changes]
53
- tfPlan -->|Issues Detected| edit
55
+ planCmd -->|Plan Generated| reviewPlan[Review Planned Changes]
56
+ planCmd -->|Issues Detected| edit
54
57
 
55
58
  reviewPlan --> codeReady[Valid, Secure Code Ready\nfor Developer Review]
56
59
 
@@ -72,17 +75,20 @@ flowchart TD
72
75
  class reviewIssues,reviewPlan warning
73
76
  class fixValidation,fixInit,manualFix error
74
77
  class edit process
75
- class newChanges decision
76
- class tfValidate,checkovScan,tfInit,tfPlan mcptool
78
+ class detectConfig,newChanges decision
79
+ class validate,checkovScan,initCmd,planCmd mcptool
77
80
  class handoff handoff
78
81
  ```
79
82
 
80
- 1. Edit Terraform Code
81
- - Write or modify Terraform configuration files for AWS resources
83
+ 1. Edit Terraform or Terragrunt Code
84
+ - Write or modify Terraform or Terragrunt configuration files for AWS resources
82
85
  - When writing code, follow this priority order:
83
86
  * FIRST check for specialized AWS-IA modules (`SearchSpecificAwsIaModules` tool)
84
87
  * If no suitable module exists, THEN use AWSCC provider resources (`SearchAwsccProviderDocs` tool)
85
88
  * ONLY fall back to traditional AWS provider (`SearchAwsProviderDocs` tool) when the above options don't meet requirements
89
+ - When using Terragrunt:
90
+ * Ensure that the terraform block references the correct module or configuration directory
91
+ * Use Terragrunt features such as locals, dependencies, generate, and inputs to manage DRY configuration
86
92
  - When a user provides a specific Terraform Registry module to use:
87
93
  * Use the `SearchUserProvidedModule` tool to analyze the module
88
94
  * Extract input variables, output variables, and README content
@@ -92,6 +98,7 @@ flowchart TD
92
98
  - Resources
93
99
  - *terraform_development_workflow* to consult this guide and to use it to ensure you're following the development workflow correctly
94
100
  - *terraform_aws_best_practices* for AWS best practices about security, code base structure and organization, AWS Provider version management, and usage of community modules
101
+ - *terragrunt_aws_best_practices* for AWS best practices about security, code base structure and organization, AWS Provider version management, and usage of community modules
95
102
  - *terraform_awscc_provider_resources_listing* for available AWS Cloud Control API resources
96
103
  - *terraform_aws_provider_resources_listing* for available AWS resources
97
104
  - Tools
@@ -100,10 +107,15 @@ flowchart TD
100
107
  - *SearchAwsccProviderDocs* tool to look up specific Cloud Control API resources
101
108
  - *SearchAwsProviderDocs* tool to look up specific resource documentation
102
109
  2. Validate Code
103
- - Tool: *ExecuteTerraformCommand* with command="validate"
104
- - Checks syntax and configuration validity without accessing AWS
105
- - Identifies syntax errors, invalid resource configurations, and reference issues
106
- - Example: ExecuteTerraformCommand(TerraformExecutionRequest(command="validate", working_directory="./my_project"))
110
+ - Tools:
111
+ - *ExecuteTerraformCommand* with command="validate"
112
+ - *ExecuteTerragruntCommand* with command="validate"
113
+ - Purpose:
114
+ - Checks syntax and configuration validity without accessing AWS
115
+ - Identifies syntax errors, invalid resource configurations, and reference issues
116
+ - Examples:
117
+ - ExecuteTerraformCommand(TerraformExecutionRequest(command="validate", working_directory="./my_project"))
118
+ - ExecuteTerragruntCommand(TerragruntExecutionRequest(command="validate", working_directory="./my_project"))
107
119
  3. Run Security Scan
108
120
  - Tool: *RunCheckovScan*
109
121
  - Scans code for security misconfigurations, compliance issues, and AWS best practice violations
@@ -113,14 +125,24 @@ flowchart TD
113
125
  - Edit the code to address security issues identified by the scan
114
126
  - Consult *terraform_aws_best_practices* resource for guidance
115
127
  5. Initialize Working Directory
116
- - Tool: *ExecuteTerraformCommand* with command="init"
128
+ - Tools:
129
+ - Terraform: *ExecuteTerraformCommand* with command="init"
130
+ - Terragrunt: *ExecuteTerragruntCommand* with command="init"
131
+ - Purpose:
117
132
  - Downloads provider plugins and sets up modules
118
- - Example: ExecuteTerraformCommand(TerraformExecutionRequest(command="init", working_directory="./my_project"))
133
+ - Example:
134
+ - ExecuteTerraformCommand(TerraformExecutionRequest(command="init", working_directory="./my_project"))
135
+ - ExecuteTerragruntCommand(TerragruntExecutionRequest(command="init", working_directory="./my_project"))
119
136
  6. Plan Changes
120
- - Tool: *ExecuteTerraformCommand* with command="plan"
137
+ - Tools:
138
+ - *ExecuteTerraformCommand* with command="plan"
139
+ - *ExecuteTerragruntCommand* with command="plan"
140
+ - Purpose:
121
141
  - Creates an execution plan showing what changes would be made (without applying)
122
142
  - Verifies that the configuration is deployable
123
- - Example: ExecuteTerraformCommand(TerraformExecutionRequest(command="plan", working_directory="./my_project", output_file="tfplan"))
143
+ - Examples:
144
+ - ExecuteTerraformCommand(TerraformExecutionRequest(command="plan", working_directory="./my_project", output_file="tfplan"))
145
+ - ExecuteTerragruntCommand(TerragruntExecutionRequest(command="plan", working_directory="./my_project", output_file="tfplan"))
124
146
  7. Review Plan & Code Ready
125
147
  - Review the plan output to ensure it reflects intended changes
126
148
  - Confirm all validation and security checks have passed
@@ -183,6 +205,110 @@ Options:
183
205
  Options:
184
206
  - `-auto-approve` - Skip interactive approval
185
207
 
208
+ ### Terragrunt Commands
209
+
210
+ #### terragrunt init
211
+
212
+ * Purpose: Initializes a Terragrunt working directory by preparing the underlying Terraform modules and provider plugins.
213
+ * When to use: Before running any other commands in a new or updated Terragrunt configuration directory.
214
+
215
+ Options:
216
+ - `--terragrunt-config=PATH` - Path to the Terragrunt configuration file (default: terragrunt.hcl)
217
+
218
+ ```python
219
+ ExecuteTerragruntCommand(TerragruntExecutionRequest(
220
+ command="init",
221
+ working_directory="./project_dir"
222
+ ))
223
+ ```
224
+
225
+ #### terragrunt validate
226
+
227
+ * Purpose: Validates the underlying Terraform configuration referenced by the Terragrunt wrapper.
228
+ * When to use: After editing Terragrunt or Terraform configuration files, to check for syntax and reference issues.
229
+
230
+ ```python
231
+ ExecuteTerragruntCommand(TerragruntExecutionRequest(
232
+ command="validate",
233
+ working_directory="./project_dir"
234
+ ))
235
+ ```
236
+ Options:
237
+ - `--terragrunt-config=PATH` - Path to the Terragrunt configuration file (default: `terragrunt.hcl`)
238
+
239
+ #### terragrunt plan
240
+
241
+ * Purpose: Creates an execution plan for infrastructure changes using the Terragrunt wrapper.
242
+ * When to use: After validation passes, to preview changes before applying them.
243
+
244
+ Options:
245
+ - `-var 'name=value'` - Set variable (passed to Terraform)
246
+ - `-var-file=filename` - Load variables from file (passed to Terraform)
247
+ - `--terragrunt-config=PATH` - Path to the Terragrunt configuration file (default: `terragrunt.hcl`)
248
+
249
+ ```python
250
+ ExecuteTerragruntCommand(TerragruntExecutionRequest(
251
+ command="plan",
252
+ working_directory="./project_dir",
253
+ ))
254
+ ```
255
+
256
+ #### terragrunt apply
257
+
258
+ * Purpose: Applies the planned changes using the Terragrunt wrapper.
259
+ * When to use: After plan output is approved and developer chooses to proceed.
260
+
261
+ >Note: This is typically executed by the developer after reviewing code and plan output.
262
+
263
+ Options:
264
+ - `-auto-approve` - Skip interactive approval
265
+ - `--non-interactive` - Disables all interactive approval prompts (Terragrunt as well of Terraform)
266
+ - `-var 'name=value'` - Set variable
267
+ - `--terragrunt-config=PATH` - Use a specific Terragrunt configuration file
268
+
269
+ ```python
270
+ ExecuteTerragruntCommand(TerragruntExecutionRequest(
271
+ command="apply",
272
+ working_directory="./project_dir"
273
+ ))
274
+ ```
275
+
276
+ #### terragrunt destroy
277
+
278
+ * Purpose: Destroys all infrastructure managed through the Terragrunt configuration.
279
+ * When to use: When the infrastructure is no longer needed.
280
+
281
+ >Note: This is typically executed by the developer once the application or environment is being decommissioned.
282
+
283
+ Options:
284
+ - `-auto-approve` - Skip interactive approval
285
+ - `--non-interactive` - Disables all interactive approval prompts (Terragrunt as well of Terraform)
286
+ - `--terragrunt-config=PATH` - Use a specific Terragrunt configuration file
287
+
288
+ ```python
289
+ ExecuteTerragruntCommand(TerragruntExecutionRequest(
290
+ command="destroy",
291
+ working_directory="./project_dir"
292
+ ))
293
+ ```
294
+
295
+ #### terragrunt run-all apply
296
+
297
+ * Purpose: Recursively runs the `apply` command across all child Terragrunt modules in a directory tree.
298
+ * When to use: To apply changes across an entire environment or stack, typically in a root coordination folder.
299
+
300
+ Options:
301
+ - `--non-interactive` - Disables all interactive approval prompts (Terragrunt as well of Terraform)
302
+ - `--queue-exclude-dir` - Exclude glob path that should be excluded when issuing run-all commands. If a relative path is specified, it should be relative from working-dir.
303
+ - `--queue-include-dir` - Include glob path that should be included when issuing run-all commands. If a relative path is specified, it should be relative from working-dir.
304
+
305
+ ```python
306
+ ExecuteTerragruntCommand(TerragruntExecutionRequest(
307
+ command="run-all apply",
308
+ working_directory="./live/production"
309
+ ))
310
+ ```
311
+
186
312
  ### Checkov Commands
187
313
 
188
314
  These security scanning commands are available through dedicated tools:
@@ -200,5 +326,5 @@ These security scanning commands are available through dedicated tools:
200
326
  - **Cost Optimization**: Design resources to minimize costs while meeting requirements
201
327
  - **Operational Excellence**: Implement proper monitoring, logging, and observability
202
328
  - **Serverless-First**: Prefer serverless services when possible
203
- - **Infrastructure as Code**: Use Terraform to define all infrastructure
329
+ - **Infrastructure as Code**: Define all infrastructure declaratively using Terraform (or Terragrunt where applicable)
204
330
  - **Regional Awareness**: Consider regional availability and constraints for services
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: awslabs.terraform-mcp-server
3
- Version: 0.0.11
3
+ Version: 0.0.12
4
4
  Summary: An AWS Labs Model Context Protocol (MCP) server for terraform
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: beautifulsoup4>=4.12.0
@@ -56,6 +56,12 @@ MCP server for Terraform on AWS best practices, infrastructure as code patterns,
56
56
  - Pass variables and specify AWS regions
57
57
  - Get formatted command output for analysis
58
58
 
59
+ - **Terragrunt Workflow Execution** - Run Terragrunt commands directly
60
+ - Initialize, plan, validate, apply, run-all and destroy operations
61
+ - Pass variables and specify AWS regions
62
+ - Configure terragrunt-config and and include/exclude paths flags
63
+ - Get formatted command output for analysis
64
+
59
65
  ## Tools and Resources
60
66
 
61
67
  - **Terraform Development Workflow**: Follow security-focused development process via `terraform://workflow_guide`
@@ -1,29 +1,30 @@
1
1
  awslabs/__init__.py,sha256=4zfFn3N0BkvQmMTAIvV_QAbKp6GWzrwaUN17YeRoChM,115
2
2
  awslabs/terraform_mcp_server/__init__.py,sha256=a-zIkwClerA84_XGykBggO4w5kf8f85EapnWnbAH01c,58
3
- awslabs/terraform_mcp_server/server.py,sha256=ZyX_w3oath8l2T3tH63EyH5J_l93LZGCxW2HCeL4t2s,15787
3
+ awslabs/terraform_mcp_server/server.py,sha256=6BkVZRQH3qQ44PAQg2sW30x3lL-OKdO7ahCP2KwTFGY,18558
4
4
  awslabs/terraform_mcp_server/impl/resources/__init__.py,sha256=bxqHGDtuwWq8w-21lT5GzOuxBqkmnUvW6cnSA36ve3A,388
5
5
  awslabs/terraform_mcp_server/impl/resources/terraform_aws_provider_resources_listing.py,sha256=ohd-LOCuwLh0XchmUVRNIlgEcb1qJbiWMvVVklfZZyI,1991
6
6
  awslabs/terraform_mcp_server/impl/resources/terraform_awscc_provider_resources_listing.py,sha256=rcxTeN2SvzddNi5bMzMF8oZP9O-Nq4PxzFBiqHbsY-I,2078
7
- awslabs/terraform_mcp_server/impl/tools/__init__.py,sha256=4D7D6cYF98qj4lltiO5UOHNFRl8Gfg7Zv9n-wRlOj3o,715
7
+ awslabs/terraform_mcp_server/impl/tools/__init__.py,sha256=QUowqVKDnxQUKR36rGJvE1AGxV7xX8ky6ymt-QJoFBw,826
8
8
  awslabs/terraform_mcp_server/impl/tools/execute_terraform_command.py,sha256=_fPxC2wT23oWa9XaAoUEV1j5lK7Xpi7MqBAq85fLNdU,8507
9
+ awslabs/terraform_mcp_server/impl/tools/execute_terragrunt_command.py,sha256=7WDV9DhQMLaPXm1kOO2mAczU0ZUiBv6gA3mm9dmgcmc,13024
9
10
  awslabs/terraform_mcp_server/impl/tools/run_checkov_scan.py,sha256=oS6qgUPPti7lpa2VNsUwPbswiq2hgpe49fggVUI_PfM,13435
10
11
  awslabs/terraform_mcp_server/impl/tools/search_aws_provider_docs.py,sha256=w7NX4oQwsCeVQPj8YZzvXvXcox8drzZimW3mRL8Kd84,29049
11
12
  awslabs/terraform_mcp_server/impl/tools/search_awscc_provider_docs.py,sha256=fY8eRQ1j6oB4XyfAoUC6mTUXNkoFaY0vsmMhV6w0NR8,27297
12
13
  awslabs/terraform_mcp_server/impl/tools/search_specific_aws_ia_modules.py,sha256=Kny5iharA1Wj-9tnhoPHntu4qM9n-2mC2dB6TXwhqfk,20148
13
14
  awslabs/terraform_mcp_server/impl/tools/search_user_provided_module.py,sha256=6d_QHnDwpGicMsmQmpfs0hzTtf-XAVXZBNUsBnkfxtw,14491
14
15
  awslabs/terraform_mcp_server/impl/tools/utils.py,sha256=GB1OuhYgrg00AzKfhgaUpQwbVBK5D56GQLcm60NHd1c,20500
15
- awslabs/terraform_mcp_server/models/__init__.py,sha256=-kCRp9lGMz0-SXv0XvXP48_dVCeMbQIJqkxLTqXlmhk,801
16
- awslabs/terraform_mcp_server/models/models.py,sha256=oQutL78FdbXXQgekXjp8Dhotq-A-wBJLylQAHRMyNs0,12614
16
+ awslabs/terraform_mcp_server/models/__init__.py,sha256=BmcLbcCd_ORzgr4TjmOMrwHHtp4iyz_BoeRYnEFYiHg,931
17
+ awslabs/terraform_mcp_server/models/models.py,sha256=4kFNKRyDgLAL7TzL9CoADB--90rCCy7aQcubDbOKtjg,15600
17
18
  awslabs/terraform_mcp_server/scripts/generate_aws_provider_resources.py,sha256=wxwt3MxD3xUsrDXnfa9-3EAQfBg3fO-CzwkzjYNMIRU,56770
18
19
  awslabs/terraform_mcp_server/scripts/generate_awscc_provider_resources.py,sha256=ieHzBfTHPbxkTL3d_mRVga2-xLRRma4TnXC6Amq1ugc,48823
19
20
  awslabs/terraform_mcp_server/scripts/scrape_aws_terraform_best_practices.py,sha256=t_eFbciBwZXdK6pNkkcp4X7VPR4vXyXkmE_YLhm6Xr4,3783
20
21
  awslabs/terraform_mcp_server/static/AWSCC_PROVIDER_RESOURCES.md,sha256=I_vu3dWXzd9Pxcd7tkdxFQs97wtuunyoXdJCAkCUXnE,440270
21
22
  awslabs/terraform_mcp_server/static/AWS_PROVIDER_RESOURCES.md,sha256=OMboscC0Ov6O3U3K1uqrzRzx18nq_5AsJzITc5-CA8Y,303030
22
23
  awslabs/terraform_mcp_server/static/AWS_TERRAFORM_BEST_PRACTICES.md,sha256=cftJ9y2nZ0kMendoV6WBlQFsNw-QnGnmF6dR88eoYdA,87665
23
- awslabs/terraform_mcp_server/static/MCP_INSTRUCTIONS.md,sha256=P82tv9KJJxhoG5UFKaG16nQS5a0ud6Fcvg_BUypz-z0,6445
24
- awslabs/terraform_mcp_server/static/TERRAFORM_WORKFLOW_GUIDE.md,sha256=1RrSF7NH0BNVnQTZFwPhuaWsxElmCcwvl07iLOnO2gw,9768
24
+ awslabs/terraform_mcp_server/static/MCP_INSTRUCTIONS.md,sha256=r-ChGWXW4EbXquzAeILVayqgTrOoA9XpkzyrHwCrER8,7368
25
+ awslabs/terraform_mcp_server/static/TERRAFORM_WORKFLOW_GUIDE.md,sha256=jCLvjatXFL-1aN0CAuZkWb5IfQP8DVbrc3RsVeze3Fs,15045
25
26
  awslabs/terraform_mcp_server/static/__init__.py,sha256=mgAvoiD1_fgcgK5Sbf2nZLlX47D6ZuwuZbMrbNsyUKE,603
26
- awslabs_terraform_mcp_server-0.0.11.dist-info/METADATA,sha256=6RMm-IRV9vllVfJiyf7XIMWv_Cc4uYhk2NRf5HWskZY,5104
27
- awslabs_terraform_mcp_server-0.0.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
28
- awslabs_terraform_mcp_server-0.0.11.dist-info/entry_points.txt,sha256=jCTPQeUJ74jpIDcYwVHQCk-y0n0ehRFFerh_Qm4ZU1c,90
29
- awslabs_terraform_mcp_server-0.0.11.dist-info/RECORD,,
27
+ awslabs_terraform_mcp_server-0.0.12.dist-info/METADATA,sha256=3YSd4udjnQ_x-vcoBV8DMILt-KUWa-BK4qk9xNjEBOU,5403
28
+ awslabs_terraform_mcp_server-0.0.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
29
+ awslabs_terraform_mcp_server-0.0.12.dist-info/entry_points.txt,sha256=jCTPQeUJ74jpIDcYwVHQCk-y0n0ehRFFerh_Qm4ZU1c,90
30
+ awslabs_terraform_mcp_server-0.0.12.dist-info/RECORD,,