Skip to main content
Glama
japperJ

eWeLink CUBE MCP Server

by japperJ

eWeLink CUBE MCP Server

A standalone Model Context Protocol server for the eWeLink CUBE (iHost) smart-home gateway. It exposes every Cube function — pairing, gateway info, device control, live events and sensor history — as MCP tools over Streamable HTTP, so any AI assistant or coder agent can operate your house. It also serves a small live dashboard web page.

Sonoff iHost (eWeLink CUBE) gateway

Fully independent: the Cube client, types, SSE handling and history database are re-implemented here. Zero dependency on the dashboard repo.

Features

  • Pairing — register against the Cube box via the physical link button

  • Gateway — info, runtime stats, volume, mute/unmute

  • Devices — list, inspect, rename, power, brightness, color temperature, RGB, generic state control, capability queries (e.g. power consumption)

  • Live — one persistent SSE connection to the box with auto-reconnect, event buffer and live device cache

  • History — own SQLite database, auto-records sensor snapshots every 5 min; queryable per device/metric over 1h…all

  • Dashboard — GET /dashboard: climate charts with date picker, live event feed

Related MCP server: Home Assistant MCP Server

Prerequisites

  • Node.js 20+ and npm

  • An eWeLink CUBE / iHost gateway on the same LAN (this was built against firmware 2.13.2 at http://(you local IP of the Cupe box or software))

Setup

git clone <this-repo> && cd ewelink-cube-mcp
cp .env.example .env
npm install

Edit .env:

CUBE_BASE_URL=http://192.168.50.22   # your Cube's address, no trailing slash
CUBE_ACCESS_TOKEN=                   # leave blank until paired (see below)
CUBE_APP_NAME=ewelink-mcp

MCP_PORT=3001
MCP_API_KEY=                         # optional: clients must send Authorization: Bearer <key>

HISTORY_DB_PATH=./mcp-history.db
HISTORY_AUTO_RECORD_MS=300000        # snapshot interval, 0 = disabled

Start it:

npm run dev    # development (tsx)
# or
npm run build && npm start

Endpoints:

URL

What

http://localhost:3001/mcp

MCP Streamable HTTP endpoint (for AI clients)

http://localhost:3001/dashboard

Live dashboard web page

http://localhost:3001/health

Health + SSE status

Docker:

docker build -t ewelink-cube-mcp .
docker run -p 3001:3001 --env-file .env ewelink-cube-mcp

Connecting to the Cube box (pairing)

The Cube issues tokens only after a physical confirmation:

  1. Call the cube_pair_wait tool (default 30 s window).

  2. Within the window, press the link button on the iHost (a confirmation pop-up may also appear in the iHost web console at http://ihost.local).

  3. The tool returns {"token": "..."} and activates it immediately.

  4. Persist it: set CUBE_ACCESS_TOKEN=<token> in .env (survives restarts; the token stays valid until the gateway is factory-reset).

Single attempt instead of polling: cube_pair_once. Check state any time: cube_token_status.

Tool signature conventions

Every tool speaks plain JSON. Conventions used across all signatures:

  • Device identity — serialNumber (the Cube serial_number UUID, e.g. "05a98571-6f4b-4404-b6a2-3d24be50ed62"). Use cube_list_devices to discover them.

  • State object — state mirrors the Cube capability model: { "<capability>": { "<field>": value } }. Examples:

    • power: { "power": { "powerState": "on" } }

    • multi-gang: { "toggle": { "toggleState": "off" } }

    • brightness: { "brightness": { "brightness": 80 } } (1–100)

    • color temp: { "color-temperature": { "colorTemperature": 50 } } (0–100)

    • color: { "color-rgb": { "red": 255, "green": 0, "blue": 255 } }

  • Success — { "error": 0, "data": {...}, "message": "success" }

  • Failure — { "error": <code>, "data": {}, "message": "<reason>" }, e.g. 110005 = device offline, 110021 = capability not queryable on that device.

  • History ranges — 1h | 6h | 24h | 7d | 30d | 90d | 1y | all.

  • Metric names — temperature (°C), humidity (%), battery (%), rssi (dBm), voltage (V), electric-power (W).

MCP tools (26)

Auth

Tool

Signature

Description

cube_token_status

()

Whether base URL + token are configured, plus SSE status

cube_pair_once

()

One token request (press link button first)

cube_pair_wait

({ timeoutMs?: 5000–120000 = 30000 })

Poll until the button press registers; activates token

Gateway

Tool

Signature

Description

cube_gateway_info

()

Bridge info: ip, mac, firmware, name

cube_gateway_runtime

()

cpu %, ram %, cpu temp, uptime, SD usage

cube_gateway_volume

({ volume: 0–100 })

Speaker volume

cube_gateway_mute / cube_gateway_unmute

()

Mute / unmute speaker

Devices & control

Tool

Signature

Description

cube_list_devices

({ category?: string, onlineOnly?: false })

All Zigbee devices; filter by display_category

cube_get_device

({ serialNumber })

Full detail incl. capabilities + current state

cube_set_device_state

({ serialNumber, state })

Generic control, any capability payload

cube_power

({ serialNumber, action: "on" | "off" | "toggle" })

Power via power or toggle capability, auto-detected

cube_set_brightness

({ serialNumber, brightness: 1–100 })

Light brightness

cube_set_color_temp

({ serialNumber, colorTemperature: 0–100 })

0 warm … 100 cool

cube_set_rgb

({ serialNumber, red, green, blue: 0–255 })

RGB color

cube_rename_device

({ serialNumber, name })

Rename

cube_query_state

({ serialNumber, capability, query_state })

Live capability query, e.g. power-consumption with { type: "summarize", timeRange: { start, end } }

Live events

Tool

Signature

Description

cube_events_status

()

Persistent SSE connection state

cube_events_recent

({ limit: 1–200 = 50 })

Recent box events (state, online, add, delete)

cube_live_cache

()

Device state cache built from SSE + list seeding

History (own SQLite DB)

Tool

Signature

Description

history_record_snapshot

({ serialNumber })

Record one device now

history_record_all

()

Record all online devices now

history_query

({ serialNumber, capability, range = "24h", limit = 2000 (max 20000) })

Readings series

history_devices

()

Devices with history + their metrics

history_latest

()

Latest reading per device/metric

history_stats

()

Total reading count

MCP resources

  • ewelink://gateway/info — gateway info JSON

  • ewelink://devices/list — full device list JSON

  • ewelink://events/recent — recent live events JSON

REST + dashboard

Besides MCP, the server exposes plain REST (used by the dashboard):

Climate dashboard with device picker, chart and legend

  • GET /dashboard — climate charts (device picker, metric, presets + custom from/to date picker), live event feed. No build step, no external assets.

  • GET /api/gateway, GET /api/devices, GET /api/events?limit=, GET /api/history/devices

  • GET /api/history?serial=&capability=&range=&limit= or &from=&to= (ISO datetime or epoch ms)

  • POST /api/power { serialNumber, action }

Graph signatures

Each chart line is one device (colors in the legend); X = time in browser timezone, Y = metric value. Points are 5-minute snapshots — gaps mean no recording. Metrics: Temperature °C (air temp), Humidity % (relative), Battery % (wireless devices), Signal dBm (nearer 0 = stronger; −50 good, −80 weak), Power W (current draw), Voltage V. "no data" = no readings for that device/metric/period. The same explanation is shown on the dashboard itself under "Reading the graphs".

Connecting an AI client (opencode example)

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": { "servers": { "ewelink": {
    "type": "remote",
    "url": "http://localhost:3001/mcp",
    "oauth": false
  } } }
}

Any Streamable-HTTP MCP client works. If MCP_API_KEY is set, send Authorization: Bearer <key>; clients must also send Accept: application/json, text/event-stream.

Once connected, just ask — the assistant can list devices, read sensors, switch lights and pull history through the tools above:

AI chat controlling eWeLink devices through MCP tools

Project structure

src/
  index.ts          # Express + MCP transport + background jobs
  config.ts         # env handling
  cube/client.ts    # Open API v2 client (fetch)
  cube/types.ts     # Cube type declarations
  sse/manager.ts    # long-lived SSE: reconnect, event buffer, live cache
  db/history.ts     # SQLite history layer
  mcp/buildServer.ts# all 26 tools + 3 resources
  http/api.ts       # REST endpoints
  http/dashboardPage.ts # dashboard HTML (self-contained)

Troubleshooting

  • link button not pressed (401) — press the iHost button, then retry within the window.

  • 110005 Device Offline — the end device is unreachable; commands to it fail until it rejoins.

  • 110021 on cube_query_state — that capability isn't queryable on that device (temperature/humidity are report-only; only power-consumption has history, and only on devices that declare the capability).

  • History gaps — the box exposes no sensor-history API (its UI graphs come from internal storage). History exists only for periods this server (or the dashboard app) was running and recording.

  • Session not found (-32001) — the MCP client must complete initialize first and send Mcp-Session-Id + Mcp-Protocol-Version headers afterwards.

Related MCP Connectors

Related MCP Servers