6.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:
ping— verify connectivity / return Homey system infolist_devices(zone_id?)— devices with current capability valuesget_device(device_id)— full device objectlist_zones— rooms / areasset_capability(device_id, capability, value)— setonoff,dim,target_temperature, …list_flows— all flowstrigger_flow(flow_id)— start a flowlist_recent_events(limit, kind?)— recent realtime events from the in-memory buffer
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: 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 <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.
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. - 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