Netbox Integration Walkthrough
Date: May 2026
FMCP Version: 0.6
Agent: GPT
Claim: A Netbox instance was accessible to Claude.ai and GPT via MCP — with zero changes to Netbox's source code. Both agents built independent network environments on the same live instance. The database is preserved.
Note: The Netbox instance has since been torn down, but the complete dataset was captured in docs_for_demo/netbox/netbox_starfleet_demo.dump and netbox_starfleet_demo.sql before decommission.
The Standard We Are Held To
Netbox is maintained by NetBox Labs with a clear plugin contract: extend via PLUGINS, configure via configuration.py, and leave everything in netbox/netbox/, netbox/dcim/, netbox/ipam/ (and all other core app directories) untouched. The AGENTS.md at the root of the repository is explicit: "Only documented public APIs are stable. Internal NetBox code may change without notice." and "Plugin API: only documented public APIs are stable."
The integration documented here uses only the documented plugin API.
What Was Running
Server: MacBook (local), tunneled via ngrok
Netbox Version: 4.6 (Python 3.12+, Django 6.x)
MCP Endpoint: ngrok public URL → localhost:8080/api/mcp
Database: PostgreSQL (preserved — see netbox_starfleet_demo.dump)
The Complete Integration — One File
The entire integration lives in netbox/development/configuration.py. This is the instance configuration file — gitignored by default, never committed, the documented place for all site-specific settings. No Netbox source file was edited.
Step 1: Plugin Registration — One Line
# configuration.py
PLUGINS = ["frisian_mcp_netbox"]
Netbox's PLUGINS list is the sanctioned extension point for all third-party capabilities. frisian_mcp_netbox is a thin plugin wrapper that registers frisian-mcp with Netbox's plugin lifecycle (PluginConfig.ready() hook). It does not modify any Netbox model, view, serializer, or URL. The frisian-mcp MCP endpoint mounts at the path configured below, alongside Netbox's own /api/ — not replacing it.
Step 2: Settings — Configuration, Not Code
# MCP endpoint — mounts at /api/mcp alongside Netbox's /api/
FRISIAN_MCP_PATH = "api/mcp"
# Anonymous callers see read-tier tools only
FRISIAN_MCP_UNAUTHENTICATED_TIER = "read"
# Authentication stack:
# 1. frisian-mcp OAuth bearer token (Claude.ai, GPT PKCE flow)
# 2. frisian-mcp static token (testing, scripts)
# Netbox's TokenAuthentication is intentionally excluded: it matches
# "Bearer" headers and would reject any frisian-mcp OAuth token with
# AuthenticationFailed before frisian-mcp's own authenticator can claim it.
FRISIAN_MCP_AUTHENTICATION_CLASSES = [
"frisian_mcp.contrib.oauth.authentication.OAuthTokenAuthentication",
"frisian_mcp.contrib.tokens.authentication.FrisianMcpTokenAuthentication",
]
# PKCE flow for Claude.ai (auto-register: no pre-created client row needed)
FRISIAN_MCP_OAUTH_AUTO_APPROVE = True
FRISIAN_MCP_OAUTH_PKCE_AUTO_REGISTER = True
FRISIAN_MCP_OAUTH_PKCE_DEFAULT_PERMISSION = "admin"
# Dynamic Client Registration (RFC 7591) for GPT
# ChatGPT uses DCR — it POSTs to /oauth/register/ before starting the OAuth
# flow. Claude.ai uses a hardcoded client_id + PKCE instead. Both work on
# the same server; this one setting is the only GPT-specific configuration.
FRISIAN_MCP_OAUTH_REGISTRATION_OPEN = True
# Trust one upstream proxy (ngrok) when constructing the OAuth issuer URL
# so that /.well-known/oauth-authorization-server returns the correct https://
# ngrok URL rather than http://localhost.
FRISIAN_MCP_TRUSTED_PROXY_COUNT = 1
# Map Netbox user roles to MCP permission tiers
FRISIAN_MCP_TOKEN_TIER_MAP = {
"superuser": "read_write",
"staff": "read_write",
"default": "read_write",
}
Step 3: Dispatcher Groups — Tool Surface Configuration
Netbox 4.6 exposes over 1,100 API operations across 9 app domains. The dispatcher configuration collapses these into named groups. This is the only place where the tool surface is defined — no code, no custom views, no ViewSet subclasses:
FRISIAN_MCP_DISPATCH_GROUPS = {
"dcim": [
"region", "sitegroup", "site", "location",
"rackgroup", "racktype", "rackrole", "rack", "rackreservation",
"manufacturer", "devicetype", "moduletype",
"devicerole", "platform", "device", "virtualdevicecontext", "module",
"consoleport", "consoleserverport", "powerport", "poweroutlet",
"interface", "frontport", "rearport",
"modulebay", "devicebay", "inventoryitem",
"cable", "cabletermination", "virtualchassis",
"powerpanel", "powerfeed", "connected_device",
# ... all remaining DCIM resources
],
"ipam": [
"asn", "asnrange", "vrf", "routetarget", "rir", "aggregate",
"role", "prefix", "iprange", "ipaddress",
"fhrpgroup", "vlangroup", "vlan",
"servicetemplate", "service",
],
"circuits": ["provider", "provideraccount", "providernetwork",
"circuittype", "circuit", "circuittermination",
"circuitgroup", "virtualcircuit"],
"tenancy": ["tenantgroup", "tenant", "contactgroup",
"contactrole", "contact", "contactassignment"],
"virtualization": ["clustertype", "clustergroup", "cluster",
"virtualmachine", "vminterface", "virtualdisk"],
"vpn": ["ikepolicy", "ikeproposal", "ipsecpolicy",
"ipsecproposal", "tunnel", "tunneltermination", "l2vpn"],
"wireless": ["wirelesslangroup", "wirelesslan", "wirelesslink"],
"extras": ["eventrule", "webhook", "customfield", "exporttemplate",
"tag", "configcontext", "configtemplate", "script"],
"users": ["user", "group", "token", "objectpermission"],
}
Result: 1,148 underlying API operations, exposed as 9 dispatcher groups (~23 MCP tools total). Every CRUD operation, bulk operation, and Netbox-specific action (render config, trace cable path) is accessible through the same dispatcher pattern without a single line of custom code.
What the Two-Token Split Demonstrated
The Netbox MCP server was connected to Claude Code with two separate permission levels simultaneously:
| Connection | Token | Capability | Use Case |
|---|---|---|---|
mcp__Netbox__* |
Read-only | list, retrieve, trace, paths | Audit, compliance, documentation |
mcp__claude_ai_Netbox__* |
Full CRUD | + create, update, delete, bulk ops | Provisioning, data entry |
This is a configuration decision — two API tokens with different Netbox object permissions, both connecting to the same MCP endpoint. No code changes were required to support this split. The MCP server serves both; the difference is in what each token is permitted to do by Netbox's own RBAC.
What Agents Built
The Netbox instance was torn down after testing, but the complete dataset was saved. The two builds below coexist in netbox_starfleet_demo.dump.
Build 1 — Claude.ai: Starfleet/Federation Network
Agent: Claude.ai (claude-sonnet-4-6)
Method: MCP connector over ngrok tunnel
Date: 2026-05-07
Claude.ai built a complete Star Trek: TNG / DS9-themed network environment from scratch. Every object was created via MCP tool calls — natural language translated to Netbox:dcim(resource='device', action='create', params={...}). No scripts, no direct API calls, no Netbox UI.
Infrastructure built:
| Resource | Count |
|---|---|
| Regions | 4 (Alpha, Beta, Gamma, Delta Quadrants) |
| Sites | 4 (Starbase-1, Deep Space 9, Utopia Planitia, Bajor Relay) |
| Manufacturers | 4 (Daystrom Industries, Soong Technologies, Cardassian Union Fabrication, Yoyodyne) |
| Device Types | 5 |
| Platforms | 3 (LCARS-OS, BajorOS, CardOS) |
| Device Roles | 5 (Router, Core Switch, Access Switch, Firewall, OOB Console) |
| Devices | 10 |
| VLANs | 4 |
| VRFs | 4 (MGMT, DATA, HOLONET, TRANSPORTER — each with route distinguisher) |
| Prefixes | 13 (supernets + per-site /24 subnets) |
| Interfaces | 11 |
| IP Addresses | 3 (with DNS names) |
| Cables | 4 (physical cabling between devices) |
| Total objects | 76 |
Sample topology (Starbase-1, Alpha Quadrant):
Starbase-1
├── uss-enterprise-rtr01 (Router, LCARS-OS) 10.10.1.1/24
│ ├── Gi0/0 ──CAT6── starbase1-fw01 Gi0/0 [SB1-RTR-FW]
│ └── Gi0/1 ──CAT6── starbase1-core-sw01 Gi0/0 [SB1-RTR-CORE]
├── starbase1-core-sw01 (Core Switch, LCARS-OS) 10.10.1.2/24
│ └── Gi0/1 ──CAT6── starbase1-acc-sw01 Gi0/0 [SB1-CORE-ACC]
├── starbase1-acc-sw01 (Access Switch, BajorOS)
├── starbase1-fw01 (Firewall, CardOS)
└── starbase1-oob01 (OOB Console)
Notable finding during build: Netbox enforces manufacturer/platform pairing at the API level. When Claude.ai attempted to assign LCARS-OS (Daystrom Industries) to a device with a Soong Technologies device type, the API returned a validation error. Claude.ai caught the error and corrected it in real-time — switching to BajorOS (Soong Technologies). This validated that frisian-mcp correctly surfaces Netbox's validation errors to the agent rather than silently failing.
Build 2 — GPT: Klingon Empire Network
Agent: GPT
Method: Dynamic Client Registration (RFC 7591) → OAuth PKCE → MCP connector over ngrok
Date: 2026-05-07 (same session, same Netbox instance)
GPT connected to the same Netbox instance that Claude.ai had just built. It registered its own OAuth client via DCR (one POST /oauth/register/ call), completed PKCE, received a bearer token, and then built an entirely separate network environment without any overlap with the Federation topology.
Infrastructure built:
| Resource | Count |
|---|---|
| Region | 1 (Klingon Empire) |
| Sites | 4 (Qonos Prime, Tygokor Fleet Yard, Rura Penthe Relay, Starfleet Border Front) |
| Manufacturer | 1 (Klingon Imperial Engineering) |
| Device Roles | 5 (Battle Cruiser Core Router, Bird of Prey Edge Router, Cloaking Gateway, Honor Guard Switch, Subspace DNS Node) |
| Device Types | 4 |
| RIR | 1 (Klingon Imperial Registry) |
| VRF | 1 (klingon-imperial-vrf, RD: 65070:1) |
| Aggregate | 1 (10.70.0.0/16) |
| Prefixes | 6 |
| VLANs | 5 |
| Devices | 6 (iks-qonos-core-01, iks-tygokor-core-01, etc.) |
| Interfaces | 6 (Loopback0 per device) |
| IP Addresses | 6 (all with DNS names: *.klingon.empire) |
GPT also ran post-build verification by re-querying the Netbox MCP to confirm every object it created was present and correctly formed.
Sample addressing:
| Device | IP | DNS Name |
|---|---|---|
iks-qonos-core-01 |
10.70.255.1/32 |
qonos-core-01.klingon.empire |
iks-tygokor-core-01 |
10.70.255.2/32 |
tygokor-core-01.klingon.empire |
iks-cloak-gw-01 |
10.70.255.10/32 |
cloak-gw-01.klingon.empire |
iks-subspace-dns-01 |
10.70.1.53/24 |
subspace-dns-01.klingon.empire |
Combined Final State (from tool analysis scan)
After both builds, the instance contained:
| Resource | Count |
|---|---|
| Regions | 5 (4 Quadrants + Klingon Empire) |
| Sites | 8 (4 Federation + 4 Klingon) |
| Devices | 16 (10 Federation + 6 Klingon) |
| Manufacturers | 5 |
| VRFs | 5 (4 Federation + 1 Klingon) |
| Prefixes | 19 |
| IP Addresses | 9 |
| VLANs | 9 (4 Federation + 5 Klingon) |
The Federation and Klingon environments coexist with no cross-contamination. Each is scoped to its own VRF, region, and site structure.
Token Efficiency — Measured on This Instance
From the tool analysis scan run after both builds:
| Approach | Tools Loaded | Schema Tokens (approx.) |
|---|---|---|
| Raw Netbox REST API | 1,100+ endpoints | ~400,000+ |
| Flat MCP (1 tool per endpoint) | 1,148 | ~200,000+ |
| Group Dispatcher (this Netbox MCP) | ~23 | ~3,000–5,000 |
50:1 schema token compression. An agent connecting to the raw API would spend its entire context budget on tool schemas before making a single call. With the dispatcher, the schema overhead is ~4,000 tokens — leaving the rest of the context for data, reasoning, and tool calls.
What Was Not Touched
The following directories contain only unmodified, as-shipped Netbox code:
netbox/netbox/netbox/ — Core settings, URLs, plugin infrastructure
netbox/netbox/dcim/ — DCIM app (devices, racks, cables, interfaces)
netbox/netbox/ipam/ — IPAM app (prefixes, addresses, VLANs, VRFs)
netbox/netbox/circuits/ — Circuits app
netbox/netbox/extras/ — Extras app (tags, custom fields, webhooks)
netbox/netbox/tenancy/ — Tenancy app
netbox/netbox/users/ — Users and tokens
netbox/netbox/virtualization/ — VM and cluster management
netbox/netbox/vpn/ — VPN tunnel management
netbox/netbox/wireless/ — Wireless LAN management
The git history of the Netbox repository contains no frisian-mcp commits in any core app directory. The frisian_mcp_netbox plugin wrapper — a small external package — was installed via pip and declared in PLUGINS. That is the full extent of the integration.
Why This Matters
Netbox is a shared platform in network automation environments. Teams depend on upgrade stability. An integration that patches core code must be rebased on every Netbox release, tested against the new version, and re-applied before the upgrade can proceed.
An integration that only touches configuration.py carries no upgrade burden. pip install --upgrade netbox runs clean. The PLUGINS = ["frisian_mcp_netbox"] entry and all FRISIAN_MCP_* settings remain in place. On next startup, frisian-mcp reads the new Netbox version's OpenAPI schema and the MCP endpoint is live again.
The integration is also multi-client by design. Claude.ai and GPT used different OAuth flows (PKCE auto-register vs. Dynamic Client Registration) and connected to the same endpoint without conflict. Cursor and Claude Code connect using the same OAuth PKCE flow as Claude.ai. No server-side changes are required to support a new client.
The Preserved Data
Because the instance was torn down before all documentation was captured, the dataset lives in:
| File | Contents |
|---|---|
netbox_starfleet_demo.dump |
PostgreSQL binary dump — full database including both Federation and Klingon environments |
netbox_starfleet_demo.sql |
SQL script version of the same dump |
netbox-starfleet-build-report.md |
Full object inventory from the Claude.ai Federation build |
klingon_netbox_buildout_report.md |
Full object inventory from the GPT Klingon build |
netbox_mcp_tool_analysis.md |
Post-build tool structure analysis and token efficiency measurements |
The database can be restored to any Netbox 4.6 instance to reproduce the demo environment.
Summary
| What | How | Where |
|---|---|---|
| Package install | pip install frisian_mcp_netbox |
Standard Python packaging |
| Plugin registration | PLUGINS = ["frisian_mcp_netbox"] |
configuration.py only |
| MCP endpoint | FRISIAN_MCP_PATH = "api/mcp" |
configuration.py only |
| Authentication | FRISIAN_MCP_AUTHENTICATION_CLASSES |
configuration.py only |
| Tool surface | FRISIAN_MCP_DISPATCH_GROUPS |
configuration.py only |
| Netbox core changes | None | — |
| Clients supported | Claude.ai, Claude Code, Cursor, GPT | Same endpoint, standard OAuth |
Source data: build reports and tool analysis from live instance, 2026-05-07. Configuration source: netbox/development/configuration.py — the only file modified during integration.