Skip to content

Have an agent propose a change over MCP

llms.txtlists every page for an agent
Optional: hand this page to your coding agentThe steps work by hand too.
Show the whole prompt
Read https://intentius.io/terragucci/guides/agent-propose-over-mcp/.
Tell me the command line and the environment variables to add terragucci mcp --propose to my MCP client for this repo, and the terragucci guard command to run; do not add or run either yourself, and do not create or print credentials.
Never apply, approve (a pull request review or `terragucci approve`), override a policy denial (`terragucci override`), use `--mode apply`, or merge; never touch `.chant/allowed_signers` or `chant/lifecycle`.

A coding agent working in a checkout gets its change planned by the pipeline without leaving its MCP client. It commits to a branch, and terragucci mcp --propose pushes the branch, opens a pull request and reads back the plan note and the policy result. A person still approves the apply. terragucci guard makes the local shortcut, an apply with the agent’s own credentials, refuse.

The agent’s plan_result call on the pull request it opened:

{
"pull_request": 7,
"state": "open",
"head": "9c1e0b7a4d2f8e6c3b5a1f0e9d8c7b6a5f4e3d2c",
"planned": true,
"report": "github.com/acme/infra/2026/10/9c1e0b7a4d2f8e6c3b5a1f0e9d8c7b6a5f4e3d2c/tf-plan",
"plan": {
"roots": [{ "path": "envs/prod/app", "status": "planned", "counts": { "update": 1 }, "policy": { "result": "passed", "denials": [], "warnings": [] } }],
"gate": [{ "wave": 1, "roots": ["envs/prod/app"], "waits": true }]
}
}

waits: true says the wave’s gate will hold it for an approval when the pull request merges.

You need Why
The pipeline on the repo, with reports.bucket set plan_result reads the head’s plan report from the bucket
A forge token in the environment the client starts the server from, in the variable token_env names (GITHUB_TOKEN, GITLAB_TOKEN or FORGEJO_TOKEN by default) the server opens the pull request and posts comments with it, never with a token from the agent
git credentials that can push a branch to origin, in the same environment the server pushes with git’s own credentials
  1. Add the server to your MCP client with --propose, from the repo’s root:

    {
    "mcpServers": {
    "terragucci": {
    "command": "npx",
    "args": ["-y", "@intentius/terragucci", "mcp", "--propose"],
    "env": {
    "GITHUB_TOKEN": "${GITHUB_TOKEN}",
    "AWS_ACCESS_KEY_ID": "${AWS_ACCESS_KEY_ID}",
    "AWS_SECRET_ACCESS_KEY": "${AWS_SECRET_ACCESS_KEY}",
    "AWS_REGION": "us-east-1"
    }
    }
    }
    }

    The AWS variables are the reports bucket’s read credentials (Read the estate over MCP). Give the forge token the least it needs: contents and pull requests write on one repository.

  2. Write the guard into the checkout:

    Terminal window
    npx terragucci guard

    It writes wrappers for tofu, terraform, terragrunt and choudoufu under the git directory, and a PreToolUse hook into .claude/settings.local.json, which Claude Code reads. For any other agent, put the wrappers ahead of the binaries in the agent’s shell with the export PATH=... line it prints. Run it again after adding or moving a root.

  3. Have the agent work the loop:

    Step Tool
    commit the change to a local branch git, in the checkout
    push the branch and open a pull request propose, with branch, title and body
    wait for the pipeline’s plan of the head, and read the note, the policy’s denials and whether the gate will hold each wave plan_result, with pull_request and wait
    fix what the plan or the policy found, commit and push again git, then propose again on the same branch
    plan again without a push, or one root alone request_plan, which comments /terragucci plan [root]

    Then the agent stops. A reviewer merges, and the merge’s apply goes through the gate like any other.

A call The answer
propose of the default branch, chant/lifecycle, or a branch apply.branches names an error, and nothing is pushed
propose of a branch with no local commit an error
propose of a branch origin has moved past git’s refusal: the push is never forced
propose with the token’s variable unset an error naming the variable
any tool with an argument it does not list, such as token an error naming the argument: credentials come from the server’s environment
approve, apply, override, merge, or any tool not listed an error: these belong to a person
In a root of the pipeline The guard
apply, destroy, import, taint, untaint, force-unlock, state rm, state mv, state push, state replace-provider, any command with -auto-approve refuses with a message naming propose, and runs nothing
terragrunt run --all apply or run-all apply from a directory that holds a root refuses
init, validate, fmt, plan, show, output, state list runs the real binary

Outside the pipeline’s roots, the wrappers run every command. The hook also refuses terragucci approve, override, stage tf-apply, unlock-state, pr-merge and --mode apply anywhere in the repo.

The guard catches an agent that holds credentials it should not use. An agent that calls a binary by a path the hook does not see, runs it from a script, or edits the hook gets past it. The control is the credentials: a plan role that cannot write, per-environment state roles (oidc.roles), and approvals bound to the plan digest. The threat model lists what each one stops.

terragucciHelp setting it up: Intentius

These docs count page views and clicks with PostHog. They set no cookies, store nothing in your browser, and send nothing when your browser asks not to be tracked.