SwitchBot Ships @switchbot/openapi-cli: An Official CLI With Built-In MCP Server and MQTT Stream for AI Agents
Contents
The official SwitchBot Japan account announced that they have published a CLI tool for the SwitchBot OpenAPI.
The repository is OpenWonderLabs/switchbot-openapi-cli, and the npm distribution is @switchbot/openapi-cli.
It’s MIT-licensed, the first commit landed on 2026-04-17, and as I write this it has about 88 GitHub stars.
Scanning through it, you can hit Hub / Bot / Curtain / Lock / various sensors / plugs / IR appliances straight from the CLI, and on top of that it drops straight into Claude or Cursor as an MCP server, which is a more ambitious scope than I expected. Rough notes below.
What it is
One-liner: the official CLI for hitting the SwitchBot Cloud API v1.1.
It’s a TypeScript implementation that runs on Node.js ≥ 18. npm install -g @switchbot/openapi-cli gives you a switchbot command.
The README is upfront about targeting three audiences — “Human / Script / Agent” — and I found that framing interesting.
- Human: colored tables, error hints, shell completion,
switchbot doctorfor self-diagnostics - Script:
--json/--format=tsv/yaml/id, column control via--fields, stable exit codes,history replay, audit log - Agent:
switchbot mcp serve(stdio MCP server),schema export,plan run, guards on destructive commands
The same binary shares the same catalog, cache, and HMAC client, so switching modes is near zero-cost, the README says.
Setup
Grab a token and secret from the SwitchBot app’s “Profile → Preferences → Developer Options”, then hand them to the CLI.
npm install -g @switchbot/openapi-cli
# Saved to ~/.switchbot/config.json (perms 0600)
switchbot config set-token <token> <secret>
# List devices on your account
switchbot devices list
# Send a command
switchbot devices command <deviceId> turnOn
The env vars SWITCHBOT_TOKEN / SWITCHBOT_SECRET take precedence over the config file.
Use those for CI.
All the usual operations are there
Quick rundown of the main subcommands. --help works on all of them.
devices list/devices status/devices command/devices batch/devices watchscenes list/scenes executewebhook setup/query/update/delete(manage event destination URLs)events tail(open a local port and receive webhooks)events mqtt-tail(stream events directly from SwitchBot’s MQTT)plan run(declarative batch execution written in JSON)mcp serve(MCP stdio server)doctor/quota/history/catalog/schema/capabilities/cache/completion
A few things that struck me as well-thought-out.
--dry-run lets you fire POST/PUT/DELETE with just the intended payload printed, no network mutation.
GETs still run as normal, so you can inspect a device’s current state before a destructive operation.
Unknown device IDs or commands not in the catalog exit with code 2, so it works as a pre-flight gate.
devices expand turns packed strings like setAll "26,2,2,on" into something readable like --temp 26 --mode cool --fan low --power on.
It’s for air conditioners / curtains / blind tilts / relay switches.
You don’t have to memorize the comma-separated incantation.
devices explain returns both the catalog-level metadata (supported commands, parameters, status fields) and the live status in a single API call.
For Hubs it includes child devices.
No need to call status and describe separately.
quota tracks the per-account 10,000 req/day limit in a local ~/.switchbot/quota.json.
You can disable tracking with --no-quota.
429 retries are configurable via backoff, with exponential or linear options.
catalog carries 42 standard device types as an offline catalog, and you can override or extend it by dropping a ~/.switchbot/catalog-overlay.json.
You can look up commands and parameter shapes without hitting the API, so you can ask things like switchbot devices commands Bot.
events mqtt-tail looks very handy
This is the part that hit me the hardest. Without standing up a REST webhook, you can connect to SwitchBot’s MQTT using just the REST token and stream shadow-update events directly. Client certificates are auto-provisioned on first access.
# Tail all events as JSONL
switchbot events mqtt-tail --json
# Auto-terminate after 30 seconds
switchbot events mqtt-tail --for 30s --json
# Filter by topic
switchbot events mqtt-tail --topic 'switchbot/#'
Output comes out one event per line in JSONL, like this:
{ "t": "2024-01-01T12:00:00.000Z", "topic": "switchbot/abc123/status", "payload": { } }
On top of that, --sink selects a destination. You can push straight to file / webhook / openclaw / telegram / homeassistant,
so for example you can wire it into a Home Assistant webhook trigger and your state sync is done.
switchbot events mqtt-tail \
--sink homeassistant \
--ha-url http://homeassistant.local:8123 \
--ha-webhook-id switchbot
As a bonus, each device’s latest state is persisted into ~/.switchbot/device-history/<deviceId>.json as a ring buffer (latest + last 100 entries) automatically.
This is what backs the MCP get_device_history tool described next.
The real headline: built-in MCP server
switchbot mcp serve runs it as an MCP server over stdio. Wire it up in Claude Desktop / Cursor / Claude Code and you get the following 8 tools plus 1 resource.
list_devicesdescribe_deviceget_device_statussend_commandlist_scenesrun_scenesearch_catalogaccount_overview- Resource
switchbot://events(real-time shadow updates)
The key point is that MCP mode shares the same catalog and cache as the CLI. That means the agent can figure out what a device type supports before issuing any command, without an API call. Destructive commands like Smart Lock unlock have guards so the agent can’t casually unlock your door, the README notes.
If you want to hand state off to an agent framework,
switchbot schema export
switchbot capabilities --json
dumps the catalog and CLI manifest as JSON.
Each command in capabilities carries metadata like {mutating, consumesQuota, idempotencySupported, agentSafetyTier, verifiability, typicalLatencyMs},
apparently intended to be embedded into the agent’s tool-selection prompt.
plan (declarative batch execution)
plan run plan.json runs command / scene / wait steps in order.
By default it stops on the first failure (--continue-on-error runs through everything).
plan schema emits the JSON Schema, so you can feed it straight to an LLM and have it write a plan.
switchbot plan schema # print JSON Schema
switchbot plan validate plan.json # validate only, no execution
switchbot --dry-run plan run plan.json # run GETs, suppress mutations
switchbot plan run plan.json --yes # allow destructive steps
The design intent is: instead of a shell script, write something like “at 7am dim the living room to 50%, wait 10 seconds, then turn on the AC” as JSON and hand it to plan run.
It’s biased toward being invoked by external runners (cron / launchd / GitHub Actions).
Solid engineering
Looking at the README,
- Vitest with 692 cases, axios mocked, CI passes with no network
- HMAC-SHA256 signatures are built properly as
token + t + nonce → sign --verbosedumps HTTP req/res to stderr- Audit log at
~/.switchbot/audit.logrecords every mutating command in JSONL history replay <n>re-runs past operations as-is- Error codes (151/152/160/161/171/190/401/429) are mapped to human-readable English
Overall it’s built with operations in mind.
Shell completion covers bash / zsh / fish / powershell too, so
echo 'source <(switchbot completion zsh)' >> ~/.zshrc
gives you completions immediately.
Shipping official MCP support is a big deal
SwitchBot’s ecosystem has leaned on unofficial libraries for ages, so an official release bundling CLI + MCP + MQTT is genuinely significant. Especially with the MCP server included,
- Add
switchbot mcp serveto Claude Desktop or similar - Say “set the living room AC to 26°C in cool mode”
- The agent checks the command shape with
search_catalog, then fires it off viasend_command
This flow works end-to-end without any extra tool implementation. The bar for wiring home sensor values into an LLM and building “it’s getting warm, turn on the AC” automations has dropped significantly.
Personally I want to try Home Assistant webhook integration and events mqtt-tail --sink file for JSONL logging.
Whether I actually replace my existing scrappy SwitchBot API scripts is something I’ll decide after plugging in the token and poking at it.
Come to think of it, back in January when I wrote Building an environment to talk to AI (3): finally talking, I had Kana-chan poll the SwitchBot temperature/humidity sensor to answer “what’s the temperature?” and toggle lights with “turn off the light”.
At the time I was writing a thin axios wrapper with HMAC signing and only the endpoints I needed.
With @switchbot/openapi-cli out, signature generation, quota tracking, and 429 retries all move to the CLI side, so I can probably rip out the homemade wrapper and swap in plain switchbot devices command calls.
And if I also keep a events mqtt-tail --sink file running, I’d have a rolling JSONL of temperature, humidity, and CO2 that I could later ask Gemini things like “how did the room temperature change after I got home yesterday”.
I’m starting to want to redo that whole setup.
References: README (OpenWonderLabs/switchbot-openapi-cli) / @switchbot/openapi-cli on npm / SwitchBot API v1.1 docs