Skip to main content
Glama
mcp-server-zwave-js-ui

mcp-server-zwave-js-ui

by cacack

mcp-server-zwave-js-ui

PyPI Python versions CI License: MIT

An MCP server for managing a Z-Wave network through Z-Wave JS UI. It connects to the zwave-js-server WebSocket that Z-Wave JS UI exposes and surfaces the mesh — controller, nodes, values, and configuration parameters — as tools an MCP client (e.g. Claude) can call.

Status: early / read + write + lifecycle. Read-only introspection, write control (values, config parameters, node name/location, associations), and admin/lifecycle operations (re-interview, route rebuild, inclusion/exclusion, remove failed node) are available. Set ZWAVE_JS_READ_ONLY to hide every mutating tool and expose only the read tools. Triggering an OTA firmware update is still on the roadmap.

Quickstart

  1. In Z-Wave JS UI, make sure the Z-Wave JS Server WebSocket is enabled (Settings → Home Assistant → WS Server; default port 3000). See What it connects to.

  2. Add the server to Claude Code, pointing ZWAVE_JS_URL at that WebSocket. No manual install needed — uvx fetches and runs the published package:

    claude mcp add zwave-js-ui \
      --env ZWAVE_JS_URL=ws://<host>:3000 \
      -- uvx mcp-server-zwave-js-ui
  3. Ask Claude about your mesh — it calls the read-only tools to answer:

    "Which Z-Wave controller am I running, and how many nodes are on the network?"

    "List my Z-Wave nodes and flag any that are dead or asleep."

For other MCP clients, isolated installs, and configuration details, see the sections below.

Related MCP server: openhab

What it connects to

Z-Wave JS UI runs two servers: the web UI (default port 8091) and the Z-Wave JS Server WebSocket (default port 3000) that Home Assistant and this MCP server talk to. Point ZWAVE_JS_URL at the WebSocket, not the UI.

Install

Requires Python 3.12+.

pip install mcp-server-zwave-js-ui
# or, isolated:
pipx install mcp-server-zwave-js-ui
# or, no install:
uvx mcp-server-zwave-js-ui

Configure

Variable

Default

Description

ZWAVE_JS_URL

ws://localhost:3000

WebSocket URL of the Z-Wave JS Server.

ZWAVE_JS_READ_ONLY

(unset)

Set to 1/true/yes/on to hide all write and admin tools (only the read tools are registered).

Use with Claude Code

claude mcp add zwave-js-ui \
  --env ZWAVE_JS_URL=ws://<host>:3000 \
  -- uvx mcp-server-zwave-js-ui

Or add it to an MCP client config directly:

{
  "mcpServers": {
    "zwave-js-ui": {
      "command": "uvx",
      "args": ["mcp-server-zwave-js-ui"],
      "env": { "ZWAVE_JS_URL": "ws://<host>:3000" }
    }
  }
}

Tools

Write and admin tools (everything below the read-only rows) are hidden from the registry when ZWAVE_JS_READ_ONLY is set.

Read-only

Tool

Description

zwave_controller_info

Controller and network summary (home id, versions, RF region, node counts).

zwave_list_nodes

One-line summary of every node (status, readiness, security, device).

zwave_node_info

Full detail for a node (device class, command classes, endpoints, signal).

zwave_node_values

A node's current values, excluding configuration parameters.

zwave_node_config

A node's configuration parameters with current values and metadata.

zwave_association_groups

A node's association groups and their capabilities.

zwave_associations

A node's current associations, keyed by group.

zwave_rebuild_routes_status

Whether a network-wide route rebuild (heal) is in progress.

zwave_firmware_update_status

Whether an OTA firmware update is in progress.

Write control (level 2)

Tool

Description

zwave_set_value

Set a value by id (on/off/dim/etc.); validated against live metadata.

zwave_set_config_parameter

Set a manufacturer configuration parameter (optional bit mask).

zwave_set_node_name

Set a node's friendly name.

zwave_set_node_location

Set a node's location label.

zwave_add_association

Associate a target node into a source node's group.

zwave_remove_association

Remove a target node from a source node's group.

Admin / lifecycle (level 3)

Tool

Description

zwave_reinterview_node

Re-run a node's interview to refresh capabilities and values.

zwave_rebuild_node_routes

Rebuild mesh routes for a single node.

zwave_begin_rebuilding_routes / zwave_stop_rebuilding_routes

Start/stop a network-wide route rebuild (heal).

zwave_remove_failed_node

Remove a controller-flagged failed node from the network.

zwave_begin_inclusion / zwave_stop_inclusion

Enter/leave inclusion mode to add a node.

zwave_begin_exclusion / zwave_stop_exclusion

Enter/leave exclusion mode to remove a node.

Note on secure inclusion: interactive S2 security bootstrap (DSK/PIN grant) can't complete through this stateless server — use the Z-Wave JS UI for secure inclusion.

Roadmap

  • Trigger OTA firmware updates. Reporting update status is available (zwave_firmware_update_status), but starting a flash streams progress events over minutes, which the per-call connection model can't observe within a single tool call; delivering it needs a persistent-connection design.

Development

git clone https://github.com/cacack/mcp-server-zwave-js-ui
cd mcp-server-zwave-js-ui
uv sync --extra dev            # create .venv from the checked-in uv.lock
uv run pytest
uv run ruff check . && uv run ruff format --check .

See CLAUDE.md for architecture and design notes.

License

MIT

Available Tools

24 tools
zwave_add_associationA

Add an association from a source node's group to a target node.

Associations let a device control another directly (e.g. a switch driving a light). Use zwave_association_groups to pick a valid group. Raises ValueError for an unknown source node id.

Args: node_id: The source Z-Wave node id, e.g. 5 group: The association group id on the source node target_node_id: The node id to associate into the group source_endpoint: Optional source endpoint (defaults to the root device) target_endpoint: Optional target endpoint (defaults to the root device)

Inputs: group (required), node_id (required), target_node_id (required), source_endpoint, +1 more.

zwave_association_groupsA

List a node's association groups and their capabilities.

Returns each group id mapped to its max node count, lifeline flag, multi-channel flag, and label. Use this to find the group to pass to zwave_add_association. Raises ValueError for an unknown node id.

Args: node_id: The source Z-Wave node id, e.g. 5 endpoint: Optional endpoint index (defaults to the root device)

Inputs: node_id (required), endpoint.

zwave_associationsA

List a node's current associations, keyed by group id.

Each group maps to a list of association targets ({node_id, endpoint}). Raises ValueError for an unknown node id.

Args: node_id: The source Z-Wave node id, e.g. 5 endpoint: Optional endpoint index (defaults to the root device)

Inputs: node_id (required), endpoint.

zwave_begin_exclusionA

Put the controller into exclusion mode to remove a node.

Returns as soon as exclusion mode is entered; put the device into its exclusion/unpair mode to complete removal. Use zwave_stop_exclusion to cancel.

Inputs: no named parameters.

zwave_begin_inclusionA

Put the controller into inclusion mode to add a new node.

Returns as soon as inclusion mode is entered; put the device into pairing mode to complete the add. strategy is one of "default", "s2", "s0", or "insecure". Note: interactive S2 security bootstrap (DSK/PIN grant) cannot complete through this stateless server — use the Z-Wave JS UI for secure inclusion. Use zwave_stop_inclusion to cancel.

Args: strategy: Inclusion strategy — "default", "s2", "s0", or "insecure"

Inputs: strategy.

zwave_begin_rebuilding_routesA

Start a network-wide route rebuild (network heal).

Returns once the rebuild is started; it proceeds in the background across the whole mesh. Use zwave_stop_rebuilding_routes to cancel.

Inputs: no named parameters.

zwave_controller_infoA

Get Z-Wave controller and network summary.

Returns the controller's home id, type, SDK/API/firmware versions, RF region, primary/inclusion state, and node counts. Use this first for a quick health snapshot of the mesh. controller_type is a {"value": int, "label": str} object (label is null for an unmapped code).

Inputs: no named parameters.

zwave_firmware_update_statusA

Report whether an OTA firmware update is currently in progress.

Returns {"in_progress": bool}. (Triggering an update is not yet supported; see the project roadmap.)

Inputs: no named parameters.

zwave_list_nodesA

List all Z-Wave nodes with a one-line summary each.

Each entry has node id, name, location, status (alive/asleep/dead/etc.), readiness, listening/routing/sleep capability, security, manufacturer, device label, firmware version, and interview stage. Use zwave_node_info for full detail on a single node.

Inputs: no named parameters. Returns: result

zwave_node_configA

List a node's configuration parameters and their current values.

Returns each manufacturer-defined parameter with its current value, default, allowed range or named states, unit, size, and writeability — the device-specific tuning knobs (LED behavior, report intervals, motion sensitivity, etc.). Set a parameter with zwave_set_config_parameter. Raises ValueError if the node id is unknown.

Args: node_id: The Z-Wave node id, e.g. 5

Inputs: node_id (required). Returns: result

zwave_node_infoA

Get full detail for a single Z-Wave node.

Includes device class, supported command classes, endpoint count, security class, protocol version, last-seen time, and signal statistics, on top of the summary fields. protocol_version is a {"value": int, "label": str} object (label is null for an unmapped code). Raises ValueError if the node id is unknown.

Args: node_id: The Z-Wave node id, e.g. 5

Inputs: node_id (required).

zwave_node_valuesA

List a node's current values (excluding configuration parameters).

Returns each value's id, command class, endpoint, property, current reading, and metadata (label, unit, type, range, states, writeability). Configuration parameters are reported separately by zwave_node_config. Raises ValueError if the node id is unknown.

Args: node_id: The Z-Wave node id, e.g. 5

Inputs: node_id (required). Returns: result

zwave_rebuild_node_routesB

Rebuild mesh network routes for a single node.

Returns {node_id, success}. Raises ValueError for an unknown node id.

Args: node_id: The Z-Wave node id, e.g. 5

Inputs: node_id (required).

zwave_rebuild_routes_statusA

Report whether a network-wide route rebuild (heal) is in progress.

Returns {"is_rebuilding": bool | null} from the controller state. Poll this after zwave_begin_rebuilding_routes to track a heal to completion.

Inputs: no named parameters.

zwave_reinterview_nodeA

Re-run a node's interview to refresh its capabilities and values.

Fire-and-forget: returns once the interview is requested; the interview itself runs in the background and can take a while for battery devices. Raises ValueError for an unknown node id.

Args: node_id: The Z-Wave node id, e.g. 5

Inputs: node_id (required).

zwave_remove_associationB

Remove an association from a source node's group to a target node.

Raises ValueError for an unknown source node id.

Args: node_id: The source Z-Wave node id, e.g. 5 group: The association group id on the source node target_node_id: The associated node id to remove from the group source_endpoint: Optional source endpoint (defaults to the root device) target_endpoint: Optional target endpoint (defaults to the root device)

Inputs: group (required), node_id (required), target_node_id (required), source_endpoint, +1 more.

zwave_remove_failed_nodeA

Remove a node the controller has marked failed from the network.

Only works on nodes the controller considers failed (dead/unreachable). Raises ValueError for an unknown node id.

Args: node_id: The Z-Wave node id, e.g. 5

Inputs: node_id (required).

zwave_set_config_parameterA

Set a node's manufacturer configuration parameter.

parameter is the parameter number (the property field from zwave_node_config). bitmask is the optional partial-parameter bit mask (its property_key); omit it for whole-parameter writes. Returns the command status (ACCEPTED or QUEUED). Raises ValueError for an unknown node.

Args: node_id: The Z-Wave node id, e.g. 5 parameter: The configuration parameter number value: The new integer value bitmask: Optional partial-parameter bit mask

Inputs: value (required), node_id (required), parameter (required), bitmask.

zwave_set_node_locationA

Set a node's location label.

Raises ValueError for an unknown node id.

Args: node_id: The Z-Wave node id, e.g. 5 location: The new location for the node

Inputs: node_id (required), location (required).

zwave_set_node_nameA

Set a node's friendly name.

Raises ValueError for an unknown node id.

Args: node_id: The Z-Wave node id, e.g. 5 name: The new name for the node

Inputs: name (required), node_id (required).

zwave_set_valueA

Set a Z-Wave value and report the command outcome.

value_id is the id from zwave_node_values (e.g. "5-38-0-targetValue"). value must match the value's type (a number, bool, or string as its metadata describes). Returns the command status (SUCCESS, WORKING, FAIL, QUEUED for a sleeping node, etc.) with any message. Raises ValueError for an unknown node id; the value must exist on the node and be writeable.

Args: node_id: The Z-Wave node id, e.g. 5 value_id: The value id from zwave_node_values value: The new value to set

Inputs: value (required), node_id (required), value_id (required).

zwave_stop_exclusionA

Take the controller out of exclusion mode.

Inputs: no named parameters.

zwave_stop_inclusionA

Take the controller out of inclusion mode.

Inputs: no named parameters.

zwave_stop_rebuilding_routesA

Stop an in-progress network-wide route rebuild.

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 24 tools

    Disambiguation5/5

    Each tool targets a distinct Z-Wave operation (e.g., add association vs remove association, begin inclusion vs stop inclusion, node info vs node config vs node values). There is no functional overlap between tools, and descriptions clearly differentiate their purposes.

    Naming Consistency5/5

    All tool names follow a consistent 'zwave_verb_noun' pattern in snake_case (e.g., zwave_add_association, zwave_list_nodes, zwave_set_value). Verbs are action-oriented and nouns clearly indicate the resource, making the convention predictable across all 24 tools.

    Tool Count4/5

    24 tools is on the higher side of typical, but the Z-Wave domain requires many distinct operations (network management, node configuration, value control, associations). Each tool serves a well-defined purpose without redundancy, so the count is justified and not excessive.

    Completeness4/5

    The tool surface covers core Z-Wave workflows: node discovery, configuration, value setting, associations, inclusion/exclusion, route rebuilding, and firmware status. Minor gaps exist (e.g., no firmware update trigger, incomplete S2 secure inclusion), but these are explicitly noted and do not significantly impair common tasks.

    Maintenance

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      D
      maintenance
      MCP server for full Home Assistant control, enabling AI agents to manage dashboards, automations, files, apps, entities, and more via REST API, WebSocket, and SSH.
      66
      182 npm
      MIT
    • A
      license
      B
      quality
      B
      maintenance
      MCP server for OpenHAB v5+ that exposes the entire REST API as tools for AI models, enabling complete control over items, things, rules, persistence, and semantic model.
      25
      7
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      A comprehensive MCP server that enables AI assistants to interact with Home Assistant, control smart home devices, query states, execute services, and manage automations via natural language.
      77
      196,503 PyPI
      7,659
      MIT