Skip to main content

MCP server that exposes homelab infrastructure tools to AI assistants

Project description

mcp-homelab

An MCP server that gives AI assistants real-time access to your homelab infrastructure. Connect it to Claude Desktop, VS Code Copilot, or any MCP-compatible client and your assistant can query node status, manage Docker containers, control Proxmox VMs, and inspect OPNsense firewall state — all through natural conversation.

Why

AI assistants are useful for infrastructure work, but they can't see your environment. You end up copy-pasting docker ps output, describing your network layout, and manually feeding context. mcp-homelab fixes that by giving the assistant direct access to live infrastructure data over SSH and REST APIs.

What it supports:

  • Any Linux host accessible via SSH (bare-metal, VMs, LXC containers)
  • Docker container listing, logs, and restart
  • Proxmox VE VM management (optional)
  • OPNsense firewall inspection (optional)

Proxmox and OPNsense are optional — the server works with just SSH-accessible hosts.

Requirements

  • Python 3.10+
  • SSH key access to at least one Linux host
  • MCP client: Claude Desktop, VS Code with Copilot, or any MCP-compatible client
  • (Optional) Proxmox VE with an API token
  • (Optional) OPNsense with API key/secret

Quick Start

git clone git@github.com:asvarnon/mcp-homelab.git
cd mcp-homelab
python -m venv .venv && .venv/Scripts/activate  # or source .venv/bin/activate on Linux/macOS
pip install -e .
mcp-homelab init                # creates config.yaml + .env from templates
# Edit config.yaml with your hosts, .env with API credentials
mcp-homelab setup check         # validates config and tests connectivity
mcp-homelab setup client        # auto-configures Claude Desktop / VS Code

That's it. Your MCP client will now spawn the server automatically when it needs homelab data.

Tools

Category Tool Description
Discovery scan_infrastructure Full topology snapshot (all nodes, VMs, containers, interfaces)
Discovery generate_context Auto-generate Markdown docs from live scan data
Discovery list_context_files Manifest of all files in the context directory
Nodes list_nodes All configured nodes from config
Nodes get_node_status Uptime, CPU, RAM, disk via SSH
Nodes list_containers Docker containers on a node
Nodes get_container_logs Last N lines of container logs
Nodes restart_container Restart a container
Proxmox list_vms All VMs with status and resources
Proxmox get_vm_status Detailed status for one VM
Proxmox start_vm Start a stopped VM
Proxmox stop_vm Gracefully stop a VM
OPNsense get_dhcp_leases Active DHCP leases
OPNsense get_interface_status Interface state
OPNsense get_firewall_aliases Alias definitions

Detailed Setup

The Quick Start above covers the basics. This section has details for specific integrations.

Configure

cp config.yaml.example config.yaml
cp .env.example .env
# Edit config.yaml with your hosts, then .env with API credentials

Proxmox API token (optional)

In the Proxmox web UI (https://your-pve-host:8006):

  1. Datacenter → Permissions → API Tokens → Add
  2. User: your PVE user (e.g. admin@pam)
  3. Token ID: mcp-homelab (or any label)
  4. Privilege Separation: Uncheck (token inherits user permissions)
  5. Copy the token secret — it's shown only once

Add to .env:

PROXMOX_TOKEN_ID=admin@pam!mcp-homelab
PROXMOX_TOKEN_SECRET=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

The Proxmox host/port/SSL settings are in config.yaml under the proxmox: section.

Node access

Each node's SSH credentials are defined in config.yaml (per-node ssh_user and ssh_key_path fields). Edit these to match your environment.

Docker sudo (if required)

If the SSH user is not in the docker group, set sudo_docker: true for that node in config.yaml. This requires passwordless sudo for the docker binary on the target host:

# On the remote node:
echo '<username> ALL=(ALL) NOPASSWD: /usr/bin/docker' | sudo tee /etc/sudoers.d/docker-nopasswd
sudo chmod 440 /etc/sudoers.d/docker-nopasswd
sudo visudo -cf /etc/sudoers.d/docker-nopasswd   # must print "parsed OK"

If the SSH user is already in the docker group, set sudo_docker: false (the default) and no sudoers changes are needed.

Hardware memory details (optional)

generate_context and scan_infrastructure gather hardware specs via SSH. Most data comes from unprivileged commands (lscpu, /proc/meminfo, lsblk), but per-DIMM memory details (type, speed, manufacturer) require dmidecode, which needs root access.

If you want memory module details in your generated docs, grant passwordless sudo for dmidecode:

# On each remote node:
echo '<username> ALL=(ALL) NOPASSWD: /usr/sbin/dmidecode' | sudo tee /etc/sudoers.d/dmidecode-nopasswd
sudo chmod 440 /etc/sudoers.d/dmidecode-nopasswd
sudo visudo -cf /etc/sudoers.d/dmidecode-nopasswd   # must print "parsed OK"

Without this, everything else still works — the memory modules section is simply omitted from generated docs.

MCP client connection

The setup client command auto-configures Claude Desktop and VS Code to use your server. It detects your venv Python, resolves paths, and merges the entry into existing config files without overwriting other servers.

# Interactive — picks Claude Desktop, VS Code, or both
mcp-homelab setup client

# Preview what would be written (no changes)
mcp-homelab setup client --dry-run

This writes the correct stdio transport entry including the MCP_HOMELAB_CONFIG_DIR env var, so the server can find config.yaml and .env regardless of the client's working directory.

Manual configuration (if you prefer editing JSON directly)

Claude Desktop — edit %APPDATA%/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "homelab": {
      "command": "C:/path/to/mcp-homelab/.venv/Scripts/python.exe",
      "args": ["C:/path/to/mcp-homelab/server.py"],
      "env": {
        "MCP_HOMELAB_CONFIG_DIR": "C:/path/to/mcp-homelab"
      }
    }
  }
}

VS Code (Copilot) — add .vscode/mcp.json in your workspace:

{
  "servers": {
    "homelab": {
      "command": "C:/path/to/mcp-homelab/.venv/Scripts/python.exe",
      "args": ["C:/path/to/mcp-homelab/server.py"],
      "env": {
        "MCP_HOMELAB_CONFIG_DIR": "C:/path/to/mcp-homelab"
      }
    }
  }
}

The MCP_HOMELAB_CONFIG_DIR env var is required — without it, MCP clients that spawn from a different working directory won't find your config files.

Running directly

python server.py

The server starts on stdio transport (standard for MCP). Normally you don't run this directly — the MCP client spawns it automatically.

Custom context notes

mcp-homelab generates infrastructure docs into context/generated/ from live scan data. If you also have your own curated notes (architecture docs, runbooks, etc.) that you want your AI assistant to reference, don't put them in this project.

Instead, connect your documentation workspace to the MCP client directly:

  • Claude Desktop / ChatGPT: Add a separate filesystem MCP server pointing at your docs folder
  • VS Code / Copilot: Add your docs folder to the workspace — the agent sees all workspace files automatically

This keeps concerns separated: mcp-homelab handles live infrastructure state, your docs workspace handles curated knowledge, and the MCP client aggregates both.

Testing

Unit tests use pytest with full mocking — no real infrastructure required.

Install test dependencies

pip install pytest pytest-asyncio

Run tests

# All tests
python -m pytest tests/ -v

# Single module
python -m pytest tests/unit/test_node_parsers.py -v

# Single test class
python -m pytest tests/unit/test_ssh.py::TestConnect -v

# Single test
python -m pytest tests/unit/test_config.py::TestBootstrapConfigDir::test_sets_env_when_unset -v

Test structure

tests/
├── conftest.py                  # Shared fixtures (sample configs, mock SSH, env helpers)
└── unit/
    ├── test_config.py           # Config loading, bootstrap, env validation, Pydantic models
    ├── test_ssh.py              # Connection caching, stale eviction, credential resolution
    ├── test_node_parsers.py     # All SSH output parsers (uptime, CPU, memory, disk, Docker,
    │                            #   lscpu, meminfo, lsblk, dmidecode, labels, rounding)
    ├── test_proxmox_tools.py    # VM listing, status conversion, node discovery
    ├── test_opnsense_tools.py   # DHCP leases, interfaces, firewall aliases
    ├── test_prompts.py          # Input validation (IP, int, path, yes/no, node names)
    ├── test_config_writer.py    # YAML round-trip, .env upserts, section preservation
    └── test_client_setup.py     # JSONC stripping, OS detection, atomic writes, config merging

Project Structure

mcp-homelab/
├── server.py              # MCP entry point — registers all tools
├── tools/
│   ├── discovery.py       # Composite scan tool for agent bootstrapping
│   ├── context_gen.py     # Documentation generation from scan data
│   ├── nodes.py           # SSH-based node tools + output parsers
│   ├── proxmox.py         # Proxmox REST API tools
│   └── opnsense.py        # OPNsense REST API tools
├── core/
│   ├── config.py          # Config loader, bootstrap, env var accessors
│   ├── ssh.py             # SSH connection manager (paramiko)
│   ├── proxmox_api.py     # Proxmox REST API client (httpx)
│   └── opnsense_api.py    # OPNsense REST API client (httpx)
├── mcp_homelab/
│   ├── cli.py             # CLI entry point (init, serve, setup)
│   └── setup/
│       ├── prompts.py     # Validated input prompts
│       ├── config_writer.py # YAML/env round-trip writer
│       ├── node_setup.py  # Interactive node configuration
│       ├── client_setup.py # MCP client config writer (Claude Desktop, VS Code)
│       ├── check.py       # Read-only health check
│       └── ssh_helpers.py # SSH test + capability detection
├── tests/                 # pytest unit tests (see Testing section)
├── config.yaml.example    # Example host definitions (copy to config.yaml)
├── .env.example           # Required env vars template
├── requirements.txt       # Runtime dependencies
├── pyproject.toml         # Package metadata + pytest config
└── Dockerfile             # Container packaging

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_homelab-1.1.0.tar.gz (68.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_homelab-1.1.0-py3-none-any.whl (45.0 kB view details)

Uploaded Python 3

File details

Details for the file mcp_homelab-1.1.0.tar.gz.

File metadata

  • Download URL: mcp_homelab-1.1.0.tar.gz
  • Upload date:
  • Size: 68.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.6

File hashes

Hashes for mcp_homelab-1.1.0.tar.gz
Algorithm Hash digest
SHA256 3246ed9bab7146f521a202e7e453fc6c9e6eafd2e82ed61b3eee09d630b4a896
MD5 31389a8a7173101f07fafd7032e40d57
BLAKE2b-256 96e13153cf4472a986a8ba6afe8158221ca0d061ad7b3a73900312effee27b63

See more details on using hashes here.

File details

Details for the file mcp_homelab-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: mcp_homelab-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 45.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.6

File hashes

Hashes for mcp_homelab-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c98be84934c82fc4ddef50d8c854c0055aea4b4b674456e9603bc047244feb6f
MD5 ef41fd153a7644d84730059e260cbd3e
BLAKE2b-256 271cb1dfdaddd80174d10cc7b537ca286017f992ff30d55cfada3e1a95b6203d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page