Files
leo-claude-mktplace/mcp-servers/netbox/mcp_server/config.py
lmiranda 8129be5ef3 feat(netbox)!: gut server from 182 to 37 tools
BREAKING CHANGE: Removed circuits, tenancy, VPN, wireless modules entirely.
Stripped DCIM, IPAM, virtualization, extras to only essential tools.
Deleted NETBOX_ENABLED_MODULES filtering — no longer needed.

- Delete circuits.py, tenancy.py, vpn.py, wireless.py
- Strip dcim.py to sites, devices, interfaces only (11 tools)
- Strip ipam.py to IPs, prefixes, services only (10 tools)
- Strip virtualization.py to clusters, VMs, VM interfaces only (10 tools)
- Strip extras.py to tags, journal entries only (6 tools)
- Remove all module filtering code from config.py and server.py
- Rewrite README.md with accurate 37-tool documentation
- Update CHANGELOG.md with breaking change entry
- Token reduction: ~19,810 → ~3,700 (~81%)

Remaining work: Update cmdb-assistant plugin skills (10 files) in follow-up PR

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 21:25:43 -05:00

109 lines
3.5 KiB
Python

"""
Configuration loader for NetBox MCP Server.
Implements hybrid configuration system:
- System-level: ~/.config/claude/netbox.env (credentials)
- Project-level: .env (optional overrides)
"""
from pathlib import Path
from dotenv import load_dotenv
import os
import logging
from typing import Dict, Optional
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class NetBoxConfig:
"""Configuration loader for NetBox MCP Server"""
def __init__(self):
self.api_url: Optional[str] = None
self.api_token: Optional[str] = None
self.verify_ssl: bool = True
self.timeout: int = 30
def load(self) -> Dict[str, any]:
"""
Load configuration from system and project levels.
Project-level configuration overrides system-level.
Returns:
Dict containing api_url, api_token, verify_ssl, timeout
Raises:
FileNotFoundError: If system config is missing
ValueError: If required configuration is missing
"""
# Load system config
system_config = Path.home() / '.config' / 'claude' / 'netbox.env'
if system_config.exists():
load_dotenv(system_config)
logger.info(f"Loaded system configuration from {system_config}")
else:
raise FileNotFoundError(
f"System config not found: {system_config}\n"
"Create it with:\n"
" mkdir -p ~/.config/claude\n"
" cat > ~/.config/claude/netbox.env << EOF\n"
" NETBOX_API_URL=https://your-netbox-instance/api\n"
" NETBOX_API_TOKEN=your-api-token\n"
" EOF"
)
# Load project config (overrides system)
project_config = Path.cwd() / '.env'
if project_config.exists():
load_dotenv(project_config, override=True)
logger.info(f"Loaded project configuration from {project_config}")
# Extract values
self.api_url = os.getenv('NETBOX_API_URL')
self.api_token = os.getenv('NETBOX_API_TOKEN')
# Optional settings with defaults
verify_ssl_str = os.getenv('NETBOX_VERIFY_SSL', 'true').lower()
self.verify_ssl = verify_ssl_str in ('true', '1', 'yes')
timeout_str = os.getenv('NETBOX_TIMEOUT', '30')
try:
self.timeout = int(timeout_str)
except ValueError:
self.timeout = 30
logger.warning(f"Invalid NETBOX_TIMEOUT value '{timeout_str}', using default 30")
# Validate required variables
self._validate()
# Normalize API URL (remove trailing slash)
if self.api_url and self.api_url.endswith('/'):
self.api_url = self.api_url.rstrip('/')
return {
'api_url': self.api_url,
'api_token': self.api_token,
'verify_ssl': self.verify_ssl,
'timeout': self.timeout
}
def _validate(self) -> None:
"""
Validate that required configuration is present.
Raises:
ValueError: If required configuration is missing
"""
required = {
'NETBOX_API_URL': self.api_url,
'NETBOX_API_TOKEN': self.api_token
}
missing = [key for key, value in required.items() if not value]
if missing:
raise ValueError(
f"Missing required configuration: {', '.join(missing)}\n"
"Check your ~/.config/claude/netbox.env file"
)