Controlling Your Homelab with Claude Code and MCP Servers
After building out my homelab automation stack with Ansible, Semaphore, and Zabbix, I started looking for the next level of productivity. The answer turned out to be Model Context Protocol (MCP) - an open standard from Anthropic that lets AI assistants like Claude talk directly to external tools and APIs. Once I had MCP servers wired into my homelab, I could ask Claude things like "show me all active Zabbix problems" or "restart the docker01 container" and actually get results.
What Is MCP?#
MCP is a client-server protocol that lets AI assistants invoke tools in external systems. The AI (Claude) acts as a client that can call tools exposed by MCP servers. Each MCP server wraps an API or service and exposes a set of tools with defined schemas.
Think of it as a standardized interface for AI tool use. Instead of writing custom code for every integration, you run an MCP server that wraps your API and Claude can discover and use its tools automatically.
The workflow is simple:
Claude Code (client) → MCP Server → Your API/Service
You configure which MCP servers to connect to in a .mcp.json file, and Claude Code loads them at startup. From that point, Claude can call any tool the server exposes.
The Servers I Deployed#
Zabbix MCP#
The most useful server day-to-day. I use uvx zabbix-mcp which wraps the Zabbix API and exposes tools for querying hosts, problems, triggers, templates, and maintenance windows.
Typical use cases:
- "Are there any active problems right now?"
- "What triggers are firing on docker01?"
- "Create a maintenance window for pve02 for the next 2 hours"
- "Show me the last 10 events for pihole"
Critical version pin: FastMCP 3.0.x broke tool registration entirely. The MCP panel in Claude Code showed "connected" but no tools were discoverable. The fix is pinning fastmcp==2.14.5 and zabbix-mcp==0.2.0 in .mcp.json:
{
"mcpServers": {
"zabbix": {
"command": "uvx",
"args": [
"--with", "fastmcp==2.14.5",
"--with", "zabbix-mcp==0.2.0",
"zabbix-mcp"
],
"env": {
"ZABBIX_URL": "http://10.0.1.103",
"ZABBIX_TOKEN": "your-token-here",
"PATH": "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"
}
}
}
}The PATH override is required because uvx uses realpath internally, which is in Homebrew's bin on macOS. Without it, the server fails to start silently.
Proxmox MCP#
Wraps the Proxmox API to give Claude visibility into VMs, LXC containers, nodes, and storage. I use it to check VM status, view resource usage, and manage snapshots.
The server needed two fixes before it worked reliably:
-
safety_policy.json: The server ships with a safety policy that blocks destructive operations by default. I configured a
safety_policy.jsonto allow the operations I actually use (power control, snapshot management) while keeping truly dangerous operations blocked (delete, format). -
URL format: The server expects the base URL to end with
/api2/json. Without this, API calls return 404s. Make sure your configured URL ishttps://10.0.1.45/api2/jsonnot justhttps://10.0.1.45.
With those fixes, I can ask Claude "what's running on pve01?" and get a live list of VMs and containers with their status and resource usage.
Semaphore MCP#
The Semaphore MCP server (published to PyPI) exposes all 48 Semaphore API endpoints as tools. I use it most for checking recent task history, triggering playbook runs, and debugging failed tasks.
Killer feature: analyze_task_failure - when a Semaphore task fails, I can ask Claude "why did template 15 fail on the last run?" and get an actual analysis of the task log with the specific error and likely cause. This beats SSH-ing into the Semaphore host and scrolling through log output.
UniFi MCP#
This one I wrote from scratch because no decent UniFi MCP server existed at the time. It wraps the UniFi Network Application API using X-API-KEY authentication.
Tools include:
list_clients- all connected devices with IP, MAC, and signal strengthlist_devices- all UniFi hardware with statusget_site_stats- overall network healthlist_port_forwards- all configured port forwardsupdate_wlan- modify wireless network settingsblock_client/unblock_client- client access control
Being able to ask "which devices are connected to the guest network right now?" or "add a DHCP reservation for this MAC address" and have it actually execute is genuinely useful.
GitHub MCP#
Used for managing my homelab and personal repos without leaving the terminal. Had a bad experience with version 2026.1.14 which had significant regressions - rolled back to 2025.4.8 which is stable.
Other Servers#
- Weather MCP: Basic weather lookup. Mostly used as a test server when debugging MCP connectivity.
- YouTube-DLP MCP: Download audio or video from YouTube URLs directly from Claude. Handy for pulling podcast audio for offline listening.
- Bacularis MCP: Wraps the Bacula/Bacularis API for backup job status. Still working on getting credentials sorted.
The .mcp.json Configuration#
All server configurations live in a .mcp.json file in the project directory (or globally in ~/.claude/mcp.json). Here is the pattern I use:
{
"mcpServers": {
"proxmox": {
"command": "uvx",
"args": ["proxmox-mcp"],
"env": {
"PROXMOX_HOST": "10.0.1.45",
"PROXMOX_TOKEN_ID": "root@pam!claude-code",
"PROXMOX_TOKEN_SECRET": "your-token-secret",
"PROXMOX_VERIFY_SSL": "false"
}
},
"semaphore": {
"command": "uvx",
"args": ["semaphore-mcp"],
"env": {
"SEMAPHORE_URL": "http://10.0.1.177:3000",
"SEMAPHORE_API_TOKEN": "your-token"
}
}
}
}The uvx runner handles installing the package in an isolated environment automatically. No virtual environments to manage, no pip installs - just uvx package-name and it works.
Real-World Workflow#
Here is a typical troubleshooting session using MCP tools:
- Get a Telegram alert from Zabbix: "Host pve01 CPU utilization > 85%"
- Open Claude Code, ask: "What active Zabbix problems are there right now?"
- Claude calls
mcp__zabbix__problem_get(severities=[2,3,4,5])and returns current problems - "Show me what is running on pve01 that might be causing high CPU"
- Claude calls
mcp__proxmox__list_vms(node='pve01')andmcp__proxmox__get_resource_usage() - "Run the ping playbook against all hosts to check connectivity"
- Claude calls
mcp__semaphore__run_task(template_id=12)
The whole investigation that used to involve opening four browser tabs (Zabbix, Proxmox, Semaphore, terminal) now happens in one conversation. Claude has the context of the entire session so it can correlate information across tools.
Lessons Learned#
Version Pins Matter#
Package versions for MCP servers matter more than you would expect. I burned several hours on the FastMCP 3.0.x regression before finding the fix. When an MCP server shows "connected" but tools are not discoverable, start by checking the FastMCP version.
Keep Credentials Out of .mcp.json#
The .mcp.json file should never contain raw credentials. Use environment variable references or a secrets file that is excluded from version control. I use my Enigma credential store and load values from ~/.secrets which is sourced by my shell but never committed.
Not Every Tool Needs MCP#
MCP shines for interactive investigation and ad-hoc operations. For scheduled automation, Semaphore + Ansible is still the right tool. MCP is the human-in-the-loop layer, not a replacement for proper automation infrastructure.
Safety Policies Are Important#
The Proxmox MCP server's safety policy concept is worth using for any server that can cause damage. Define explicit allow lists for operations you want to permit and default to denying everything else. The operational cost of a misfire in a homelab is low, but building the habit of explicit permissions is worth it.
What's Next#
- Bacularis credentials: Getting the backup monitoring MCP fully wired up so I can query job history and verify restores from Claude
- Unraid MCP: The Unraid API is GraphQL-based, which makes it a good candidate for a custom MCP server with tools for array status, Docker container management, and VM control
- SIEM integration: Exploring a Graylog MCP for querying log events during investigations
For the underlying infrastructure these tools manage, see Building My Homelab. For the Ansible automation layer, check out Automating Proxmox with Ansible and Semaphore.