# mcp-server-terraform [![CI](https://github.com/RajeevSirohi/mcp-server-terraform/actions/workflows/ci.yml/badge.svg)](https://github.com/RajeevSirohi/mcp-server-terraform/actions/workflows/ci.yml) [![npm](https://img.shields.io/npm/v/%40rajsir%2Fmcp-server-terraform)](https://www.npmjs.com/package/@rajsir/mcp-server-terraform) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that lets Claude manage Terraform infrastructure through natural language. > Run plans, apply changes, inspect state, and diagnose failures — all from a Claude conversation. ## What it does Instead of switching to a terminal to run `terraform plan`, you can ask Claude: > "Plan the changes in `/infra/staging` and explain what will change" > "Apply it — but only if no resources will be destroyed" > "Show me all the outputs from the prod workspace" > "Something broke after the last apply — diagnose it" The server translates these into real `terraform` CLI commands on your machine, with a built-in safety confirmation flow before any destructive operation runs. ## Tools | Tool | Description | Destructive | |------|-------------|-------------| | `tf_init` | Initialize a Terraform working directory | No | | `tf_validate` | Validate configuration syntax | No | | `tf_plan` | Run a plan and return the diff + risk/cost summary | No | | `tf_apply` | Apply changes (requires `confirmed: true`) | Yes | | `tf_destroy` | Destroy infrastructure (requires `confirmed: true`) | Yes | | `tf_output` | Read output values from state | No | | `tf_state` | List, show, move, or remove state entries | Partial | | `tf_workspace` | List, show, select, or create workspaces | No | | `tf_preflight` | Check provider CLI authentication before running | No | | `tf_drift` | Detect resources changed outside Terraform | No | | `tf_resource` | Import, taint, untaint, or refresh resources | Yes | ### Plan risk & cost summary Every plan (and every apply preview) is analyzed via `terraform show -json` and annotated with a structured summary — destroyed resources are called out, and always-on resources that commonly cause bill shock are flagged with rough monthly costs: ``` ── Plan Summary ── + 3 create, ~ 1 update, - 0 destroy, ± 0 replace 💸 EXPENSIVE — always-on resources being created: ⚠ aws_nat_gateway.main (~$32/month + data processing if left running) Remember to tf_destroy when you're done experimenting. ``` Cost-flagged resource types include NAT gateways, load balancers, EKS/AKS/GKE control planes, RDS/Cloud SQL instances, ElastiCache, Redshift, MSK, and Azure Firewall (~$900/month!). ### Drift detection `tf_drift` runs a refresh-only plan and reports resources that were changed outside Terraform (e.g. manually in the cloud console), with the changed attribute names and remediation options. ### Audit logging Set `AUDIT_LOG_PATH` to a file path and every tool call is appended as a JSON line with timestamp, tool name, outcome, and duration. Variable **values** are always redacted (`db_password=`) — only names are logged. ### Confirmation flow `tf_apply` and `tf_destroy` use a two-step safety flow: 1. **First call** (no `confirmed`) → runs `terraform plan`, shows the diff, does nothing else 2. **Second call** (`confirmed: true`) → actually applies or destroys Claude is instructed to never pass `confirmed: true` without first presenting the plan to you. ### Prompt The server exposes a `/tf-diagnose` prompt that guides Claude through a systematic 5-step diagnosis of plan or apply failures. ## Prerequisites - [Node.js](https://nodejs.org) 18 or later - [Terraform](https://developer.hashicorp.com/terraform/downloads) CLI on your PATH - [Claude Desktop](https://claude.ai/download) (or any MCP-compatible client) ## Installation No install needed — run it straight from npm: ```bash npx @rajsir/mcp-server-terraform ``` Or, for development, from source: ```bash git clone https://github.com/RajeevSirohi/mcp-server-terraform.git cd mcp-server-terraform npm install npm run build ``` ## Claude Desktop setup Add to your Claude Desktop config file: **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` ```json { "mcpServers": { "terraform": { "command": "npx", "args": ["-y", "@rajsir/mcp-server-terraform"] } } } ``` (If running from source instead, use `"command": "node"` with `"args": ["/absolute/path/to/dist/index.js"]`.) Restart Claude Desktop. You should see a hammer icon indicating tools are available. ## Usage Once connected, just talk to Claude about your Terraform workspaces in plain language. Some examples: ### First time in a new workspace > "Initialize the terraform config in `C:\infra\staging` and check if I'm logged into the right cloud accounts" Claude runs `tf_init`, then `tf_preflight` — if you're not authenticated it tells you exactly which command to run (`az login`, `aws configure`, ...). ### The everyday plan → review → apply loop > "Plan the changes in `C:\infra\staging` and explain what will change" You get the plan diff plus a summary: how many resources created/updated/destroyed, anything destructive called out explicitly, and cost warnings for expensive always-on resources. > "Looks good, apply it" Claude shows the plan preview one more time and asks for your confirmation — nothing is applied until you say yes. This two-step gate is built into the server itself, not just the prompt, so Claude *cannot* skip it. ### Checking on your infrastructure > "Did anyone change anything outside terraform in the prod workspace?" `tf_drift` compares state against reality and reports what was modified in the console, with options to accept or revert. > "Show me all the outputs" · "List everything in state" · "What workspaces exist?" ### Learning / experimenting (e.g. cert prep) > "Apply the VPC lab in `C:\labs\vpc`, and when I say 'done' destroy everything" The cost flags are your friend here — if a lab creates a NAT gateway or EKS cluster, the plan summary warns you what it costs per month if forgotten: ``` 💸 EXPENSIVE — always-on resources being created: ⚠ aws_nat_gateway.main (~$32/month + data processing if left running) Remember to tf_destroy when you're done experimenting. ``` ### Fixing things > "terraform plan is failing in `C:\infra\staging` — diagnose it" The `/tf-diagnose` prompt walks Claude through validate → providers → plan → state → outputs systematically. There's also `/tf-login` for step-by-step authentication setup per provider. > "Import the S3 bucket `my-legacy-bucket` into state as `aws_s3_bucket.legacy`" > "Taint the web server so it gets recreated on the next apply" ### Recommended setup for shared or cautious environments Run with `ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS=true` (see Safety modes below) so apply/destroy are unavailable entirely, and set `AUDIT_LOG_PATH` so every operation is logged. ## Safety modes Control which tools are available via environment variables: | Variable | Effect | |----------|--------| | `ALLOW_ONLY_READONLY_TOOLS=true` | Only `tf_validate`, `tf_plan`, `tf_output` | | `ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS=true` | Blocks `tf_apply`, `tf_destroy`, `tf_state mv/rm` | | `ALLOWED_TOOLS=tf_plan,tf_output` | Explicit comma-separated allowlist | Example — read-only mode: ```json { "mcpServers": { "terraform": { "command": "node", "args": ["/path/to/dist/index.js"], "env": { "ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS": "true" } } } } ``` ## Development ```bash npm run dev # watch mode (recompiles on save) npm test # run tests npm run build # production build ``` ### Project structure ``` src/ index.ts # MCP server entry point, tool registration config/ # (reserved for future config/telemetry) models/ common-parameters.ts # Shared Zod schemas security/ tf-flags.ts # Dangerous flag blocking tools/ tf-init.ts tf-validate.ts tf-plan.ts tf-apply.ts # Two-step confirmation flow tf-destroy.ts # Two-step confirmation flow tf-output.ts tf-state.ts tf-workspace.ts utils/ terraform-runner.ts # Core exec wrapper, workspace switching prompts/ index.ts # /tf-diagnose prompt tests/ tf-flags.test.ts tf-apply.test.ts ``` ### Adding a new tool 1. Create `src/tools/tf-yourcommand.ts` — export a `*Schema` const and an async handler function 2. Import both in `src/index.ts` 3. Add the schema to `readonlyTools` or `destructiveTools` array 4. Add a `case` in the `CallToolRequestSchema` handler switch ## Roadmap - [ ] Terraform Cloud / Enterprise API support (Phase 2) - [ ] OpenTelemetry tracing - [ ] SSE / streamable HTTP transport for remote deployments - [ ] Docker image on GitHub Container Registry - [x] Plan risk & cost analysis - [x] Drift detection - [x] Import / taint / untaint / refresh - [x] Audit logging - [x] CI (build, test matrix, e2e against real terraform) ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md). ## License MIT — see [LICENSE](LICENSE).