s2-netbox-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| NETBOX_API_PATH | No | The NBAPI path appended to NETBOX_BASE_URL. The default is the verified path on NetBox 6.x controllers. Only set this to override the default — e.g. to the legacy, pre-6.x path /goforms/nbapi, which returns HTTP 410 Gone on 6.x controllers. A value without a leading / has one added automatically. | /nbws/goforms/nbapi |
| NETBOX_BASE_URL | Yes | Base URL of the NetBox controller's web interface, e.g. https://netbox.example.internal. No trailing slash or path — the client appends NETBOX_API_PATH itself. | |
| NETBOX_PASSWORD | Yes | NBAPI session-login password. Never logged, never written to any tracked file. | |
| NETBOX_USERNAME | Yes | NBAPI session-login username. | |
| NETBOX_ENABLE_WRITES | No | Set to true/1/yes to register the write tools. Unset (or any other value) leaves the server strictly read-only. | false |
| NETBOX_EVENT_API_PATH | No | Request path used only for trigger_event. Unset/empty tracks whatever NETBOX_API_PATH resolves to; a non-empty override is used verbatim (leading / added if missing) — e.g. the doc's pre-6.x Event API path /appd/nbapi, if your controller serves it separately. | |
| NETBOX_ALLOW_INSECURE_TLS | No | Set to true/1/yes to accept a self-signed/on-prem TLS certificate. Explicit opt-in only — any other value (including unset) keeps normal certificate verification. | false |
| NETBOX_ENABLE_DESTRUCTIVE | No | Set to true/1/yes, together with NETBOX_ENABLE_WRITES, to additionally register the 11 destructive tools. | false |
| NETBOX_UNLOCK_NAME_PREFIX | No | Name prefix of every object the managed unlock window creates: the portal group (<prefix>), the time spec group (<prefix> time specs), and the per-segment holidays/time specs (<prefix> first/middle/last). 1-40 characters so the longest name fits the 64-character NAME limit. | MCP Unlock Window |
| NETBOX_LIVE_TEST_PORTALKEY | No | The PORTALKEY of the one door you designate safe to physically unlock during npm run test:live:write/npm run test:live:write:daily. Read only by those scripts, never by the server itself. | |
| NETBOX_UNLOCK_HOLIDAY_GROUPS | No | The holiday groups reserved for the managed unlock window, in first,middle,last segment order. Must be 1-3 distinct integers in 1..8, comma-separated; reserve groups nothing else on the controller uses. | 8,7,6 |
| NETBOX_DAILY_UNLOCK_NAME_PREFIX | No | Name prefix of every object the managed daily unlock window creates: the portal group (<prefix>), the time spec group (<prefix> time specs), and the one holiday/time spec (<prefix> schedule). 1-40 characters so the longest name fits the 64-character NAME limit. | MCP Daily Unlock Window |
| NETBOX_DAILY_UNLOCK_HOLIDAY_GROUP | No | The single holiday group reserved for the managed daily recurring unlock window. Must be a single integer in 1..8, and must not be a member of NETBOX_UNLOCK_HOLIDAY_GROUPS (the two features' reserved groups can never collide). | 5 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| check_connectionA | Confirms the server can authenticate to the configured S2 NetBox controller and returns the NBAPI version string (wraps GetAPIVersion). No parameters required. |
| get_guideA | Returns static reference guidance on this server’s S2 NetBox domain knowledge. Makes no controller call. Call with no topic for an index of all six topics; call with topic set to one of access-model, unlock-windows, group-and-name-gotchas, credentials-and-card-formats, api-quirks, write-safety for that topic’s full content. |
| get_personA | Returns the full person record for a given PERSONID (wraps NBAPI GetPerson). |
| search_person_dataA | Searches for person records matching the given criteria (wraps NBAPI SearchPersonData). Every documented SearchPersonData filter field is modeled explicitly; omit all filters to return every record. |
| get_card_access_detailsA | Returns card/credential access details for a given card (wraps NBAPI GetCardAccessDetails). Identifies the card by ENCODEDNUM + CARDFORMAT, not PERSONID — GetCardAccessDetails has no PERSONID parameter. RESOLVEDESCRIPTIONS defaults to true — an inverted, opt-out default (unlike most optional booleans in this codebase): each returned ACCESS record is enriched with the reader's human-readable READERDESCRIPTION via one GetReaders full-table fetch per call (not per record); set RESOLVEDESCRIPTIONS: false to skip it. Set RESOLVENAMES: true to enrich the response with the card owner's FIRSTNAME/LASTNAME/FULLNAME/NOTES (default false — off) via a single GetPerson lookup for the card's one PERSONID — cheaper than get_access_history's RESOLVENAMES, which pays one GetPerson call per distinct person across many records, since a card has exactly one owner. The four fields land on the top level of the response, alongside PERSONID/DISABLED/EXPDATE, not on each ACCESS record. |
| get_card_formatsB | Returns the card formats configured on the NetBox system (wraps NBAPI GetCardFormats). No parameters required. |
| get_pictureA | Returns a person's photo ID image (wraps NBAPI GetPicture). The response's PICTURE field is a Base64-encoded JPEG and may be very large — a full-size badge photo runs to hundreds of kilobytes of Base64 text, so prefer PICTUREURL when you only need to identify the file. The response also carries PERSONID, PICTUREURL, LASTNAME, FIRSTNAME and LASTMOD. The payload is passed through unmodified: this tool neither decodes, resizes nor truncates the Base64 string. A person with no photo answers FAIL with "No picture URL for this person ID" or "Picture file does not exist"; an oversized image answers "Person picture image file size exceeds maximum to be returned/exported". |
| get_virtual_credential_requestA | Retrieves a mobile (virtual) credential and its assignment state for a person and card format (wraps NBAPI GetVirtualCredentialRequest). Returns CARDFORMAT, PERSONID and STATUS. A card format the controller does not know answers FAIL with "CARDFORMAT NOT FOUND"; use get_card_formats for valid names. |
| get_access_levelA | Returns the details of a single access level for a given ACCESSLEVELKEY (wraps NBAPI GetAccessLevel). RESOLVEGROUPNAMES defaults to true — an inverted, opt-out default (unlike most optional booleans in this codebase): the raw response carries only bare TIMESPECGROUPKEY/READERGROUPKEY/THREATLEVELGROUPKEY foreign keys, so this resolves TIMESPECGROUPKEY and READERGROUPKEY into new sibling TIMESPECGROUPNAME/READERGROUPNAME fields via one full-table GetTimeSpecGroups fetch and one full-table GetReaderGroups fetch per call — a fixed cost regardless of anything else, since a single access level carries exactly one of each key. THREATLEVELGROUPKEY is never resolved (no NBAPI read command exists for threat level groups). Set RESOLVEGROUPNAMES: false to skip both fetches and return the response exactly as GetAccessLevel provides it. |
| get_access_levelsB | Lists access levels configured on the NetBox system (wraps NBAPI GetAccessLevels). |
| get_access_level_groupA | Returns the details of a single access level group for a given ACCESSLEVELGROUPKEY (wraps NBAPI GetAccessLevelGroup). |
| get_access_level_groupsB | Lists access level groups configured on the NetBox system (wraps NBAPI GetAccessLevelGroups). |
| get_access_level_namesB | Lists access level names configured on the NetBox system (wraps NBAPI GetAccessLevelNames). |
| get_portalsA | Lists portals (doors) configured on the NetBox system, each with its nested readers (wraps NBAPI GetPortals, paginated via STARTFROMKEY/NEXTKEY — there is no single-portal filter). RESOLVEDESCRIPTIONS defaults to true — an inverted, opt-out default (unlike most optional booleans in this codebase): GetPortals never populates a nested reader's own DESCRIPTION field (only READERKEY/NAME/PORTALORDER), so this fills it in directly on each nested reader via one GetReaders full-table fetch per call (not per portal/reader). Set RESOLVEDESCRIPTIONS: false to return readers exactly as GetPortals provides them, with no DESCRIPTION field and no GetReaders call. |
| get_readerA | Returns the details of a single reader for a given READERKEY (wraps NBAPI GetReader). |
| get_readersA | Lists readers configured on the NetBox system (wraps NBAPI GetReaders). There is no portal-id filter — use get_portals to see each reader nested under its portal. |
| get_outputsB | Lists auxiliary outputs configured on the NetBox system (wraps NBAPI GetOutputs). |
| get_portal_statesA | Lists the portal states the NetBox system defines (wraps NBAPI GetPortalStates). Returns STATEKEY/STATENAME pairs — the vocabulary get_portal_statuses reports against, and the values its STATEKEY filter accepts. |
| get_portal_statusesA | Returns the live status of portals (doors) — the current state of each door, not its configuration (wraps NBAPI GetPortalStatuses). Each PORTALSTATUS block carries PORTALKEY, PORTALNAME, STATEKEY, STATENAME, THREATLEVELNAME, LOCATIONKEY, LOCATIONNAME, TYPEKEY and PARTITIONKEY. Filter by portal, state, partition or location; use get_portal_states for the STATEKEY vocabulary and get_locations for LOCATIONKEY values. |
| get_locationsA | Lists the locations configured on the NetBox system (wraps NBAPI GetLocations). Each record carries LOCATIONKEY, PARTITIONKEY and a nested PARENTLOCATION { PARENTKEY, NAME } block, so the result describes a location tree. LOCATIONKEY values feed get_portal_statuses and set_threat_level. |
| find_portalsA | Finds portals (doors) by location or name. Portal names are site codes (e.g. 01OF05A), so this also searches each portal's reader names and reader descriptions (e.g. 'WORKSHOP TO MAINTENANCE OFFICE'). Case-insensitive; a portal matches when every whitespace-separated term appears in its name, a reader name, or a reader description. Reads every page of GetPortals and GetReaders and joins them by READERKEY. The result also lists portals with no reader description, which can only match by name. |
| get_event_historyB | Returns historical NetBox events for an optional event name/date range (wraps NBAPI GetEventHistory). |
| list_eventsA | Lists the event types/definitions known to the NetBox system (wraps NBAPI ListEvents). RESOLVEPARTITIONNAMES defaults to true — on by default, the same inverted opt-out default used by this codebase's other fixed-cost enrichments: each returned event is enriched with a PARTITIONNAME field resolved from its PARTITIONID via one GetPartitions fetch per call, not per event (GetPartitions costs the same whether it resolves one event or a thousand). Set RESOLVEPARTITIONNAMES: false to skip it. |
| get_access_historyA | Returns historical access (grant/deny) records for optional filters (wraps NBAPI GetAccessHistory). Identifies a person by ENCODEDNUM/HOTSTAMP, not PERSONID — GetAccessHistory has no PERSONID parameter. Set RESOLVENAMES: true to enrich each returned record with the badge-holder's FIRSTNAME/LASTNAME/FULLNAME/NOTES (default false — off); enabling it costs one extra GetPerson call per distinct person found in the result, which is why it is opt-in rather than on by default. RESOLVEDESCRIPTIONS defaults to true — the only default-on optional boolean in this codebase (an inverted, opt-out default, unlike RESOLVENAMES/dryRun-style flags elsewhere): each returned record is enriched with the reader's human-readable READERDESCRIPTION via one GetReaders full-table fetch per call (not per record, since the reader table is small and fixed-size); set RESOLVEDESCRIPTIONS: false to skip it. |
| get_reader_access_historyA | Returns a single reader's access (grant/deny) history for a given READERKEY, with each match's PERSONID enriched to a name (composite: wraps NBAPI GetAccessHistory + GetPerson). GetAccessHistory has no server-side reader filter, so this reads and filters client-side. Rather than a date range, it scans the most recent SCANWINDOW system-wide records (default 2000). RESOLVEDESCRIPTIONS defaults to true — an inverted, opt-out default like get_access_history's own RESOLVEDESCRIPTIONS: it attaches a single top-level READERDESCRIPTION field for the given READERKEY (not one per match — every match already shares this identical READERKEY by construction) via one GetReaders full-table fetch; set to false to omit it entirely. |
| get_time_specA | Returns the details of a single time spec for a given TIMESPECKEY (wraps NBAPI GetTimeSpec). |
| get_time_specsA | Lists time specs configured on the NetBox system (wraps NBAPI GetTimeSpecs). |
| get_time_spec_groupB | Returns the details of a single time spec group for a given TIMESPECGROUPKEY (wraps NBAPI GetTimeSpecGroup). |
| get_time_spec_groupsA | Lists time spec groups configured on the NetBox system (wraps NBAPI GetTimeSpecGroups). RESOLVEMEMBERNAMES defaults to true — an inverted, opt-out default (unlike most optional booleans in this codebase): GetTimeSpecGroups' TIMESPECKEYS.TIMESPECKEY member field carries only bare TIMESPECKEY strings, so this replaces each group member with a {TIMESPECKEY, NAME} object via one GetTimeSpecs full-table fetch per call (not per group/member). An unmatched (unknown/deleted) member key resolves to NAME: ''. Applies only to this plural tool, not the singular get_time_spec_group (confirmed broken/NOT FOUND on this controller — out of scope). Set RESOLVEMEMBERNAMES: false to skip the fetch and return TIMESPECKEYS exactly as GetTimeSpecGroups provides it (bare string or array of strings). |
| get_holidayA | Returns the details of a single holiday for a given HOLIDAYKEY (wraps NBAPI GetHoliday). |
| get_holidaysA | Lists holiday keys configured on the NetBox system (wraps NBAPI GetHolidays). Returns a comma-separated key string, not a list of records — use get_holiday per key for details. GetHolidays has no documented calling parameters (no pagination). |
| get_portal_groupA | Returns the details of a single portal group for a given PORTALGROUPKEY (wraps NBAPI GetPortalGroup). RESOLVEGROUPNAMES defaults to true — an inverted, opt-out default (unlike most optional booleans in this codebase): the raw response carries only a bare UNLOCKTIMESPECGROUPKEY foreign key, so this resolves it into a new sibling UNLOCKTIMESPECGROUPNAME field via one full-table GetTimeSpecGroups fetch per call — a fixed cost regardless of anything else, since a single portal group carries exactly one UNLOCKTIMESPECGROUPKEY. THREATLEVELGROUPKEY is never resolved (no NBAPI read command exists for threat level groups). Set RESOLVEGROUPNAMES: false to skip the fetch and return the response exactly as GetPortalGroup provides it. |
| get_portal_groupsA | Lists portal groups configured on the NetBox system (wraps NBAPI GetPortalGroups). RESOLVEGROUPNAMES defaults to true — an inverted, opt-out default (unlike most optional booleans in this codebase): each returned group's UNLOCKTIMESPECGROUPKEY is a bare foreign key, so this resolves it into a new sibling UNLOCKTIMESPECGROUPNAME field on every group. Costs at most one full-table GetTimeSpecGroups fetch per call — not per group — built once and skipped entirely when every group on the page has an empty/absent UNLOCKTIMESPECGROUPKEY. THREATLEVELGROUPKEY is never resolved (no NBAPI read command exists for threat level groups). Set RESOLVEGROUPNAMES: false to skip the fetch and return groups exactly as GetPortalGroups provides them. |
| get_reader_groupB | Returns the details of a single reader group for a given READERGROUPKEY (wraps NBAPI GetReaderGroup). |
| get_reader_groupsB | Lists reader groups configured on the NetBox system (wraps NBAPI GetReaderGroups). |
| get_threat_levelsA | Lists threat levels configured on the NetBox system, optionally filtered (wraps NBAPI GetThreatLevels). |
| get_partitionsA | Lists partitions configured on the NetBox system (wraps NBAPI GetPartitions). No parameters required. |
| get_udf_listsB | Lists user-defined field (UDF) lists configured on the NetBox system (wraps NBAPI GetUDFLists). No parameters required. |
| get_udf_list_itemsA | Returns the items of a single UDF list for a given UDFLISTKEY (wraps NBAPI GetUDFListItems). |
| get_mercury_panelsA | Lists the Mercury panels configured on the NetBox system, optionally filtered (wraps NBAPI GetMercuryPanels). Returns an empty collection (or a FAIL/"NOT FOUND") on a system with no Mercury hardware. |
| get_mercury_panelA | Returns the details of a single Mercury panel for a given MERCURYKEY (wraps NBAPI GetMercuryPanel). |
| get_network_nodesC | Lists the network nodes configured on the NetBox system, optionally filtered (wraps NBAPI GetNetworkNodes). |
| get_network_nodeA | Returns the details of a single network node for a given NODEKEY (wraps NBAPI GetNetworkNode). |
| get_siosA | Lists the SIOs (serial I/O boards) attached to one Mercury panel (wraps NBAPI GetSios). There is no unfiltered "all SIOs" listing — MERCURYKEY is required; the response carries a NEXTKEY pagination cursor. |
| get_sioA | Returns the details of a single SIO for a given SIOKEY (wraps NBAPI GetSio). Note: the v2 guide's worked example for GetSio sends MERCURYKEY, but its Calling Parameters list — which the guide makes authoritative — specifies SIOKEY, so SIOKEY is what this tool sends. |
| get_alarmsA | Returns alarm information from the NetBox system, optionally filtered by partition, alarm ID, event ID, activity ID or owner (wraps NBAPI GetAlarms). Responds with an ALARMS/ALARM collection; a system with no active alarms answers with an empty collection or a documented NOT FOUND. |
| get_elevatorsA | Lists elevators configured on the NetBox system (wraps NBAPI GetElevators). |
| get_floorsA | Lists floors configured on the NetBox system (wraps NBAPI GetFloors). |
| ping_appB | Pings the NetBox NBAPI application to confirm it is responsive (wraps NBAPI PingApp). No parameters required. |
| get_unlock_windowA | Reports the managed unlock window, if any: the managed portal group "MCP Unlock Window" (key, portals, its unlock time spec group and whether that is the managed time spec group "MCP Unlock Window time specs"), that group and its members (read from paginated GetTimeSpecGroups), the managed time specs and holidays, the window derived from them, and whether it is active right now on the host clock. Read-only: issues only Get commands. No parameters required. |
| get_daily_unlock_windowA | Reports the managed daily recurring unlock window, if any: the managed portal group "MCP Daily Unlock Window" (key, portals, its unlock time spec group and whether that is the managed time spec group "MCP Daily Unlock Window time specs"), that group and its members (read from paginated GetTimeSpecGroups), the one managed time spec and holiday, the window derived from them, and whether it is active right now on the host clock. Read-only: issues only Get commands. No parameters required. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 51 tools
Most tools map cleanly to a distinct resource and action, and the singular/plural pairs (e.g. get_time_spec vs get_time_specs) are clearly explained. A few sets such as ping_app vs check_connection, get_portal_states vs get_portal_statuses, and the access-history tools could cause misselection when skimming, but the detailed descriptions disambiguate them.
The dominant get_<entity> / get_<entity>s pattern is predictable and applied across most of the 51 tools. It is diluted by a few different verb styles (check_connection, ping_app, search_person_data, find_portals, list_events, get_guide), but there is no chaotic casing or inconsistent pluralization.
At 51 tools, the surface is far beyond the well-scoped range and even exceeds the 25+ 'too many' threshold. While each tool maps to an NBAPI read command, the sheer number makes the set unwieldy and in need of consolidation or modularization.
The read surface covers many NetBox entities, but there are zero create/update/delete tools, so agents can query but not manage the system. The gap is especially visible because get_locations references set_threat_level and the guide mentions write-safety, yet no such tool is exposed.