Make a change through an agent
This walkthrough takes you through the full write path: ask an agent to update something in Infrahub, watch it auto-create an isolated session branch, and open a Proposed Change for human review. No data on your default branch is modified until a human approves the merge.
Prerequisites
- The First agent run walkthrough is complete (server reachable, client connected, read-only calls working).
INFRAHUB_MCP_READ_ONLYis not set (or isfalse) — writes are enabled.- Your Infrahub API token has permission to create branches and proposed changes.
How it works
Every write starts by auto-creating a session branch on the first mutation. The default naming pattern is:
mcp/session-YYYYMMDD-<hex>
All subsequent writes in the same MCP session go to the same branch. When the agent calls propose_changes, Infrahub opens a CoreProposedChange (a pull-request equivalent) from the session branch back to the default branch. A human reviews, approves, and merges — only then does the change land.
You can customize the pattern via INFRAHUB_MCP_BRANCH_PATTERN. Supported placeholders:
| Placeholder | Resolves to |
|---|---|
{date} | Current date in YYYYMMDD format |
{hex} | Short random hex suffix for uniqueness |
{user} | Authenticated user identity (OIDC mode only — see Authentication architecture) |
If the generated branch already exists (rare, with {hex}), the server retries up to INFRAHUB_MCP_MAX_BRANCH_RETRIES times (default 5).
1. Ask the agent to make a change
In your MCP client, prompt something like:
Update the description of the device named
leaf-01to"Rack 3A, upgraded 2026-04".
The agent should:
- Discover the schema — read
infrahub://schemaand theninfrahub://schema/{kind}for the relevant device kind to confirm the attribute name. - Look up the node — call
search_nodes(query="leaf-01", kind="...")orget_nodeswith aname__valuefilter to resolve the UUID or human-friendly ID. - Create the session branch — happens implicitly on the first write. You'll see it in the
infrahub://branchesresource. - Call
node_upsertwithidorhfidto update thedescriptionattribute. - Confirm the write — report the branch name and node ID.
2. Open a Proposed Change for review
Follow up with:
Open a proposed change titled "Update leaf-01 description" so the team can review.
The agent calls propose_changes(title=..., description=..., destination_branch=...). The response includes the CoreProposedChange ID and the source/destination branches. The session branch stays active, so you can keep making related changes and they'll all show up in the same proposed change.
3. Review in Infrahub
Open the Infrahub UI and navigate to Proposed Changes. The change you just opened will show:
- The diff between the session branch and the default branch.
- The agent that created the branch (in audit logs, if OIDC is enabled).
- Any check results, if you have Infrahub checks configured.
Approve and merge when ready. Until a human approves, the default branch is untouched.
Guardrails at a glance
- Branch isolation — every write lives on an ephemeral session branch; the default branch is never modified directly.
- Read-only kill switch — setting
INFRAHUB_MCP_READ_ONLY=truehides all write tools from discovery and rejects calls that hardcode them. - Scope gating (OIDC only) — set
INFRAHUB_MCP_AUTH_SCOPES_WRITE=infrahub:writeto require a specific OAuth scope for write tools. - Audit logs — every tool call is logged with a request ID, tool name, branch, and (under OIDC) the authenticated user.
- Human approval —
propose_changesis the only way changes reach the default branch. Agents cannot merge.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
node_upsert fails with "kind not found" | Schema name mismatch (case, namespace) | Ask the agent to read infrahub://schema first and copy the exact kind name. |
| Agent tries to update a relationship and fails | node_upsert accepts scalar attributes only | Use mutate_graphql with a GraphQL mutation for relationship changes. |
propose_changes returns an error about no changes | Session branch is empty | Make at least one successful node_upsert / node_delete / mutate_graphql call before proposing. |
| Write tools are hidden from the agent | Server is in read-only mode, or user lacks the write scope | Check INFRAHUB_MCP_READ_ONLY and INFRAHUB_MCP_AUTH_SCOPES_WRITE on the server. |
Next steps
- Safe changes via branch isolation — deeper look at the branch-per-session model.
- Brownfield network onboarding — use the write path to bulk-import existing state.
- Methods reference — every tool, resource, and prompt the server exposes.