Skip to main content
Glama
chadkunsman

NetBox MCP Server

by chadkunsman
server.py11.3 kB
""" NetBox MCP Server A read-only FastMCP server that provides comprehensive tools for interacting with NetBox API. This server supports devices, sites, circuits, and IP prefixes, enabling natural language queries about network infrastructure in a NetBox instance without allowing any modifications to the NetBox data. """ import os from dotenv import load_dotenv from fastmcp import FastMCP, Context from fastmcp.exceptions import ToolError from models.device import DeviceFilterParameters, DeviceQuery, DeviceSummary from models.site import SiteSummary, SiteBasic from models.circuit import CircuitFilterParameters, CircuitQuery, CircuitSummary from models.prefix import PrefixFilterParameters, PrefixQuery, PrefixSummary from models.vlan import VlanFilterParameters, VlanQuery, VlanSummary from tools.devices import get_devices_by_filter, get_device_by_name, query_devices from tools.sites import get_site_info_by_name, list_all_sites from tools.circuits import get_circuits_by_filter, get_circuit_by_cid, query_circuits from tools.vlans import get_vlans_by_filter, get_vlan_by_id, query_vlans # Load environment variables load_dotenv() # Initialize the MCP server mcp = FastMCP("NetBox MCP Server") # Register tools @mcp.tool() async def get_devices(filter_params: DeviceFilterParameters, ctx: Context) -> list[DeviceSummary]: """ Get devices from NetBox based on filter parameters. Available filters: - site: Filter by site name (e.g., "SF1", "NYC1") - role: Filter by device role (e.g., "office_access_switch", "net-firewall") - status: Filter by status (e.g., "active", "planned", "offline") - name: Exact device name - name_contains: Pattern matching for device names (case-insensitive) - search: Cross-field search across name, model, description, and serial IMPORTANT: Treats multiple words as AND (all must match). For OR logic, use separate calls. Example: "UPS PDU" requires BOTH "UPS" AND "PDU" in the same record - use separate calls for UPS OR PDU devices. - manufacturer: Filter by manufacturer name - model: Filter by model name - limit: Maximum number of results (default 50, max 1000) Search strategy recommendations: - For device types: Use separate calls (search="UPS", then search="PDU") rather than "UPS PDU" - For patterns: Use name_contains (e.g., name_contains="ion" finds all ION devices) - For models/descriptions: Use search with single terms for best results Args: filter_params: Parameters to filter devices by ctx: MCP context """ return get_devices_by_filter(mcp, filter_params, ctx) @mcp.tool() async def get_device(name: str, ctx: Context) -> DeviceSummary: """ Get a specific device by name. Returns detailed information about a single device. Args: name: Device name ctx: MCP context """ return get_device_by_name(mcp, name, ctx) @mcp.tool() async def ask_about_devices(query: DeviceQuery, ctx: Context) -> list[DeviceSummary]: """ Query devices using natural language. Examples: - "Show me all devices at site SF1" - "List all active firewalls" - "Tell me about device sf1.as1" - "Show the first 5 switches at NYC location" Args: query: Natural language query string ctx: MCP context """ return query_devices(mcp, query, ctx) @mcp.tool() async def get_sites(limit: int = 50, ctx: Context = None) -> list[SiteBasic]: """ List all sites with basic information. Returns a list of all sites in NetBox with basic details like name, status, and region. Useful for discovering available sites before querying specific site details. Args: limit: Maximum number of sites to return (default 50, max 1000) ctx: MCP context """ # Validate limit if limit > 1000: limit = 1000 elif limit < 1: limit = 1 return list_all_sites(mcp, limit, ctx) @mcp.tool() async def get_site_info(name: str, ctx: Context) -> SiteSummary: """ Get comprehensive information about a site including device and rack counts. Provides detailed site information including: - Basic site details (name, status, region, etc.) - Physical location information - Device count at the site - Rack count at the site Args: name: Site name ctx: MCP context """ return get_site_info_by_name(mcp, name, ctx) @mcp.tool() async def get_circuits(filter_params: CircuitFilterParameters, ctx: Context) -> list[CircuitSummary]: """ Get circuits from NetBox based on filter parameters. Available filters: - cid: Exact circuit ID - cid_contains: Pattern matching for circuit IDs (case-insensitive) - provider: Filter by provider name (e.g., "Zayo", "Lumen", "Verizon") - type: Filter by circuit type (e.g., "Internet", "MPLS", "Point-to-Point") - status: Filter by status (e.g., "active", "provisioning", "decommissioned") - site: Filter by termination site (both A-side and Z-side) - search: Cross-field search across CID, provider, description, and terminations IMPORTANT: Treats multiple words as AND (all must match). Use separate calls for OR logic. - limit: Maximum number of results (default 50, max 1000) Search strategy recommendations: - For multiple providers: Use separate calls rather than "Zayo Lumen" search - For circuit patterns: Use cid_contains for partial CID matching - For general search: Use single terms for best results Args: filter_params: Parameters to filter circuits by ctx: MCP context """ return get_circuits_by_filter(mcp, filter_params, ctx) @mcp.tool() async def get_circuit(cid: str, ctx: Context) -> CircuitSummary: """ Get a specific circuit by circuit ID (CID). Returns detailed information about a single circuit including provider, type, status, and termination sites. Args: cid: Circuit ID ctx: MCP context """ return get_circuit_by_cid(mcp, cid, ctx) @mcp.tool() async def ask_about_circuits(query: CircuitQuery, ctx: Context) -> list[CircuitSummary]: """ Query circuits using natural language. Examples: - "Show me all internet circuits" - "List all circuits from provider Verizon" - "Tell me about circuit CID-12345" - "Show active MPLS circuits at site SF1" Args: query: Natural language query string ctx: MCP context """ return query_circuits(mcp, query, ctx) @mcp.tool() async def get_prefixes_tool(filter_params: PrefixFilterParameters, ctx: Context) -> dict: """ Get prefixes from NetBox with filtering options. Available filters: - prefix: Exact prefix (e.g., "192.168.1.0/24") - site: Filter by site name (e.g., "SF1", "NYC1") - vrf: Filter by VRF name - tenant: Filter by tenant name - status: Filter by status (e.g., "active", "reserved", "deprecated") - role: Filter by prefix role - family: IP family (4 for IPv4, 6 for IPv6) - vlan: Filter by VLAN ID or name - is_pool: Filter for prefix pools (true/false) - search: Cross-field search across prefix, description, VLAN, and site IMPORTANT: Treats multiple words as AND (all must match). Use separate calls for OR logic. - limit: Maximum number of results (default 50, max 1000) Search strategy recommendations: - For multiple sites: Use separate calls rather than "SF1 NYC1" search - For CIDR patterns: Use exact prefix filter or search with single terms - For general search: Use single terms for best results Args: filter_params: Parameters to filter prefixes by (prefix, site, vrf, status, etc.) ctx: MCP context """ from tools.prefixes import get_prefixes as get_prefixes_impl return get_prefixes_impl(filter_params, ctx) @mcp.tool() async def get_prefix_tool(prefix_id: int, ctx: Context) -> dict: """ Get detailed information about a specific prefix by ID. Returns comprehensive information about a single prefix including utilization, available IPs, site assignment, and related details. Args: prefix_id: NetBox prefix ID ctx: MCP context """ from tools.prefixes import get_prefix as get_prefix_impl return get_prefix_impl(prefix_id, ctx) @mcp.tool() async def ask_about_prefixes_tool(query: PrefixQuery, ctx: Context) -> dict: """ Query prefixes using natural language. Examples: - "Show me all IPv4 prefixes at site SF1" - "List active prefixes in VRF production" - "Find all /24 subnets" - "Show reserved prefix pools" - "Get prefixes for tenant ABC" Args: query: Natural language query string ctx: MCP context """ from tools.prefixes import ask_about_prefixes as ask_about_prefixes_impl return ask_about_prefixes_impl(query, ctx) @mcp.tool() async def get_vlans(filter_params: VlanFilterParameters, ctx: Context) -> list[VlanSummary]: """ Get VLANs from NetBox based on filter parameters. Available filters: - vid: VLAN ID number (e.g., 100) - name: Exact VLAN name - name_contains: Pattern matching for VLAN names (case-insensitive) - site: Filter by site name (e.g., "SF1", "NYC1") - group: Filter by VLAN group name - tenant: Filter by tenant name - role: Filter by VLAN role - status: Filter by status (e.g., "active", "reserved", "deprecated") - search: Cross-field search across name, description, and VID IMPORTANT: Treats multiple words as AND (all must match). Use separate calls for OR logic. - description_contains: Pattern matching for VLAN descriptions (case-insensitive) - tag: Filter by tag - limit: Maximum number of results (default 50, max 1000) Search strategy recommendations: - For VLAN names: Use name_contains for substring matching (e.g., name_contains="90" finds "VLAN-90-Production") - For VLAN IDs: Use vid for exact matches - For general search: Use search with single terms for best results Args: filter_params: Parameters to filter VLANs by ctx: MCP context """ return get_vlans_by_filter(mcp, filter_params, ctx) @mcp.tool() async def get_vlan(vlan_id: int, ctx: Context) -> VlanSummary: """ Get a specific VLAN by ID. Returns detailed information about a single VLAN including VID, name, site assignment, group, tenant, role, and status. Args: vlan_id: NetBox VLAN ID ctx: MCP context """ return get_vlan_by_id(mcp, vlan_id, ctx) @mcp.tool() async def ask_about_vlans(query: VlanQuery, ctx: Context) -> list[VlanSummary]: """ Query VLANs using natural language. Examples: - "Show me VLAN 100" - "List all VLANs at site SF1" - "Find VLANs with '90' in the name" - "Show active VLANs for tenant ABC" - "Get all production VLANs" Args: query: Natural language query string ctx: MCP context """ return query_vlans(mcp, query, ctx) if __name__ == "__main__": mcp.run()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/chadkunsman/netbox_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server