DEV Community

ひとし 田畑
ひとし 田畑

Posted on

The Terraform MCP server has 35+ tools and none of them can see the resource I made in the console

Everything is getting an MCP server, and Terraform is no exception — HashiCorp
ships an official one now. Point your AI at it and you get 35+ tools: search the
provider registry, pull module inputs and examples, look up Sentinel policies,
list and drive HCP Terraform workspaces, runs, and variables. As an
Infrastructure-as-Code copilot it's genuinely great.

I build a drift detector, so I asked it the one question I always ask any new
Terraform tool: can you find the security group my coworker opened by hand in
the AWS console last Tuesday?

No. And — this is the interesting part — it structurally can't, for the exact
same boring reason terraform plan can't. A shiny AI wrapper doesn't patch the
hole; it inherits it.

What the Terraform MCP server actually sees

Look at what its tools are grouped into: provider docs, module registry
metadata, policy (Sentinel), and HCP Terraform / Enterprise workspace
management — runs, variables, tags, stacks. Notice what's not in that list:
there is no scan_aws_account, no list_untracked_resources, nothing that
reaches into a live cloud and enumerates what's really there.

When anything in that ecosystem "detects drift," it bottoms out at the same
command it always has:

terraform plan -refresh-only
Enter fullscreen mode Exit fullscreen mode

Refresh reconciles your state file against the real world. For every resource
already in state, it re-reads the live attributes and shows you what moved.
That's the whole mechanism — and the whole limitation.

The blind spot is the data source, not the interface

Here's the part that no amount of AI changes. terraform plan starts from
state and asks: "do the things I already know about still match reality?"

So the resources it can tell you about are exactly the resources Terraform put
there. The security group someone created in the console has no state entry.
There's no row to refresh, nothing to compare, so plan — and by extension the
MCP server orchestrating it — reports a clean, confident "No changes."

The most dangerous drift isn't a managed resource that wandered. It's the
resource that was never managed at all: the emergency S3 bucket, the
click-ops RDS instance, the SG opened to 0.0.0.0/0 at 2am during an incident.
State-based tooling is blind to all of it by construction, because you can't
refresh a row that doesn't exist.

Start from the cloud, not from the state

My tool asks the opposite question — not "does my state still match?" but
"what is actually in this account?" — by listing the account directly with
boto3:

def scan_ec2(session):
    ec2 = session.client('ec2')
    for page in ec2.get_paginator('describe_instances').paginate():
        for reservation in page['Reservations']:
            for inst in reservation['Instances']:
                yield normalize(inst)   # everything AWS has, not what tf knows
Enter fullscreen mode Exit fullscreen mode

There's one of these per service — EC2, S3, security groups, RDS, and so on —
each just enumerating what the API says is live. Then it diffs that against the
imported tfstate. A resource that shows up in the scan with no matching state
entry
is the thing terraform plan will never mention: real, running, and
unmanaged.

The difference is entirely in where you begin. State-first tools can only ever
describe the map they were handed. Cloud-first tools describe the territory.

To be fair to the MCP server

None of this is a knock on the Terraform MCP server — it's aimed at a different
job, and it's good at it. Authoring config against current provider docs,
discovering modules, wiring up HCP workspaces and runs, checking policy: those
are real wins, and having an AI do them against live registry data instead of
its stale training memory is exactly right.

It just isn't a cloud-discovery tool, and "add an MCP server" doesn't turn a
state-based engine into one. If your worry is config authoring, reach for it.
If your worry is what did someone spin up behind Terraform's back, you need
something that queries the cloud, not the state.

Takeaways

  • The official Terraform MCP server is a registry + HCP-orchestration copilot. Its 35+ tools do not include live cloud discovery.
  • Any drift it surfaces still runs through terraform plan -refresh-only, which only reconciles resources already in state.
  • Console-made ("click-ops") resources have no state row, so state-based tooling — CLI or MCP — is blind to them by construction. This is a data-source limit, not a UX one.
  • To catch unmanaged resources you have to invert the question: list the cloud directly and diff that against state, not the other way around.

This is the core of a self-hosted tool that scans your live AWS and flags what
Terraform never planted — open source (MIT), one docker compose up:
syncvey.com. When a resource appears in your account that
nobody wrote HCL for, what catches it today — a scheduled scanner, a CSPM tool,
or an angry bill at the end of the month?

Top comments (0)