home-assistant-mcp
An MCP (Model Context Protocol) proxy for Home Assistant. Connects to your
Home Assistant instance's MCP server and re-exposes tools locally with
permission management — so LLMs can interact with your smart home without
having direct access to your HA token.
Features
- Dynamic tool discovery — automatically discovers all tools from your HA instance
- Permission gating — read-only tools always available; write/destructive tools gated by flags
- Multi-instance support — manage multiple HA instances with encrypted credential storage
- Tool filtering — glob-based allow/deny lists for fine-grained control
- Token isolation — HA access tokens stay local, encrypted at rest, never exposed to the LLM
- stdio transport — works directly in
~/.copilot/mcp-config.json, Claude Desktop, Cursor, etc.
- Rate limiting — configurable per-minute limits for read and write operations
Installation
go install github.com/tamcore/home-assistant-mcp-proxy/cmd/home-assistant-mcp@latest
Or build from source:
go build -o home-assistant-mcp ./cmd/home-assistant-mcp/
Quick Start
Option 1: Instance Management (Recommended)
Add and manage HA instances with encrypted credential storage:
# Add your first instance (automatically becomes default)
home-assistant-mcp instance add home \
--url https://ha.home.example.com \
--token "your-long-lived-access-token"
# Add a second instance
home-assistant-mcp instance add office \
--url https://ha.office.example.com \
--token "another-token"
# Verify connectivity
home-assistant-mcp instance validate home
# List all instances
home-assistant-mcp instance list
Then configure your MCP client to just run serve:
{
"mcpServers": {
"home-assistant": {
"command": "home-assistant-mcp",
"args": ["serve", "--allow-write"]
}
}
}
Option 2: Flags / Environment Variables
Pass credentials directly (single instance only):
{
"mcpServers": {
"home-assistant": {
"command": "home-assistant-mcp",
"args": ["serve", "--allow-write"],
"env": {
"HA_URL": "https://your-home-assistant.example.com",
"HA_TOKEN": "your-long-lived-access-token"
}
}
}
}
Read-only mode (default)
Only tools classified as read-only will be available:
home-assistant-mcp serve
Instance Management
Credentials are stored in ~/.config/home-assistant-mcp/config.json with
tokens encrypted using AES-256-GCM. The encryption key is stored in the
system keyring (macOS Keychain / Linux secret-tool) with a file-based
fallback.
| Command |
Description |
instance list |
List all configured instances |
instance add <name> --url <url> --token <token> [--default] |
Add a new instance |
instance remove <name> |
Remove an instance |
instance set-default <name> |
Set the default instance |
instance validate <name> |
Test connection and list available tools |
The first instance added automatically becomes the default.
Multi-Instance Behavior
When serving multiple instances:
- Default instance tools are registered without a prefix (e.g.
HassTurnOn)
- Other instances tools are prefixed with
<name>__ (e.g. office__HassTurnOn)
- A built-in
list_instances tool lets the LLM discover available instances
--ha-url/--ha-token flags take precedence (single-instance mode)
Configuration
| Flag |
Env Var |
Default |
Description |
--ha-url |
HA_URL |
(optional) |
Home Assistant URL (single-instance mode) |
--ha-token |
HA_TOKEN |
(optional) |
Long-lived access token (single-instance mode) |
--transport |
|
stdio |
Transport: stdio, sse, streamable-http |
--allow-write |
|
false |
Enable write tools |
--allow-destructive |
|
false |
Enable destructive tools (implies --allow-write) |
--allowed-tools |
|
* |
Glob patterns for allowed tool names |
--denied-tools |
|
(none) |
Glob patterns for denied tool names |
--rate-limit-read |
|
120 |
Max read calls/minute (0 = unlimited) |
--rate-limit-write |
|
30 |
Max write calls/minute (0 = unlimited) |
Permission Model
Tools discovered from Home Assistant are classified by their MCP annotations:
| Tool Annotation |
Classification |
Required Flag |
readOnlyHint = true |
Read-only |
(always available) |
readOnlyHint ≠ true |
Write |
--allow-write |
destructiveHint = true |
Destructive |
--allow-destructive |
If Home Assistant doesn't set annotations on a tool (which is currently the case),
the proxy classifies them automatically:
- Tools starting with
Get (e.g. GetDateTime, GetLiveContext) → read-only
- All other tools (
HassTurnOn, HassLightSet, etc.) → write
Home Assistant Setup
- Install the MCP Server integration in Home Assistant
- Create a Long-lived access token in your HA profile
- Configure the proxy with
instance add or via flags/env vars
Development
# Run tests
go test -race ./...
# Build
go build ./cmd/home-assistant-mcp/
# Lint
golangci-lint run
License
See LICENSE for details.