homelab-codex-ws/kb/runbooks/ha-mcp-install.md
oskar 6b85c7ef68 feat(kb): SPLIT service+runbook — 10 serwisow -> 20 dokumentow
Wzorzec mechaniczny: sekcje deploy/verify/install/testy wycinane do
kb/runbooks/<serwis>-*.md, reszta zostaje dokumentem type: service.
Wzajemne `links` w obie strony. Tresc sekcji nietknieta — przenoszone
doslownie, dodany wylacznie naglowek H1 nowego runbooka.

kb-query, paperless-worker, planner-agent, ha-diag-agent, ollama-piha,
narty27, home-assistant, ha-mcp, job-gmail-header-backfill, job-mail-body-ingest.

Weryfikacja: dla kazdego pliku multizbior niepustych linii
(main + runbook) == oryginal z HEAD. Zero zgubionych, zero dodanych.

Recon szacowal 13 splitow service+runbook; faktycznie 2-typowych jest 10,
pozostale 5 (paperless, nextcloud, gokapi, fleet-prometheus, deploy-runner)
sa 3-typowe i ida osobno jako splity wielotypowe.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 16:58:46 +02:00

98 lines
3.4 KiB
Markdown

---
okf: "0.1"
type: runbook
visibility: private
status: active
updated: 2026-07-30
links:
- ../services/ha-mcp.md
---
# ha-mcp — instalacja i rejestracja
## Install
The `mcp` SDK (and its pydantic/anyio/httpx dependency tree) is not packaged
for Debian and is not needed by anything else in this repo, so it goes into a
venv rather than into the system Python:
```bash
python3 -m venv --system-site-packages services/ha-mcp/.venv
services/ha-mcp/.venv/bin/pip install mcp pytest
```
`--system-site-packages` is deliberate: `requests`, `PyYAML` and
`websocket-client` are already installed system-wide and used by
`scripts/ha/lib/*`; the venv reuses those exact versions instead of shadowing
them with a second copy. `.venv/` is already covered by the repo `.gitignore`.
`pip install --break-system-packages mcp` also works and is one line shorter,
but it writes into the system interpreter that runs every deploy script on
this workstation — a venv keeps a 40-package dependency tree out of that blast
radius for a tool only Claude Code uses. Use the venv.
`run.sh` prefers `services/ha-mcp/.venv/bin/python` and falls back to the
system `python3`; if neither can import `mcp` it exits with one actionable
line on stderr rather than a traceback.
## Registration in Claude Code
`.mcp.json` in the repo root (project scope — shared with anyone who checks
out this repo):
```json
{
"mcpServers": {
"ha": {
"command": "./services/ha-mcp/run.sh",
"args": [],
"env": {}
}
}
}
```
The command path is relative, so it resolves in any checkout (main or task
worktree) as long as Claude Code is started from the repo root. Start CC
there; on first run it asks whether to trust the project's MCP servers. Check
with `/mcp` — the server appears as `ha`, its tools as `mcp__ha__<tool>`.
Which repo the server reads is derived from its own location; override with
the `HA_MCP_REPO` environment variable if you ever need to point one checkout
at another's config.
## Standalone
```bash
./services/ha-mcp/run.sh # stdio server — speaks JSON-RPC on stdout
services/ha-mcp/tests/run.sh # offline test suite (no HA, no token)
services/ha-mcp/.venv/bin/python services/ha-mcp/tests/smoke_live.py [instance] [entity_id]
```
`smoke_live.py` is the only thing here that touches the network (GET only). A
one-off tool call without a client is easiest through the package:
```bash
PYTHONPATH=services/ha-mcp/src services/ha-mcp/.venv/bin/python -c "
from ha_mcp import tools; from ha_mcp.backend import LiveBackend
from ha_mcp.config import get_instance, repo_root
n, c = get_instance('ken', repo_root()); print(tools.instance_status(LiveBackend(n, c, repo_root())))"
```
## Tests
```bash
services/ha-mcp/tests/run.sh # 42 tests, offline
```
Offline in the same sense as `scripts/ha/tests/*`: no network, no HA
instance, no token. Small hand-made fixtures under `tests/fixtures/` (shaped
like real `/api/states` and WebSocket registry payloads) cover the tool logic;
the repo's own `config/ken/automations/` and newest `fixtures/ken-states-*.yaml`
cover the repo-backed and at-scale paths (ranking over ~1650 real entities
behaves differently from ranking over ten).
Live smoke (read-only, run against `ken` on 2026-07-30):
`instance_status` → HA 2026.7.2, 1647 entities, 377 unavailable, 115
automations, 13 areas; `get_state("sensor.thsalon_temperature")``24.5 °C`.