Date: 2026-04-04 Host: docker-host (LXC 100) IP address: 192.168.0.110
23 - Homelable Network Visualization + MCP Setup¶
What is Homelable¶
Homelable is a self-hosted infrastructure visualization and monitoring tool. It provides an interactive drag-and-drop canvas for mapping homelab topology, live node status checks (ping, HTTP, TCP, SSH), automatic network scanning via nmap, and an MCP server for AI integration.
Chosen over alternatives (Scanopy, homelab-hub, RackPeek) because: - MCP server allows Claude Code to query infrastructure state directly - Active development (weekly releases) - Simpler configuration than Scanopy (which was previously attempted but too complex) - Live health checks complement Uptime Kuma
Architecture¶
Three Docker containers running on LXC 100:
| Container | Image | Role |
|---|---|---|
homelable-backend |
ghcr.io/pouzor/homelable-backend:latest |
Python/FastAPI backend, SQLite DB |
homelable-frontend |
ghcr.io/pouzor/homelable-frontend:latest |
React frontend served via nginx |
homelable-mcp |
built from /opt/homelable/mcp |
FastAPI MCP server for AI clients |
Backend and frontend use prebuilt images from GitHub Container Registry. The MCP service has no prebuilt image and is built from source (cloned separately at /opt/homelable).
All three containers share an internal bridge network (homelable). Only frontend (3001) and MCP (8001) are exposed to the host network.
Installation¶
Prerequisites¶
Clone the homelable source (needed for MCP build context):
git clone https://github.com/Pouzor/homelable.git /opt/homelable
mkdir -p /srv/docker-data/homelable
Install passlib for bcrypt hash generation:
Generate Secrets¶
# SECRET_KEY
python3 -c "import secrets; print(secrets.token_hex(32))"
# MCP_API_KEY
python3 -c "import secrets; print(secrets.token_hex(32))"
# MCP_SERVICE_KEY
python3 -c "import secrets; print(secrets.token_hex(32))"
# AUTH_PASSWORD_HASH (replace 'yourpassword')
python3 -c "from passlib.context import CryptContext; print(CryptContext(schemes=['bcrypt']).hash('yourpassword'))"
Komodo Stack Setup¶
Compose file is in the homelab git repo at compose/proxmox-lxc-100/homelable/docker-compose.yml.
Stack path in Komodo: compose/proxmox-lxc-100/homelable
Stack Environment (sensitive values, not in git):
SECRET_KEY=<generated>
AUTH_USERNAME=admin
AUTH_PASSWORD_HASH='$2b$12$...'
MCP_API_KEY=<generated>
MCP_SERVICE_KEY=<generated>
Note: AUTH_PASSWORD_HASH must be wrapped in single quotes because bcrypt hashes contain $ characters that Docker would otherwise interpret as variable substitution.
Deploy¶
In Komodo: Deploy Stack → homelable. Komodo writes the Stack Environment to .env, pulls prebuilt images for backend/frontend, and builds the MCP image from /opt/homelable/mcp.
Access: http://192.168.0.110:3001 - default credentials admin / admin (change immediately after first login).
Docker Compose¶
Key design decisions:
- Service names are
backend,frontend,mcp(nothomelable-*) - the frontend nginx config hardcodesbackendas the upstream hostname, so Docker DNS must resolve that name env_file: .envon backend and mcp services - Komodo writes Stack Environment to.env, which the containers read for secrets- Non-sensitive vars (
SCANNER_RANGES,STATUS_CHECKER_INTERVAL,CORS_ORIGINS) are hardcoded in the compose file cap_add: NET_RAWon backend - required for ICMP ping-based status checks
MCP Integration with Claude Code¶
The MCP server exposes the homelab topology to Claude Code. This allows Claude to query which nodes are online, trigger network scans, and manage the canvas without the user manually describing the infrastructure.
Available MCP Tools¶
| Tool | Description |
|---|---|
list_nodes |
List all devices on the canvas |
get_canvas |
Full topology (nodes + edges) |
create_node |
Add a new device |
update_node |
Edit device properties |
delete_node |
Remove a device |
create_edge |
Add a network link |
delete_edge |
Remove a link |
trigger_scan |
Run nmap scan on configured CIDR ranges |
list_pending_devices |
Devices discovered but not yet approved |
approve_device |
Add a discovered device to canvas |
hide_device |
Dismiss a discovered device |
Claude Code Configuration¶
Add to ~/.claude.json under mcpServers for the /root/homelab project:
"homelable": {
"type": "http",
"url": "http://192.168.0.110:8001/mcp",
"headers": {
"X-API-Key": "your_mcp_api_key_here"
}
}
Note: Use "type": "http" not "type": "sse" - SSE transport is deprecated in Claude Code. The MCP server uses StreamableHTTP which is compatible with the HTTP transport type.
Update Procedure¶
Backend and frontend update automatically via Komodo's nightly image pull (03:00). The MCP service is different - it has no prebuilt image and is built from source, so the upstream repo must be pulled before redeploying.
Why a separate procedure is needed¶
All other stacks use prebuilt Docker images. Komodo's auto-update just pulls the latest image and restarts the container. Homelable MCP has no published image - it is built locally from /opt/homelable/mcp. Without pulling the upstream repo first, Komodo would rebuild the same old source every time.
Komodo Action: homelable-git-pull¶
Action File contents:
await komodo.execute_server_terminal({
server: "LXC 100",
command: "cd /opt/homelable && git pull",
init: { command: "bash" },
}, {
onLine: (line) => console.log(line),
onFinish: (code) => console.log("Exit code:", code),
});
Komodo Procedure: homelable-update¶
| Stage | Type | Target |
|---|---|---|
| Stage 1 | Run Action | homelable-git-pull |
| Stage 2 | Deploy Stack | homelable |
Stages run sequentially - Stage 2 only starts after the git pull completes.
Schedule¶
The procedure is scheduled to run daily at 03:10 (after Komodo's 03:00 auto-update):
Full nightly flow:
- 03:00 - Komodo auto-update pulls new homelable-backend and homelable-frontend images
- 03:10 - homelable-update procedure: git pull MCP source → redeploy (rebuilds MCP + re-pulls images)
To update manually: Komodo > Procedures > homelable-update > Run.
Data¶
| Path | Description |
|---|---|
/srv/docker-data/homelable/ |
SQLite database (homelab.db) |
/opt/homelable/ |
Upstream source clone (MCP build context) |
Lessons Learned¶
- Service naming matters for Docker DNS: The frontend nginx config has
proxy_pass http://backend:8000hardcoded. Naming the backend servicehomelable-backendin docker-compose breaks this - Docker DNS resolves by service name, not container name. Services must be namedbackend,frontend,mcp. - SSE vs HTTP transport in Claude Code: The MCP server uses
StreamableHTTPSessionManager(HTTP-based). Configuring Claude Code with"type": "sse"causes a "connecting" state that never resolves. Use"type": "http"instead - SSE transport is deprecated. - MCP has no prebuilt image: Only backend and frontend are published to
ghcr.io. The MCP service must be built from source. This requires the upstream repo to be cloned on the Docker host and referenced as an absolute path build context in docker-compose. - passlib not available via pip3 on Debian: The
pip3command was not installed. Useapt-get install python3-passlib python3-bcryptinstead for bcrypt hash generation. - Komodo Stack Environment and bcrypt: When pasting a bcrypt hash into Komodo Stack Environment, wrap it in single quotes in the value field. Bcrypt hashes contain
$2b$and$sequences which are interpreted as shell variable references without quoting.