A Model Context Protocol (MCP) Server as a Home Assistant Local Add-on.
Full HA REST API coverage + SSH file access + GitHub integration.
Works with Claude.ai, ChatGPT and any MCP-compatible AI client.
MCP Specification November 2025 compliant: PKCE, Dynamic Client Registration, Protected Resource Metadata.
Claude.ai / ChatGPT
│ OAuth 2.1 + PKCE + DCR (automatic)
▼
ha-mcp.yourdomain.com/mcp ← this add-on (port 5555)
│
├── HA REST API ──────────► http://homeassistant:8123
│ Full coverage: entities, automations, scenes, scripts,
│ calendars, persons, zones, energy, logbook, templates,
│ events, input helpers, config check, backup, ...
│
├── SSH (optional) ───────► root@homeassistant.local
│ Read/write files, run ha CLI, Supervisor API,
│ system logs, network info, version bump, build & test
│
└── GitHub (optional) ────► github.com/<user>/<repo>
Commit, push, create repos — all from Claude
| Category | Tools | Requirement | |
|---|---|---|---|
| ✅ | HA Control | 14 | Always active |
| ✅ | HA System | 5 | Always active |
| ✅ | HA Advanced | 17 | Always active |
| ⚙️ | SSH Files & Add-ons | 8 | ssh_enabled |
| ⚙️ | Supervisor & OS | 7 | ssh_enabled |
| ⚙️ | Dev Workflow | 3 | ssh_enabled |
| ⚙️ | GitHub | 6 | ssh_enabled + github_enabled |
| Total | 36 – 60 |
✅ always active · ⚙️ optional toggle in add-on config
- Home Assistant OS or Supervised (aarch64 / amd64)
- HTTPS domain + reverse proxy (NGINX, Caddy, Cloudflare Tunnel)
- (SSH tools) Advanced SSH & Web Terminal add-on installed on HA
- (GitHub tools) GitHub Personal Access Token with
reposcope
# Unpack the tar and copy via SCP
tar xzf ha-mcp-v0.6.13.tar.gz
scp -r ha-mcp/ root@homeassistant.local:/addons/Or copy the folder directly if you have Samba / file access configured.
Settings → Add-ons → Add-on Store → ⋮ → Check for local add-ons
HA-MCP appears → Install
Open the Configuration tab. All options are documented inline in the HA UI.
Minimum required: ha_token and external_url.
HA → Profile → Security → Long-Lived Access Tokens → Create Token
Paste the token into the ha_token field.
After starting, the Log tab shows the startup banner:
╔══════════════════════════════════════════════════╗
║ HA-MCP v0.6.13 starting ║
╠══════════════════════════════════════════════════╣
║ MCP endpoint : https://ha-mcp.yourdomain.com/mcp
╠══════════════════════════════════════════════════╣
║ TOOL GROUPS ║
║ HA Control : 14 tools (always active)
║ HA System : 5 tools (always active)
║ HA Advanced : 17 tools (always active)
║ SSH + Dev : 18 tools (enabled ✓)
║ GitHub : 6 tools (enabled ✓)
║ ─────────────────────────────────────────────
║ Total : 60 tools
╚══════════════════════════════════════════════════╝
| Option | Default | Description |
|---|---|---|
ha_token |
(required) | HA Long-Lived Access Token — masked |
external_url |
(required) | Public HTTPS URL, e.g. https://ha-mcp.yourdomain.com |
port |
5555 |
Server port — also remappable via HA Network tab |
log_level |
info |
debug · info · warning · error |
| Option | Default | Description |
|---|---|---|
ssh_enabled |
false |
Master toggle — enables SSH + Dev + Supervisor tools |
ssh_host |
homeassistant.local |
HA hostname or IP |
ssh_port |
22 |
SSH port |
ssh_user |
root |
SSH username |
ssh_password |
(empty) | SSH password — masked |
ssh_addons_path |
/addons |
Local add-ons path on HA |
⚠️ SSH tools give Claude root access to your HA system. Only enable on personal, trusted setups.
| Option | Default | Description |
|---|---|---|
github_enabled |
false |
Master toggle |
github_user |
(empty) | GitHub username |
github_token |
(empty) | PAT with repo scope — masked |
github_repo |
ha-mcp |
Target repository name |
github_email |
(empty) | Commit email (defaults to GitHub no-reply) |
Create PAT: GitHub → Settings → Developer settings → Personal access tokens → scope: repo
- Settings → Connectors → Add custom connector
- Name:
Home Assistant - URL:
https://ha-mcp.yourdomain.com/mcp - Advanced Settings → OAuth Client ID:
https://claude.ai· Secret: (leave empty) - Add → consent page appears in browser → authorize
- Enable Developer Mode in ChatGPT settings
- Add MCP server:
https://ha-mcp.yourdomain.com/mcp - OAuth + DCR flow runs automatically
| Tool | Description |
|---|---|
tool_get_all_entities |
All entities, optional domain filter (e.g. light, switch) |
tool_get_entity |
State + attributes of a single entity |
tool_turn_on |
Turn on — supports brightness, brightness_pct, color_temp, rgb_color, transition, service_data |
tool_turn_off |
Turn off — supports optional transition |
tool_toggle |
Toggle between on and off |
tool_call_service |
Call any HA service with custom data dict |
tool_get_history |
Entity state history (default: 24h, adjustable) |
tool_get_automations |
List all automations with state + alias |
tool_trigger_automation |
Manually trigger an automation |
tool_enable_automation |
Enable an automation |
tool_disable_automation |
Disable an automation |
tool_send_notification |
Send persistent HA notification (title + message) |
tool_get_scenes |
List all scenes |
tool_activate_scene |
Activate a scene by entity_id |
| Tool | Description |
|---|---|
tool_ha_config_check |
Validate HA config via REST API, SSH fallback |
tool_ha_restart |
Restart HA Core (~30–60s downtime) |
tool_ha_backup_create |
Trigger full backup via Supervisor |
tool_ha_get_energy |
All energy monitoring entities (kWh / W / Wh) |
tool_ha_get_logbook |
Logbook entries — optional entity_id + hours filter |
| Tool | Description |
|---|---|
tool_ha_status |
HA version, location name, timezone, component count |
tool_ha_error_log |
Current session error log via Supervisor |
tool_get_services |
All service domains + optional keyword filter |
tool_render_template |
Render any Jinja2 template |
tool_fire_event |
Fire a custom HA event with optional data |
tool_get_calendars |
List all calendar entities |
tool_get_calendar_events |
Events in a time range (default: next 7 days) |
tool_get_areas |
Areas / rooms |
tool_get_persons |
Person entities + current location state |
tool_get_zones |
Zone entities (home, work, school, ...) |
tool_get_scripts |
List all scripts |
tool_run_script |
Run a script with optional variables |
tool_set_input_boolean |
Set input_boolean on/off |
tool_set_input_number |
Set input_number to a value |
tool_set_input_select |
Select an option on input_select |
tool_set_input_text |
Set input_text value |
tool_set_input_datetime |
Set input_datetime (date, time or datetime) |
| Tool | Description |
|---|---|
tool_file_read |
Read any file on the HA system (base64 via exec) |
tool_file_write |
Write/create a file — auto-creates directories |
tool_file_delete |
Delete a file |
tool_file_list |
List directory contents |
tool_addon_restart |
Restart a local add-on via ha CLI |
tool_addon_logs |
Get last N log lines of a named add-on |
tool_addon_list |
List all local add-ons |
tool_exec_command |
Run any shell command as root (use with care) |
| Tool | Description |
|---|---|
tool_supervisor_info |
Supervisor version, channel, architecture |
tool_ha_core_logs |
HA Core log output (last N lines) |
tool_supervisor_logs |
Supervisor log output (last N lines) |
tool_list_backups |
List all backups with date + size |
tool_network_info |
Network config — IPs, interfaces, DNS |
tool_os_info |
HA OS version + board type |
tool_ha_update_check |
Check available updates for core / OS / add-ons |
| Tool | Parameters | Description |
|---|---|---|
tool_version_bump |
path, bump (patch/minor/major), changelog_entry |
Bump version in config.yaml + main.py + CHANGELOG.md |
tool_addon_build_test |
addon_slug, log_lines |
Stop → rebuild → start → tail logs |
tool_file_search |
pattern, path, file_ext, case_sensitive |
Recursive file search (grep -r) |
| Tool | Description |
|---|---|
tool_git_create_repo |
Create a new GitHub repository via API |
tool_git_init_repo |
Init git repo + push initial commit (run once per project) |
tool_git_status |
Working tree status + branch + remote info |
tool_git_diff |
Unstaged, staged changes + untracked files |
tool_git_log |
Recent commit history |
tool_git_commit_push |
Stage all → commit with message → push to GitHub |
| Configuration | Always | SSH | GitHub | Total |
|---|---|---|---|---|
| Default (no SSH) | 36 | — | — | 36 |
| SSH enabled | 36 | +18 | — | 54 |
| SSH + GitHub | 36 | +18 | +6 | 60 |
tool_file_read → inspect current file
tool_file_write → apply fix or new feature
tool_addon_build_test → rebuild + verify startup logs
tool_ha_config_check → validate HA configuration
tool_version_bump → bump version + update CHANGELOG
tool_git_commit_push → commit and push to GitHub
tool_ha_status → check HA version + location + component count
tool_ha_error_log → review integration errors (Supervisor logs)
tool_ha_core_logs → full Core log tail
tool_supervisor_logs → Supervisor-level issues
tool_ha_config_check → validate config before restart
tool_get_all_entities(domain='light') → find all lights
tool_get_persons → who's home
tool_get_zones → zone boundaries
tool_render_template('{{states("sun.sun")}}') → sunrise/set info
tool_get_calendar_events('calendar.family') → today's events
tool_set_input_select('input_select.mode','Evening') → set mode
| Endpoint | Method | RFC | Description |
|---|---|---|---|
/.well-known/oauth-authorization-server |
GET | 8414 | OAuth server metadata |
/.well-known/oauth-protected-resource |
GET | 9728 | Resource metadata (required by MCP spec) |
/register |
POST | 7591 | Dynamic Client Registration |
/oauth/authorize |
GET | — | Consent page |
/oauth/authorize |
POST | — | Process consent + issue auth code |
/oauth/token |
POST | — | Exchange code for access token (PKCE verified) |
/mcp |
GET/POST | — | MCP Streamable HTTP endpoint (Bearer required) |
| Topic | Detail |
|---|---|
tool_ha_error_log |
Uses Supervisor /core/logs. /api/error_log was removed in HA 2026.x |
tool_ha_config_check |
ha core check may report pre-existing automation validation warnings in HA 2026 — this does not affect runtime |
tool_ha_config_check |
REST endpoint /api/config/core/check is the primary method; SSH ha core check is fallback |
| SSH file I/O | Uses cat | base64 and echo <b64> | base64 -d via exec — no SFTP (SFTP channel closes on HA OS) |
| Docker cache | After file changes, use rebuild in HA (not just restart) to pick up updated Python files |
| ASGI middleware | Uses pure ASGI middlewares (add_middleware()), not BaseHTTPMiddleware — required for FastMCP streaming compatibility |
| Event | Level | Example |
|---|---|---|
| Startup | info | Full banner with tool counts |
| DCR | info | DCR: Client registered — name=Claude.ai |
| OAuth | info | Auth Code issued · Token issued |
| MCP request | info | MCP Request — client=https://claude.ai |
| Unauthorized | warning | 401 Unauthorized — 1.2.3.4 → GET /mcp |
| HA restart | warning | ha_restart: initiating HA Core restart |
| File write | info | file_write: /addons/ha-mcp/src/main.py |
| Root command | warning | exec_command (Root): ha addons restart ... |
| Version bump | info | version_bump: 0.6.10 → 0.6.11 (patch) |
| Git push | info | git: pushed to github.com/user/ha-mcp/main |
Set log_level: debug for full request + OAuth step logging.
pip install -r src/requirements.txt
export HA_TOKEN="your_token"
export HA_BASE_URL="http://192.168.1.x:8123"
export EXTERNAL_URL="http://localhost:5555"
export PORT=5555
export LOG_LEVEL="debug"
# Optional SSH
export SSH_ENABLED=true
export SSH_HOST="192.168.1.x"
export SSH_USER="root"
export SSH_PASSWORD="password"
export SSH_ADDONS_PATH="/addons"
# Optional GitHub
export GITHUB_ENABLED=true
export GITHUB_USER="your_username"
export GITHUB_TOKEN="ghp_..."
export GITHUB_REPO="ha-mcp"
python src/main.py# Test OAuth + MCP with the Inspector
npx @modelcontextprotocol/inspector http://localhost:5555/mcpserver {
listen 443 ssl;
server_name ha-mcp.yourdomain.com;
location / {
proxy_pass http://localhost:5555;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}ha-mcp/
├── config.yaml ← HA add-on manifest + UI config schema
├── Dockerfile ← ghcr.io/home-assistant/aarch64-base + python3
├── run.sh ← reads config, exports env vars, startup banner
├── TESTING.md ← beta test plan + delta test matrix
├── README.md ← this file
├── CHANGELOG.md ← full version history
└── src/
├── main.py ← FastMCP server, tool registration, pure ASGI middlewares
├── oauth.py ← OAuth 2.1 + PKCE + DCR (RFC 7591/8414/9728)
├── ha_client.py ← HA REST API client (20+ async methods)
├── ssh_client.py ← SSH via paramiko, all file I/O via exec+base64
├── requirements.txt ← fastmcp>=2.12.4, pydantic<2.13, paramiko, ...
└── tools/
├── entities.py ← entity control (7 tools)
├── automations.py ← automations, scenes, notifications (7 tools)
├── ha_system.py ← config check, restart, backup, energy, logbook (5 tools)
├── ha_advanced.py ← services, templates, calendar, persons, zones,
│ scripts, input helpers (17 tools)
├── system.py ← SSH file tools + add-on management (8 tools)
├── supervisor.py ← Supervisor, OS, logs, backups, network, updates (7 tools)
├── dev.py ← version bump, build & test, file search (3 tools)
└── github.py ← git status/diff/log/commit/push/create (6 tools)
- FastMCP
>=2.12.4with Starlette Streamable HTTP transport lifespan=mcp_app.lifespanpassed to Starlette — required for session manager init- Pure ASGI middlewares via
app.add_middleware()(AuthMiddleware,RequestLogMiddleware) — notBaseHTTPMiddleware, which buffers responses and breaks streaming - SSH file I/O via exec+base64 — no SFTP (SFTP channel closes on HA OS)
- Token storage persists in
/data/tokens.json+/data/clients.json
See TESTING.md for the complete beta test plan and delta test matrix.
See CHANGELOG.md
Built on lessons learned from Paperless-MCP and Printix-MCP.
OAuth extended with PKCE, DCR and MCP Spec November 2025 compliance.
MIT — see LICENSE