--- 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__`. 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`.