Skip to main content
Glama
solaegis

Hubitat MCP Server

by solaegis
README.md
# Hubitat MCP Server

MCP server for [Hubitat](https://hubitat.com/) Elevation hubs. Control devices through the documented **Maker API**, with optional gated access to undocumented local admin routes.

## Design claims

These constraints drive the architecture:

| # | Claim | Implication |
|---|-------|-------------|
| 1 | **Two API surfaces; only Maker API is supported** | First-class tools use Maker API (`/apps/api/{appId}/…`). Hub management (firmware, Z-Wave mesh, backups, reboot) lives on undocumented admin routes that break across firmware updates — gated behind `HUBITAT_ENABLE_ADMIN=true`. Run `task recon` against *your* hub before relying on admin tools. |
| 2 | **Cache + eventsocket is the scale solution** | Hitting `/devices/all` on every call is fine under ~50 devices (default). Set `HUBITAT_DEVICE_STORE=cached` to hydrate once and apply `ws://[hub]/eventsocket` deltas (with dedupe). |
| 3 | **Rule Machine has no API** | You cannot list, read, or trigger rules programmatically. Levers are **virtual switches** and **hub variables** only. |

## Quick start

1. Install the **Maker API** app on your hub, authorize the devices you want exposed, copy the app ID and access token.
2. Clone this repo and configure:

```bash
task env:create
# edit .env — HUBITAT_HOST, HUBITAT_APP_ID, HUBITAT_ACCESS_TOKEN
task setup          # build + hub-check + MCP client registration (when credentials are set)
```

3. Restart **Claude Desktop** and/or reload MCP in **Cursor**.
4. Optional: `task inspect` for the MCP Inspector UI.

### Maker API setup

1. Hubitat UI → **Apps** → **Add Built-In App** → **Maker API**
2. Select devices (or allow all)
3. Copy local URLs; note `apps/api/<APP_ID>/…?access_token=<TOKEN>`

## MCP clients

| Task | Target |
|------|--------|
| `task setup-cursor` | `~/.cursor/mcp.json` |
| `task setup-claude-code` | `claude mcp add hubitat --scope user` |
| `task setup-claude-desktop` | Claude Desktop `claude_desktop_config.json` |
| `task setup-mcp` | All of the above |

To refresh Claude Code after `.env` changes: `claude mcp remove hubitat` then `task setup-claude-code`.

## Tools

| Tool | Purpose |
|------|---------|
| `hubitat_list_devices` | Paginated/filterable device list |
| `hubitat_get_device` | Device detail + attributes |
| `hubitat_get_device_commands` | Commands for a device |
| `hubitat_send_command` | Generic command + optional value |
| `hubitat_set_color` | Hex → URL-encoded `setColor` JSON map |
| `hubitat_list_virtual_devices` | Virtual switch/button candidates (Rule Machine levers) |
| `hubitat_get_hub_variable` / `hubitat_set_hub_variable` | Hub variables (admin routes; firmware-sensitive) |

### Admin plane (`HUBITAT_ENABLE_ADMIN=true`)

Undocumented and firmware-sensitive. Read tools first; `hubitat_hub_reboot` requires `confirm=true`.

| Tool | Risk |
|------|------|
| `hubitat_hub_info` | read |
| `hubitat_backup_status` | read |
| `hubitat_list_apps` | read |
| `hubitat_zwave_status` | read |
| `hubitat_hub_reboot` | **destructive** |

### Resources

- `hubitat://capabilities` — static capability → common commands index

## Automating Rule Machine

Rule Machine has **no API**. To drive rules from this server:

1. Create a **virtual switch** (or button) and subscribe a rule to it, then `hubitat_send_command` with `on`/`off`/`push`, or
2. Create a **hub variable** subscription and use `hubitat_set_hub_variable`.

## Configuration

See [`.env.example`](.env.example).

| Variable | Default | Purpose |
|----------|---------|---------|
| `HUBITAT_HOST` | required | Hub IP/hostname |
| `HUBITAT_APP_ID` | required | Maker API app ID |
| `HUBITAT_ACCESS_TOKEN` | required | Maker API token |
| `HUBITAT_ENABLE_ADMIN` | `false` | Register admin tools |
| `HUBITAT_POLL_CACHE_TTL_MS` | `0` | Soft TTL for polling store (`0` = always fresh) |
| `HUBITAT_DEVICE_STORE` | `polling` | `polling` or `cached` (eventsocket) |

## Task reference

```bash
task --list
```

| Task | Purpose |
|------|---------|
| `build` / `dev` / `start` / `inspect` | Build and run |
| `env:create` / `hub-check` / `recon` | Credentials + hub probe |
| `test` / `typecheck` / `check` / `clean` | Quality |
| `commit` / `changelog` / `bump` | Commitizen releases |
| `pre-commit` / `pre-commit:install` | Hooks |
| `setup-cursor` / `setup-claude-*` / `setup` | MCP clients |

Prefer `task commit` for conventional commits. `task bump` updates `package.json`, changelog, and tags `v*`.

## Recon (Phase 0)

```bash
task recon   # writes docs/recon-{firmware}.yaml
```

Documents Maker API size, EventSocket samples, and which admin routes return JSON vs HTML/404 on your firmware.

## Streamable HTTP (optional)

```bash
npm install express
npm run build
node dist/index.js --http :3000
# POST http://localhost:3000/mcp
```

Default transport remains **stdio** for Cursor / Claude Desktop.

## License

MIT

TDQS

A4.3/5.0

Scored across 8 tools

Disambiguation5/5

Every tool targets a distinct resource (hub variable vs device) and action (list/get/send/set), and the descriptions explicitly provide 'Do NOT use when' guidance to steer agents away from wrong choices. The get vs list vs send tools are clearly separated by their 'Use when'/'Do NOT use when' annotations, leaving no realistic ambiguity.

Naming Consistency4/5

The naming follows a consistent hubitat_verb_noun pattern (hubitat_list_devices, hubitat_get_device, hubitat_send_command). Minor deviations: 'hubitat_list_virtual_devices' reads more as an adjective-modifier than a pure noun, and set_color/send_command/hub_variable all mix nouns, but the pattern is mostly uniform with one verb-noun structure throughout.

Tool Count5/5

8 tools is a well-scoped count for a home-automation hub server. Each pair (list/get, get/send, get_device_commands/send_command, list/get hub_variable) earns its place, and the set covers discovery, control, color, and rule-machine levers without bloat.

Completeness4/5

The surface covers device discovery, state querying, command listing, generic command sending, and color setting, plus virtual-switch and hub-variable rule triggers. Minor gaps: there's no tool for device detail beyond get_device or updating device config, but the core workflows (discover, query, control, trigger) are all covered with no dead-end operations.

Maintenance

ActivitySlowing
ResponsivenessNo issues