Initial commit: Javis project
This commit is contained in:
commit
435c645f36
164 files changed
+35279
No files matched your search
@@ -0,0 +1,200 @@
|
||||
# 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: <https://tools.developer.homey.app/> (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=<a long random secret>
|
||||
```
|
||||
|
||||
```powershell
|
||||
.\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:
|
||||
|
||||
```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
|
||||
```
|
||||
Reference in new issue
Block a user