MCP Server for Home Assistant (HTTP Transport)
A Home Assistant Custom Component that provides an MCP (Model Context Protocol) server using HTTP transport, allowing AI assistants like Claude to interact with your Home Assistant instance.
Why HTTP transport with OAuth? This project was built primarily to support MCP Streamable HTTP transport, enabling web-based clients like Claude that require OIDC and OAuth 2.0 Dynamic Client Registration (RFC 7591). Since Home Assistant already has an official MCP integration that supports SSE transport, there wasn't a need to duplicate that. For local or custom client setups, Long-Lived Access Token authentication can be enabled as an alternative.
Features
- ๐ HTTP transport (not SSE) - works remotely, not just locally
- ๐ OAuth 2.0 authentication with Dynamic Client Registration (via hass-oidc-server)
- ๐ Long-Lived Access Token authentication (opt-in) for local and custom client setups
- ๐ Full Home Assistant API access (entities, services, areas, devices, history, statistics)
- ๐ง Easy HACS installation
- ๐ CRUD management of automations, scenes, scripts, and helper entities (input_boolean, counter, timer, schedule, and more)
- ๐ Lovelace dashboard management (list, get/save/delete config, create/update/delete dashboards)
- ๐ฉบ System administration tools (error log, config validation, restart, system status)
- ๐ YAML config file management โ read, write, delete files with automatic backup before every change and built-in config validation (opt-in)
- ๐ท Camera & image access โ capture live camera frames and read saved image files for visual analysis (opt-in)
- ๐ Resources, prompts, and completions for richer AI interactions
- ๐งน Optimization prompts for auditing automations, naming conventions, and scheduling
Prerequisites
The integration supports two authentication methods:
- OAuth 2.0 (default): Required for browser-based clients like Claude. Requires hass-oidc-server to be installed and configured.
- Long-Lived Access Tokens (opt-in): For local agents and custom MCP clients that can't run an OAuth browser flow. No extra dependencies. Must be enabled in the integration settings.
You can use both methods at the same time. When both are active, the server tries OAuth first and falls back to the Long-Lived Access Token.
Installation
HACS (Recommended)
- Open HACS in Home Assistant
- Search for "MCP Server"
- Click "Download"
- Restart Home Assistant
- Configure the integration (see Configuration section below)
Manual Installation
- Copy the
custom_components/mcp_server_http_transportfolder to your Home Assistantcustom_componentsdirectory - Restart Home Assistant
- Configure the integration (see Configuration section below)
Configuration
- Go to Settings > Devices & Services
- Click "Add Integration"
- Search for "MCP Server"
- Choose your authentication method:
- Leave "Enable native Home Assistant authentication" unchecked for OAuth-only (requires hass-oidc-server)
- Check it to allow Long-Lived Access Tokens (can be used alongside OAuth or on its own)
You can change this setting later via Settings > Devices & Services > MCP Server > Configure.
Usage with Claude in Browser (OAuth)
This requires the hass-oidc-server integration to be installed.
The MCP server uses OAuth 2.0 Dynamic Client Registration (DCR), which allows Claude to automatically register itself without manual client setup.
In Claude (claude.ai):
- Open Profile (bottom left corner)
- Click Settings (gear icon)
- Navigate to "Connectors"
- Click "Add custom connector"
- Enter your MCP server URL:
https://your-home-assistant.com/api/mcp - Click "Connect"
Claude will automatically:
- Discover your Home Assistant's OAuth endpoints
- Register itself as an OAuth client
- Redirect you to Home Assistant for authentication
- Request access to your Home Assistant data
In Home Assistant:
- Log in if not already authenticated
- Review the permissions requested by Claude
- Click "Authorize" to grant access
That's it! Claude will now be able to interact with your Home Assistant instance through the MCP server.
Usage with Long-Lived Access Tokens
For local agents or MCP clients that can't run an OAuth browser flow, you can authenticate with a Home Assistant Long-Lived Access Token. This must be enabled first.
- Enable native authentication: Settings > Devices & Services > MCP Server > Configure > check "Enable native Home Assistant authentication"
- Create a token: go to your Home Assistant user profile > Long-Lived Access Tokens > Create Token
- Configure your MCP client to send the token as a Bearer header to
http://your-home-assistant:8123/api/mcp
MCP Capabilities
Tools
Entities & State
| Tool | Description |
|---|---|
get_state |
Get the current state of any entity (optional fields to limit attributes) |
batch_get_state |
Get state for multiple entities in one call (max 50) |
list_entities |
List all entities, with optional domain, detailed, and fields parameters |
search_entities |
Search entities by friendly name, device class, domain, or area |
call_service |
Call any Home Assistant service |
fire_event |
Fire a custom event on the Home Assistant event bus |
get_history |
Get state history of an entity over a time range |
get_logbook |
Fetch logbook entries for an entity or time range |
get_statistics |
Fetch long-term statistics (energy, climate) with configurable period |
render_template |
Evaluate a Jinja2 template |
Automations, Scenes & Scripts
| Tool | Description |
|---|---|
list_automations |
List all automations with full configuration |
get_automation_config |
Get full configuration of a single automation |
create_automation |
Create a new automation |
update_automation |
Update an existing automation |
delete_automation |
Delete an automation |
list_scenes |
List all scenes with full configuration |
get_scene_config |
Get full configuration of a single scene |
create_scene |
Create a new scene |
update_scene |
Update an existing scene |
delete_scene |
Delete a scene |
list_scripts |
List all scripts with full configuration |
get_script_config |
Get full configuration of a single script |
create_script |
Create a new script |
update_script |
Update an existing script |
delete_script |
Delete a script |
Helpers
| Tool | Description |
|---|---|
list_helpers |
List all helper entities, optionally filtered by domain |
get_helper_config |
Get the raw stored configuration of a UI-managed helper (experimental) |
create_helper |
Create a new helper (input_boolean, input_number, input_text, input_select, input_datetime, input_button, counter, timer, schedule) (experimental) |
update_helper |
Update an existing UI-managed helper by entity ID (experimental) |
delete_helper |
Delete a UI-managed helper by entity ID (experimental) |
Config Files
| Tool | Description |
|---|---|
list_config_files |
List all YAML files in the config directory (first level, secrets excluded) |
get_config_file |
Read the contents of a YAML config file (max 1 MB) |
save_config_file |
Write or replace a YAML config file; auto-backs up all files first, then validates config |
delete_config_file |
Delete a YAML config file; auto-backs up all files first |
batch_edit_config_files |
Write and/or delete multiple YAML files in one call; one backup and one config check for the whole batch |
backup_config_files |
Manually snapshot all YAML files into mcp_backups/<timestamp>/ |
list_config_backups |
List all available backup snapshots, newest first |
restore_config_backup |
Restore files from the latest or a specific backup; creates a pre-restore snapshot of the current state and runs config validation after restoring |
cleanup_config_backups |
Delete backup snapshots older than N days (default 30); keeps the folder from growing indefinitely |
Dashboards
| Tool | Description |
|---|---|
list_dashboards |
List all Lovelace dashboards with metadata |
get_dashboard_config |
Get full dashboard configuration (views/cards) |
save_dashboard_config |
Save (replace) full dashboard configuration |
delete_dashboard_config |
Reset a dashboard configuration to empty |
create_dashboard |
Create a new Lovelace dashboard (experimental) |
update_dashboard |
Update dashboard metadata (experimental) |
delete_dashboard |
Delete a dashboard and its config (experimental) |
System & Infrastructure
| Tool | Description |
|---|---|
get_config |
Get Home Assistant configuration (version, location, units, timezone) |
get_system_status |
System overview: version, domain counts, entity totals, problem entities |
get_domain_stats |
Aggregate stats for a single domain (count, state breakdown, examples) |
check_config |
Validate Home Assistant configuration without restarting |
restart_ha |
Restart Home Assistant (requires explicit confirmation) |
get_error_log |
Fetch the Home Assistant error log (last N lines) |
list_areas |
List all areas |
list_devices |
List devices, optionally filtered by area |
list_services |
List available services, optionally filtered by domain |
list_integrations |
List installed integrations and their status |
list_labels |
List all labels for cross-domain grouping |
Camera & Images
These tools are disabled by default; enable them per capability via Settings โ Devices & Services โ MCP Server โ Configure. They return images directly to the model for visual analysis.
| Tool | Description |
|---|---|
get_camera_image |
Capture the current frame from a camera entity (optional width/height to downscale); no snapshot file is written (requires "Enable camera image access") |
get_image_file |
Read an image file (JPEG, PNG, GIF, WebP) from an allowed directory, e.g. a snapshot saved by camera.snapshot (requires "Enable image file access") |
Resources
| URI | Description |
|---|---|
hass://config |
Home Assistant configuration |
hass://areas |
All areas |
hass://devices |
All registered devices |
hass://services |
All available services by domain |
hass://floors |
All configured floors |
hass://entities |
All entities organized by domain |
hass://labels |
All labels |
hass://integrations |
Installed integrations with status |
hass://entity/{entity_id} |
State and attributes of a specific entity |
hass://dashboard/{url_path} |
Full configuration of a specific dashboard |
hass://entities/domain/{domain} |
Entities filtered by a specific domain |
Prompts
| Prompt | Description |
|---|---|
troubleshoot_device |
Diagnose issues with a specific entity |
daily_summary |
Summarize recent activity across all entities |
automation_review |
Review an automation's config for issues and improvements |
energy_report |
Summarize energy consumption data over a time range |
setup_guide |
Guided troubleshooting for an entity in a problem state |
automation_builder |
Step-by-step guided automation creation |
automation_debugger |
Debug why an automation is not firing or misbehaving |
automation_audit |
Audit all automations for conflicts, redundancies, and anti-patterns |
schedule_optimizer |
Analyze automation schedules and suggest timing improvements |
naming_conventions |
Scan entity names for inconsistencies and suggest standardization |
dashboard_builder |
Suggest a Lovelace dashboard layout for given entities or area |
change_validator |
Pre-flight check after creating or modifying configurations |
security_review |
Scan for security issues in entities, integrations, and configuration |
Completions
Autocompletion is supported for entity_id, entity_ids, domain, service, area_id, url_path, automation_id, scene_id, script key, trigger_type, period, config_type, and helper domain arguments.
FAQ
How do I list all automations, scenes, or scripts?Use the dedicated list tools to get full configurations:
list_automations() // all automations with triggers, conditions, actions
list_scenes() // all scenes with entity states
list_scripts() // all scripts with sequences
To get the configuration of a single item:
get_automation_config(automation_id="abc-123")
get_scene_config(scene_id="def-456")
get_script_config(key="morning_routine")
You can also use list_entities(domain="automation") to get entity states, but the tools above return the full YAML configuration.
Use create_automation with a standard HA automation config:
create_automation(config={
"alias": "Turn on lights at sunset",
"trigger": [{"platform": "sun", "event": "sunset"}],
"action": [{"service": "light.turn_on", "target": {"entity_id": "light.living_room"}}]
})
The same pattern applies to scenes and scripts. Scripts use a key parameter instead of an auto-generated ID:
create_script(key="morning_routine", config={
"alias": "Morning Routine",
"sequence": [{"service": "light.turn_on", "target": {"entity_id": "light.bedroom"}}]
})
How do I call a service like turning on a light?
Use call_service with the domain, service, and optionally an entity and extra data:
call_service(domain="light", service="turn_on", entity_id="light.living_room", data={"brightness": 200})
To discover what services are available:
list_services() // all services
list_services(domain="light") // just light services
How do I manage Lovelace dashboards?
Use list_dashboards to see all dashboards, then get_dashboard_config and save_dashboard_config to read and modify their content. Use url_path="default" for the main Overview dashboard:
get_dashboard_config(url_path="default")
save_dashboard_config(url_path="default", config={"views": [{"title": "Home", "cards": [...]}]})
To create or delete dashboards themselves, use the experimental create_dashboard and delete_dashboard tools. These use internal HA APIs and may break with future HA updates.
Use list_helpers to see all helpers, optionally filtered by type:
list_helpers() // all helper types
list_helpers(domain="input_boolean") // only toggles
To create a helper, specify the domain and a config with at least a name:
create_helper(domain="input_boolean", config={"name": "Vacation Mode", "icon": "mdi:palm-tree"})
create_helper(domain="input_number", config={"name": "Target Temperature", "min": 15, "max": 30, "step": 0.5, "unit_of_measurement": "ยฐC"})
create_helper(domain="input_select", config={"name": "House Mode", "options": ["Home", "Away", "Sleep"]})
create_helper(domain="counter", config={"name": "Motion Events", "initial": 0, "step": 1})
create_helper(domain="timer", config={"name": "Cooking Timer", "duration": "00:30:00"})
To update or delete, use the entity ID:
update_helper(entity_id="input_boolean.vacation_mode", config={"name": "Vacation Mode", "icon": "mdi:airplane"})
delete_helper(entity_id="counter.motion_events")
How do I read or edit YAML configuration files?Note: These tools only manage UI-created helpers stored in Home Assistant's
.storage/files. Helpers defined in YAML configuration are read-only from the perspective of these tools.
Use list_config_files to see all editable YAML files, then get_config_file and save_config_file to read and modify them:
list_config_files()
get_config_file(filename="automations.yaml")
save_config_file(filename="automations.yaml", content="...")
save_config_file automatically runs a full Home Assistant config validation after every save and reports any errors inline. Pass run_check: false to skip this.
To remove a custom file:
delete_config_file(filename="my_custom.yaml")
When editing multiple files in one session use batch_edit_config_files instead โ it creates one backup snapshot before all changes and runs one config check at the end:
batch_edit_config_files(
saves=[
{"filename": "templates.yaml", "content": "..."},
{"filename": "sensors.yaml", "content": "..."},
],
deletes=["binary_sensor.yaml", "old_lights.yaml"],
)
Both saves and deletes are optional โ you can use either or both in the same call.
How do I let the AI see a camera or analyze an image?Note: Only first-level
.yaml/.ymlfiles in the config directory are accessible. Subdirectories and non-YAML files are blocked. The following files are also blocked from direct edits โ use the dedicated tools instead:
secrets.yamlโ never readable, contains credentialsautomations.yaml,scenes.yaml,scripts.yamlโ owned by Home Assistant's storage layer; usecreate_automation/update_automation/delete_automation(and the equivalents for scenes and scripts) so UI-managed entries stay consistent. These files are still included in backups, so a restore never drops them.
Camera and image access are disabled by default. Enable them per capability via Settings โ Devices & Services โ MCP Server โ Configure: "Enable camera image access" for live camera frames, and "Enable image file access" for reading saved image files.
To analyze what a camera sees right now, capture the current frame directly โ no snapshot file is needed:
get_camera_image(entity_id="camera.front_door")
get_camera_image(entity_id="camera.front_door", width=1024)
To analyze a snapshot already saved to disk (for example by the camera.snapshot service), read it back by path:
get_image_file(path="www/snapshots/front_door.jpg")
get_image_file(path="/config/www/snapshots/front_door.jpg")
The image is returned directly to the model for analysis. get_image_file supports JPEG, PNG, GIF, and WebP, and can only read from directories Home Assistant is allowed to access (the config directory and configured media dirs) โ the same allowlist that governs where camera.snapshot can write.
Every call to save_config_file and delete_config_file automatically creates a full snapshot of all first-level YAML files (excluding secrets.yaml) before making any change. When using batch_edit_config_files, only one backup is created for the entire batch โ regardless of how many files are saved or deleted. Snapshots are stored in:
config/mcp_backups/2026-04-26_14-30-00-123456/
The backup path is included in the tool response so you always know where to look. You never need to remember to back up manually before an edit โ it happens every time.
To create an additional manual snapshot before a larger operation:
backup_config_files()
To see all available snapshots:
list_config_backups()
To restore the latest snapshot (or a specific one by timestamp):
restore_config_backup()
restore_config_backup(timestamp="2026-04-26_14-30-00-123456")
restore_config_backup only overwrites files present in the backup โ files created after the snapshot are left untouched. Before any files are overwritten it creates a pre-restore snapshot of the current state, so you can always roll back from a restore (the snapshot path is included in the response). A config check runs automatically after restoring.
If Home Assistant fails to start after a bad edit: backup files are always accessible at
config/mcp_backups/<timestamp>/and can be copied back manually via the filesystem or SSH.
Restoring a single file: restore_config_backup always restores all files from a snapshot at once โ there is no tool to restore a single file. If you only need one file back, either restore the full snapshot and re-apply your other changes, or copy the file manually from config/mcp_backups/<timestamp>/<filename> via SSH, Samba, or the File Editor add-on.
Cleaning up old backups: Snapshots accumulate with every edit. Use cleanup_config_backups to remove old ones:
cleanup_config_backups() // delete backups older than 30 days (default)
cleanup_config_backups(older_than_days=7) // delete backups older than 7 days
You can also delete entries from config/mcp_backups/ manually via SSH, the Samba share, or the File Editor add-on.
Some tools use internal Home Assistant APIs that are not publicly exposed and may break with future HA updates.
Dashboard tools: create_dashboard, update_dashboard, and delete_dashboard use DashboardsCollection and replicate side effects (panel registration, dashboards dict updates) that HA normally handles internally. The config-level tools (list_dashboards, get/save/delete_dashboard_config) use stable public APIs and are not experimental.
Helper tools: get_helper_config, create_helper, update_helper, and delete_helper use StorageCollection internals to manage UI-created helpers. They only affect helpers stored in .storage/ โ helpers defined in YAML are read-only from the perspective of these tools. list_helpers uses public APIs and is not experimental.
License
MIT