"""MCP tools for VLAN queries."""
import logging
from typing import Any, Dict, List, Optional
from mcp.types import TextContent, Tool
from src.netbox_client import NetBoxClient
from src.state_confidence import StateConfidenceClient
logger = logging.getLogger(__name__)
def get_vlan_tools(
netbox_client: NetBoxClient, state_client: Optional[StateConfidenceClient]
) -> List[Tool]:
"""Get all VLAN-related MCP tools.
Args:
netbox_client: NetBox API client
state_client: Optional state confidence client
Returns:
List of Tool definitions
"""
return [
Tool(
name="list_vlans",
description="List all VLANs from NetBox. Supports filtering by VLAN ID, name, or site.",
inputSchema={
"type": "object",
"properties": {
"vid": {
"type": "integer",
"description": "Filter by VLAN ID",
},
"name": {
"type": "string",
"description": "Filter by VLAN name (partial match supported)",
},
"site": {
"type": "string",
"description": "Filter by site slug",
},
"limit": {
"type": "integer",
"description": "Maximum number of results (default: 100)",
"default": 100,
},
"include_certainty": {
"type": "boolean",
"description": "Include state confidence scores in response",
"default": True,
},
},
},
),
Tool(
name="get_vlan",
description="Get detailed information about a specific VLAN by VLAN ID.",
inputSchema={
"type": "object",
"properties": {
"vlan_id": {
"type": "integer",
"description": "VLAN ID",
},
"include_certainty": {
"type": "boolean",
"description": "Include state confidence score in response",
"default": True,
},
},
"required": ["vlan_id"],
},
),
Tool(
name="list_vlan_ips",
description="List all IP addresses assigned to a specific VLAN.",
inputSchema={
"type": "object",
"properties": {
"vlan_id": {
"type": "integer",
"description": "VLAN ID",
},
"include_certainty": {
"type": "boolean",
"description": "Include state confidence scores in response",
"default": True,
},
},
"required": ["vlan_id"],
},
),
]
async def handle_list_vlans(
arguments: Dict[str, Any],
netbox_client: NetBoxClient,
state_client: Optional[StateConfidenceClient],
) -> List[TextContent]:
"""Handle list_vlans tool call.
Args:
arguments: Tool arguments
netbox_client: NetBox API client
state_client: Optional state confidence client
Returns:
List of TextContent with results
"""
vid = arguments.get("vid")
name = arguments.get("name")
site = arguments.get("site")
limit = arguments.get("limit", 100)
include_certainty = arguments.get("include_certainty", True)
vlans = netbox_client.list_vlans(
vid=vid, name=name, site=site, limit=limit
)
results = []
for vlan in vlans:
result = vlan.copy()
if include_certainty and state_client:
vlan_id = str(vlan.get("vid", ""))
certainty = state_client.get_certainty_score(
state_id=vlan_id, state_type="vlan"
)
if certainty:
result["certainty"] = certainty
results.append(result)
import json
return [
TextContent(
type="text",
text=f"Found {len(results)} VLAN(s):\n\n{json.dumps(results, indent=2)}",
)
]
async def handle_get_vlan(
arguments: Dict[str, Any],
netbox_client: NetBoxClient,
state_client: Optional[StateConfidenceClient],
) -> List[TextContent]:
"""Handle get_vlan tool call.
Args:
arguments: Tool arguments
netbox_client: NetBox API client
state_client: Optional state confidence client
Returns:
List of TextContent with result
"""
vlan_id = arguments.get("vlan_id")
if vlan_id is None:
return [
TextContent(
type="text",
text="Error: vlan_id parameter is required",
)
]
include_certainty = arguments.get("include_certainty", True)
vlan = netbox_client.get_vlan(vlan_id)
if not vlan:
return [
TextContent(
type="text",
text=f"VLAN {vlan_id} not found in NetBox",
)
]
result = vlan.copy()
if include_certainty and state_client:
certainty = state_client.get_certainty_score(
state_id=str(vlan_id), state_type="vlan"
)
if certainty:
result["certainty"] = certainty
import json
return [
TextContent(
type="text",
text=f"VLAN details:\n\n{json.dumps(result, indent=2)}",
)
]
async def handle_list_vlan_ips(
arguments: Dict[str, Any],
netbox_client: NetBoxClient,
state_client: Optional[StateConfidenceClient],
) -> List[TextContent]:
"""Handle list_vlan_ips tool call.
Args:
arguments: Tool arguments
netbox_client: NetBox API client
state_client: Optional state confidence client
Returns:
List of TextContent with results
"""
vlan_id = arguments.get("vlan_id")
if vlan_id is None:
return [
TextContent(
type="text",
text="Error: vlan_id parameter is required",
)
]
include_certainty = arguments.get("include_certainty", True)
ip_addresses = netbox_client.list_vlan_ip_addresses(vlan_id)
if ip_addresses is None:
return [
TextContent(
type="text",
text=f"VLAN {vlan_id} not found in NetBox",
)
]
results = []
for ip_addr in ip_addresses:
result = ip_addr.copy()
if include_certainty and state_client:
ip_addr_str = ip_addr.get("address", "")
# Remove CIDR notation for state_id lookup
state_id = (
ip_addr_str.split("/")[0]
if "/" in ip_addr_str
else ip_addr_str
)
certainty = state_client.get_certainty_score(
state_id=state_id, state_type="ip_address"
)
if certainty:
result["certainty"] = certainty
results.append(result)
import json
return [
TextContent(
type="text",
text=f"Found {len(results)} IP address(es) in VLAN {vlan_id}:\n\n{json.dumps(results, indent=2)}",
)
]