refactor: bundle MCP servers inside plugins for cache compatibility
Claude Code only caches the plugin directory when installed from a
marketplace, not parent directories. This broke the shared mcp-servers/
architecture because relative paths like ../../mcp-servers/ resolved
to non-existent locations in the cache.
Changes:
- Move gitea and wikijs MCP servers into plugins/projman/mcp-servers/
- Move netbox MCP server into plugins/cmdb-assistant/mcp-servers/
- Update .mcp.json files to use ${CLAUDE_PLUGIN_ROOT}/mcp-servers/
- Update setup.sh to handle new bundled structure
- Add netbox.env config template to setup.sh
- Update CLAUDE.md and CANONICAL-PATHS.md documentation
This ensures plugins work correctly when installed and cached.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
108
plugins/cmdb-assistant/mcp-servers/netbox/mcp_server/config.py
Normal file
108
plugins/cmdb-assistant/mcp-servers/netbox/mcp_server/config.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""
|
||||
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"
|
||||
)
|
||||
Reference in New Issue
Block a user