1. Conduid
  2. Developer Tools
  3. Hass MCP Server
MCP server · Developer Tools

Hass MCP Server

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 over HTTP

56Fair

Scored 5 hours ago · breakdown

About Hass MCP Server

Hass MCP Server is an MCP server published by ganhammar in the Developer Tools category: 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 over HTTP.

The repository has 78 stars and 20 forks, with the last commit 5 days ago. Recent commit activity is the strongest signal that reported issues will get attention.

Install

From source
git clone https://github.com/ganhammar/hass-mcp-server

This server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.

Tools (19)

adjust_statisticsCorrect a statistic's sum from a point in time onward (spike/bad reset); sum statistics only

Parameters not published.

batch_get_stateGet state for multiple entities in one call (max 50)

Parameters not published.

call_serviceCall any Home Assistant service

Parameters not published.

clear_statisticsPermanently delete a statistic's history so it can start clean (irreversible; requires `confirm=true`)

Parameters not published.

create_calendar_eventCreate a one-off calendar event (local calendars; entity API)

Parameters not published.

create_recurring_calendar_eventCreate a recurring calendar series with RRULE (local calendars)

Parameters not published.

delete_calendar_eventsDelete events by uid or summary filter (supports dry_run preview)

Parameters not published.

fire_eventFire a custom event on the Home Assistant event bus

Parameters not published.

get_device_detailsGet a device and every entity registered to it (all domains), with optional states

Parameters not published.

get_historyGet state history of an entity over a time range

Parameters not published.

Show all 19 tools
get_logbookFetch logbook entries for an entity or time range

Parameters not published.

get_stateGet the current state of any entity (optional `fields` to limit attributes)

Parameters not published.

get_statisticsFetch long-term statistics (energy, climate) with configurable period

Parameters not published.

list_calendar_eventsList events in a time window (uid for deletes; descriptions omitted by default)

Parameters not published.

list_entitiesList all entities, with optional `domain`, `detailed`, and `fields` parameters

Parameters not published.

list_statistic_idsList statistic IDs and their metadata (source, unit, whether they carry a mean/sum)

Parameters not published.

render_templateEvaluate a Jinja2 template

Parameters not published.

search_entitiesSearch entities by friendly name, device class, domain, or area

Parameters not published.

validate_statisticsReport statistics issues the recorder detected — the Developer Tools "Fix issues" list

Parameters not published.

Ask AI

✦

Ask AI about Hass MCP Server

Powered by Claude · Grounded in docs

I know everything about Hass MCP Server. Ask me about installation, configuration, usage, or troubleshooting.

Security checks

Static checks derived from the repository 5 hours ago. Heuristics on the source, not an audit.

  • ✓README presentThe repository ships documentation.
  • ✓License declaredUsable under a stated license.
  • ✓Tests presentA test suite exists in the repository.
  • ✓Dependencies pinnedA lockfile pins dependency versions.
  • ✓No dynamic code executionSource scan found no eval, dynamic Function, or shell execution.
  • !Scoped permissionsDoesn't declare a permission scope. Assume it can do anything its process can.

Releases

v1.18.0v1.18.0 · 5 Oct 2026What's Changed feat: make the name reported in serverInfo configurable by @OdynBrouwer in https://github.com/ganhammar/hass-mcp-server/pull/98 chore: bump version to 1.18.0 by @ganhammar in…
v1.17.1v1.17.1 · 21 Sep 2026What's Changed refactor: drop the unused mcp SDK dependency by @ganhammar in https://github.com/ganhammar/hass-mcp-server/pull/97 fix: prompt input errors, daily_summary history, and AppDaemon root guidance by @ganhammar in…
v1.17.0v1.17.0 · 5 Sep 2026What's Changed perf: emit compact JSON in tool, resource, and prompt output by @ganhammar in https://github.com/ganhammar/hass-mcp-server/pull/92 Full Changelog**: https://github.com/ganhammar/hass-mcp-server/compare/v1.16.0...v1.17.0
v1.16.0v1.16.0 · 4 Sep 2026What's Changed fix: return service response data from call_service by @michiel-dewilde in https://github.com/ganhammar/hass-mcp-server/pull/75 refactor: fetch statistics through recorder.get_statistics by @ganhammar in…
v1.15.0v1.15.0 · 10 Aug 2026What's Changed feat: add automation & script trace tools (list_traces, get_trace) by @suprawsmninja in https://github.com/ganhammar/hass-mcp-server/pull/72 feat: statistics repair tools (list/validate/adjust/clear) by @suprawsmninja in…

README

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)
  • 🔍 Automation & script traces — inspect why a run fired, didn't fire, or took the wrong branch, step by step (read-only)
  • 📋 Lovelace dashboard management (list, get/save/delete config, create/update/delete dashboards) with outline reads and JSON Patch edits so a single card can be changed without resending the whole dashboard
  • 🩺 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)

  1. Open HACS in Home Assistant
  2. Search for "MCP Server"
  3. Click "Download"
  4. Restart Home Assistant
  5. Configure the integration (see Configuration section below)

Manual Installation

  1. Copy the custom_components/mcp_server_http_transport folder to your Home Assistant custom_components directory
  2. Restart Home Assistant
  3. Configure the integration (see Configuration section below)

Configuration

  1. Go to Settings > Devices & Services
  2. Click "Add Integration"
  3. Search for "MCP Server"
  4. 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.

Server name

By default, every instance of this integration reports the name home-assistant-mcp-server to MCP clients (serverInfo.name). That only matters when one client connects to more than one Home Assistant instance: some clients derive the namespace they show for a server's tools from that name, so two servers reporting the same name become one and only one instance stays reachable. VS Code, for example, keeps the first 13 characters of the name before using it.

Set MCP server name (Settings > Devices & Services > MCP Server > Configure) to something distinct per instance when a client connects to several. Keep the names distinct within their first 13 characters if your client shortens them. The default is the name every client saw before this option existed, so a single-instance setup can leave it alone.

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.

  1. 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, or https://your-home-assistant.com/api/mcp_http if Home Assistant's built-in MCP Server integration is also installed (see Another integration also serves /api/mcp)
    • Click "Connect"
  2. 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
  3. 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.

  1. Enable native authentication: Settings > Devices & Services > MCP Server > Configure > check "Enable native Home Assistant authentication"
  2. Create a token: go to your Home Assistant user profile > Long-Lived Access Tokens > Create Token
  3. Configure your MCP client to send the token as a Bearer header to http://your-home-assistant:8123/api/mcp (or /api/mcp_http, see Another integration also serves /api/mcp)

Troubleshooting

Another integration also serves /api/mcp

Home Assistant's built-in Model Context Protocol Server integration (mcp_server) serves its streamable HTTP transport on /api/mcp, the same path this integration uses. It has done so since Home Assistant 2025.11.

Home Assistant cannot share a path between two integrations: whichever registered it first at startup answers every request there, and the other is silently unreachable on that path. Nothing is logged, both integrations keep showing as healthy, and an MCP client connects successfully to whichever server won, so the only visible symptom is the client getting the wrong set of tools.

This integration therefore also answers on /api/mcp_http, which nothing else claims. If /api/mcp is already taken when this integration starts, it stays off that path entirely and serves only /api/mcp_http. Either way it raises a repair naming the conflict. Point your MCP client at https://your-home-assistant/api/mcp_http.

The repair is the reliable signal, and it is raised on every version. Failing that, look for Model Context Protocol Server under Settings > Devices & Services. A 405 from the probe below confirms it as well, but only from 2026.8 onwards, which is when the built-in server added its per-API paths; on 2025.11 to 2026.7 the probe returns 404 while the conflict is real, so a 404 proves nothing on its own. The 401 challenge on /api/mcp is no help either, because both servers use the same realm.

curl -o /dev/null -w '%{http_code}\n' https://your-home-assistant/api/mcp/assist

Deleting the built-in integration's config entry does not release the path on its own: Home Assistant binds HTTP routes at startup and cannot unbind them, so restart afterwards.

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
get_device_details Get a device and every entity registered to it (all domains), with optional states
call_service Call any Home Assistant service
create_calendar_event Create a one-off calendar event (local calendars; entity API)
create_recurring_calendar_event Create a recurring calendar series with RRULE (local calendars)
list_calendar_events List events in a time window (uid for deletes; descriptions omitted by default)
delete_calendar_events Delete events by uid or summary filter (supports dry_run preview)
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
list_statistic_ids List statistic IDs and their metadata (source, unit, whether they carry a mean/sum)
validate_statistics Report statistics issues the recorder detected — the Developer Tools "Fix issues" list
adjust_statistics Correct a statistic's sum from a point in time onward (spike/bad reset); sum statistics only
clear_statistics Permanently delete a statistic's history so it can start clean (irreversible; requires confirm=true)
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, optionally in a category
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, optionally in a category
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, optionally in a category
update_script Update an existing script
delete_script Delete a script
list_traces List recent execution traces for an automation/script (or a whole domain), newest first
get_trace Get the full step-by-step execution trace of one run — which trigger fired, which conditions passed/failed, and the variables at each step (summary=true for an outline of large traces)

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), optionally in a category (experimental)
update_helper Update an existing UI-managed helper by entity ID (experimental)
delete_helper Delete a UI-managed helper by entity ID (experimental)

Categories

Tool Description
list_categories List the categories for automations, scripts, scenes or helpers, with the entities in each
set_category Put an automation, script, scene or helper in a category (created by name if new), or take it out of one

Config Files

Tool Description
list_config_files List YAML files in the config directory (first level by default, recursive=true for split configs; 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

AppDaemon Files (opt-in)

Tool Description
list_appdaemon_files List regular files under the configured AppDaemon apps root with SHA-256 hashes
get_appdaemon_file Read one relative AppDaemon app file with its SHA-256 hash
save_appdaemon_file Atomically save one AppDaemon app file after creating a rollback snapshot
delete_appdaemon_file Delete one AppDaemon app file after creating a rollback snapshot
backup_appdaemon_files Create a controlled snapshot of the AppDaemon apps tree
list_appdaemon_backups List available AppDaemon snapshots
cleanup_appdaemon_backups Delete AppDaemon snapshots older than N days (default 30)
restore_appdaemon_backup Restore a named AppDaemon snapshot with rollback protection

AppDaemon file reads and save payloads are limited to 1 MB. Rollback snapshots use a separate streaming-copy path with bounded memory and no per-file payload limit, so an existing large history/data file does not make an unrelated save or delete unusable. A snapshot is published only after every regular file has been copied and source identity/metadata checked for changes during copying.

Dashboards

Tool Description
list_dashboards List all Lovelace dashboards with metadata
get_dashboard_config Get a dashboard configuration; summary=true returns an outline of views and cards, path returns just the part a JSON Pointer addresses
patch_dashboard_config Apply JSON Patch operations to a dashboard: move, add, remove, or edit individual cards without resending the whole config
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
describe_service Get a service's full parameter schema: fields, selectors, examples, and targets
list_integrations List installed integrations and their status
list_labels List all labels for cross-domain grouping

KNX

Tool Description
knx_recent_telegrams Read Home Assistant's KNX group-monitor telegram history — recent bus telegrams incl. source device and decoded value; regex-filter by group address / name, with a result limit. Retrospective (reads the stored buffer), ideal for finding which KNX device wrote a given group address
knx_get_base_data KNX connection + project info: bus connection status, gateway address, xknx version, loaded ETS project metadata, and UI-creatable platforms
knx_get_entities List KNX group addresses and the entities bound to each (the KNX-specific group-address↔entity binding view); optional regex filter on the group address
knx_create_entity Create a KNX entity in the KNX UI config (config_store) from platform + data (experimental)
knx_update_entity Update a UI-managed KNX entity by entity_id (experimental)
knx_delete_entity Delete a UI-managed KNX entity by entity_id (experimental)

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

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"}}]
})

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

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": [...]}]})

A real dashboard can easily be over 100 KB, which is too much to read and write back for a one-card change. For anything smaller than a rewrite, work through the outline instead.

get_dashboard_config(url_path="default", summary=true) returns each view and card as type, label, and entities, with a JSON Pointer for every entry:

{
  "view_count": 2,
  "views": [
    {"pointer": "/views/0", "index": 0, "title": "Living Room", "path": "living", "card_count": 2,
     "cards": [
       {"pointer": "/views/0/cards/0", "index": 0, "type": "tile", "entity": "light.sofa"},
       {"pointer": "/views/0/cards/1", "index": 1, "type": "tile", "entity": "fan.air_purifier"}
     ]}
  ]
}

Pass one of those pointers as path to read a single card in full, and to patch_dashboard_config to change it. Operations follow RFC 6902 (add, remove, replace, move, copy, test) and apply in order, all-or-nothing, so a failing operation leaves the dashboard untouched:

get_dashboard_config(url_path="default", path="/views/0/cards/1")

patch_dashboard_config(url_path="default", operations=[
  {"op": "test", "path": "/views/0/cards/1/entity", "value": "fan.air_purifier"},
  {"op": "move", "from": "/views/0/cards/1", "path": "/views/1/cards/-"}
])

A leading test operation makes the patch fail rather than edit the wrong card if the dashboard changed since it was read. End an array path with /- to append.

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")

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.

Split configurations. If your configuration.yaml splits config across folders — !include_dir_merge_list, !include_dir_named, packages, and friends — pass recursive=true to find those files, then read or edit them by their relative path:

list_config_files(recursive=True)
# → ["configuration.yaml", "includes/templates/dishwasher.yaml", "packages/hvac.yaml", ...]

get_config_file(filename="includes/templates/dishwasher.yaml")
save_config_file(filename="includes/templates/dishwasher.yaml", content="...")

Recursive listing skips hidden folders (.storage, …), custom_components, deps, www, node_modules, tts, and mcp_backups. save_config_file will not create missing directories — create the folder in Home Assistant first.

Note: Only .yaml/.yml files inside the config directory are accessible. Paths are resolved before use and must stay within the config directory — .., absolute paths, and symlinks pointing outside are rejected. The following are also blocked from direct edits — use the dedicated tools instead:

  • secrets.yaml — never readable, contains credentials. Blocked at any depth, so includes/secrets.yaml is protected too.
  • automations.yaml, scenes.yaml, scripts.yaml — owned by Home Assistant's storage layer; use create_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. Only the top-level files are blocked — a split-config file that happens to be named packages/scripts.yaml is your own and stays editable.
  • Anything inside mcp_backups/ — use list_config_backups / restore_config_backup instead.

Backup caveat: the automatic snapshot taken before every save/delete covers first-level YAML files only. Edits to files in subdirectories are not captured by it, so there is no automatic rollback for those — keep your own copy (or use version control) before editing split config.

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. Files in subdirectories are not included in this snapshot. 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/patch/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.

AppDaemon file access is disabled by default. Enabling write access allows an AI/MCP client to modify executable AppDaemon Python code, granting code-execution-equivalent capability inside the AppDaemon environment and whatever Home Assistant API access AppDaemon has. Enable it only after reviewing the contents and secrets of the apps tree. The appdaemon_apps_root option defaults to the legacy AppDaemon private apps path, /addon_configs/a0d7b954_appdaemon/apps, for compatibility with installations that mount that folder into Home Assistant Core themselves. On Home Assistant OS it never works: the Core container only mounts /config, /share, /media and /ssl, and an add-on's private config folder (/addon_configs/..., or /app_configs/... as other add-ons see it) is not among them, so neither path can be reached from this integration. Use a shared root instead: set app_dir: /share/appdaemon/apps (or a folder under /media) in AppDaemon's appdaemon.yaml, move the apps there, and configure the same path as the AppDaemon apps root here.

Only the legacy root and paths below /share/ or /media/ are accepted. Absolute paths, malformed components, .. traversal, symlink components, and paths escaping the configured root are rejected. All list, read, save, delete, backup, and restore operations use the same validated root. Mutating operations create controlled snapshots, and saves use atomic replacement where supported. Only .py, .yaml, .yml, and .json files can be created, written, or deleted. Backups are bounded by the AppDaemon root and can be pruned with cleanup_appdaemon_backups. There is no direct MCP shell or AppDaemon process-control tool, but writing AppDaemon Python files remains code-execution-equivalent within the AppDaemon environment and its available Home Assistant API permissions. Existing files with other extensions are captured in backups but are reported as skipped during restore; they are never made writable by restore.

License

MIT

README fetched from the repository 5 hours ago. The original is authoritative.

Questions

About Hass MCP Server

How do I install Hass MCP Server?

No package has been published for this server, so install it from source: clone the repository and follow its README.

Is Hass MCP Server safe to use with an AI agent?

Its trust score is 56 out of 100 (fair). It passes 5 of the 6 static security checks run so far; the failures are listed above. It has no ConduID identity yet, so agent calls to it are not receipted.

Is Hass MCP Server still maintained?

Yes — the latest release is v1.18.0 (5 Oct 2026), and the last commit was 5 days ago. The repository has 78 stars and 4 open issues.