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.