# Homelab MCP Server

**Last updated:** 2026-03-21

The homelab MCP (Model Context Protocol) server exposes tools that allow AI assistants (OpenCode/Claude) to interact directly with homelab infrastructure. It runs as a stdio subprocess started by OpenCode on session init.

---

## Location & Config

| Item | Path |
|------|------|
| Server source | `scripts/homelab-mcp/server.py` |
| OpenCode config | `~/.config/opencode/opencode.json` |
| Runtime | Python 3, `fastmcp` library |
| Transport | stdio (started per-session by OpenCode) |

Changes to `server.py` take effect on the **next OpenCode session** (the server is restarted each session).

---

## Tool Categories

### 1. Portainer — Docker orchestration

Manages containers and stacks across all 5 Portainer endpoints.

| Tool | What it does |
|------|-------------|
| `check_portainer` | Health check — version and stack count |
| `list_endpoints` | List all endpoints (Atlantis, Calypso, NUC, Homelab VM, RPi5) |
| `list_stacks` | List all stacks, optionally filtered by endpoint |
| `get_stack` | Get details of a specific stack by name or ID |
| `redeploy_stack` | Trigger GitOps redeploy (pull from Git + redeploy) |
| `list_containers` | List running containers on an endpoint |
| `get_container_logs` | Fetch recent logs from a container |
| `restart_container` | Restart a container |
| `start_container` | Start a stopped container |
| `stop_container` | Stop a running container |
| `list_stack_containers` | List all containers belonging to a stack |

**Endpoints:** `atlantis` (id=2), `calypso` (id=443397), `nuc` (id=443398), `homelab` (id=443399), `rpi5` (id=443395)

---

### 2. Gitea — Source control

Interacts with the self-hosted Gitea instance at `git.vish.gg`.

| Tool | What it does |
|------|-------------|
| `gitea_list_repos` | List all repos in the org |
| `gitea_list_issues` | List open/closed issues for a repo |
| `gitea_create_issue` | Create a new issue |
| `gitea_list_branches` | List branches for a repo |

**Default org:** `vish` — repo names can be `homelab` or `vish/homelab`

---

### 3. AdGuard — Split-horizon DNS

Manages DNS rewrite rules on the Calypso AdGuard instance (`192.168.0.250:9080`).

Critical context: the wildcard `*.vish.gg → 100.85.21.51` (matrix-ubuntu Tailscale IP) requires specific overrides for services that internal hosts need to reach directly (e.g. `pt.vish.gg`, `sso.vish.gg`, `git.vish.gg` all need `→ 192.168.0.154`).

| Tool | What it does |
|------|-------------|
| `adguard_list_rewrites` | List all DNS overrides |
| `adguard_add_rewrite` | Add a new domain → IP override |
| `adguard_delete_rewrite` | Remove a DNS override |

---

### 4. NPM — Nginx Proxy Manager

Manages reverse proxy hosts and SSL certs on matrix-ubuntu (`192.168.0.154:81`).

**Critical cert rule:** Never reuse an existing `npm-N` ID. Always use the next available number when adding new certs.

| Tool | What it does |
|------|-------------|
| `npm_list_proxy_hosts` | List all proxy hosts with domain, forward target, cert ID |
| `npm_list_certs` | List all SSL certs with type and expiry |
| `npm_get_proxy_host` | Get full details of a proxy host including advanced nginx config |
| `npm_update_cert` | Swap the SSL cert on a proxy host |

**Cert reference:**
| ID | Domain | Type |
|----|--------|------|
| npm-1 | `*.vish.gg` + `vish.gg` | Cloudflare Origin (proxied only) |
| npm-6 | `mx.vish.gg` | Let's Encrypt |
| npm-7 | `livekit.mx.vish.gg` | Let's Encrypt |
| npm-8 | `*.vish.gg` CF Origin | Cloudflare Origin (all proxied `*.vish.gg`) |
| npm-9 | `*.thevish.io` | Let's Encrypt |
| npm-10 | `*.crista.love` | Let's Encrypt |
| npm-11 | `pt.vish.gg` | Let's Encrypt |
| npm-12 | `sso.vish.gg` | Let's Encrypt |

---

### 5. Headscale — Tailnet management

Manages nodes and pre-auth keys via SSH to Calypso → `docker exec headscale`.

| Tool | What it does |
|------|-------------|
| `headscale_list_nodes` | List all tailnet nodes with IPs and online status |
| `headscale_create_preauth_key` | Generate a new node auth key (with expiry/reusable/ephemeral options) |
| `headscale_delete_node` | Remove a node from the tailnet |
| `headscale_rename_node` | Rename a node's given name |

**Login server:** `https://headscale.vish.gg:8443`
**New node command:** `tailscale up --login-server=https://headscale.vish.gg:8443 --authkey=<key> --accept-routes=false`

---

### 6. Authentik — SSO identity provider

Manages OAuth2/OIDC apps, providers, and users at `sso.vish.gg`.

| Tool | What it does |
|------|-------------|
| `authentik_list_applications` | List all SSO apps with slug, provider, launch URL |
| `authentik_list_providers` | List all OAuth2/proxy providers with PK and type |
| `authentik_list_users` | List all users with email and active status |
| `authentik_update_app_launch_url` | Update the dashboard tile URL for an app |
| `authentik_set_provider_cookie_domain` | Set cookie domain on a proxy provider (must be `vish.gg` to avoid redirect loops) |

**Critical:** All Forward Auth proxy providers must have `cookie_domain: vish.gg` or they cause `ERR_TOO_MANY_REDIRECTS`.

---

### 7. Cloudflare — DNS management

Manages DNS records for the `vish.gg` zone.

| Tool | What it does |
|------|-------------|
| `cloudflare_list_dns_records` | List all DNS records, optionally filtered by name |
| `cloudflare_create_dns_record` | Create a new A/CNAME/TXT record |
| `cloudflare_delete_dns_record` | Delete a DNS record by ID |
| `cloudflare_update_dns_record` | Update an existing record's content or proxied status |

**Proxied (orange cloud):** Most `*.vish.gg` services
**Unproxied (DNS-only):** `mx.vish.gg`, `headscale.vish.gg`, `livekit.mx.vish.gg`, `pt.vish.gg`, `sso.vish.gg`, `derp*.vish.gg`

---

### 8. Uptime Kuma — Monitoring

Manages monitors and groups via SSH to Pi-5 → SQLite DB manipulation.

**Always call `kuma_restart` after adding or modifying monitors** — Kuma caches config in memory.

| Tool | What it does |
|------|-------------|
| `kuma_list_monitors` | List all monitors with type, status, URL/hostname, group |
| `kuma_list_groups` | List all group monitors with IDs (for use as `parent_id`) |
| `kuma_add_monitor` | Add a new http/port/ping/group monitor |
| `kuma_set_parent` | Assign a monitor to a group |
| `kuma_restart` | Restart Kuma container to apply DB changes |

**Monitor group hierarchy:**
```
Homelab (3) → Atlantis (4), Calypso (49), Concord_NUC (44),
              Raspberry Pi 5 (91), Guava (73), Setillo (58),
              Proxmox_NUC (71), Seattle (111),
              Matrix-Ubuntu (115), Moon (114)
```

---

### 9. Prometheus — Metrics queries

Queries the Prometheus instance at `192.168.0.210:9090`.

| Tool | What it does |
|------|-------------|
| `prometheus_query` | Run a PromQL instant query |
| `prometheus_targets` | List all scrape targets and their health |

---

### 10. Grafana — Dashboards & alerts

Inspects dashboards and alert rules at `192.168.0.210:3300`.

| Tool | What it does |
|------|-------------|
| `grafana_list_dashboards` | List all dashboards with folder |
| `grafana_list_alerts` | List all alert rules and current state |

---

### 11. Media — Sonarr / Radarr / SABnzbd

Manages the media download stack on Atlantis.

| Tool | What it does |
|------|-------------|
| `sonarr_list_series` | List TV series, optionally filtered by title |
| `sonarr_queue` | Show current Sonarr download queue |
| `radarr_list_movies` | List movies, optionally filtered by title |
| `radarr_queue` | Show current Radarr download queue |
| `sabnzbd_queue` | Show SABnzbd download queue with progress |
| `sabnzbd_pause` | Pause the SABnzbd queue |
| `sabnzbd_resume` | Resume the SABnzbd queue |

---

### 12. SSH — Remote command execution

Runs shell commands on homelab hosts via SSH.

| Tool | What it does |
|------|-------------|
| `ssh_exec` | Run a command on a named host |

**Known hosts:** `atlantis`, `calypso`, `setillo`, `setillo-root`, `nuc`, `homelab-vm`, `rpi5`, `pi-5`, `matrix-ubuntu`, `moon`, `olares`, `guava`, `pve`, `seattle-tailscale`, `gl-mt3000`

---

### 13. Filesystem — Local file access

Read/write files on the homelab-vm filesystem.

| Tool | What it does |
|------|-------------|
| `fs_read` | Read a file (allowed: `/home/homelab`, `/tmp`) |
| `fs_write` | Write a file (allowed: `/home/homelab`, `/tmp`) |
| `fs_list` | List directory contents |

---

### 14. Repo — Homelab repository inspection

Inspects the homelab Git repository at `/home/homelab/organized/repos/homelab`.

| Tool | What it does |
|------|-------------|
| `list_homelab_services` | List all compose files, optionally filtered by host |
| `get_compose_file` | Read a compose file by partial path or name (searches `docker-compose.yml/yaml` and standalone `*.yaml/*.yml` stacks) |

---

### 15. Notifications — ntfy push

Sends push notifications via the self-hosted ntfy instance.

| Tool | What it does |
|------|-------------|
| `send_notification` | Send a push notification to ntfy topic |

**Default topic:** `homelab-alerts`  
**Priorities:** `urgent`, `high`, `default`, `low`, `min`

---

### 16. Health checks

| Tool | What it does |
|------|-------------|
| `check_url` | HTTP health check against a URL with expected status code |

---

## Bug Fixes Applied (2026-03-21)

| Bug | Symptom | Fix |
|-----|---------|-----|
| `list_homelab_services` | `AttributeError: 'str' object has no attribute 'parts'` — crashed every call | Changed `str(f).parts` → `f.parts` |
| `get_compose_file` | Couldn't find standalone stack files like `homarr.yaml`, `whisparr.yaml` | Extended search to all `*.yaml/*.yml`, prefers `docker-compose.*` when both match |
| `check_portainer` | Type error on `stacks.get()` — stacks is a list not a dict | Added `isinstance` guards |
| `gitea_create_issue` | Type error on `data['number']` — subscript on `dict \| list` union | Added `isinstance(data, dict)` guard |

---

## Adding New Tools

1. Add helper function (e.g. `_myservice(...)`) to the helpers section
2. Add `@mcp.tool()` decorated function with a clear docstring
3. Update the `instructions=` string in `mcp = FastMCP(...)` with the new category
4. Add `pragma: allowlist secret` to any token/key constants
5. Commit and push — changes take effect next OpenCode session

---

## Related docs

- `docs/admin/ai-integrations.md` — AI/LLM integrations overview
- `docs/troubleshooting/matrix-ssl-authentik-incident-2026-03-19.md` — NPM cert reference
- `docs/services/individual/uptime-kuma.md` — Kuma monitor group reference
