Infrahub Source of Truth
MCP Server
- Repository: opsmill/infrahub-mcp
- Version: 1.1.7+ (reworked — first stable release + production hardening)
- Distribution: PyPI (
pip install infrahub-mcp), Docker (registry.opsmill.io/opsmill/infrahub-mcp), or from source
- Entry point:
infrahub-mcp console script
- Transport:
stdio (default) or streamable-http (remote clients / auth modes)
- Requires:
INFRAHUB_ADDRESS + (INFRAHUB_API_TOKEN or INFRAHUB_USERNAME+INFRAHUB_PASSWORD)
- Python: 3.13+
- Dependencies:
fastmcp>=3.2.0, infrahub-sdk>=1.20.0
- Docs: docs.infrahub.app/mcp (per-client setup, auth, configuration)
What changed in the rework: the server moved to a modular src/infrahub_mcp/ layout on
FastMCP 3.x, added a branch-isolated write model (writes never touch the default branch),
exposes MCP resources and prompts in addition to tools, serializes schema output with TOON
internally to cut tokens, and ships as a PyPI package + Docker image with optional auth,
rate limiting, caching, and OpenTelemetry/Prometheus observability. The old read-only tool
surface (get_node_filters, get_related_nodes, get_schema_mapping, get_schemas,
get_graphql_schema, get_branches, branch_create) has been replaced — see the table below.
How Infrahub Differs
Infrahub is not just another IPAM/DCIM tool. Key differentiators:
- Schema-driven — define your own infrastructure models (not just built-in IPAM/DCIM). Devices, circuits, IP addresses, services, cloud resources — any infrastructure object can be modeled.
- Versioned branches — Git-like branching for infrastructure data. Changes are made on a branch, reviewed as a diff, and merged when approved. No more "who changed this in production?"
- GraphQL-native — full GraphQL API for flexible queries, not just REST. Query exactly the fields you need, traverse relationships in a single request.
- Relationship-first — rich relationship model between objects with relationship-level filters and traversal.
Safety Model: Branch-Isolated Writes
The reworked server makes destructive operations safe by construction:
- Writes never hit the default branch. On the first write in a session, the server lazily
auto-creates a session branch named
mcp/session-YYYYMMDD-<hex> (pattern configurable via
INFRAHUB_MCP_BRANCH_PATTERN). All node_upsert / node_delete / mutate_graphql land there.
- Human review is mandatory to merge.
propose_changes opens a Proposed Change (PR) from
the session branch to the default branch — a human reviews and merges it in the Infrahub UI. The
agent never merges.
- Session-branch recovery. Stale/merged/deleted session branches are validated before reuse and
auto-recovered on the next write;
reset_session_branch clears or switches the active branch.
- Read-only mode. Setting
INFRAHUB_MCP_READ_ONLY=true hides all write tools and blocks GraphQL
mutations — use it for pure analysis/audit connections.
MCP Tools (10 tools)
Read Tools (5)
| Tool |
Parameters |
What It Does |
get_nodes |
kind, filters?, partial_match?, include_attributes?, offset?, limit?, branch? |
Typed read of nodes of a kind. Supports attribute/relationship filters (attr__value, rel__attr__value), partial matching, and paging (returns total_count/has_more). |
search_nodes |
kind, value, branch? |
Find nodes of a kind by partial substring via Infrahub's any__value filter. Works on concrete and abstract/generic kinds. |
get_schema |
kind?, branch? |
Discover schema kinds (catalog) or, given a kind, its attributes/relationships/filter-map (TOON-encoded). Tool fallback for clients without MCP resources. |
get_session_info |
none |
Report current session state — active session_branch, infrahub_address, has_session_branch. Call before writes to know the target branch. |
query_graphql |
query, branch? |
Execute a read-only GraphQL query (mutations are rejected here). |
Write Tools (5) — hidden when INFRAHUB_MCP_READ_ONLY=true
| Tool |
Parameters |
What It Does |
node_upsert |
kind, data, ... |
Create or update a node on the active session branch. |
node_delete |
kind, id |
Delete a node on the active session branch. |
mutate_graphql |
mutation, ... |
Execute a GraphQL mutation (relationship edits / bulk ops typed tools can't express). Branch/schema-management mutations are blocked. |
propose_changes |
title?, description? |
Open a Proposed Change from the session branch to the default branch for human review. |
reset_session_branch |
branch? |
Clear the cached session branch (next write creates a fresh one) or point the session at a named branch. Rejects the default branch and merged/read-only branches. |
Resources (3 + 1 template)
| Resource URI |
Content |
infrahub://schema |
Kind catalog (JSON) |
infrahub://schema/{kind} |
Per-kind schema + filter map (template) |
infrahub://graphql-schema |
Full GraphQL SDL (text) |
infrahub://branches |
All branches including the session branch (JSON) |
Prompts (4)
infrahub_agent (system prompt; read-only vs read-write aware), answer_infra_question,
make_infra_change, explore_schema.
Workflow: Discover Available Data
When first connecting to Infrahub:
- List kinds: read resource
infrahub://schema (or get_schema with no kind) — what infrastructure types are modeled?
- Inspect schema:
get_schema(kind="InfraDevice") — what attributes and relationships does a device have?
- Get nodes:
get_nodes(kind="InfraDevice") — list all devices (page with offset/limit).
- Report: infrastructure data model overview with node counts per kind.
Workflow: Infrastructure Audit
When auditing infrastructure state in Infrahub:
- Schema overview:
get_schema (no kind) — discover all kinds.
- Device inventory:
get_nodes(kind="InfraDevice") — all devices.
- IP addresses:
get_nodes(kind="InfraIPAddress") — all IPs (if IPAM is modeled).
- Prefixes:
get_nodes(kind="InfraPrefix") — all subnets.
- Search:
search_nodes(kind="InfraDevice", value="core") — fuzzy find by substring.
- Report: infrastructure inventory from Infrahub with relationship context.
Workflow: Branch-Isolated Change
When proposing an infrastructure change (the safe write path):
- Check session:
get_session_info — see the active session branch (or that none exists yet).
- Make changes:
node_upsert(...), node_delete(...), or mutate_graphql(...). The first
write auto-creates the mcp/session-* branch — you never edit the default branch directly.
- Verify:
get_nodes(...) on the session branch — confirm changes look correct.
- Propose:
propose_changes(title="Add VLAN 200", description="...") — opens a Proposed
Change for human review.
- Human merges in the Infrahub UI. To start a fresh unrelated change, call
reset_session_branch.
- Report: change summary + the Proposed Change link for review.
Workflow: GraphQL Exploration
When building custom queries:
- Schema: read resource
infrahub://graphql-schema — full SDL, understand query structure.
- Test query:
query_graphql(query="{ InfraDevice { edges { node { name { value } } } } }").
- Filtered query:
query_graphql(query="{ InfraDevice(name__value: \"core-rtr\") { ... } }").
- Mutations go through
mutate_graphql (write tool) and land on the session branch — never query_graphql.
- Report: custom data extraction with exactly the fields needed.
Companion: infrahub-skills Plugin
The MCP server is for live data — querying and changing a running Infrahub instance. For
authoring the artifacts that define and validate that data, use the OpsMill
infrahub-skills plugin (infrahub@opsmill, 12
skills). Rule of thumb: infrahub-sot (this skill / the MCP) reads and changes live data;
infrahub-skills writes the files (schemas, checks, transforms, generators) that shape it.
| Need |
Use |
| Query live nodes / IPAM, run GraphQL, make a branch-isolated change |
infrahub-sot (this skill, MCP-backed) |
| Analyze/correlate live data, drift & impact analysis |
infrahub-analyzing-data (also MCP-backed) |
| Design/validate schema YAML (nodes, generics, relationships) |
infrahub-managing-schemas |
| Populate object data YAML (devices, sites, orgs) |
infrahub-managing-objects |
| Write validation checks for Proposed Change pipelines |
infrahub-managing-checks |
| Build transforms / Jinja2 config artifacts |
infrahub-managing-transforms |
| Build design-driven generators |
infrahub-managing-generators |
| Custom web-UI menus |
infrahub-managing-menus |
| Audit an Infrahub repo against best practices |
infrahub-auditing-repo |
| Import CSV/TSV into object YAML |
infrahub-importing-data |
File a bug/feature to the right opsmill/infrahub-* repo |
infrahub-reporting-issues |
| Collect a redacted diagnostic bundle for support |
infrahub-collecting-diagnostics |
Install: npx skills add opsmill/infrahub-skills (cross-tool) or, in Claude Code,
/plugin marketplace add opsmill/claude-marketplace then /plugin install infrahub@opsmill.
Only infrahub-analyzing-data requires a connected Infrahub MCP server; the rest are
file-authoring/reading and pair naturally with this skill's live-data workflows.
Integration with Other Skills
| Skill |
How They Work Together |
netbox-reconcile |
Infrahub as primary SoT, NetBox as legacy — compare and migrate |
nautobot-sot |
Infrahub as primary SoT, Nautobot as legacy — compare IPAM data |
pyats-topology |
Infrahub provides intended state; pyATS discovers actual device state for reconciliation |
pyats-network |
Cross-reference Infrahub infrastructure model with live device configs |
pyats-routing |
Validate routing table entries against Infrahub prefix/IP allocations |
aci-fabric-audit |
Infrahub fabric model vs ACI actual state |
meraki-network-ops |
Infrahub planned state vs Meraki actual DHCP/VLAN assignments |
aws-network-ops |
Infrahub cloud model vs AWS VPC actual state |
radkit-remote-access |
Use Infrahub to identify device IPs, then RADKit for remote CLI access |
servicenow-change-workflow |
Infrahub Proposed Changes map to ServiceNow CRs — one session branch per change |
gait-session-tracking |
Record all Infrahub queries, session-branch writes, and Proposed Changes |
Infrahub vs NetBox vs Nautobot
NetClaw supports all three source-of-truth platforms:
| Feature |
NetBox |
Nautobot |
Infrahub |
| Origin |
DigitalOcean / NetBox Labs |
Network to Code |
OpsMill |
| Data model |
Fixed DCIM/IPAM + custom fields |
Fixed DCIM/IPAM + Jobs + custom fields |
Fully schema-driven (define any model) |
| Versioning |
No branching |
No branching |
Git-like branches for data |
| API |
REST + GraphQL |
REST + GraphQL |
GraphQL-native |
| MCP tools |
Read-write via FastMCP |
Read-only IPAM (5 tools) |
Read + branch-isolated write + Proposed Changes (10 tools) |
| Use when |
Standard IPAM/DCIM |
Standard IPAM/DCIM (NTC ecosystem) |
Custom infrastructure models, versioned & reviewed changes |
Important Rules
- Discover before querying — read
infrahub://schema (or get_schema with no kind) first to learn what kinds exist. Don't guess kind names, then get_schema(kind=...) for its filters.
- Never write on the default branch — use the write tools (
node_upsert / node_delete / mutate_graphql). They land on the auto-created session branch by design; query_graphql is read-only.
- Always propose, never merge — finish a change with
propose_changes and hand the Proposed Change to a human. The agent does not merge to the default branch.
- Check the session first —
get_session_info before writes to see the target branch; reset_session_branch to start a clean, unrelated change.
- Mutations need write permission — the token/user must have write rights for
node_upsert, node_delete, and mutate_graphql.
- Read-only when auditing — connect with
INFRAHUB_MCP_READ_ONLY=true for pure analysis so write tools are unavailable.
- Partial matching — use
partial_match=True in get_nodes, or search_nodes, for fuzzy value matching.
- Record in GAIT — log all Infrahub queries, session-branch writes, and Proposed Changes.
Environment Variables
Connection / credentials (consumed by infrahub-sdk; no prefix):
INFRAHUB_ADDRESS — required, Infrahub instance URL (e.g., http://infrahub.example.com:8000)
INFRAHUB_API_TOKEN — API token auth, or
INFRAHUB_USERNAME + INFRAHUB_PASSWORD — username/password auth (one auth method required)
Server behavior (pydantic-settings, prefix INFRAHUB_MCP_; defaults shown):
INFRAHUB_MCP_READ_ONLY (false) — hide write tools and block GraphQL mutations
INFRAHUB_MCP_BRANCH_PATTERN (mcp/session-{date}-{hex}) — session-branch naming; INFRAHUB_MCP_MAX_BRANCH_RETRIES (5)
INFRAHUB_MCP_LOG_LEVEL (info)
- Rate limiting / retries:
INFRAHUB_MCP_RATE_LIMIT_RPS, INFRAHUB_MCP_RATE_LIMIT_BURST, INFRAHUB_MCP_RETRY_MAX_ATTEMPTS, INFRAHUB_MCP_RETRY_BASE_DELAY
- Caching:
INFRAHUB_MCP_CACHE_ENABLED (false), INFRAHUB_MCP_CACHE_LIST_TTL, INFRAHUB_MCP_CACHE_READ_TTL
- Observability:
INFRAHUB_MCP_OTEL_ENABLED, INFRAHUB_MCP_PROMETHEUS_ENABLED
- Auth (non-
none modes require streamable-http): INFRAHUB_MCP_AUTH_MODE (none|oidc|token-passthrough|basic-passthrough) plus OIDC settings (INFRAHUB_MCP_OIDC_CONFIG_URL, INFRAHUB_MCP_OIDC_CLIENT_ID, INFRAHUB_MCP_OIDC_BASE_URL, …)
Transport flags: --transport {stdio,streamable-http} (default stdio), --host (default 127.0.0.1), --port (default 8001).
1---2name: infrahub-sot3description: OpsMill Infrahub — infrastructure source of truth with schema-driven nodes, GraphQL queries, and branch-isolated changes. Use when querying Infrahub for device/IPAM inventory, browsing infrastructure schemas, running GraphQL queries, or making infrastructure changes safely via an auto-created session branch and a Proposed Change for human review.4license: Apache-2.05---6
7# Infrahub Source of Truth
8
9## MCP Server
10
11- **Repository**: [opsmill/infrahub-mcp](https://github.com/opsmill/infrahub-mcp)
12- **Version**: 1.1.7+ (reworked — first stable release + production hardening)
13- **Distribution**: PyPI (`pip install infrahub-mcp`), Docker (`registry.opsmill.io/opsmill/infrahub-mcp`), or from source
14- **Entry point**: `infrahub-mcp` console script
15- **Transport**: `stdio` (default) or `streamable-http` (remote clients / auth modes)
16- **Requires**: `INFRAHUB_ADDRESS` + (`INFRAHUB_API_TOKEN` *or* `INFRAHUB_USERNAME`+`INFRAHUB_PASSWORD`)
17- **Python**: 3.13+
18- **Dependencies**: `fastmcp>=3.2.0`, `infrahub-sdk>=1.20.0`
19- **Docs**: [docs.infrahub.app/mcp](https://docs.infrahub.app/mcp) (per-client setup, auth, configuration)
20
21> **What changed in the rework**: the server moved to a modular `src/infrahub_mcp/` layout on
22> FastMCP 3.x, added a **branch-isolated write model** (writes never touch the default branch),
23> exposes **MCP resources and prompts** in addition to tools, serializes schema output with **TOON**
24> internally to cut tokens, and ships as a **PyPI package + Docker image** with optional auth,
25> rate limiting, caching, and OpenTelemetry/Prometheus observability. The old read-only tool
26> surface (`get_node_filters`, `get_related_nodes`, `get_schema_mapping`, `get_schemas`,
27> `get_graphql_schema`, `get_branches`, `branch_create`) has been replaced — see the table below.
28
29## How Infrahub Differs
30
31Infrahub is not just another IPAM/DCIM tool. Key differentiators:
32
33- **Schema-driven** — define your own infrastructure models (not just built-in IPAM/DCIM). Devices, circuits, IP addresses, services, cloud resources — any infrastructure object can be modeled.
34- **Versioned branches** — Git-like branching for infrastructure data. Changes are made on a branch, reviewed as a diff, and merged when approved. No more "who changed this in production?"
35- **GraphQL-native** — full GraphQL API for flexible queries, not just REST. Query exactly the fields you need, traverse relationships in a single request.
36- **Relationship-first** — rich relationship model between objects with relationship-level filters and traversal.
37
38## Safety Model: Branch-Isolated Writes
39
40The reworked server makes destructive operations safe by construction:
41
42- **Writes never hit the default branch.** On the first write in a session, the server lazily
43 auto-creates a session branch named `mcp/session-YYYYMMDD-<hex>` (pattern configurable via
44 `INFRAHUB_MCP_BRANCH_PATTERN`). All `node_upsert` / `node_delete` / `mutate_graphql` land there.
45- **Human review is mandatory to merge.** `propose_changes` opens a **Proposed Change** (PR) from
46 the session branch to the default branch — a human reviews and merges it in the Infrahub UI. The
47 agent never merges.
48- **Session-branch recovery.** Stale/merged/deleted session branches are validated before reuse and
49 auto-recovered on the next write; `reset_session_branch` clears or switches the active branch.
50- **Read-only mode.** Setting `INFRAHUB_MCP_READ_ONLY=true` hides all write tools and blocks GraphQL
51 mutations — use it for pure analysis/audit connections.
52
53## MCP Tools (10 tools)
54
55### Read Tools (5)
56
57| Tool | Parameters | What It Does |
58|------|-----------|--------------|
59| `get_nodes` | `kind, filters?, partial_match?, include_attributes?, offset?, limit?, branch?` | Typed read of nodes of a kind. Supports attribute/relationship filters (`attr__value`, `rel__attr__value`), partial matching, and paging (returns `total_count`/`has_more`). |
60| `search_nodes` | `kind, value, branch?` | Find nodes of a kind by partial substring via Infrahub's `any__value` filter. Works on concrete and abstract/generic kinds. |
61| `get_schema` | `kind?, branch?` | Discover schema kinds (catalog) or, given a `kind`, its attributes/relationships/filter-map (TOON-encoded). Tool fallback for clients without MCP resources. |
62| `get_session_info` | none | Report current session state — active `session_branch`, `infrahub_address`, `has_session_branch`. Call before writes to know the target branch. |
63| `query_graphql` | `query, branch?` | Execute a **read-only** GraphQL query (mutations are rejected here). |
64
65### Write Tools (5) — hidden when `INFRAHUB_MCP_READ_ONLY=true`
66
67| Tool | Parameters | What It Does |
68|------|-----------|--------------|
69| `node_upsert` | `kind, data, ...` | Create or update a node on the active session branch. |
70| `node_delete` | `kind, id` | Delete a node on the active session branch. |
71| `mutate_graphql` | `mutation, ...` | Execute a GraphQL mutation (relationship edits / bulk ops typed tools can't express). Branch/schema-management mutations are blocked. |
72| `propose_changes` | `title?, description?` | Open a Proposed Change from the session branch to the default branch for human review. |
73| `reset_session_branch` | `branch?` | Clear the cached session branch (next write creates a fresh one) or point the session at a named branch. Rejects the default branch and merged/read-only branches. |
74
75### Resources (3 + 1 template)
76
77| Resource URI | Content |
78|--------------|---------|
79| `infrahub://schema` | Kind catalog (JSON) |
80| `infrahub://schema/{kind}` | Per-kind schema + filter map (template) |
81| `infrahub://graphql-schema` | Full GraphQL SDL (text) |
82| `infrahub://branches` | All branches including the session branch (JSON) |
83
84### Prompts (4)
85
86`infrahub_agent` (system prompt; read-only vs read-write aware), `answer_infra_question`,
87`make_infra_change`, `explore_schema`.
88
89## Workflow: Discover Available Data
90
91When first connecting to Infrahub:
92
931. **List kinds**: read resource `infrahub://schema` (or `get_schema` with no `kind`) — what infrastructure types are modeled?
942. **Inspect schema**: `get_schema(kind="InfraDevice")` — what attributes and relationships does a device have?
953. **Get nodes**: `get_nodes(kind="InfraDevice")` — list all devices (page with `offset`/`limit`).
964. **Report**: infrastructure data model overview with node counts per kind.
97
98## Workflow: Infrastructure Audit
99
100When auditing infrastructure state in Infrahub:
101
1021. **Schema overview**: `get_schema` (no kind) — discover all kinds.
1032. **Device inventory**: `get_nodes(kind="InfraDevice")` — all devices.
1043. **IP addresses**: `get_nodes(kind="InfraIPAddress")` — all IPs (if IPAM is modeled).
1054. **Prefixes**: `get_nodes(kind="InfraPrefix")` — all subnets.
1065. **Search**: `search_nodes(kind="InfraDevice", value="core")` — fuzzy find by substring.
1076. **Report**: infrastructure inventory from Infrahub with relationship context.
108
109## Workflow: Branch-Isolated Change
110
111When proposing an infrastructure change (the safe write path):
112
1131. **Check session**: `get_session_info` — see the active session branch (or that none exists yet).
1142. **Make changes**: `node_upsert(...)`, `node_delete(...)`, or `mutate_graphql(...)`. The first
115 write **auto-creates** the `mcp/session-*` branch — you never edit the default branch directly.
1163. **Verify**: `get_nodes(...)` on the session branch — confirm changes look correct.
1174. **Propose**: `propose_changes(title="Add VLAN 200", description="...")` — opens a Proposed
118 Change for human review.
1195. **Human merges** in the Infrahub UI. To start a fresh unrelated change, call
120 `reset_session_branch`.
1216. **Report**: change summary + the Proposed Change link for review.
122
123## Workflow: GraphQL Exploration
124
125When building custom queries:
126
1271. **Schema**: read resource `infrahub://graphql-schema` — full SDL, understand query structure.
1282. **Test query**: `query_graphql(query="{ InfraDevice { edges { node { name { value } } } } }")`.
1293. **Filtered query**: `query_graphql(query="{ InfraDevice(name__value: \"core-rtr\") { ... } }")`.
1304. **Mutations** go through `mutate_graphql` (write tool) and land on the session branch — never `query_graphql`.
1315. **Report**: custom data extraction with exactly the fields needed.
132
133## Companion: infrahub-skills Plugin
134
135The MCP server is for **live data** — querying and changing a running Infrahub instance. For
136**authoring the artifacts** that define and validate that data, use the OpsMill
137[**infrahub-skills**](https://github.com/opsmill/infrahub-skills) plugin (`infrahub@opsmill`, 12
138skills). Rule of thumb: **`infrahub-sot` (this skill / the MCP) reads and changes live data;
139`infrahub-skills` writes the files** (schemas, checks, transforms, generators) that shape it.
140
141| Need | Use |
142|------|-----|
143| Query live nodes / IPAM, run GraphQL, make a branch-isolated change | **`infrahub-sot`** (this skill, MCP-backed) |
144| Analyze/correlate live data, drift & impact analysis | `infrahub-analyzing-data` (also MCP-backed) |
145| Design/validate schema YAML (nodes, generics, relationships) | `infrahub-managing-schemas` |
146| Populate object data YAML (devices, sites, orgs) | `infrahub-managing-objects` |
147| Write validation checks for Proposed Change pipelines | `infrahub-managing-checks` |
148| Build transforms / Jinja2 config artifacts | `infrahub-managing-transforms` |
149| Build design-driven generators | `infrahub-managing-generators` |
150| Custom web-UI menus | `infrahub-managing-menus` |
151| Audit an Infrahub repo against best practices | `infrahub-auditing-repo` |
152| Import CSV/TSV into object YAML | `infrahub-importing-data` |
153| File a bug/feature to the right `opsmill/infrahub-*` repo | `infrahub-reporting-issues` |
154| Collect a redacted diagnostic bundle for support | `infrahub-collecting-diagnostics` |
155
156Install: `npx skills add opsmill/infrahub-skills` (cross-tool) or, in Claude Code,
157`/plugin marketplace add opsmill/claude-marketplace` then `/plugin install infrahub@opsmill`.
158Only `infrahub-analyzing-data` requires a connected Infrahub MCP server; the rest are
159file-authoring/reading and pair naturally with this skill's live-data workflows.
160
161## Integration with Other Skills
162
163| Skill | How They Work Together |
164|-------|----------------------|
165| `netbox-reconcile` | Infrahub as primary SoT, NetBox as legacy — compare and migrate |
166| `nautobot-sot` | Infrahub as primary SoT, Nautobot as legacy — compare IPAM data |
167| `pyats-topology` | Infrahub provides intended state; pyATS discovers actual device state for reconciliation |
168| `pyats-network` | Cross-reference Infrahub infrastructure model with live device configs |
169| `pyats-routing` | Validate routing table entries against Infrahub prefix/IP allocations |
170| `aci-fabric-audit` | Infrahub fabric model vs ACI actual state |
171| `meraki-network-ops` | Infrahub planned state vs Meraki actual DHCP/VLAN assignments |
172| `aws-network-ops` | Infrahub cloud model vs AWS VPC actual state |
173| `radkit-remote-access` | Use Infrahub to identify device IPs, then RADKit for remote CLI access |
174| `servicenow-change-workflow` | Infrahub Proposed Changes map to ServiceNow CRs — one session branch per change |
175| `gait-session-tracking` | Record all Infrahub queries, session-branch writes, and Proposed Changes |
176
177## Infrahub vs NetBox vs Nautobot
178
179NetClaw supports all three source-of-truth platforms:
180
181| Feature | NetBox | Nautobot | Infrahub |
182|---------|--------|----------|----------|
183| Origin | DigitalOcean / NetBox Labs | Network to Code | OpsMill |
184| Data model | Fixed DCIM/IPAM + custom fields | Fixed DCIM/IPAM + Jobs + custom fields | Fully schema-driven (define any model) |
185| Versioning | No branching | No branching | Git-like branches for data |
186| API | REST + GraphQL | REST + GraphQL | GraphQL-native |
187| MCP tools | Read-write via FastMCP | Read-only IPAM (5 tools) | Read + branch-isolated write + Proposed Changes (10 tools) |
188| Use when | Standard IPAM/DCIM | Standard IPAM/DCIM (NTC ecosystem) | Custom infrastructure models, versioned & reviewed changes |
189
190## Important Rules
191
192- **Discover before querying** — read `infrahub://schema` (or `get_schema` with no kind) first to learn what kinds exist. Don't guess kind names, then `get_schema(kind=...)` for its filters.
193- **Never write on the default branch** — use the write tools (`node_upsert` / `node_delete` / `mutate_graphql`). They land on the auto-created session branch by design; `query_graphql` is read-only.
194- **Always propose, never merge** — finish a change with `propose_changes` and hand the Proposed Change to a human. The agent does not merge to the default branch.
195- **Check the session first** — `get_session_info` before writes to see the target branch; `reset_session_branch` to start a clean, unrelated change.
196- **Mutations need write permission** — the token/user must have write rights for `node_upsert`, `node_delete`, and `mutate_graphql`.
197- **Read-only when auditing** — connect with `INFRAHUB_MCP_READ_ONLY=true` for pure analysis so write tools are unavailable.
198- **Partial matching** — use `partial_match=True` in `get_nodes`, or `search_nodes`, for fuzzy value matching.
199- **Record in GAIT** — log all Infrahub queries, session-branch writes, and Proposed Changes.
200
201## Environment Variables
202
203**Connection / credentials** (consumed by `infrahub-sdk`; no prefix):
204
205- `INFRAHUB_ADDRESS` — **required**, Infrahub instance URL (e.g., `http://infrahub.example.com:8000`)
206- `INFRAHUB_API_TOKEN` — API token auth, **or**
207- `INFRAHUB_USERNAME` + `INFRAHUB_PASSWORD` — username/password auth (one auth method required)
208
209**Server behavior** (pydantic-settings, prefix `INFRAHUB_MCP_`; defaults shown):
210
211- `INFRAHUB_MCP_READ_ONLY` (`false`) — hide write tools and block GraphQL mutations
212- `INFRAHUB_MCP_BRANCH_PATTERN` (`mcp/session-{date}-{hex}`) — session-branch naming; `INFRAHUB_MCP_MAX_BRANCH_RETRIES` (`5`)
213- `INFRAHUB_MCP_LOG_LEVEL` (`info`)
214- Rate limiting / retries: `INFRAHUB_MCP_RATE_LIMIT_RPS`, `INFRAHUB_MCP_RATE_LIMIT_BURST`, `INFRAHUB_MCP_RETRY_MAX_ATTEMPTS`, `INFRAHUB_MCP_RETRY_BASE_DELAY`
215- Caching: `INFRAHUB_MCP_CACHE_ENABLED` (`false`), `INFRAHUB_MCP_CACHE_LIST_TTL`, `INFRAHUB_MCP_CACHE_READ_TTL`
216- Observability: `INFRAHUB_MCP_OTEL_ENABLED`, `INFRAHUB_MCP_PROMETHEUS_ENABLED`
217- Auth (non-`none` modes require `streamable-http`): `INFRAHUB_MCP_AUTH_MODE` (`none`|`oidc`|`token-passthrough`|`basic-passthrough`) plus OIDC settings (`INFRAHUB_MCP_OIDC_CONFIG_URL`, `INFRAHUB_MCP_OIDC_CLIENT_ID`, `INFRAHUB_MCP_OIDC_BASE_URL`, …)
218
219**Transport flags**: `--transport {stdio,streamable-http}` (default `stdio`), `--host` (default `127.0.0.1`), `--port` (default `8001`).