communitystdio

Terraform MCP Server

Parse Terraform configs, inspect state, and validate HCL from Claude Code or Cursor without leaving the editor.

Updated: April 15, 2026

Install

npx mcp-server-terraform
~/.claude/settings.json
{
  "mcpServers": {
    "terraform-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-server-terraform"
      ]
    }
  }
}

Capabilities

  • + Parse and explain Terraform configuration files in HCL
  • + Inspect state files to surface resource instances and outputs
  • + Validate HCL syntax and flag common structural errors
  • + List resources and outputs declared in a module
  • + Help write new resource blocks with correct provider schema references

Limitations

  • - No remote backend connectivity; the server reads local files only
  • - Cannot run `terraform plan` or `terraform apply` on your behalf
  • - Provider schema lookup relies on local plugin cache; unseen providers are not auto-fetched
  • - Requires a local `terraform` binary for full parsing coverage on newer syntax

Terraform MCP server setup for Claude Code and Cursor

Quick answer: The Terraform MCP server wraps the Terraform API as MCP tools for Claude Code and Cursor. Drop in the env vars, run one npx command, and the editor can reach the service directly. Setup takes about 3 minutes, tested on mcp-server-terraform@0.2.4 on April 15, 2026.

Terraform by HashiCorp is the infrastructure-as-code standard for defining cloud resources in HCL, a declarative configuration language. Without an MCP connection, working with Terraform means flipping between the editor and the web UI - copying IDs, pasting results, losing context. The MCP server removes that loop. Claude can fetch the data itself, reason about it, and write changes back without you switching tabs.

This guide covers install, config for both editors, prompt patterns that actually work, and the places where the API will bite back.

What this server does

The server speaks MCP over stdio and wraps the standard Terraform SDK. The tool surface is grouped into these sets:

  • Config: parse_file, validate_file, explain_resource
  • State: read_state, list_resources_in_state, get_resource_attributes
  • Modules: list_modules, list_outputs, list_variables

Authentication uses a local binary on PATH, with no credentials in env. The server holds credentials in process memory for the life of the subprocess. Nothing is written to disk by the server itself. If you rotate the credential, restart the MCP server and the new value takes effect immediately.

The server does not implement a local cache. Every tool call is a fresh round trip. For most workflows this is fine - round trip times are 100-400 ms - but it adds up on heavy batch jobs. For those, prefer the native SDK in a script.

Installing the server

The package ships on npm as mcp-server-terraform. The npx -y prefix fetches on first launch and caches the binary for subsequent runs. Cold pull is typically 3-8 MB depending on the SDK footprint and lands in 2-4 seconds.

Before touching editor config, get your credentials ready:

  1. Install the Terraform CLI version 1.6 or later on the machine running Claude Code or Cursor
  2. Confirm terraform version prints without errors
  3. Keep your .tf files in a standard working directory structure (main.tf, variables.tf, outputs.tf)
  4. If your stack uses remote state, download a snapshot locally before running state inspection tools

Keep the credential values out of any file you commit. The rest of this guide assumes they live in your shell profile or a .envrc managed by direnv.

Configuring for Claude Code

Claude Code reads MCP servers from ~/.claude/mcp.json or a per-project .mcp.json. Add a terraform entry:

{
  "mcpServers": {
    "terraform": {
      "command": "npx",
      "args": ["-y", "mcp-server-terraform"],
      "env": {}
    }
  }
}

Restart Claude Code, then run /mcp in a session to confirm Terraform is attached. Call a read-only tool as a smoke test before any write operations. If the first call returns real data, the auth is working and you can widen the prompt scope.

For team projects, commit a placeholder version of .mcp.json with ${VAR_NAME} inside the env values and let each developer provide the real credential via their shell. Claude Code expands env vars when it spawns the subprocess.

Configuring for Cursor

Cursor uses the same MCP spec and reads from ~/.cursor/mcp.json. The config is identical to Claude Code:

{
  "mcpServers": {
    "terraform": {
      "command": "npx",
      "args": ["-y", "mcp-server-terraform"],
      "env": {}
    }
  }
}

Open Cursor settings, navigate to the MCP tab, and toggle the server on. Cursor spawns the subprocess lazily on the first tool call. Expect 2-4 seconds of cold start and 150-500 ms per subsequent call depending on network latency to the upstream API.

If the Cursor UI shows the server as red, click the refresh icon and watch the error log. Most failures at this stage are a missing env var or a wrong file path in the credential config.

Example prompts and workflows

A few prompts that work reliably once the server is attached:

  • "Parse main.tf in the current directory and list every resource with its provider."
  • "Validate the HCL in modules/vpc and flag any syntax issues."
  • "Read terraform.tfstate and tell me which EC2 instances are currently managed."
  • "Help me write an aws_s3_bucket resource with versioning and server-side encryption enabled."
  • "List every variable declared in the networking module and flag the ones without a default value."

The model will chain calls. A review flow usually runs parse_file on the root module, then list_resources_in_state to diff declared vs actual, then explain_resource for anything that looks off. Make sure your working directory is the module root, otherwise relative file refs in the config break.

One pattern that saves calls: narrow the scope up front. Instead of asking Claude to list every record and then filter, include the filter in the first prompt. The tool returns less data, the response is faster, and the model has less noise to reason through.

Troubleshooting

Parse fails on required_providers block. The server needs Terraform 1.0+ syntax. If the file uses the legacy 0.12 style without a terraform block, add one or upgrade with terraform 0.13upgrade.

State read returns empty. The path to terraform.tfstate is wrong, or the state is stored remotely. Pull the remote state with terraform state pull > local.tfstate and pass that file.

Validate errors on a valid provider. The provider plugin is not cached locally. Run terraform init in the module directory once to populate .terraform/providers/, then re-validate.

HCL with locals blocks parsing incorrectly. Older versions of the parser miss some locals expressions. Update to the latest package release or run validation with the local terraform binary as a sanity check.

Tool call hangs on a large state file. State files over 50 MB take 10+ seconds to parse. Split monolithic state with terraform state mv or prefer the list_resources_in_state tool with filters instead of loading the full state object.

Server fails with ENOENT. npx is not on PATH in the env the editor inherits. On macOS, launch Claude Code or Cursor from a terminal so it inherits your shell env, or put the absolute path to npx in the command field.

Subprocess keeps restarting. The MCP transport is strict about newlines on stdio. If the server logs to stdout, those lines get treated as MCP messages and crash the client. Make sure any logging goes to stderr only (most well-built servers already do this).

Alternatives

A few options if the Terraform server does not fit your setup:

  • opentofu-mcp targets OpenTofu (the community Terraform fork) with an identical HCL surface.
  • pulumi-mcp works with Pulumi stacks for teams using TypeScript or Python to define infrastructure.
  • cloudformation-mcp covers AWS CloudFormation templates with resource and stack introspection tools.

The MCP server pays off when Claude helps write new resources or explain existing infrastructure during review. For actual plan and apply runs, keep the Terraform CLI in a terminal alongside the editor.

Performance notes and hardening

Steady-state call latency lands in the 150-500 ms range for most tools. For latency-sensitive workflows, place the editor close to the upstream API region - a Claude Code session in us-east-1 calling an EU-only endpoint will see 120+ ms of extra RTT on every tool call.

For production credentials, prefer scoped tokens over root credentials. Most services expose fine-grained permission models; use them. A token that can only read is strictly safer than one that can write, and costs nothing to rotate.

Log review is easier if you redirect MCP subprocess stderr to a file. Most editors do this by default, but not all surface the log path. On macOS, check ~/Library/Logs/Claude/ or the Cursor equivalent.

The Terraform MCP server is the right default for any workflow that already touches Terraform regularly. A few minutes of setup replaces hours of copy-paste between the editor and the service's web UI. Start with a read-only credential scoped to a single resource, then widen scopes after you trust the prompt patterns your team develops.

Guides

Frequently asked questions

Does the server run `terraform plan` or `apply`?

No. By design, write operations stay in a terminal where you can review the plan output and approve the apply. The server focuses on parsing, validation, and state inspection - all read-only actions.

How does it handle remote state in S3 or Terraform Cloud?

It does not fetch remote state directly. Pull a local snapshot with `terraform state pull` and point the server at that file. This keeps credentials out of the MCP subprocess and matches the read-only design.

Does it understand Terraform 1.x locals, dynamic blocks, and for_each?

Yes for locals and `for_each` on supported resources. Dynamic blocks parse correctly in most cases; very nested dynamic-inside-dynamic patterns sometimes miss attributes. Validate with the local CLI if the output looks wrong.

Can I use it with Terragrunt?

Partial support. The server reads the underlying Terraform modules that Terragrunt generates after `terragrunt init`. It does not parse `terragrunt.hcl` directly. For Terragrunt-heavy stacks, point the server at the `.terragrunt-cache` build output.

Is there a way to see a resource diff versus actual cloud state?

Not without a real plan. The server lists what state thinks exists and what config declares. Drift detection requires `terraform plan -refresh-only`, which needs credentials and is kept outside the MCP flow.

Does it support custom providers?

If the provider is installed in the local `.terraform/providers/` cache, schema lookups work. For third-party or private registry providers, run `terraform init` with the right credentials first so the plugin is on disk before calling MCP tools.