npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@northernrough/hc3-mcp-server

v4.24.0

Published

Standalone Model Context Protocol server for Fibaro Home Center 3. 130+ tools with read-modify-write + post-write-verify guards on every mutating endpoint, HTTP transport, Z-Wave diagnostics, an audit family for cross-surface drift detection, and a 24-mod

Readme

HC3 MCP Server

Standalone Model Context Protocol server giving Claude, Cursor, or any MCP client live, guard-railed access to a Fibaro Home Center 3.

Not to be confused with the unscoped mcp-server-hc3 package on npm. That package covers a smaller core surface (rooms, devices, scenes). This server adds QuickApp file management, Z-Wave diagnostics, profile orchestration, custom events, alarm partitions, and 130+ tools total, with verified write guardrails on all destructive operations.

This project began as a fork of jangabrielsson/HC3_mcp but has since been substantially rewritten — the tool surface grew roughly 3×, every write tool gained read-modify-write + post-write-verify guards, an HTTP transport was added for remote use, and (in 3.4.0) the codebase was rearchitected from a single 7,300-line class into 23 per-domain modules. Credit to jgab for the original concept and starting point.

Install

npm install -g @northernrough/hc3-mcp-server

Or run directly with npx (no install):

npx @northernrough/hc3-mcp-server

Configure

The server reads four environment variables:

| Variable | Required | Default | Description | |---|---|---|---| | FIBARO_HOST | yes | — | HC3 IP address or hostname (e.g. 192.168.1.57) | | FIBARO_USERNAME | yes | — | HC3 user (admin recommended for full surface) | | FIBARO_PASSWORD | yes | — | HC3 password | | FIBARO_PORT | no | 80 | HC3 port |

For development you can put these in a local .env file (the server uses dotenv automatically).

HTTP transport (for Claude mobile / always-on hosts)

By default the server speaks MCP over stdio, which is what Claude Desktop and Claude Code launch. To run as a long-lived HTTP server (e.g. on a Pi or container, fronted by Cloudflare Tunnel for mobile-app reachability), set:

MCP_TRANSPORT=http
MCP_HTTP_HOST=127.0.0.1   # bind address, default 127.0.0.1
MCP_HTTP_PORT=3000        # listen port, default 3000
MCP_HTTP_TOKEN=<at least 16 chars>   # required by default; see "external auth" below

Endpoints:

  • POST /mcp — JSON-RPC. Requires Authorization: Bearer <MCP_HTTP_TOKEN> (unless external auth mode is enabled, see below).
  • GET /mcp — SSE stream for server-pushed messages.
  • GET /healthz — unauthenticated readiness check.

Quick test:

curl -X POST http://127.0.0.1:3000/mcp \
  -H "Authorization: Bearer $MCP_HTTP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

External auth boundary (Cloudflare Access / reverse proxy)

Which Claude surface is talking to the server matters here:

  • Claude Desktop and Claude Code with stdio — no HTTP, no token. Skip this section.
  • Claude Code with HTTP transport (claude mcp add --transport http --header "Authorization: Bearer ...") — can pass a static bearer token. Use MCP_HTTP_TOKEN and you're done.
  • claude.ai custom connectors (web app and the iOS / Android mobile apps) — at time of writing these only support OAuth 2.1 with Dynamic Client Registration and cannot send a static Authorization: Bearer … header. This is the case that needs the workaround below.

To use the server from a claude.ai custom connector (web or mobile), disable bearer auth on the MCP layer and rely on an external authentication layer (Cloudflare Access, a reverse proxy with auth, IP allowlists, etc.) to enforce identity:

MCP_TRANSPORT=http
MCP_HTTP_HOST=127.0.0.1
MCP_HTTP_PORT=3000
MCP_HTTP_ALLOW_UNAUTH=true   # opt-in; disables bearer check on /mcp
# MCP_HTTP_TOKEN unset

When MCP_HTTP_ALLOW_UNAUTH=true is set and MCP_HTTP_TOKEN is not, the server logs a loud warning at startup and accepts requests on /mcp without checking any header. Anyone able to reach MCP_HTTP_HOST:MCP_HTTP_PORT then has full read+write control of HC3 — device control, scene execution, QuickApp edits, global variable writes. Binding to 127.0.0.1 and exposing the endpoint via Cloudflare Tunnel + Cloudflare Access (with a service token or SSO policy) is the recommended deployment for this mode. See DEPLOYMENT.md for a step-by-step walkthrough.

Both flags must be deliberate: with neither MCP_HTTP_TOKEN nor MCP_HTTP_ALLOW_UNAUTH=true set, the server refuses to start in HTTP mode.

Wire into your MCP client

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "hc3": {
      "command": "npx",
      "args": ["-y", "@northernrough/hc3-mcp-server"],
      "env": {
        "FIBARO_HOST": "192.168.1.57",
        "FIBARO_USERNAME": "admin",
        "FIBARO_PASSWORD": "your_password"
      }
    }
  }
}

Restart Claude Desktop. The HC3 tools appear in the tools menu.

Claude Code

claude mcp add hc3 -- npx -y @northernrough/hc3-mcp-server \
  --env FIBARO_HOST=192.168.1.57 \
  --env FIBARO_USERNAME=admin \
  --env FIBARO_PASSWORD=your_password

Cursor / Cline / Continue

Each client uses a similar JSON shape; consult its docs for the config file location. The shape is the same as Claude Desktop's:

{
  "mcpServers": {
    "hc3": {
      "command": "npx",
      "args": ["-y", "@northernrough/hc3-mcp-server"],
      "env": {
        "FIBARO_HOST": "192.168.1.57",
        "FIBARO_USERNAME": "admin",
        "FIBARO_PASSWORD": "your_password"
      }
    }
  }
}

Testing

Six-phase MCP test harness in scripts/test/. Read-only phases catch schema and protocol regressions; mutating phases verify CRUD round-trips on disposable resources.

| Phase | What it catches | Mutating? | |---|---|---| | 0 | tool count / schema validity / full parity vs golden (names, descriptions, schemas) | no | | 1 | every read tool returns expected response shape | no | | 2 | create / update / delete round-trips end-to-end | YES — gated | | 3 | known-bitten regressions (UTF-8, 501, content shape, validation) | partial | | 6 | every hc3.request(...) URL is live (catches dead endpoints) | no |

Run

npm run compile
node scripts/test/phase0-parity.mjs
node scripts/test/phase1-readonly-sweep.mjs

Phase 0 needs no gateway and runs automatically as the first step of npm test, in --check mode. After an intentional tool change, regenerate the snapshot it checks against and commit the result:

node scripts/test/phase0-parity.mjs --update

The harness reads FIBARO_HOST / FIBARO_USERNAME / FIBARO_PASSWORD from the environment (same vars the server uses; .env is honoured).

Run mutating phases

Phase 2 creates and deletes globals, custom events, rooms, scenes, and QAs on the live HC3. Gated behind an explicit env var so you can't run it by accident:

MCP_TEST_ALLOW_MUTATIONS=1 node scripts/test/phase2-mutations.mjs

All resources are prefixed TEST_${runId}_ (or TEST-${runId}-) and torn down in finally even on test failure. A pre-flight orphan sweep removes any leftovers from previously-crashed runs (covers globals, devices, custom events, and scenes).

CI / pre-commit

GitHub Actions (.github/workflows/ci.yml) runs on every push to master and every pull request. Everything it runs is hermetic — no HC3 gateway and no credentials, since the unit suites inject fake clients or stub fetch, and the phase 0 parity check drives the server over stdio with stub env:

  • npm run lint and npm test on Node 18, 20, 22 and 24
  • release hygienepackage.json, the newest CHANGELOG.md entry and src/mcp/version.ts must agree on the version (scripts/check-release-hygiene.mjs)
  • golden snapshot freshness, checked twice. npm test runs phase0-parity.mjs --check, which fails if the committed tools.golden.json differs from what the server registers in any name, description or schema. The hygiene job additionally regenerates the file and fails if it moved, which catches the case --check cannot: a snapshot hand-edited to match nothing. Since release.yml also runs npm test, a release cannot ship a stale snapshot either
  • npm pack --dry-run, so a broken files list is caught before publish rather than after a bad tarball reaches the registry

The phases that need a live gateway are not in CI and stay manual. Phase 0 no longer needs remembering, since npm test runs it; per CLAUDE.md ("Test before commit"), run phase 1 before merging anything that touches MCP protocol or HC3 API code. Phase 2 is worth running before any release that touches CRUD tools.

See scripts/test/README.md for per-phase detail.


Releasing

Tag-driven. .github/workflows/release.yml publishes to npm when a v* tag is pushed, so a release is git push origin vX.Y.Z and nothing else.

It refuses to publish if the tag disagrees with package.json, if the version is already on the registry (they are immutable), or if lint, tests or the release-hygiene check fail. After publishing it waits for the version to become resolvable rather than assuming success.

Requires an npm automation token in the NPM_TOKEN repository secret. Automation tokens carry their own 2FA bypass, which is what makes an unattended publish possible — an interactive npm publish on a 2FA account prompts for a one-time password that no script can supply.


Feedback loop

The server records where it wastes people's time, locally and with nothing transmitted.

Automatic. Every tool failure is recorded (redacted, size-capped) and grouped by tool and normalised message. A tool failing the same way repeatedly is usually a missing or wrong description rather than user error. Read it via the hc3://friction resource.

Opt-in. report_finding lets an agent or operator record a surprise while they still have the context. It requires a reproduction that varies one thing — of the claims in the last field report received here, two were wrong and one blamed the wrong cause, because two variables had changed at once.

Writing a reproduction cheaply. scripts/probe.mjs provides throwaway QuickApps, icons and globals with guaranteed teardown, plus a single() helper that runs both arms of a one-variable test and prints a verdict. Use it rather than probing live objects — a delete_icon used as a reachability probe destroyed a live user icon on this gateway.

Triage. npm run triage writes FRICTION.md: every item a candidate with a verdict of confirmed / refuted / untested. Nothing there is a fact until re-tested against a gateway, and refuted items stay in the file so they are not re-adopted from the original report later.

Storage is MCP_FRICTION_LOG, else the first writable candidate; MCP_FRICTION_DISABLE=true turns it off. Under a hardened systemd unit (ProtectSystem=strict) the service may have nowhere persistent to write — add StateDirectory=hc3-mcp to the unit, or the log lives in a private /tmp and is wiped on every restart. hc3://friction says which applies.


Resources (at-a-glance views)

Beyond tools, the server exposes four read-only MCP Resources. They take no arguments and need no tool call — a client lists them and you read one. Each renders Markdown, so it is legible to you and to an agent.

| URI | What it answers | |---|---| | hc3://health | Is anything broken? Firmware, fleet size, dead devices named, battery outliers, disabled devices | | hc3://watchdog | Is the automation machinery alive? Every *Heartbeat global aged against HC3's own clock, with a stale verdict | | hc3://binder | Did the bindings resolve? Roles by resolution method, everything not at L0_cached, heal history, parameter drift | | hc3://globals | What is the automation state? Scalar globals, structured globals summarised, dead-device watcher decoded | | hc3://friction | Where is this server wasting time? Recurring failures grouped, plus submitted findings |

Heartbeats are discovered by name pattern rather than hard-coded, so a QuickApp added later shows up without a code change.

To render all four as one self-contained HTML page (no external requests, light and dark):

npm run dashboard

The resources are the source of truth and the page is a view over them, so it cannot drift from what the server reports. It is a snapshot — re-run to refresh.


What this does

This server exposes 130+ tools spanning the full HC3 read and write surface, with write guardrails on every destructive operation. Every mutating tool reads the target first, deep-merges the submitted change, writes, refetches, and asserts the change took effect. If HC3 silently dropped or normalised a field, the tool throws rather than reporting a misleading success.

A condensed summary follows. See the live tools/list from the running server (or expand each section below) for the authoritative list.

Devices and Rooms

  • get_devices - List devices, with filters for type, room, interface, visibility, and more
  • get_device_info - Get a single device by ID
  • filter_devices - Server-side multi-criteria filter with attribute projection (POST /api/devices/filter). Much smaller payloads than get_devices when you know which fields you need
  • find_devices_by_name - Resolve a name to parent/top-level devices (substring / exact, optional roomId and visibleOnly filters). Trimmed record output — much smaller than get_devices for lookup workflows
  • find_device_by_endpoint - Resolve a multi-endpoint child device by (parentId, endpointId). Stable identity for children that survives Z-Wave re-inclusion. Returns an array — endpoint 0 is commonly ambiguous
  • get_device_property - Read a single device property (much smaller than get_device_info for scalar fields)
  • cancel_delayed_action - Cancel a queued delayed device action by (deviceId, timestamp)
  • delete_device - Delete a single device by id. Refuses ids <10, Z-Wave physical devices (without allow_physical), and devices with children (without cascade). Post-delete verified
  • control_device - Invoke device actions (turnOn, turnOff, setValue, setColor, etc.)
  • modify_device - Edit top-level fields (name, roomID, enabled, visible) and nested properties in a single verified PUT
  • get_rooms - List rooms and sections
  • get_room - Get a single room by id
  • create_room - Create a new room (pre-validates 20-char name limit)
  • modify_room - Update a room via read-modify-write + verify
  • delete_room - Delete a room, with guards for the default room and rooms with devices (reassign_to target)
  • assign_devices_to_room - Batch-move devices to a room (groupAssignment), with per-device post-move verify

Scenes

  • get_scenes - List scenes with filters (returns every scene with full content — can be very large)
  • get_scene - Fetch a single scene by id (full record incl. Lua/scenario content); includeContent=false returns metadata only with contentLength
  • run_scene - Start a scene (async, returns immediately)
  • run_scene_sync - Run a scene synchronously, waiting for completion. Useful for sequenced automation steps
  • stop_scene - Stop a running scene
  • modify_scene - Update scene metadata (name, icon, room, etc.)
  • create_scene - Create a new scene (with HC3-required field defaults; post-create verify)
  • update_scene_content - Replace scene Lua (actions/conditions) content wholesale. Returns lengths + md5 by default rather than three copies of the body (returnContent: true restores the old shape)
  • patch_scene_content - Change part of a scene by supplying only the text to replace. Each old must match exactly count times or nothing is written. Atomic, dryRun, expectedHash, returns a unified diff. A scene cannot be split across files the way a QuickApp can, so this is the only way to keep scene edits small
  • delete_scene - Delete a scene by id with read-first-for-recovery-trail, refusal of currently-running scenes, and post-delete refetch verify

Icons

  • list_icons - List all icons HC3 knows about, grouped by device/room/scene
  • get_icon - Fetch an icon's binary content base64-encoded; detects HC3's silent SVG-fallback for missing icons
  • upload_icons - Batch upload for state-variant sets. Labelled array in, label→id map plus a pasteable Lua table out. Sequential and not atomic; validates the whole batch before the first write
  • upload_icon - Upload a new user icon. Device icons require deviceTemplate (the Fibaro device type they are filed under, e.g. com.fibaro.binarySwitch); room and scene icons must not pass it. Pre-validates PNG bytes (signature, 128×128, palette mode) before posting; HC3's PNG validator silent-500s on non-palette PNGs. SVG uploads as-is. Auto-assigned name returned
  • delete_icon - Delete a user-uploaded icon. Built-in icons return 403

System

  • get_server_info - Report the MCP server's identity: name, version (read from package.json at startup), transport (stdio/http), and configured HC3 host/port. No HC3 round-trip; useful for "which version am I connected to" questions
  • get_system_info - HC3 version, serial, and system details
  • get_hc3_time - HC3's current wall-clock time (NTP-sourced) from /api/settings/info: epoch plus human-readable UTC/local forms and an explicit server-computed weekday. Use to establish "now" rather than inferring it from event timestamps or a stale host clock. Uses timestamp (never serverStatus); warns on >120s host-clock skew
  • snapshot - Single-call dump of every mutable HC3 configuration surface (devices, rooms, scenes, QAs with files, globals, custom events, alarm, climate, system, users, HC3 API docs) for backup regimes and drift detection. Per-surface atomicity; opt-in zwave-parameters surface
  • get_network_status - Network connectivity status
  • get_energy_data - Energy consumption data
  • get_diagnostics - System health diagnostics
  • get_weather - Current weather data
  • get_home_status - Current home mode
  • set_home_status - Set home mode (Home/Away/Vacation/Night)
  • get_profiles - List HC3 profiles + activeProfile id (Home/Away/Vacation orchestration)
  • get_profile - Get one profile's detail (devices/scenes/climateZones/partitions)
  • activate_profile - Switch the active profile with post-activation verify
  • modify_profile - Update a profile (name/icon/devices/scenes/climateZones/partitions) with read-modify-write + verify
  • create_profile - Create a new profile (post-create verify)
  • delete_profile - Delete a profile (refuses the active one; post-delete verify)
  • reset_profiles - DESTRUCTIVE: resets every profile to HC3 defaults. Requires explicit confirm=true
  • set_profile_scene_action - Set how a profile handles a specific scene on activation
  • set_profile_climate_zone_action - Set how a profile handles a specific climate zone on activation
  • set_profile_partition_action - Set how a profile handles a specific alarm partition on activation
  • get_location_info - Home location settings
  • update_location_settings - Update location, timezone, and related settings

Global Variables

  • get_global_variables - List all global variables
  • set_global_variable - Update an existing global variable (type-coerced to the stored type)
  • create_global_variable - Create a new global variable (refuses if name exists; validates name regex; supports isEnum with enumValues)
  • delete_global_variable - Delete a global variable by name. Reads lastValue first (returned as recovery trail); refuses readOnly system globals unless allow_system=true. Post-delete verified

Users

  • get_users - List users and permissions
  • update_user_rights - Modify a user's access rights (devices, scenes, climateZones, profiles, alarmPartitions). Read-modify-write + post-write-verify. Safety guards against writing rights.advanced (privilege escalation) or setting rights.*.all=true (mass grant) unless explicitly overridden; refuses superuser targets

Climate

  • get_climate_zones - List climate zones
  • get_climate_zone - Get a single climate zone
  • update_climate_zone - Update climate zone settings

Alarm

  • get_alarm_partitions - List alarm partitions
  • get_alarm_partition - Get a single alarm partition
  • arm_alarm_partition - Arm a partition
  • disarm_alarm_partition - Disarm a partition
  • get_alarm_history - Alarm event history
  • get_alarm_devices - Security devices

Sprinklers

  • get_sprinkler_systems - List sprinkler systems
  • get_sprinkler_system - Get a single sprinkler system
  • control_sprinkler_system - Start/stop irrigation with duration and delay

Custom Events

  • get_custom_events - List custom event definitions
  • create_custom_event - Create a new custom event
  • trigger_custom_event - Emit a custom event
  • get_custom_event - Read a single custom event by name
  • update_custom_event - Update userDescription and/or rename (read-modify-write)
  • delete_custom_event - Delete by name (captures last userDescription)

Notifications

  • get_notifications - List notifications
  • mark_notification_read - Mark a notification read
  • clear_all_notifications - Clear all notifications
  • get_notification - Read a single notification by id
  • update_notification - Update notification fields (wasRead, data, priority) with read-modify-write
  • delete_notification - Delete by id, capturing last data as recovery trail. Refuses canBeDeleted=false unless allow_system=true

Backups

  • can_create_backup - Check whether backups can be created
  • get_local_backup_status - Local backup status
  • get_remote_backup_status - Remote backup status
  • get_backups - List backups
  • create_backup - Create a new backup

iOS Devices

  • get_ios_devices - List registered iOS devices
  • register_ios_device - Register a new iOS device

Debug

  • get_debug_messages - Retrieve debug messages with client-side filtering
  • clear_debug_messages - Clear all debug messages (returns count cleared). Useful for test loops

System Events

  • get_event_history - HC3 system event feed (scene starts, device property changes, device actions) — the data behind /app/history. Supports a from/to time window (Unix epoch, forwarded server-side so retrospective queries reach arbitrarily far back), object_id (single) / object_ids (a set) filtered client-side against each event's objects[].id (HC3 ignores objectId unless objectType is also given, so the id filter is enforced locally), optional object_type (lets HC3 also narrow server-side for a single id), event_type, and limit (capped at 1000). since_timestamp is kept as a deprecated alias for from.
  • get_refresh_states - Live poll of HC3's native event/state-change stream (GET /api/refreshStates?last=cursor). Returns changes (state deltas) + events + new cursor. Complementary to get_event_history — refreshStates is live, event_history is retrospective

Z-Wave Diagnostics

  • get_zwave_mesh_health - Aggregate mesh health from /api/devices?interface=zwave: dead/unconfigured counts, dead devices with node IDs and reasons, breakdowns by room and manufacturer
  • get_zwave_node_diagnostics - Per-node Z-wave transmission counters (frame totals, outgoing failures, CRC/S0/S2/TransportService/MultiChannel failures, nonce exchanges) enriched with device name, room, and computed outgoing-failed percent. Sources an undocumented endpoint
  • get_zwave_reconfiguration_tasks - Active reconfiguration tasks with status, target device and node, child-device summary. Sources an undocumented endpoint
  • get_device_parameters - Z-Wave device configuration parameters with human-readable labels, descriptions, defaults, and format. Merges current values with the template catalogue. Flags provenance honestly: on HC3 5.x the mesh read-back path does not work, so most values are template defaults rather than live device readings
  • set_device_parameter - Write a Z-Wave configuration parameter via the setConfiguration device action. The only working REST path for parameter writes on firmware 5.x — the documented setParameter and reconfigure actions return "not implemented", and the properties.parameters PUT path silently caches without transmitting. Reads-before, polls cache after with backoff, returns {before, after, cacheUpdated, actionResponse, transmissionNote}. Mesh transmission is not programmatically verifiable on HC3 5.x but empirically confirmed working

QuickApps

  • get_quickapps - List QuickApps
  • get_quickapp - Get a single QuickApp
  • create_quickapp - Create a new empty QuickApp on HC3 from scratch (not from a .fqa file; use import_quickapp for that)
  • get_quickapp_available_types - List the QuickApp device types the current firmware accepts, for picking a type when calling create_quickapp
  • restart_quickapp - Restart a QuickApp
  • get_quickapp_variable - Read a single quickAppVariable
  • set_quickapp_variable - Update an existing quickAppVariable (preserves declared type, post-write verified)
  • create_quickapp_variable - Create a new quickAppVariable on a QA without a UI round-trip; optional varType declares the stored HC3 type, otherwise inferred from value's JS type
  • delete_quickapp_variable - Remove a quickAppVariable by name; returns the previous {type, value} as a recovery trail

QuickApp File Management

  • list_quickapp_files - List source files for a QuickApp
  • get_quickapp_file - Get a single file's content, plus contentHash for optimistic concurrency. Supports partial reads: startLine/endLine, or contains for a line-numbered excerpt around every match
  • create_quickapp_file - Create a new source file (arg: fileName; renamed from name in 4.0.0)
  • update_quickapp_file - Replace an existing source file wholesale
  • patch_quickapp_file - Change part of a file by supplying only the text to replace, instead of reproducing the whole thing. Each old must match exactly count times or the whole patch aborts before anything is written. Atomic, dryRun, expectedHash, Lua sanity warnings, returns a unified diff
  • update_multiple_quickapp_files - Batch update multiple files
  • delete_quickapp_file - Delete a source file (main files cannot be deleted)
  • export_quickapp - Export as .fqa (open) or .fqax (encrypted)
  • import_quickapp - Import a QuickApp from a .fqa. Takes the file as base64 (use this when driving a remote server) or as a server-side filePath. Validates the .fqa is parseable JSON before posting, and verifies the created device by refetching it

System Intelligence and Context

  • get_system_context - Comprehensive system overview
  • get_device_relationships - Device relationships and room assignments
  • get_automation_suggestions - Automation recommendations
  • explain_device_capabilities - Detailed capability explanations

HC3 Programming Documentation

  • get_hc3_configuration_guide - HC3 configuration reference
  • get_hc3_quickapp_programming_guide - QuickApp programming guide
  • get_hc3_lua_scenes_guide - Lua scenes programming guide
  • get_hc3_programming_examples - Code examples and snippets

Plugin Management

  • get_plugins - All plugins (installed plus available)
  • get_installed_plugins - Installed plugins
  • get_plugin_types - Plugin type catalogue
  • get_plugin_view - Plugin view/configuration interface
  • update_plugin_view - Update plugin view components
  • call_ui_event - Trigger UI events on plugin interface elements
  • create_child_device - Create child devices
  • manage_plugin_interfaces - Add or remove interfaces from devices
  • restart_plugin - Restart a plugin
  • update_device_property - Update device property values directly
  • publish_plugin_event - Publish system events through the plugin system
  • get_ip_cameras - Available IP camera types
  • install_plugin - Install a plugin
  • delete_plugin - Uninstall a plugin

Audit (cross-cutting, dev-time)

Read-only batch tools that walk multiple HC3 surfaces (QAs + scenes + globals + devices) to answer questions a single-domain tool can't. Stateless; do not modify HC3. Cost: 30-90s per call on a typical HC3 — they fetch every QA file and every scene to grep through.

  • audit_id_references - Find every place a device id is referenced across all QuickApp source files, every Lua/scenario scene's actions and conditions, every JSON (block-editor) scene's nested action tree, and every global variable's value. Universal HC3 question: "if I delete or replace this device, what breaks?"
  • audit_qa_devices - For a given QuickApp, parse every numeric device id its source files reference and classify each as ALIVE / DEAD / DELETED via /api/devices/{id} (properties.dead / properties.deleted). Optional bindAware: true mode also parses bind("RoleStem", { ... }) descriptors and runs the L0-L4 resolver waterfall (cached / endpoint / nameInParent / newParentEndpoint / globalName) on each role entry — useful for spotting descriptors whose cached id has drifted after a Z-Wave Reconfigure
  • introspect_device_group - Take a Devices.X.Y = { foo = 1234, bar = 5678 } numeric group inside a QA file and return a structured snapshot of the live state behind each id. Auto-detects flat vs endpoint mode. Output formats: json (canonical), markdown-table (pasteable into a doc), bind-lua (ready-to-paste descriptor block matching the SceneManager bind() pattern), yaml

Each tool includes input validation, error handling, and detailed response data to help AI assistants understand and work with your Fibaro HC3 system effectively.

How this differs from upstream and mcp-server-hc3

Upstream was a starting point, not a maintained product. The original author has moved on to a different QuickApp development workflow (his plua repo + skills) and has greenlit independent evolution of this line. Almost no upstream code remains on the runtime path — what's been added since then:

  • Write guardrails on every mutating tool. Read-modify-write, post-write verify, refetch-and-compare on every destructive endpoint. Catches HC3's known silent-drop classes (e.g. Z-Wave parameter writes that cache without transmitting; QA file writes that need byte-exact verification; user-rights writes that would 403 if the full record is echoed back). See CHANGELOG.md for the inventory of caught classes.
  • Z-Wave diagnostics and writes: get_zwave_mesh_health, get_zwave_node_diagnostics (per-node frame/CRC/security counters), get_zwave_reconfiguration_tasks, get_device_parameters (with honest provenance — values are HC3-stored, not live device readings on this firmware), set_device_parameter (4.3.0 — the working REST path for Z-Wave configuration parameter writes on firmware 5.x via setConfiguration; the documented setParameter and reconfigure actions return "not implemented" on this firmware).
  • Resilient name → id resolution for manifest-driven sync that survives Z-Wave re-inclusion (find_devices_by_name, find_device_by_endpoint).
  • Profile orchestration end-to-end (read, activate, modify, full CRUD, association PUTs).
  • Snapshot tool for nightly backup regimes — single-call dump of every mutable surface with per-surface atomicity.
  • HTTP transport with bearer auth and a Cloudflare-Access-friendly unauthenticated mode for claude.ai custom connectors. See DEPLOYMENT.md.
  • Modular architecture (3.4.0): 24 per-domain tool modules under src/mcp/tools/, with shared write-verify helpers in src/mcp/util.ts and a tool-registry dispatcher in src/mcp/tools/registry.ts. The orchestrator is 244 lines.
  • Standalone, no dependency on plua or any local development toolchain. Works out of the box with npx.
  • Audit family (3.5.0+): audit_id_references, audit_qa_devices (with optional bind-aware L0-L4 resolver waterfall), introspect_device_group (json / markdown-table / bind-lua / yaml outputs). Read-only batch tools that walk QAs + scenes + globals + devices to surface drift across surfaces.

Migrating from 3.x to 4.x

Single breaking change. The QuickApp file-arg was inconsistently named across the QA-file tools — three used fileName, two used name. 4.0.0 settles on fileName everywhere, immediately, with no deprecation shim.

If you're upgrading from any 3.x release:

  • create_quickapp_file — rename argument namefileName.
  • update_multiple_quickapp_files — within each item in the files array, rename namefileName.

The other QA-file tools (get_quickapp_file, update_quickapp_file, delete_quickapp_file, list_quickapp_files) already used fileName and need no change. HC3's wire shape still uses name for the file's own name in the request body; the wrapper now remaps automatically — callers don't see HC3's wire form.

If you are happy on a smaller core surface, the unscoped mcp-server-hc3 may suit you better. If you maintain a household HC3 with QuickApps, scenes, and Z-Wave actors and want the agent to be able to do meaningful, safe work over the full system, this is what you want.

Security

This server runs with your HC3 admin credentials and exposes write access to your home: devices, scenes, QuickApps, global variables, profiles, users, rooms, alarm partitions, and the notification centre. Any MCP client (Claude Code, Claude Desktop, Cursor, Cline, etc.) connected to it can read and mutate that state. Treat the credentials and the agent's prompts accordingly.

  • Credentials are taken from environment variables (FIBARO_HOST, FIBARO_USERNAME, FIBARO_PASSWORD, optional FIBARO_PORT). They are never written to disk by this code.
  • The published npm tarball contains only compiled JS, LICENSE, README.md, CHANGELOG.md, SECURITY.md, DEPLOYMENT.md, and KNOWN_DEAD_ENDPOINTS.md. No .env, no local configuration files.
  • HC3 does not currently expose TLS on its REST surface; the credential transit is HTTP Basic auth. Run this on the same trusted network as the HC3, or front it with a reverse proxy.

To report a vulnerability, see SECURITY.md. Please email rather than file a public issue.

Maintenance

This package is maintained for the author's personal HC3 setup and is published as-is for the wider Fibaro community. There is no SLA. Issues and PRs are welcome; response time is best-effort. Stable interfaces are SemVer-respected — patch releases are bug fixes, minors are additive, majors are breaking. Subscribe to GitHub releases on northernRough/HC3_mcp to track new versions.

Known issues

  • IPv6 addresses are not supported
  • TLS to the HC3 requires a fronting reverse proxy (HC3 firmware is HTTP-only on the REST surface)
  • Some advanced HC3 features (notification centre creation, certain Z-Wave write paths) are firmware-quirky on 5.x; tools that hit those quirks fail loudly rather than silently and document the boundary in their tool descriptions
  • A handful of historical HC3 REST endpoints are no longer routed on current firmware (5.20x). Tools that previously called them have been migrated to working alternatives. The full catalogue, with curl reproductions and replacement endpoints for each, lives in KNOWN_DEAD_ENDPOINTS.md. Consult it before authoring a new tool against an HC3 endpoint that hasn't been exercised recently.

Contributing

Pull requests are welcome. The repo follows a strict branch-per-logical-change convention with read-modify-write + post-write verify on every mutating tool. See ~/code/hc3/HC3_mcp/CLAUDE.md (in the local checkout) for the workflow expectations.

License

MIT License. Original work copyright (c) 2024 GsonSoft Development; fork modifications and additions copyright (c) 2026 northernRough.

Release notes

See CHANGELOG.md.