fcp-terraform
A reference implementation of the FCP pattern in Go, with an embedded fcpcore port (internal/fcpcore/). Terraform HCL is a format most LLMs already write fluently by hand, so this project's main value isn't as a production authoring tool -- it's as a working example of the 3-layer FCP architecture (MCP intent layer -> semantic domain model -> FCP core) implemented natively in Go against a real, non-trivial target format via HashiCorp's hclwrite.
What It Does
fcp-terraform lets an LLM build Terraform configurations by describing infrastructure intent -- resources, data sources, variables, outputs -- and renders them into valid HCL. Instead of writing raw HCL syntax, the caller sends operations like add resource aws_instance web ami:"ami-0c55b159" instance_type:t2.micro and fcp-terraform manages the semantic model, dependency graph, and serialization. Built on the FCP framework.
Written in Go using HashiCorp's hclwrite library for native HCL AST generation -- no string concatenation or template rendering.
Quick Example
terraform_session('new "Main Infrastructure"')
terraform([
'add resource aws_instance web ami:"ami-0c55b159" instance_type:t2.micro',
'add resource aws_s3_bucket assets bucket:"my-assets"',
'add variable region default:"us-east-1" type:string',
'add output instance_ip value:"aws_instance.web.public_ip"',
])
terraform_query('plan')
The plan query produces:
variable "region" {
type = string
default = "us-east-1"
}
resource "aws_instance" "web" {
ami = "ami-0c55b159"
instance_type = "t2.micro"
}
resource "aws_s3_bucket" "assets" {
bucket = "my-assets"
}
output "instance_ip" {
value = aws_instance.web.public_ip
}
Available MCP Tools
| Tool | Purpose |
|---|
terraform(ops) | Batch mutations -- add, set, remove, connect, nest, label, style |
terraform_query(q) | Inspect the config -- map, list, describe, plan, graph, find |
terraform_session(action) | Lifecycle -- new, open, save, checkpoint, undo, redo |
terraform_help() | Full reference card |
Verb Reference
| Verb | Syntax |
|---|
add resource | add resource TYPE LABEL [key:value...] |
add provider | add provider PROVIDER [region:R] [key:value...] |
add variable | add variable NAME [type:T] [default:V] [description:D] |
add output | add output NAME value:EXPR [description:D] |
add data | add data TYPE LABEL [key:value...] |
add module | add module LABEL source:PATH [key:value...] |
connect | connect SRC -> TGT [label:TEXT] -- emits a real depends_on = [...] entry on SRC's HCL block, in addition to recording the edge for the graph query |
set | set LABEL key:value [key:value...] |
nest | nest LABEL BLOCK_TYPE[/CHILD_TYPE] [key:value...] |
remove | remove LABEL or remove @SELECTOR |
label | label OLD_LABEL "new_label" |
style | style LABEL tags:"Key=Val,Key2=Val2" |
Selectors
@type:aws_instance All resources of a given type
@provider:aws All blocks from a given provider
@kind:resource All blocks of kind (resource, variable, output, data)
@tag:KEY or @tag:KEY=VAL Blocks matching a tag
@all All blocks
Installation
Go install
go install github.com/os-tack/fcp-terraform/cmd/fcp-terraform@latest
GitHub Releases
Download a prebuilt binary from Releases and put fcp-terraform on your PATH.
MCP Client Configuration
{
"mcpServers": {
"fcp-terraform": {
"command": "fcp-terraform"
}
}
}
Architecture
cmd/fcp-terraform/main.go MCP server — 4 tools, stdio transport
│
internal/terraform/ Domain layer
├── model.go Semantic model (blocks, attributes, connections)
├── adapter.go FCP adapter (dispatch ops → handlers)
├── handlers.go Verb handlers (add, set, remove, nest, etc.)
├── queries.go Query dispatcher (plan, graph, describe, etc.)
├── selectors.go @type, @provider, @kind, @tag, @all
├── values.go Attribute type inference, hclwrite value generation
├── verb_specs.go Verb specifications and reference card sections
├── block_ref.go Terraform reference detection
└── index.go Label index for O(1) lookups
│
internal/fcpcore/ Shared FCP framework (Go port)
├── tokenizer.go DSL tokenizer
├── parsed_op.go Operation parser
├── verb_registry.go Verb spec registry + reference card generator
├── event_log.go Event sourcing (undo/redo)
├── session.go Session lifecycle (new, open, save, checkpoint)
└── formatter.go Response formatter