Terraform CWD MCP Server

io.github.YawLabs由 GitHub 帳號 YawLabs 發布v0.1.2更新於 Oct 31, 2026

Terraform working-dir truth: pinned provider schemas, plans, state, modules, upgrade impact

概覽

AI 產生的概覽

唯讀 MCP 伺服器,讓助理掌握本機 Terraform 工作目錄的真實狀況:鎖定的 provider schema、已儲存的計畫、狀態與模組。

可以做什麼
  • 列出 provider 及其鎖定版本,並依名稱搜尋 resource、data 與 ephemeral 類型
  • 讀取某個類型在鎖定版本下的確切參數與巢狀區塊,並在撰寫前驗證打算使用的參數路徑
  • 彙整已儲存的計畫檔或計畫 JSON,優先列出刪除與取代,且不輸出實際值
  • 檢視根模組、本機路徑或已安裝模組的介面(變數、輸出、模組呼叫)
  • 列出狀態中的資源位址,並顯示單一實體的屬性,敏感值會被遮蔽
  • 將鎖定的 provider 與指定目標版本比對,回報升級會破壞哪些內容
適用情境
適合助理在 provider 版本已鎖定的儲存庫中撰寫或修改 Terraform 時使用,因為登錄文件與模型訓練資料可能描述其他版本。也適合審閱已儲存的計畫、檢視狀態與模組,以及在升級版本前評估影響。
執行需求
透過 npx 以 stdio 在本機執行,需要 Node.js 20+ 以及 PATH 中的 Terraform 或 OpenTofu。根模組必須已執行 terraform init(伺服器本身從不執行 init)。狀態工具需要已初始化的後端,且其憑證須位於伺服器環境中;升級影響在首次取得目標版本時需要存取登錄。可選環境變數可設定預設目錄、快取、執行檔與逾時。
安裝前請注意
狀態工具會使用從 MCP 用戶端繼承的憑證讀取遠端後端(S3、GCS、HCP),這些憑證因此暴露給該程序。tf_upgrade_impact 會下載目標 provider,並在暫存目錄中執行 terraform init 與 validate。伺服器對根模組、鎖定檔與狀態為唯讀,但會讀取呼叫中指定的任何目錄,且沒有權限沙箱。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Terraform CWD MCP Server,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

@yawlabs/terraform-cwd-mcp

[Add to Yaw MCP]

One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.

What is actually true in THIS Terraform working directory: the exact provider schemas pinned in your .terraform.lock.hcl (so coding agents stop writing arguments that do not exist, were removed, or are read-only), plus your saved plans, your state (redacted), your local and installed modules, and what a provider upgrade would break. It complements HashiCorp's terraform-mcp-server rather than replacing it: that server answers from the Terraform Registry docs, which describe the latest provider release; this one answers from terraform providers schema -json in your root module, which describes the version you actually locked. Run both.

[npm version] [License: MIT]

Built and maintained by Yaw Labs.

Why this one?

Your lock file says hashicorp/aws 5.31.0; the registry docs (and the model's training data) say whatever came later or earlier. Agents then write arguments that were added after your pin, removed before it, or are computed-only and cannot be set at all. terraform validate catches it -- after the code is written. This server lets the agent check before it writes.

  • Pinned, not latest -- the source of truth is terraform providers schema -json run in your root module, with versions read from .terraform.lock.hcl.
  • Read-only, never inits -- it never runs terraform init (no downloads, no backend contact, no lock-file rewrites). An uninitialized directory gets an actionable error telling you what to run.
  • Cached per lock file -- dumps are cached in memory and on disk, keyed on the root path plus the lock file's bytes, so a provider upgrade invalidates the cache automatically. The AWS provider's schema is tens of MB; you pay for that dump once per lock-file change, not per question.
  • Small answers -- tf_get_schema renders one type as a compact indented outline with required / optional / optional+computed / computed (read-only), [deprecated], [sensitive] and [write_only] flags, instead of handing the model raw JSON.
  • Cross-platform -- macOS, Linux and Windows. Terraform is spawned directly (no shell) and its output is streamed, so there is no buffer ceiling.

Tools

ToolWhat it does
tf_list_providersProviders in the root module with their pinned versions and resource / data / ephemeral counts. Call this first.
tf_search_typesFind type names containing a substring (s3_bucket), per kind.
tf_get_schemaEvery argument and nested block of one type at the pinned version, with mode and flags. Use before writing or editing a block.
tf_check_argumentsValidate dotted paths (["bucket", "versioning.enabled"]) and get ok, ok (block) (either with [deprecated]), READ-ONLY (computed), '<x>' is an attribute, not a block or UNKNOWN per path.
tf_summarize_planSummarize a saved plan (plan_file: binary from terraform plan -out, or plan JSON) or plan JSON text (plan_json, e.g. an HCP run's plan fetched by the official server). Deletes and replaces first, with the attribute that forces each replace; then updates (changed paths), creates, imports, moves, forgets, drift, deferred changes and outputs; Terraform's own Plan: counts; a destroy warning naming renames that need a moved block. Prints no values.
tf_module_interfaceVariables (exact type expression, required/optional, default, [sensitive] / [not nullable] / [ephemeral], validation count), outputs and module calls of the root, a local module path, or an installed module by address (module.network, incl. downloaded registry/git modules). Flags module calls that are not installed or stale. No subprocess.
tf_state_addressesResource instance addresses in the current state (terraform state list), with a substring filter and id lookup.
tf_show_resourceOne instance's attribute values from state (terraform show -json), with sensitive values redacted and a footer saying what was hidden and why.
tf_upgrade_impactWhat breaks if a pinned provider moves to an exact version: the arguments, nested blocks, attribute reads and provider block arguments your configuration (root + installed modules) uses that are removed, read-only, retyped, newly required or deprecated in the target; version constraints that block it; confirmed by terraform validate on a temp copy.

Every tool takes an optional dir (the root module); kind is resource (default), data or ephemeral.

Division of authority with HashiCorp's official server. This server wins on argument validity for the version you pinned and on what this directory's plan, state and modules contain. The official server wins on usage docs, latest versions, public registry modules and HCP/TFE runs. For an HCP run's plan, get its plan id there (get_run_details), fetch the plan with get_plan_json_output(plan_id) and pass the JSON to tf_summarize_plan as plan_json (those tools need the official server's terraform toolset and TFE_TOKEN).

What is read-only, and what touches the network

  • Never written: your root module, its .terraform/, its lock file and its state. terraform init is never run in it.
  • State tools (tf_state_addresses, tf_show_resource) run terraform state list / terraform show -json, which never lock and never refresh. With a remote backend they read S3/GCS/HCP with the credentials the server inherited from its MCP client. Selecting a non-default workspace that does not exist would make Terraform create it (the s3 backend writes an empty state), so the server checks terraform workspace list first and refuses.
  • tf_upgrade_impact downloads the target provider version with terraform init in a throwaway temp dir into a plugin cache (TERRAFORM_CWD_MCP_PLUGIN_CACHE, else your TF_PLUGIN_CACHE_DIR, else <cache>/plugins), then runs terraform validate on a temp copy of your configuration whose .terraform/providers entries are links to the packages you already have. State and *.tfvars are never copied. Calls are serialized (the plugin cache is not safe for concurrent installs).
  • Redaction (tf_show_resource): Terraform's sensitive markers, plus any string equal to (or containing) a marked value anywhere in state, plus values under secret-like keys (password, api_token, client_secret, ... but not password_length or secret_arn), plus secret-shaped strings (private keys, JWTs, GitHub/GitLab/Slack/npm tokens; URL passwords are masked in place). There is deliberately no "show sensitive" switch. Unmarked derived values Terraform itself shows (e.g. content_md5 of a sensitive file) are printed.
  • Every terraform child gets CHECKPOINT_DISABLE=1, so no version check phones home.

Example tf_summarize_plan output (real plan, abridged):

plan (terraform 1.15.7, format 1.2): applyable, completetotals: 1 delete, 5 replace, 1 update, 1 create, 0 read, 1 import, 1 move, 1 forget, 0 unchanged (terraform: 1 to import, 6 to add, 1 to change, 6 to destroy)DELETE (1)  - null_resource.gone (not in configuration)REPLACE (5)  -/+ local_sensitive_file.sf delete-then-create; forced by: content [sensitive]  +/- random_string.cbd create-before-destroy; forced by: keepers  ...UPDATE (1)  ~ terraform_data.cfg: input.version, output (known after apply)WARNING: 6 object(s) will be destroyed (1 delete, 5 replace). 1 moved block(s) applied; none covers these.

Example tf_upgrade_impact output (real validate run):

upgrade hashicorp/random 2.3.1 -> 3.6.3 (major) for /work/infraconstraints: root pins 2.3.1 as local name rnd (change it to allow 3.6.3)used types: resource random_password, random_idaffected arguments (2):  random_password.p.number (main.tf:18): DEPRECATED in 3.6.3  reads random_id.i.b64 (main.tf:36): REMOVED in 3.6.3validate on a temp copy, 3.6.3 vs 2.3.1: 1 new error, 1 new warning, 1 warning resolved  error main.tf:36: Unsupported attribute - This object has no argument, nested block, or exported attribute named "b64".  warning main.tf:18 random_password.p: Attribute Deprecated - **NOTE**: This is deprecated, use `numeric` instead.verdict: BREAKING (1 error after upgrade)

Example tf_get_schema output:

resource random_password (registry.terraform.io/hashicorp/random 3.9.1)  bcrypt_hash: string computed (read-only) [sensitive] - A bcrypt hash of the generated random password. ...  keepers: ["map","string"] optional - Arbitrary map of values that, when changed, will trigger recreation of resource. ...  length: number required - The length of the password desired. ...  number: bool optional+computed [deprecated] - Include numeric characters in the result. ...  result: string computed (read-only) [sensitive] - The generated random password.

Quick start

1. Initialize the root module once (you, not the server):

bash
terraform init -backend=false

-backend=false is enough: the schema only needs the providers, not state.

2. Add the server. Claude Code, from the root module:

bash
# macOS / Linux / WSLclaude mcp add terraform-cwd -- npx -y @yawlabs/terraform-cwd-mcp@latest
# Windowsclaude mcp add terraform-cwd -- cmd /c npx -y @yawlabs/terraform-cwd-mcp@latest

Or add it to .mcp.json in the root module (or anywhere, and set TERRAFORM_CWD_MCP_DIR):

macOS / Linux / WSL:

json
{  "mcpServers": {    "terraform-cwd": {      "command": "npx",      "args": ["-y", "@yawlabs/terraform-cwd-mcp@latest"]    }  }}

Windows:

json
{  "mcpServers": {    "terraform-cwd": {      "command": "cmd",      "args": ["/c", "npx", "-y", "@yawlabs/terraform-cwd-mcp@latest"]    }  }}

Why the extra step on Windows? Since Node 20, child_process.spawn cannot directly execute .cmd files (that's what npx is on Windows). Wrapping with cmd /c is the standard workaround.

3. Restart your MCP client and ask, for example: "Add a versioned S3 bucket -- check the arguments against our pinned AWS provider first."

Tell your agent to use it

Agents use the server reliably when the project tells them to. Paste this into the root module's CLAUDE.md (or AGENTS.md):

markdown
## Terraform provider schemas
This repo pins provider versions in `.terraform.lock.hcl`; registry docs and yourtraining data describe other versions. Use the terraform-cwd MCP server:
- Call `tf_list_providers` once per session to see the pinned versions.- Before writing or editing any `resource`, `data` or `ephemeral` block, call  `tf_get_schema` for that type.- Call `tf_check_arguments` with every argument path you set (dotted for nested  blocks, e.g. `versioning.enabled`). Never use an argument it reports as  `UNKNOWN` or `READ-ONLY (computed)`; replace a `[deprecated]` one if the  schema offers an alternative.- Before calling a module, read its inputs with `tf_module_interface`.- After `terraform plan -out=tfplan`, review it with `tf_summarize_plan`  (plan_file: tfplan) and call out every DELETE and REPLACE.- Before bumping a provider version, run `tf_upgrade_impact`.

Pairs well with

HashiCorp's terraform-mcp-server

hashicorp/terraform-mcp-server answers registry and HCP questions; this server answers what is true in your working directory. Run both -- they do not overlap, and when they disagree the table says who wins:

QuestionAuthority
Is argument X valid for the provider version I have pinned?terraform-cwd-mcp
Which arguments I use break if I upgrade to vN?terraform-cwd-mcp (tf_upgrade_impact)
What does this saved plan, this state, or this local / installed module contain?terraform-cwd-mcp
How is resource X meant to be used? What do the docs and examples say?terraform-mcp-server
What is the latest provider or module version?terraform-mcp-server
Which public registry module should I use?terraform-mcp-server
HCP Terraform / TFE workspaces and runsterraform-mcp-server
An HCP run's planterraform-mcp-server fetches it (get_run_details -> plan id -> get_plan_json_output(plan_id)); tf_summarize_plan summarizes it (plan_json)

The official server starts with only its registry toolset. The HCP / TFE rows need it started with --toolsets=registry,terraform (or all) and TFE_TOKEN. Its docs search tool is search_provider_docs from v1.3.1 on (search_providers before; a BREAKING rename), which matters if you allowlist tools by name.

Yaw Mode skills

Yaw Terminal's Yaw Mode ships four skills that drive both servers, degrade gracefully when either is missing, and stop at terraform plan (they never apply or destroy):

  • /yaw-tf -- everyday write / edit / fix: check every argument against the pinned schema, then fmt, validate, plan and summarize; hands off to the three below.
  • /yaw-tf-refactor -- renames, module moves and imports with moved / import / removed blocks, done only when the plan shows zero destroys and replaces.
  • /yaw-tf-plan-review -- go / no-go punch list for a local saved plan or an HCP run: destroys first, then checkov / trivy and IAM, network and encryption hot spots.
  • /yaw-tf-upgrade -- provider bumps: latest version, tf_upgrade_impact against the arguments you actually use, the upgrade guide, then edits, re-pin, validate and plan.

Configuration

All optional.

Env varDefaultPurpose
TERRAFORM_CWD_MCP_DIRthe server's working directoryRoot module used when a tool call passes no dir.
TERRAFORM_CWD_MCP_CACHE~/.cache/terraform-cwd-mcpWhere schema dumps are cached (<key>.json). Safe to delete at any time.
TERRAFORM_CWD_MCP_BINARYterraformBinary to run, e.g. a full path, or tofu for OpenTofu (same providers schema -json output).
TERRAFORM_CWD_MCP_TIMEOUT_MS300000Kill any terraform command (schema dump, state read, target init, validate) after this long.
TERRAFORM_CWD_MCP_PLUGIN_CACHETF_PLUGIN_CACHE_DIR, else <cache>/pluginsWhere tf_upgrade_impact keeps downloaded provider packages.

Runtime (oam or Node):

The terraform-cwd-mcp command prefers oam when it finds a usable one and otherwise runs on Node. It never serves on an oam older than 0.19.1.

Env varDefaultPurpose
TERRAFORM_CWD_MCP_RUNTIMEautoauto: the newest oam at 0.19.1 or newer, else Node. oam: oam or exit with an error. node: always Node -- the escape hatch when a problem only shows up under oam.
OAM_BIN(unset)Path to the oam binary to use. Otherwise the launcher checks OAM_INSTALL_DIR, the installed locations (~/.oam/bin, and %LOCALAPPDATA%\oam\bin on Windows) and PATH, and takes the newest.

An outdated oam is fixed with oam self-update. Under Yaw MCP, which runs servers on oam by default, yaw-mcp set <namespace> runtime=node switches this server to Node. There is no --permission sandbox option: the server spawns terraform and reads whatever directory a call names, so there is nothing narrow to grant.

Requirements

  • Node.js 20+
  • Terraform (or OpenTofu) on PATH, recent enough to have terraform providers schema -json (0.12+; ephemeral resources need 1.10+)
  • An initialized root module (.terraform/ and .terraform.lock.hcl present) for every tool except tf_module_interface on the root or a local path, and tf_summarize_plan with plan JSON
  • State tools: the backend initialized (terraform init, not -backend=false) and its credentials in the server's environment
  • tf_upgrade_impact: registry access the first time a target version is requested (later runs for that version are offline)
  • .terraform/ at <dir>/.terraform: TF_DATA_DIR is not honoured

Contributing

bash
git clone https://github.com/YawLabs/terraform-cwd-mcp.gitcd terraform-cwd-mcpnpm installnpm run lint       # Biome checknpm run lint:fix   # Auto-fixnpm run build      # tsup bundle + declarationsnpm test           # Vitest (the integration test runs only when terraform is on PATH)npm run typecheck  # oam check . when oam is installed, else tsc --noEmitnpm run check:oam-floor  # the oam floor agrees across the repo and matches the latest oam release

See CONTRIBUTING.md for the full workflow, including release process.

License

MIT

[Follow @YawLabs on X]

來源:README.md,提交 edae790

工具

9

tf_list_providers

List providers and their PINNED versions for a Terraform root module (default: cwd). Call this first so code targets the versions actually locked in .terraform.lock.hcl, not the latest release. Lists only the providers locked in THIS directory; it does not search the registry. For registry search, provider docs or the latest version, use the official terraform MCP server (search_provider_docs / get_latest_provider_version).

輸入參數dir

tf_search_types

Find resource / data source / ephemeral resource type names containing `query` (e.g. 's3_bucket') in the pinned providers. kind: resource | data | ephemeral.

輸入參數dirkindlimitquery必填

tf_get_schema

Exact arguments and nested blocks for one type at the PINNED provider version. Use BEFORE writing or editing any resource/data/ephemeral block; only arguments listed here exist. 'computed (read-only)' attributes cannot be set. kind: resource | data | ephemeral.

輸入參數dirkindmax_depthtype_name必填description_chars

tf_check_arguments

Validate argument / nested-block paths against the PINNED schema before writing them, e.g. ["bucket", "region", "versioning.enabled"]. Flags unknown, read-only and deprecated paths.

輸入參數dirkindarguments必填type_name必填

tf_summarize_plan

Summarize a saved Terraform plan: deletes and replaces first (with the attribute that forces each replace), updates with changed paths, creates, imports, moves, forgets, drift and output changes, plus a destroy warning that names renames needing a moved block. Pass plan_file (binary from `terraform plan -out`, rendered with `terraform show -json` in dir, or a plan JSON file) or plan_json (e.g. from the official terraform MCP server's get_plan_json_output(plan_id) for an HCP run; get the plan id from its get_run_details). Prints no values: sensitive paths are truncated, import IDs omitted.

輸入參數dirmax_pathsplan_fileplan_jsonmax_per_section

tf_module_interface

Variables (exact type expression, required/optional, default, sensitive/nullable/ephemeral, validation count), outputs and module calls of a module in THIS working directory: the root, a local module directory, or an installed module by address (module.network, resolved through .terraform/modules/modules.json, so downloaded registry/git modules work). Module calls are checked against what is installed. For public registry modules you have not installed, use the official terraform MCP server.

輸入參數dirmoduledescription_chars

tf_state_addresses

List resource instance addresses in the current Terraform state (terraform state list), optionally filtered. Read-only: never locks, never refreshes. With a remote backend this reads S3/GCS/HCP using the server's credentials; a non-default workspace that does not exist is refused (reading it would create it).

輸入參數iddirlimitfilter

tf_show_resource

Show one resource instance's attribute values from the current Terraform state (terraform show -json). Read-only: never locks, never refreshes. Sensitive values are redacted: Terraform's own markers, plus values equal to a marked one, secret-like names and secret-shaped strings; a footer says what was hidden and why.

輸入參數diraddress必填include_nullmax_value_chars

tf_upgrade_impact

What breaks if a pinned provider is upgraded (or downgraded) to an exact version: compares the pinned schema with the target's for the arguments, nested blocks and attribute reads this configuration uses (root and installed modules), checks version constraints, and confirms with terraform validate on a temp copy. Downloads the target provider from the registry into a cache (temp dirs only; never touches dir). For the latest version number or upgrade guides, use the official terraform MCP server.

輸入參數dirversion必填provider必填validateinclude_unused

版本歷史

3
  1. v0.1.2最新Oct 31, 2026
  2. v0.1.1Oct 17, 2026
  3. v0.1.0Oct 16, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分