About
Arcus — Model Context Protocol server
README
MCP (Model Context Protocol) server that connects AI agents to the Arcus Smart Home platform via the client-bridge WebSocket API.
Architecture
Claude Code <--stdio--> MCP Server <--WebSocket--> Client Bridge <--Kafka--> Arcus Smart Home Platform
- Transport: stdio for MCP, WebSocket for Arcus bridge
- Language: TypeScript (ES2022, Node16 modules)
- Dependencies:
@modelcontextprotocol/sdk,ws,zod
Configuration
| Env Var | Required | Description |
|---|---|---|
ARCUS_BRIDGE_URL |
Yes | Bridge URL (e.g. https://client-bridge.example.com) |
ARCUS_USERNAME |
Yes* | Login username |
ARCUS_PASSWORD |
Yes* | Login password |
ARCUS_API_KEY |
No | API key for direct API server connection (replaces username/password) |
ARCUS_AUTH_TOKEN |
No | Skip login, use existing auth token directly |
ARCUS_ENABLE_WRITE |
No | Set to 1 to enable device commands, alarm control, pairing, etc. |
ARCUS_DEBUG |
No | Set to 1 to log all WebSocket traffic to stderr |
*Not required if ARCUS_AUTH_TOKEN is set.
Setup
npm install
npm run build
Claude Code integration
claude mcp add arcus -s user \
-e ARCUS_BRIDGE_URL=https://client-bridge.example.com \
-e [email protected] \
-e ARCUS_PASSWORD=password \
-e ARCUS_ENABLE_WRITE=1 \
-- node /path/to/arcus-mcp-server/dist/index.js
Or with an API key (skips login, auto-selects place):
claude mcp add arcus -s user \
-e ARCUS_BRIDGE_URL=https://client-bridge.example.com \
-e ARCUS_API_KEY=your-api-key \
-e ARCUS_ENABLE_WRITE=1 \
-- node /path/to/arcus-mcp-server/dist/index.js
To remove:
claude mcp remove arcus
Source Files
| File | Description |
|---|---|
src/index.ts |
Entry point. Creates MCP server on stdio, lazy bridge connection via ensureConnected() |
src/bridge-client.ts |
WebSocket/REST client. Login, correlation-based request/response, event buffering, auto-reconnect |
src/capabilities.ts |
Auto-generated capability constants from Arcus Smart Home platform definitions |
src/tools.ts |
All 38 MCP tool definitions (+6 admin), response summarizers, write guard, place guard, blocklist |
docs/arcus-protocol.md |
Protocol reference gathered from real client traffic |
MCP Tools (38 + 6 admin)
Session & Places
| Tool | Description |
|---|---|
list_places |
List all places (homes) accessible to the user |
set_active_place |
Activate a place — required before any device/scene/alarm operations |
Devices
| Tool | Description |
|---|---|
list_devices |
List all devices at active place (summarized) |
get_device |
Get full attributes of a single device |
get_devices |
Batch get — fetches multiple devices in parallel |
device_command |
Send command to a device (switch, lock, dimmer, thermostat, shade, etc.) |
identify_device |
Flash LED or play sound on a device to physically identify it |
search_devices |
Put hub into pairing/search mode for new or reconnecting devices |
Door Locks
| Tool | Description |
|---|---|
doorlock_buzz_in |
Temporarily unlock a door lock (auto-relocks in 30 seconds) |
doorlock_authorize_person |
Authorize a person's PIN on a door lock |
doorlock_deauthorize_person |
Deauthorize a person's PIN from a door lock |
Scenes & Rules
| Tool | Description |
|---|---|
list_scenes |
List scenes at active place |
fire_scene |
Execute a scene |
list_rules |
List automation rules |
delete_rule |
Delete a rule |
enable_rule |
Enable a rule |
disable_rule |
Disable a rule |
list_rule_templates |
List rule template categories, or templates in a category |
resolve_rule_template |
Resolve a template's variables to valid device/person options |
create_rule |
Create a rule from a template with variable mappings |
Alarm
| Tool | Description |
|---|---|
arm_alarm |
Arm alarm (ON=full, PARTIAL=perimeter). Supports bypass for triggered devices |
disarm_alarm |
Disarm alarm |
list_incidents |
List alarm incidents |
Infrastructure
| Tool | Description |
|---|---|
get_hub |
Get hub status (model, firmware, connection state, battery, Z-Wave/Zigbee info) |
reboot_hub |
Reboot the hub |
list_subsystems |
List subsystems (alarm, safety, care, etc.) |
zwave_network_info |
Get Z-Wave network info including node metrics, neighbors, routing, and zombies |
zwave_heal |
Start a Z-Wave network heal |
zwave_cancel_heal |
Cancel a Z-Wave network heal in progress |
zwave_remove_zombie |
Remove a zombie node from the Z-Wave network |
zigbee_network_info |
Get Zigbee network information |
zigbee_get_stats |
Get Zigbee radio statistics |
zigbee_scan |
Scan the Zigbee network for devices and channel information |
Events & Monitoring
| Tool | Description |
|---|---|
list_events |
Drain buffered platform events. Filters out subcare/subsafety noise, groups consecutive duplicates |
list_care_status |
Peek at care/safety events without draining. Shows latest unique per type |
list_history |
List recent history entries from the platform |
list_persons |
List persons at the active place |
Advanced
| Tool | Description |
|---|---|
send_message |
Escape hatch — send any message type to any destination |
Admin (ARCUS_ENABLE_ADMIN=1)
| Tool | Description |
|---|---|
hub_syslog |
Get hub system log |
hub_bootlog |
Get hub boot log |
hub_processes |
Get running processes on the hub |
hub_load |
Get system load on the hub |
hub_agent_db |
Get hub agent database |
hub_files |
Get file listing from the hub |
Safety Guards
Write Guard
All mutating operations require ARCUS_ENABLE_WRITE=1. Without it, device commands, alarm control, scene firing, rule creation/deletion, hub reboot, and pairing are blocked.
Place Guard
Tools that operate on a place (list_devices, get_device, get_devices, device_command, list_history, list_persons, delete_rule, fire_scene, get_hub, reboot_hub) check that a place is set before making any bridge requests. This prevents "Tsk Tsk, you are not authorized" errors that trigger security alerts on the backend.
Blocklist
18 destructive message types are blocked in both device_command and send_message:
- Account/place/person deletion and removal
- Hub deregistration and factory reset
- Device removal (normal and forced)
- Scene/rule deletion (via
send_message— dedicateddelete_ruletool exists) - Password/PIN changes
Key Design Decisions
- Lazy connection: Bridge connects on first tool call, not at startup. This avoids blocking MCP stdio transport during login/WebSocket handshake.
- Response summarizers: Every list tool extracts only the useful fields from raw platform responses to minimize token usage. For example,
list_devicesreturns name, address, type, vendor, model, connection state, and capability-specific state (switch, lock, temperature, etc.) instead of 50+ raw attributes per device. - Compact JSON: All tool responses use
JSON.stringify(x)(no pretty-print) except where readability matters (set_active_place,get_device). - Event buffer: Unsolicited WebSocket messages are buffered (max 100).
list_eventsdrains and groups them.subcare:/subsafety:events are filtered to a separatelist_care_statustool since they fire constantly. - Auto-reconnect: WebSocket reconnects with exponential backoff (1s, 2s, 5s, 10s, 30s). On reconnect, the active place is automatically restored.
- Parallel requests:
set_active_placeruns the two-phase connection flow (SetActivePlace + GetAttributes in parallel, then GetHub + ListSubsystems in parallel).get_devicesfetches all requested devices in parallel.
Device Command Examples
All device commands use base:SetAttributes:
# Turn on a switch
device_command(addr, "base:SetAttributes", {"swit:state": "ON"})
# Lock a door
device_command(addr, "base:SetAttributes", {"doorlock:lockstate": "LOCKED"})
# Set thermostat
device_command(addr, "base:SetAttributes", {"therm:heatsetpoint": 72})
# Dim a light to 50%
device_command(addr, "base:SetAttributes", {"dim:brightness": 50})
# Set shade position (0=closed, 100=open)
device_command(addr, "base:SetAttributes", {"shade:level": 75})
Protocol Notes
See docs/arcus-protocol.md for the full protocol reference. Key gotchas:
SessionCreatedmessage type has nosess:prefix- Place field is
placeName(notname) in SessionCreated - Outgoing messages need a top-level
typefield mirroringpayload.messageType - No
sourcefield in outgoing headers - Hub address format:
SERV:<hubId>:hub(e.g.SERV:LWH-7138:hub) - Scenes/rules use service destinations (
SERV:scene:,SERV:rule:) withplaceIdin attributes - To arm alarm with triggered sensors, use
subalarm:ArmBypassedinstead ofsubalarm:Arm - Pairing:
subpairing:StartPairingthensubpairing:SearchtoSERV:subpairing:<placeId>
Installing Arcus
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/wl-net/arcus-mcp-serverFAQ
Is Arcus MCP free?
Yes, Arcus MCP is free — one-click install via Unyly at no cost.
Does Arcus need an API key?
No, Arcus runs without API keys or environment variables.
Is Arcus hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Arcus in Claude Desktop, Claude Code or Cursor?
Open Arcus on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectCompare Arcus with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
