<p align="center"> <img src="assets/banner.svg" alt="Shelly API MCP — read-only MCP server for Shelly Cloud energy data" width="100%"> </p>
<p align="center"> <a href="#"><img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10%2B-3776AB?logo=python&logoColor=white"></a> <a href="https://modelcontextprotocol.io"><img alt="MCP" src="https://img.shields.io/badge/MCP-streamable--http-22C55E"></a> <a href="Dockerfile"><img alt="Docker" src="https://img.shields.io/badge/docker-ready-2496ED?logo=docker&logoColor=white"></a> <a href="#"><img alt="Access: read-only" src="https://img.shields.io/badge/access-read--only-475569"></a> </p>
<p align="center"> A small <a href="https://modelcontextprotocol.io">Model Context Protocol</a> server that wraps the <strong>Shelly Cloud Control API</strong> as curated, read-only electricity tools for AI agents — live power, lifetime energy, and historical consumption with cost. </p>
---
Why this exists
There is no official MCP for reading your own Shelly device data. The official Shelly MCP (shelly-api-docs.mcp.shelly.link) is documentation-only and never touches your account, and the community servers are either DeskAgent plugins or control-focused with no real consumption tooling.
Shelly MCP talks to the Shelly Cloud Control API directly — the same cloud your devices already report to — and exposes read-only consumption tools. No control endpoints are wrapped: it can read your meters, never switch anything.
Features
- Generic across device families — Gen2 energy meters (
em:N/emdata:N), Gen2 switches &
plugs (switch:N / pm1:N), and best-effort Gen1 (meters[] / emeters[]).
- Never fakes a zero — missing or unparseable readings are flagged as
partialwith warnings
instead of being silently summed as 0, so a total is never quietly too low.
- Historical buckets with cost — hourly/daily/monthly consumption and net-energy series, summed
across all three phases, with range totals.
- Honest about gaps — incomplete ranges report
gaps/partial_bucketsrather than presenting
a partial range as whole.
- Brief response cache to soften the Cloud's ~1 req/s rate limit.
Tools
| Tool | What it answers | |------|-----------------| | list_devices() | Inventory: id, name, model, generation, mode, online state, local IP. | | get_power(device_id?) | Live electricity draw now (W) — total + per-phase / per-channel. | | get_energy(device_id?) | Lifetime energy counters (kWh) — consumed, returned, per-phase. | | get_consumption_summary(device_id?) | One-shot per-device summary: name, model, live W, lifetime kWh, meter temp. | | get_consumption_history(device_id?, date_range, date_from?, date_to?) | Historical grid consumption over time with cost. | | get_net_energy_history(device_id?, date_range, date_from?, date_to?) | Historical net energy (import − export); consumption_kwh is signed. | | get_device_status(device_id) | Raw, complete device_status JSON — escape hatch for uncurated fields. |
device_id is optional on most tools (omit to cover all devices); it is required on get_device_status. History tools require an explicit id when the account has more than one device. For date_range use day \| week \| month \| year \| custom (custom requires both date_from and date_to as YYYY-MM-DD HH:MM:SS). Only 3-phase meters (em-3p, e.g. Shelly Pro 3EM) are supported by the history tools.
Prerequisites
- A Shelly Cloud account with at least one device.
- Your Cloud Control API auth key and server host, both from the Shelly app/web:
Settings → Authorization Cloud Key (the key, e.g. MWE...) and the server it lists (e.g. shelly-NN-eu.shelly.cloud).
- Docker (recommended) or Python 3.10+.
Configuration
Configuration is entirely via environment variables:
| Variable | Required | Default | Description | |----------|:--------:|---------|-------------| | SHELLY_SERVER | ✅ | — | Cloud server host or URL (bare host is fine; https:// is assumed). | | SHELLY_AUTH_KEY | ✅ | — | Cloud Control API auth key. | | SHELLY_TIMEOUT | | 20 | HTTP timeout, seconds. | | SHELLY_CACHE_TTL | | 5 | Response cache TTL, seconds. | | MCP_PORT | | 3000 | Port the server listens on. | | TZ | | _(UTC)_ | Timezone for named date ranges — see the note below. |
Put the secrets in a secret.env file (git-ignored) for Docker Compose:
SHELLY_SERVER=shelly-NN-eu.shelly.cloud
SHELLY_AUTH_KEY=your-cloud-control-api-key
[!IMPORTANT] Named date ranges (
day/week/…) are computed in local time, then read by the cloud in the device's timezone. SetTZto your device's zone (e.g.TZ=Europe/Paris) or ranges shift by the UTC offset. With Docker Compose,TZdefaults toEurope/Parisand is overridable.
Running
Docker Compose (recommended)
docker compose up -d --build
The MCP endpoint is then available at http://localhost:3000/mcp. Override the host port with HOST_PORT and the timezone with TZ:
HOST_PORT=8080 TZ=Europe/Berlin docker compose up -d --build
Docker
docker build -t shelly-api-mcp .
docker run --rm -p 3000:3000 --env-file secret.env -e TZ=Europe/Paris shelly-api-mcp
Local (Python)
pip install -r requirements.txt
export SHELLY_SERVER=shelly-NN-eu.shelly.cloud
export SHELLY_AUTH_KEY=your-cloud-control-api-key
python server.py
Connecting an MCP client
The server speaks streamable HTTP. Point any MCP client at the /mcp endpoint:
{
"mcpServers": {
"shelly": {
"url": "http://localhost:3000/mcp"
}
}
}
How it works
MCP client ──HTTP /mcp──> Shelly MCP (FastMCP) ──> Shelly Cloud Control API
POST /interface/device/list
POST /device/all_status
POST /device/status
GET /v2/statistics/{power-consumption,net-energy}/em-3p
Energy counters arrive in Wh on the wire and are surfaced in kWh. The Cloud Control API is rate-limited (~1 req/s); the short response cache is the only client-side mitigation. The server is strictly read-only — no control endpoints are wrapped.
Development
pip install -r requirements.txt pytest
pytest -q # 59 network-free unit tests over the parsing internals
python live_smoke.py # paced end-to-end smoke test against the real cloud (needs creds)
live_smoke.py exercises every tool and underlying endpoint against the live API, paced to respect the rate limit, and exits non-zero if any call fails.
Related
- euenergy-mcp — an MCP server exposing
European day-ahead electricity prices (ENTSO-E, ~41 bidding zones). Pairs well with this server: your own consumption here, market prices there.
Notes & limitations
- Read-only by design — no switching, no configuration writes.
- History tools cover 3-phase meters (
em-3p) only; other families return a structured error. - Cost is reported in the account's tariff currency.
- Not affiliated with Allterco / Shelly.











