Skip to content

Ten years on AWS and I had never written CloudFormation, so I let an MCP server check my homework

Introduction

Have you ever woken up after 10 years working on AWS to realise you have never built anything in CloudFormation? Well, that is exactly what happened to me. So I did.

Building it was the fun part. The part that made me nervous was the question that comes right after: how do I know it is any good? I did not want to rely on “it deployed, so it must be fine”, and I did not have a decade of CloudFormation scar tissue to lean on either. That is where the AWS IaC MCP server came in.

If you have not met MCP yet, it stands for Model Context Protocol. In plain terms, it lets an AI assistant call real tools instead of guessing. This particular server gives Claude Code access to cfn-lint and cfn-guard, so a template gets checked by the same linters you would run in CI, without leaving your editor.

This post covers how I set it up and what its checks cover.

What the server provides

The awslabs.aws-iac-mcp-server package exposes tools including:

  • validate_cloudformation_template – runs cfn-lint (syntax, schema, resource properties)
  • check_cloudformation_template_compliance – runs cfn-guard against a bundled security ruleset
  • search_cloudformation_documentation – searches the official CloudFormation docs
  • search_cdk_documentation – searches the CDK API reference, best practices guide and CDK Nag rules
  • search_cdk_samples_and_constructs – finds code samples, patterns and community constructs, filterable by language
  • cdk_best_practices – returns CDK best practices and security guidelines

It is not just for CloudFormation. The server also covers CDK, with tools for documentation, sample code and best practices. The checking tools only read CloudFormation templates, so with CDK you would run cdk synth first and check the output.

It runs locally over stdio. Claude Code launches it as a child process and talks to it over standard input and output.

Setup

The official documentation for this server lives on the AWS Labs MCP site: AWS IaC MCP Server.

You need uv installed so that uvx is available. For a personal project, the quickest route is one command, run from your project folder:

claude mcp add aws-iac-mcp-server -e FASTMCP_LOG_LEVEL=ERROR -- uvx awslabs.aws-iac-mcp-server@latest

The .mcp.json alternative

You can write the same thing as a file called .mcp.json in your project root:

{
  "mcpServers": {
    "aws-iac-mcp-server": {
      "type": "stdio",
      "command": "uvx",
      "args": ["awslabs.aws-iac-mcp-server@latest"],
      "env": {
        "FASTMCP_LOG_LEVEL": "ERROR"
      }
    }
  }
}

The upside is that the config lives in your repo, so it is easy to read and reproduce. The downside is that it is committed with your code, so only put things in it that you are happy for anyone with the repo to see. Never put keys or secrets in it.

Prefer Docker?

You can run this server in Docker instead of uvx. You build the image locally and point your MCP config at docker run, rather than at uvx. The server’s docs walk through the exact steps.

Checking it connected

Run /mcp in Claude Code to see the status of each configured server. A connected server lists its tools, which you can then ask Claude to use by name or by describing the task, for example “validate template.yml and summarise the warnings”.

Using the tools well

cfn-lint

Syntax and schema validation. It returns an error, warning and info count plus line numbers. Errors block deployment. Warnings are worth reading but are often informational.

cfn-guard

Security rules. It returns a list of violations with remediation hints. Three things to keep in mind:

  • Not every rule fits your workload. Rules such as Object Lock or replication suit compliance-heavy systems, and are overkill for a small project.
  • Output can be coarse. Some results identify the resource only as “Unknown”, so you may need to work out which resource a rule applied to.
  • Expect some noise. If you have used tfsec, you know the feeling: static analysis tools flag things that are technically correct but irrelevant to your workload, and sometimes things that are not correct at all. Treat a finding as a prompt to check, not a verdict.

What the bundled cfn-guard rules cover

AreaExamples of what it checks
S3Public read and write access, public ACLs, wildcard principals and actions in bucket policies, SSL-only requests, default encryption, versioning, logging, Object Lock, replication
Security groupsIngress open to the world, SSH open to the world, all-protocol rules, wide CIDR ranges, missing descriptions
NetworkingUnrestricted routes to an internet gateway, subnets that auto-assign public IPs, network ACL port and protocol rules
IAMWildcard actions or resources, admin or full-access policies, inline policies, PassRole with wildcards, policies attached directly to users, plaintext passwords
EC2Public IPs, instance profile attached, EBS encryption, detailed monitoring
RDSStorage encryption, public access, Multi-AZ, deletion protection, backups, logging, plaintext credentials

Rules only fire on resource types that exist in your template.

Pre-deployment validation

The server also returns instructions for CloudFormation change set validation, which catches issues such as name conflicts and non-empty bucket deletions before provisioning starts. Run it before a real deploy.

Wrapping up

Ten years in, I finally have a CloudFormation template I wrote myself, and a quick, repeatable way to sanity check it before it goes anywhere near a deploy. You might be asking, would I write CloudFormation again? Probably not. I will most likely stick with Terraform going forward.

Getting started is a single command, and /mcp tells you whether it worked. After that it is a case of asking Claude to run the checks and reading the results with a bit of healthy scepticism. cfn-lint tells you the template is valid, cfn-guard tells you how it stacks up against a set of security rules, and you decide what to fix and what to leave alone.


Tags

← Previous
How to disassociate your personal certification account from a past employer.