Skip to main content
Glama
README.md
# ha-mcp

A self-hosted [Model Context Protocol](https://modelcontextprotocol.io) server for
[Home Assistant](https://www.home-assistant.io), in TypeScript. It gives an MCP client
(Claude Desktop, Claude Code, Codex CLI, …) the **full** Home Assistant control surface:
read any entity's state, call any service, query history, render templates, and resolve
rooms/areas - over a single local stdio connection.

## Why

Home Assistant ships an official MCP Server integration, but it's deliberately narrow: it
only exposes the **Assist** intent layer over entities you've explicitly *exposed* to voice
assistants - no raw states, no arbitrary service calls, no history, no templates, no area
registry. `ha-mcp` wraps the documented [REST](https://developers.home-assistant.io/docs/api/rest/)
and [WebSocket](https://developers.home-assistant.io/docs/api/websocket/) APIs directly, so
the model can work with everything in your instance.

## Tools

| Tool | What it does |
|------|--------------|
| `ha_get_states` | List entity states; optional `domain` and/or `area` filter |
| `ha_get_entity` | Full state + attributes for one `entity_id` |
| `ha_call_service` | Call any service (`light.turn_on`, `climate.set_temperature`, `automation.trigger`, `scene.turn_on`, …) |
| `ha_get_history` | State-change history for an entity over the last N hours |
| `ha_render_template` | Render a Jinja2 template against live state |
| `ha_get_config` | HA version, location, unit system, components |
| `ha_get_error_log` | The error log, for troubleshooting |
| `ha_list_areas` | All areas/rooms |
| `ha_get_entities_by_area` | Entities in a room, resolving device→area inheritance |

> Listing automations is just `ha_get_states` filtered to `automation.*`; triggering one is
> `ha_call_service('automation','trigger')`. Scenes and scripts work the same way - no
> separate tools needed.

## Requirements

- Node.js ≥ 20
- A Home Assistant instance and a **long-lived access token**
  (HA → your profile → *Security* → *Long-lived access tokens* → *Create token*).

## Install

```bash
git clone https://github.com/qubit999/ha-mcp.git
cd ha-mcp
npm install
npm run build
```

This produces `dist/index.js` - the executable the clients launch.

## Configuration

The server reads two environment variables:

| Variable | Default | Description |
|----------|---------|-------------|
| `HASS_URL` | `http://localhost:8123` | Base URL of your Home Assistant instance |
| `HASS_TOKEN` | _(required)_ | A long-lived access token |

The same token authenticates both the REST calls and the WebSocket (used for the area
registry). For local development you can drop these in a `.env` file and run `npm run dev`.

## Connect a client

All three clients launch the server locally over stdio. Use the **absolute path** to
`dist/index.js`.

### Claude Desktop - one-click (recommended)

Download the latest `ha-mcp.mcpb` from the
[Releases page](https://github.com/qubit999/ha-mcp/releases) (no build step needed), or
build it yourself with `npm run bundle`.

Then in Claude Desktop: **Settings → Extensions → Install Extension…** (or just drag
`ha-mcp.mcpb` into the window). Claude shows a form for **Home Assistant URL** and
**token** (the token is masked and stored in your OS keychain), then launches the server
for you. Restarting the app or re-pasting config is not needed.

### Claude Desktop - manual (alternative)

If you'd rather not bundle, edit the config directly - `Settings → Developer → Edit Config`
opens the file (path: `~/Library/Application Support/Claude/claude_desktop_config.json` -
note the space in "Application Support", so quote it in a shell). Add the block below and
fully quit + relaunch the app:

```json
{
  "mcpServers": {
    "ha-mcp": {
      "command": "node",
      "args": ["/Users/alex/ha-mcp/dist/index.js"],
      "env": {
        "HASS_URL": "http://localhost:8123",
        "HASS_TOKEN": "your-long-lived-token"
      }
    }
  }
}
```

### Claude Code

```bash
claude mcp add ha-mcp \
  --scope user \
  --env HASS_URL=http://localhost:8123 \
  --env HASS_TOKEN=your-long-lived-token \
  -- node /Users/alex/ha-mcp/dist/index.js
```

Verify with `claude mcp list` / `claude mcp get ha-mcp`.

### Codex CLI

Add to `~/.codex/config.toml`:

```toml
[mcp_servers.ha-mcp]
command = "node"
args = ["/Users/alex/ha-mcp/dist/index.js"]
env = { HASS_URL = "http://localhost:8123", HASS_TOKEN = "your-long-lived-token" }
```

Then ask: *"Turn on the kitchen light"* or *"What's the temperature in the living room?"*

## Security

A long-lived token grants **full control of your Home Assistant** (and thus your home). This
server is designed to run **locally over stdio** - the client launches it as a subprocess; no
network port is opened and the token never leaves your machine. Keep the token out of version
control (the included `.gitignore` excludes `.env`). If you scope it into a shared
`.mcp.json`, use a non-admin HA user or environment variables instead. There is intentionally
**no** remote/HTTP transport here.

## Development

```bash
npm run dev      # run from source with tsx (+ .env)
npm run build    # type-check and emit dist/
```

Tools are thin wrappers over `src/ha.ts` (REST helpers + a short-lived WebSocket client for
the registries). The WebSocket connection is opened per registry fetch and cached briefly -
there's no long-lived socket to manage.

## License

MIT © qubit999

TDQS

A4/5.0

Scored across 9 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: service calls, configuration retrieval, entity queries by area or ID, error logs, history, state listing, area listing, and template rendering. No overlap in functionality.

Naming Consistency5/5

All tools follow a consistent 'ha_{verb}_{noun}' pattern with underscores, using verbs like 'call', 'get', 'list', and 'render'. The prefix 'ha_' identifies the server, and naming is predictable.

Tool Count5/5

With 9 tools covering essential Home Assistant operations (service calls, state queries, configuration, history, error logs, areas, and template rendering), the count is well-scoped for an MCP server without being excessive.

Completeness5/5

The tool set covers core Home Assistant interactions: calling any service, retrieving states, config, history, error logs, and area information. The inclusion of template rendering adds flexibility. No obvious gaps for common tasks.

Maintenance

ActivityStale
ResponsivenessNo issues