7.4 KiB
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 (read-only ones carry readOnlyHint; zone/home-wide and flow tools are marked destructiveHint):
- Connectivity:
ping - Devices:
list_devices(zone_id?),find_devices(query, zone?),get_device(device_id) - Zones:
list_zones - Status views:
get_zone_status(zone),get_house_status(class_filter?),get_temperatures - Capabilities:
get_capability,set_capability,set_light,set_capabilities_bulk - Zone / home control:
control_zone(zone, capability, value),control_all(capability, value, device_class?) - Flows:
list_flows,find_flows(query),trigger_flow(flow_id) - Logic variables:
list_variables,set_variable - Notifications:
send_notification(title, excerpt?) - Events:
list_recent_events(limit, kind?)— realtime events from the in-memory buffer
Zone names resolve exact match → prefix → substring, so Wohnzimmer never picks
Wohnzimmer Ecke. IDs are URL-encoded before they reach Homey's API.
Resources:
homey://deviceshomey://zoneshomey://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 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: https://tools.developer.homey.app/ (My Homey → API Keys / Personal Access Token).
Install
From this folder:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e .
uv works equivalently:
uv venv
uv pip install -e .
Configure
Copy .env.example to .env and fill in:
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
homey-mcp
# or
python -m homey_mcp
# or
.\run.bat
Inspect with the MCP Inspector
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):
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=<a long random secret>
.\run-lan.bat
The remote client connects to http://<this-machine-ip>:8080/mcp
(streamable-http) or /sse. Streamable HTTP clients that only accept a base
URL may use http://<this-machine-ip>:8080/; MCP traffic at / is forwarded
to /mcp, while an ordinary browser GET returns service discovery.
Important for MCP transport over LAN: requests are only accepted when their
Host header is HOMEY_MCP_ADVERTISED_HOST, localhost or 127.0.0.1
(otherwise 421 Misdirected Request). This blocks DNS-rebinding attacks, where a
web page in any browser on your LAN rebinds its domain to this server. If you
bind to 0.0.0.0, set HOMEY_MCP_ADVERTISED_HOST to the IP clients use; add
further names (e.g. a DNS name) to HOMEY_MCP_ALLOWED_HOSTS (comma-separated,
* disables the check). Without either, the check is off and a warning is logged.
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 <HOMEY_MCP_AUTH_TOKEN> 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. In bearer mode every MCP route requires it
too (/mcp, the root alias, and /sse + /messages/ for the SSE transport);
only GET / (discovery) and /openapi.json stay public.
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://<this-machine-ip>: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:
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):
{
"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 exposenonemode 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=falseto disable. The server performs Homey'shandshakeClientand subscribes tohomey:manager:devicesplus eachhomey:device:<id>(capability changes). - 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