# homey-mcp An MCP (Model Context Protocol) server that exposes a local **Homey Pro** instance to LLM clients (Claude Desktop, VS Code / GitHub Copilot Chat, MCP Inspector, …). It talks to Homey's local HTTP Web API (`/api/manager/...`) using a Personal Access Token, and optionally subscribes to Socket.IO realtime events. ## Features Tools: - `ping` — verify connectivity / return Homey system info - `list_devices(zone_id?)` — devices with current capability values - `get_device(device_id)` — full device object - `list_zones` — rooms / areas - `set_capability(device_id, capability, value)` — set `onoff`, `dim`, `target_temperature`, … - `list_flows` — all flows - `trigger_flow(flow_id)` — start a flow - `list_recent_events(limit, kind?)` — recent realtime events from the in-memory buffer Resources: - `homey://devices` - `homey://zones` - `homey://events/recent` Transport: **stdio** (default, for local LLM hosts like Javis) or **streamable-http / sse** (for remote MCP clients over the LAN, e.g. the Odysseus AI helper) — see [Run on the LAN](#run-on-the-lan-remote-mcp-clients) below. ## Prerequisites - Python **3.10+** - A Homey Pro on the local network - A **Personal Access Token** for the Homey Web API — create one at the Homey Developer Tools: (My Homey → API Keys / Personal Access Token). ## Install From this folder: ```powershell python -m venv .venv .\.venv\Scripts\Activate.ps1 pip install -e . ``` `uv` works equivalently: ```powershell uv venv uv pip install -e . ``` ## Configure Copy `.env.example` to `.env` and fill in: ```ini HOMEY_HOST=192.168.1.10 HOMEY_TOKEN=eyJhbGciOi...your PAT... HOMEY_SCHEME=http HOMEY_PORT=4859 HOMEY_TIMEOUT=10 HOMEY_EVENT_BUFFER=200 HOMEY_REALTIME=true ``` ## Run ```powershell homey-mcp # or python -m homey_mcp # or .\run.bat ``` ### Inspect with the MCP Inspector ```powershell uv run mcp dev src/homey_mcp/server.py # or npx -y @modelcontextprotocol/inspector homey-mcp ``` ### Run on the LAN (remote MCP clients) To let a remote MCP client on the same network (e.g. **Odysseus**) connect over HTTP instead of stdio, set the transport env vars and run `run-lan.bat` (or set them yourself and run `homey-mcp` / `python -m homey_mcp`): ```ini HOMEY_MCP_TRANSPORT=streamable-http # or: sse HOMEY_MCP_HOST=0.0.0.0 # bind address (or specific LAN IP) HOMEY_MCP_ADVERTISED_HOST=10.10.10.50 # advertised host for MCP validation (required for 0.0.0.0 bind) HOMEY_MCP_PORT=8080 HOMEY_MCP_AUTH_MODE=none # compatible trusted-LAN default HOMEY_MCP_AUTH_TOKEN= ``` ```powershell .\run-lan.bat ``` The remote client connects to `http://:8080/mcp` (streamable-http) or `/sse`. Streamable HTTP clients that only accept a base URL may use `http://:8080/`; MCP traffic at `/` is forwarded to `/mcp`, while an ordinary browser GET returns service discovery. **Important for MCP transport over LAN:** The MCP SDK validates that clients send the correct `Host` header. If you bind to `0.0.0.0`, you **must** set `HOMEY_MCP_ADVERTISED_HOST` to your actual server IP (e.g., `10.10.10.50`). If you instead bind to a specific IP, omit `HOMEY_MCP_ADVERTISED_HOST` and it will default to the bind address. `HOMEY_MCP_AUTH_MODE=none` is the compatible mode for OAuth-negotiating MCP clients such as Odysseus, because this server is not an OAuth authorization server. Use it only on a trusted, firewall-restricted LAN. Set the mode to `bearer` only when the MCP client can be configured to send `Authorization: Bearer ` directly; OAuth discovery and dynamic registration are not provided. Generate a token with `python -c "import secrets; print(secrets.token_urlsafe(32))"`. When `HOMEY_MCP_AUTH_TOKEN` is set, the OpenAPI REST routes always require it, regardless of the MCP auth mode. This is independent of Javis's own connection: Javis keeps talking to homey-mcp over stdio via `mcp_servers.json` as before — run the LAN instance as a second, separate process for other clients. #### Odysseus API integration If Odysseus exposes integrations through its `app_api` tool rather than a native MCP client, import this server's OpenAPI document: - Schema URL: `http://:8080/openapi.json` - Authentication: Bearer token - Token: the value of `HOMEY_MCP_AUTH_TOKEN` The API provides reads at `/api/system`, `/api/zones`, and `/api/devices`, plus writes at `/api/devices/{device_id}/capabilities/{capability}` and `/api/zones/control`. Odysseus must invoke its registered `app_api` tool as a structured tool call. It must not print or execute Python such as `api_call(...)`; `api_call` is not a Python function and is not the registered tool name. Use this integration instruction in Odysseus: ```text For Homey requests, always call the app_api tool with integration="Homey". Never write api_call(...) or place tool calls in Python/code blocks. Use GET /api/system to check connectivity, GET /api/zones and GET /api/devices to discover IDs, PUT /api/devices/{device_id}/capabilities/{capability} with {"value": ...} for one device, and POST /api/zones/control with {"zone": "...", "capability": "onoff", "value": true|false} for a room. After the tool returns, summarize the actual result. Never claim success before receiving a successful tool response. ``` ### Use from Claude Desktop / VS Code Add to your MCP client config (path varies per client): ```json { "mcpServers": { "homey": { "command": "homey-mcp", "env": { "HOMEY_HOST": "192.168.1.10", "HOMEY_TOKEN": "your-personal-access-token" } } } } ``` If `homey-mcp` is not on PATH, use the full venv path, e.g. `C:\\local\\Code\\PRIVAT\\homey-mcp\\.venv\\Scripts\\homey-mcp.exe`. ## Notes & limitations - Local API only (no cloud OAuth). - LAN MCP transport authentication is controlled by `HOMEY_MCP_AUTH_MODE`. Never expose `none` mode beyond a trusted, firewall-restricted LAN. - Realtime events are best-effort — if the Socket.IO connection fails the REST tools still work. Set `HOMEY_REALTIME=false` to disable. - No admin operations (zone/user/app management) are exposed. - Capability values are typed as `bool | int | float | str`; the model picks based on the capability (`onoff` → bool, `dim` → 0..1 float, etc.). ## Project layout ``` homey-mcp/ pyproject.toml README.md .env.example run.bat src/homey_mcp/ __init__.py __main__.py config.py homey_client.py server.py ```