# 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
```