Your coding agent's Terraform and CloudFormation security check
before the PR exists
A free hosted MCP server: grab a Client ID, point Claude Code or Cursor at the endpoint, and scan AWS Terraform and CloudFormation the moment your agent writes it — IAM attack paths, misconfigurations, cost risks. The agent that wrote the code gets the verdict from a deterministic, non-AI engine that returns identical findings for identical input, every time.
claude mcp add --transport http audytx https://audytx.com/mcp --header "X-Client-ID: YOUR_CLIENT_ID"
url = "https://audytx.com/mcp" · header X-Client-ID (or standard Authorization: Bearer YOUR_CLIENT_ID if your client or gateway prefers it)This URL is dual-purpose: GET it for these docs, POST JSON-RPC 2.0 to the same URL for the MCP API (a GET to the API path returns 405).
Free: create a Client ID · 100 scans/month · no credit card
Set up your MCP client
One endpoint, two accepted credentials: the X-Client-ID header or standard Authorization: Bearer <client-id>. Create a free Client ID first.
Claude Code one command
claude mcp add --transport http audytx https://audytx.com/mcp \ --header "X-Client-ID: YOUR_CLIENT_ID"
Cursor .cursor/mcp.json
Project-level .cursor/mcp.json (or ~/.cursor/mcp.json globally). Cursor interpolates ${env:…} so the ID can live in your environment instead of the file:
{
"mcpServers": {
"audytx": {
"url": "https://audytx.com/mcp",
"headers": { "X-Client-ID": "${env:AUDYTX_CLIENT_ID}" }
}
}
}
VS Code .vscode/mcp.json
VS Code prompts once for the Client ID and stores it as a secret — it never sits in the file:
{
"inputs": [
{
"type": "promptString",
"id": "audytx-client-id",
"description": "audytx Client ID (from audytx.com/dashboard)",
"password": true
}
],
"servers": {
"audytx": {
"type": "http",
"url": "https://audytx.com/mcp",
"headers": { "X-Client-ID": "${input:audytx-client-id}" }
}
}
}
JetBrains IDEs AI Assistant → MCP
JetBrains AI Assistant's remote-server config is URL-only (no custom
headers), so connect through the
mcp-remote stdio proxy. In
Settings | Tools | AI Assistant | Model Context Protocol (MCP),
add a server as JSON:
{
"mcpServers": {
"audytx": {
"command": "npx",
"args": [
"mcp-remote", "https://audytx.com/mcp",
"--header", "X-Client-ID:${AUDYTX_CLIENT_ID}"
],
"env": { "AUDYTX_CLIENT_ID": "YOUR_CLIENT_ID" }
}
}
}
No space after the colon in X-Client-ID:${…} — some clients split header args on spaces (a documented mcp-remote workaround).
Claude Desktop claude_desktop_config.json
Claude Desktop's native remote connectors require an OAuth sign-in flow,
which audytx has staged (RFC 9728 metadata is live; the full
authorization server is planned — see /mcp/security).
Until then, the same mcp-remote proxy works today in
Settings → Developer → Edit Config:
{
"mcpServers": {
"audytx": {
"command": "npx",
"args": [
"mcp-remote", "https://audytx.com/mcp",
"--header", "X-Client-ID:${AUDYTX_CLIENT_ID}"
],
"env": { "AUDYTX_CLIENT_ID": "YOUR_CLIENT_ID" }
}
}
}
Windsurf / any MCP client ~/.codeium/windsurf/mcp_config.json
Step 0: create your Client ID at /dashboard — the UUID is shown once, so copy it then.
Windsurf reads ~/.codeium/windsurf/mcp_config.json. Add audytx as a
remote server (Windsurf uses serverUrl for HTTP servers):
{
"mcpServers": {
"audytx": {
"serverUrl": "https://audytx.com/mcp",
"headers": { "X-Client-ID": "YOUR_CLIENT_ID" }
}
}
}
Verify: reload Windsurf's MCP servers, then ask your agent to list the audytx tools, or POST tools/list to the endpoint (discovery needs no auth).
Any other client that can reach a Streamable-HTTP server works too: point it at
https://audytx.com/mcp and send the Client ID as either the
X-Client-ID header or
Authorization: Bearer YOUR_CLIENT_ID. Clients that only speak
stdio can bridge with npx mcp-remote as in the JetBrains
example above.
Call it with curl
Discovery is open; tools/call needs your X-Client-ID.
tools/call — scan_terraform (with your Client ID)
curl -sS https://audytx.com/mcp \
-H "Content-Type: application/json" \
-H "X-Client-ID: YOUR_CLIENT_ID" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "scan_terraform",
"arguments": {
"files": [
{ "path": "main.tf", "content": "resource \"aws_s3_bucket\" \"b\" { bucket = \"example\" }" },
{ "path": "iam.tf", "content": "resource \"aws_iam_role\" \"r\" { assume_role_policy = \"{}\" }" }
]
}
}
}'
tools/list — discovery (no auth)
curl -sS https://audytx.com/mcp \
-H "Content-Type: application/json" \
-d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }'
Discovery methods (initialize, tools/list, ping) need no auth; tools/call requires the X-Client-ID header.
MCP tools
A scan-fix-explain loop for your agent — Terraform, CloudFormation, or one mixed workspace — plus a context-graph view and a cost sampler. The full input/output reference is below the grid.
Named Terraform variable files: terraform_var_files is accepted by scan_terraform, scan_workspace, autofix_terraform, dry_run_autofix, get_context_graph, and cost_sampler.
scan_terraform
Findings with file/line evidence and fixes — plus the false positives context suppressed, each with a rationale.
scan_cloudformation
The CFN twin of scan_terraform for JSON/YAML templates, SAM, and cdk.out: the Terraform rule ids plus a few CloudFormation-only ones.
scan_workspace
One mixed Terraform + CloudFormation workspace as a single scan and a single quota unit.
autofix_terraform
Applies only sound, line-anchored fixes and re-scans, up to three passes — optionally opening a PR.
autofix_cloudformation
The CFN twin of autofix_terraform — authored YAML property lines only, never a value behind an intrinsic.
dry_run_autofix
A unified diff per file showing exactly what autofix would change — nothing modified.
dry_run_autofix_cloudformation
The same preview for templates: a unified diff per template, nothing modified.
explain_finding
Full context for a rule ID: what the check expects, its severity, and the fix.
get_context_graph
The relationship graph — resources, edges, and every suppression with its reason.
cost_sampler
Dollar-ranged AWS savings opportunities with Terraform remediation.
Scan AWS Terraform for security misconfigurations, IAM privilege-escalation paths, cross-resource attack paths, and cost risks. Returns findings with file/line evidence and fix snippets, plus the findings audytx suppressed as false positives — each with its rationale.
Inputs
filesrequired Array of{path, content}— all applicable.tf/.tf.jsonfiles, automatic variable files, and selected named variable-file bodies. Cross-resource reasoning needs the full set.terraform_var_filesoptional Ordered list (max 2,000; duplicate paths are rejected) of canonical repo-relative paths already included infiles. Terraform accepts any filename:.jsonuses JSON variable syntax and every other filename uses native HCL syntax. Later entries win. When present, list every selected named non-automatic variable file and omit unselected named files fromfiles; use[]for none. Omit this argument only for legacy canonical-path inference. These path references do not consume the file or byte budget again.data_filesoptional Array of{path, content}for non-Terraform JSON files exactly referenced byjsondecode(file(...)). Shares the same file and byte budget asfiles.planoptional Output ofterraform show -json. Resolves final values and module-internal resources.
Returns
findings[]Active findings with severity, file, line, message, fix snippet, andrelated[]— the other resources a cross-resource verdict involved (empty for single-resource findings)context_suppressed[]Findings the context layer suppressed, each with its rationalesummaryCounts by severitycompliance_coverage[]Controls touched per framework (for example SOC 2, PCI-DSS, HIPAA) — advisory signal, not attestation
Scan AWS CloudFormation templates — JSON or YAML, including SAM and cdk.out-synthesized templates — for the same misconfigurations, IAM privilege-escalation paths, cross-resource attack paths, and cost risks scan_terraform finds. Findings reuse the SAME AWS_* rule ids, since the engine normalizes CloudFormation into the same resource vocabulary before evaluating.
Inputs
filesrequired Array of{path, content}— all CFN/SAM/cdk.out templates of the stack or app, paths ending.json/.yaml/.yml/.template. Cross-resource reasoning needs the full set.
Returns
findings[]Active findings with severity, file, line, message, fix snippet, andrelated[]— the other resources a cross-resource verdict involved (empty for single-resource findings)context_suppressed[]Findings the context layer suppressed, each with its rationalesummaryCounts by severitycompliance_coverage[]Controls touched per framework (for example SOC 2, PCI-DSS, HIPAA) — advisory signal, not attestation
Scan one complete workspace containing Terraform, CloudFormation, or both as one parent operation and one quota unit. audytx works out which files are Terraform and which are CloudFormation, so you send the whole workspace in one call. Returns the same combined finding, suppression, baseline, digest, and completeness shape as the dialect-specific scan tools. This is the call the VS Code extension makes for a workspace action.
Inputs
filesrequired Array of{path, content}— the whole applicable set in one globally capped array: Terraform.tf/.tf.jsonconfiguration and automatic variable files, named-var-filebodies selected throughterraform_var_filesin command-line order, confirmed CloudFormation.json/.yaml/.yml/.template(SAM templates and CDK cloud assemblies included), JSON files exactly referenced byjsondecode(file(...)), and valid CDK cloud-assembly controls. Omit unselected named variable files. Cross-resource reasoning is blind to files you omit.terraform_var_filesoptional Ordered list (max 2,000; duplicate paths are rejected) of canonical repo-relative paths already included infiles. Terraform accepts any filename:.jsonuses JSON variable syntax and every other filename uses native HCL syntax. Later entries win. When present, list every selected named non-automatic variable file and omit unselected named files fromfiles; use[]for none. Omit this argument only for legacy canonical-path inference. These path references do not consume the file or byte budget again.
Terraform plan and CloudFormation change-set enrichment are deliberately not accepted here — call the dialect-specific tool, or use the GitHub App's /plan-upload and /changeset-upload routes, when you have resolved values.
Returns
findings[]Active findings across both dialects, with severity, file, line, message, fix snippet, andrelated[]— the other resources a cross-resource verdict involved (empty for single-resource findings)context_suppressed[]Findings the context layer suppressed, each with its rationalesummaryCounts by severitycompliance_coverage[]Controls touched per framework (for example SOC 2, PCI-DSS, HIPAA) — advisory signal, not attestation
Apply audytx's sound one-click fixes and re-scan, looping until no auto-applicable findings remain (max 3 passes). Only precisely line-anchored fixes that pass its safety checks are applied, and it returns the fixed files, what was fixed, and what remains for you.
Inputs
filesrequired Array of{path, content}terraform_var_filesoptional Ordered list (max 2,000; duplicate paths are rejected) of canonical repo-relative paths already included infiles. Terraform accepts any filename:.jsonuses JSON variable syntax and every other filename uses native HCL syntax. Later entries win. When present, list every selected named non-automatic variable file and omit unselected named files fromfiles; use[]for none. Omit this argument only for legacy canonical-path inference. These path references do not consume the file or byte budget again.data_filesoptional Array of{path, content}for non-Terraform JSON files exactly referenced byjsondecode(file(...)). Shares the same file and byte budget asfiles.github_tokenoptional Use a fine-grained personal access token scoped to only the target repository, with the two repository permissions this flow needs:Contents: write(the git blob/tree/commit/ref calls) andPull requests: write(opening the PR). Withrepo, audytx commits the fixes to a new branch and opens a pull request. The token is shape-validated, used solely for this one request's GitHub API calls against the repo you name, and never logged or stored.repooptionalowner/repo— required whengithub_tokenis provided. Strictly validated; every GitHub API call the token makes is confined to this repository.base_branchoptional Branch to target for the PR. Defaults tomain.onlyoptional List of rule ids, e.g.["AWS_RDS_001"]. Restricts the fix loop to those rules so you can accept one reviewed fix at a time; everything else is left untouched and reported as remaining. An empty list applies nothing.
Returns
files[]Fixed file contentsapplied[]Which findings were auto-fixedremaining[]Findings needing manual actiononly_unknown_ids[]Entries ofonlynaming a rule this scan did not produce — reported, never silently ignored (present only when you passonly)pr_urlURL of the opened pull request (only whengithub_token+repoare supplied)
The CloudFormation twin of autofix_terraform: apply the sound fixes and re-scan, up to three passes. Only precisely line-anchored single-line fixes on authored YAML property lines are applied — a value behind an intrinsic (!Ref/!If/Fn::), an unresolved Condition, SAM or CDK synthesis, or a block scalar is never edited. The GitHub one-click suggestions apply matching safety checks. JSON templates carry no line spans, so their findings are reported as remaining rather than auto-fixed; CDK cloud-assembly findings are report-only, with remediation reframed to change the CDK source and re-synthesize.
Inputs
filesrequired Array of{path, content}— the CFN/SAM/cdk.out templates to fix.github_tokenoptional Same contract asautofix_terraform's: a fine-grained personal access token scoped to only the target repository, withContents: writeandPull requests: write. Shape-validated, used solely for this one request's GitHub API calls against the repo you name, never logged or stored.repooptionalowner/repo— required whengithub_tokenis provided.base_branchoptional Branch to target for the PR. Defaults tomain.onlyoptional List of rule ids — apply just those fixes and leave the rest alone. An empty list applies nothing.
Returns
files[]Fixed template contentsapplied[]Which findings were auto-fixedremaining[]Findings needing manual action — including every JSON-template and CDK findingonly_unknown_ids[]Entries ofonlynaming a rule this scan did not produce (present only when you passonly)pr_urlURL of the opened pull request (only whengithub_token+repoare supplied)
Preview what autofix_terraform would do: a unified diff per file showing the exact line changes, with nothing modified. Review the diffs, confirm, then apply.
Inputs
filesrequired Array of{path, content}terraform_var_filesoptional Ordered list (max 2,000; duplicate paths are rejected) of canonical repo-relative paths already included infiles. Terraform accepts any filename:.jsonuses JSON variable syntax and every other filename uses native HCL syntax. Later entries win. When present, list every selected named non-automatic variable file and omit unselected named files fromfiles; use[]for none. Omit this argument only for legacy canonical-path inference. These path references do not consume the file or byte budget again.data_filesoptional Array of{path, content}for non-Terraform JSON files exactly referenced byjsondecode(file(...)). Shares the same file and byte budget asfiles.onlyoptional List of rule ids — preview just those fixes, so the diff you review is the diff you will apply. Same semantics asautofix_terraform's.
Returns
diffs[]Unified diff per filewould_fix[]Which findings would be addressedonly_unknown_ids[]Entries ofonlynaming a rule this scan did not produce (present only when you passonly)
Preview what autofix_cloudformation would do: a unified diff per template showing the precise line changes, with nothing modified. Only authored YAML property-line fixes are previewed — a value behind an intrinsic, an unresolved Condition, SAM/CDK synthesis, or a block scalar is never edited, and JSON templates and CDK-synthesized output produce no preview edits.
Inputs
filesrequired Array of{path, content}onlyoptional List of rule ids — preview just those fixes, so the diff you review is the diff you will apply.
Returns
diffs[]Unified diff per templatewould_fix[]Which findings would be addressedonly_unknown_ids[]Entries ofonlynaming a rule this scan did not produce (present only when you passonly)
Return structured explanation and remediation for a catalog rule ID (e.g. AWS_IAM_020): what the check expects, its severity, and how to fix it. Cross-resource findings (AWS_XREF_*, ATTACK_PATH_*) are explained inline in the scan result, not here.
Inputs
rule_idrequired e.g."AWS_IAM_020"
Returns
titleCheck title and severitydescriptionFull explanationremediationStep-by-step fix guidance
Return the cross-resource relationship graph audytx computed: resources, edges (reference, depends_on, invokes, runs_as, dlq), and the findings the context layer suppressed with their rationale. Use it to understand why audytx suppressed a finding before you accept the suppression.
Inputs
filesrequired Array of{path, content}terraform_var_filesoptional Ordered list (max 2,000; duplicate paths are rejected) of canonical repo-relative paths already included infiles. Terraform accepts any filename:.jsonuses JSON variable syntax and every other filename uses native HCL syntax. Later entries win. When present, list every selected named non-automatic variable file and omit unselected named files fromfiles; use[]for none. Omit this argument only for legacy canonical-path inference. These path references do not consume the file or byte budget again.data_filesoptional Array of{path, content}for non-Terraform JSON files exactly referenced byjsondecode(file(...)). Shares the same file and byte budget asfiles.
Returns
nodes[]All parsed resources and their relationshipsedges[]Graph edges with relationship typesuppressed_findings[]Context-suppressed findings with rationale
Estimate monthly and annual AWS cost-savings opportunities: storage tiering (gp2→gp3, S3 lifecycle), non-prod right-sizing, NAT Gateway vs VPC endpoints, over-provisioned RDS/DynamoDB, and missing cost-allocation tags — each with a dollar range and Terraform remediation. See the cost sampler page.
Inputs
filesrequired Array of{path, content}— all applicable.tf/.tf.jsonfiles, automatic variable files, and selected named variable-file bodies.terraform_var_filesoptional Ordered list (max 2,000; duplicate paths are rejected) of canonical repo-relative paths already included infiles. Terraform accepts any filename:.jsonuses JSON variable syntax and every other filename uses native HCL syntax. Later entries win. When present, list every selected named non-automatic variable file and omit unselected named files fromfiles; use[]for none. Omit this argument only for legacy canonical-path inference. These path references do not consume the file or byte budget again.data_filesoptional Array of{path, content}for non-Terraform JSON files exactly referenced byjsondecode(file(...)). Shares the same file and byte budget asfiles.planoptional Output ofterraform show -jsonto resolve variable/count/module values.
Returns
findings[]Cost-savings opportunities, each with a dollar range and Terraform remediationtotal_savingsCombined estimate (us-east-1 on-demand list pricing — opportunities, not your total bill)
Beyond tools, the server implements the MCP prompts and resources primitives (spec 2025-06-18) — no Client ID needed, since they serve public catalog data that helps agents write safer Terraform.
Prompts
secure-reviewScan → triage with suppression rationales → explain → autofix → re-scanpre-commit-gateA commit verdict on staged changes against a severity threshold — audytx returns the verdict, your agent enforces it
Resources
audytx://rules-catalogThe full catalog of declarative checks
A typical coding-agent workflow
.tf files: IAM roles, Lambda functions, S3 buckets, API Gateway stages..tf files. Get findings with file/line evidence, severity, fix snippets — and suppressed false positives with rationale so the agent knows what was checked.Example agent prompts
audytx scan_terraform on all .tf files in this directory. Show me any High or Critical findings and apply the auto-fixable ones."audytx get_context_graph on these files. I want to understand why the DLQ finding was suppressed — is it because this Lambda is only invoked synchronously?"audytx dry_run_autofix first and show me the diffs. If the changes look right, then run autofix_terraform to apply them."AWS_IAM_020. Call audytx explain_finding with that rule ID so I understand the exact privilege-escalation path before I change the IAM policy."An agent tool your security team can say yes to
Read-only by default, deterministic, and it does not store your source files.
It reviews, never deploys
audytx returns findings and diffs for a human or pipeline to apply. It has no access to your cloud. It writes to a repository only when you pass your own GitHub token to open a fix pull request.
Does not store your source files
Every call is independent: your Terraform or CloudFormation is parsed in memory and your files are not stored. For each finding audytx keeps the rule, message, resource, file path and line numbers for 90 days.
Deterministic, not a model
A hand-written Rust engine with explicit checks and no LLM in the loop. Every finding cites the check that produced it.
Evaluating for enterprise? See the full MCP security posture, self-assessed against the NSA MCP guidance and the OWASP MCP Top 10.
Start free
Create a Client ID, point your agent at the endpoint, and read the verdict on the infrastructure it just wrote. The Free plan includes 100 scans a month, and the free tier is here to stay.
Agent-first? Create a free Client ID — quotas are on the pricing page.
What AI-generated Terraform gets wrong
We asked a frontier model to write Terraform for 50 realistic AWS scenarios, then measured every output. The failures are consistent: invented argument names that fail terraform validate, and a cross-resource gap (companion resources missing, secrets created but never wired for rotation) — exactly the class a relationship graph catches. Read the study →
Free, no credit card
Limits reset on the first of each month (UTC). Enterprise limits are available; get in touch. Full details at /pricing.
MCP server FAQ
How do I scan Terraform from Claude Code?
Add the server once with claude mcp add --transport http audytx https://audytx.com/mcp --header "X-Client-ID: YOUR_CLIENT_ID", using a free Client ID from your dashboard. Then ask Claude Code to run scan_terraform on your .tf files. You get findings with file and line anchors, severity, fix snippets, and the false positives audytx suppressed with rationale.
Is the audytx MCP server safe to give my coding agent?
It is read-only by default: audytx returns findings and diffs for you or your pipeline to apply, and has no access to your cloud. It writes to a repository only when you pass your own GitHub token to open a fix pull request. Your Terraform or CloudFormation is parsed in memory and your files are not stored; for each finding audytx keeps the rule, message, resource, file path and line numbers for 90 days. The engine is deterministic Rust, and every finding cites the check that produced it.
What does the audytx MCP server cost?
It is free. A Client ID takes about 30 seconds to create, needs no credit card, and includes 100 scans per account each month across all your Client IDs. The GitHub App has its own Free allowance for each installation; each accepted scan operation costs one credit, while non-scan helpers are free. Scans audytx fails to complete are not charged. A scan that skips a file it cannot read and analyses the rest is a completed scan. Free refills on the first of the month, UTC. Paid tiers open Nov 01, 2026; enterprise limits are available on request.
The same engine also reviews the pull request (review-time) and the terraform plan before apply (plan-time). See the whole delivery layer →