Home Assistant MCP Server (ha-mcp)

Control, configure and debug a Home Assistant smart home from any MCP client

By The Unofficial Home Assistant AI Toolkit Python Local · stdio DevOps and monitoringProductivity

93 popularity score ★ 5.5k ↓ 230k/mo

Connect your client

Local (PyPI)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

It needs HOMEASSISTANT_URL, HOMEASSISTANT_TOKEN. Replace each <NAME> with your value.

Claude CodeTerminal
claude mcp add home-assistant-ha -e HOMEASSISTANT_URL=<HOMEASSISTANT_URL> -e HOMEASSISTANT_TOKEN=<HOMEASSISTANT_TOKEN> -- uvx ha-mcp@latest
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "home-assistant-ha": {
      "command": "uvx",
      "args": [
        "ha-mcp@latest"
      ],
      "env": {
        "HOMEASSISTANT_URL": "<HOMEASSISTANT_URL>",
        "HOMEASSISTANT_TOKEN": "<HOMEASSISTANT_TOKEN>"
      }
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "home-assistant-ha": {
      "command": "uvx",
      "args": [
        "ha-mcp@latest"
      ],
      "env": {
        "HOMEASSISTANT_URL": "<HOMEASSISTANT_URL>",
        "HOMEASSISTANT_TOKEN": "<HOMEASSISTANT_TOKEN>"
      }
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "home-assistant-ha": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "ha-mcp@latest"
      ],
      "env": {
        "HOMEASSISTANT_URL": "<HOMEASSISTANT_URL>",
        "HOMEASSISTANT_TOKEN": "<HOMEASSISTANT_TOKEN>"
      }
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.home-assistant-ha]
command = "uvx"
args = ["ha-mcp@latest"]

[mcp_servers.home-assistant-ha.env]
HOMEASSISTANT_URL = "<HOMEASSISTANT_URL>"
HOMEASSISTANT_TOKEN = "<HOMEASSISTANT_TOKEN>"
Gemini CLITerminal
gemini mcp add --scope user -e HOMEASSISTANT_URL=<HOMEASSISTANT_URL> -e HOMEASSISTANT_TOKEN=<HOMEASSISTANT_TOKEN> home-assistant-ha uvx -- ha-mcp@latest
Local (container)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

It needs HOMEASSISTANT_URL, HOMEASSISTANT_TOKEN. Replace each <NAME> with your value.

Claude CodeTerminal
claude mcp add home-assistant-ha -e HOMEASSISTANT_URL=<HOMEASSISTANT_URL> -e HOMEASSISTANT_TOKEN=<HOMEASSISTANT_TOKEN> -- docker run -i --rm -e HOMEASSISTANT_URL -e HOMEASSISTANT_TOKEN ghcr.io/homeassistant-ai/ha-mcp
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "home-assistant-ha": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "HOMEASSISTANT_URL",
        "-e",
        "HOMEASSISTANT_TOKEN",
        "ghcr.io/homeassistant-ai/ha-mcp"
      ],
      "env": {
        "HOMEASSISTANT_URL": "<HOMEASSISTANT_URL>",
        "HOMEASSISTANT_TOKEN": "<HOMEASSISTANT_TOKEN>"
      }
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "home-assistant-ha": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "HOMEASSISTANT_URL",
        "-e",
        "HOMEASSISTANT_TOKEN",
        "ghcr.io/homeassistant-ai/ha-mcp"
      ],
      "env": {
        "HOMEASSISTANT_URL": "<HOMEASSISTANT_URL>",
        "HOMEASSISTANT_TOKEN": "<HOMEASSISTANT_TOKEN>"
      }
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "home-assistant-ha": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "HOMEASSISTANT_URL",
        "-e",
        "HOMEASSISTANT_TOKEN",
        "ghcr.io/homeassistant-ai/ha-mcp"
      ],
      "env": {
        "HOMEASSISTANT_URL": "<HOMEASSISTANT_URL>",
        "HOMEASSISTANT_TOKEN": "<HOMEASSISTANT_TOKEN>"
      }
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.home-assistant-ha]
command = "docker"
args = ["run", "-i", "--rm", "-e", "HOMEASSISTANT_URL", "-e", "HOMEASSISTANT_TOKEN", "ghcr.io/homeassistant-ai/ha-mcp"]

[mcp_servers.home-assistant-ha.env]
HOMEASSISTANT_URL = "<HOMEASSISTANT_URL>"
HOMEASSISTANT_TOKEN = "<HOMEASSISTANT_TOKEN>"
Gemini CLITerminal
gemini mcp add --scope user -e HOMEASSISTANT_URL=<HOMEASSISTANT_URL> -e HOMEASSISTANT_TOKEN=<HOMEASSISTANT_TOKEN> home-assistant-ha docker -- run -i --rm -e HOMEASSISTANT_URL -e HOMEASSISTANT_TOKEN ghcr.io/homeassistant-ai/ha-mcp

Settings 12

HOMEASSISTANT_URL Required: Address of your Home Assistant instance, starting with http:// or https://.
HOMEASSISTANT_TOKEN secret Required: Long-lived access token (an administrator's is recommended); demo uses the public demo token.
READ_ONLY_MODE Optional: Hide tools that change anything and block writes. Default false.
DISABLED_TOOLS Optional: Comma-separated tool names to turn off.
ENABLE_TOOL_SECURITY_POLICIES Optional: Apply per-tool approval policies. Default false.
REDACT_SECRETS Optional: Mask secrets in tool output. Default false.
HA_VERIFY_SSL Optional: Verify Home Assistant's TLS certificate. Default true.
Set together: tool search
ENABLE_TOOL_SEARCH Optional: Replace the full tool list with search-based discovery. Default false.
TOOL_SEARCH_MAX_RESULTS Optional: Results per tool search, 2 to 10. Default 5.
Set together: beta
ENABLE_BETA_FEATURES Optional: Master switch for beta tools; each also needs its own flag. Default false.
HAMCP_ENABLE_FILESYSTEM_TOOLS Optional: Turn on file read and write tools (with ENABLE_BETA_FEATURES and the custom component). Default false. For ha_read_file, ha_write_file.
ENABLE_YAML_CONFIG_EDITING Optional: Turn on configuration.yaml editing (with ENABLE_BETA_FEATURES and the custom component). Default false. For ha_config_set_yaml.

In a container, a setting goes in with -e NAME=value after docker run.

What it does

ha-mcp is an unofficial MCP server for Home Assistant. Besides reading live states, calling any service and controlling many devices in one call, it builds and maintains the setup itself: automations, scripts, scenes, helpers, dashboards, areas, zones, groups, calendars, to-do lists, blueprints, backups, updates, apps (add-ons), HACS, radios and the device and entity registries. For debugging it reads history, long-term statistics, logs, camera snapshots and automation traces, and renders templates.

The tool data shipped with the current release counts 87 tools; 60 are listed here. A few are beta and stay hidden until switched on: file reading and writing, configuration.yaml editing, dashboard screenshots and a code mode that runs short Python snippets in a sandbox (capped at 30 seconds and 10 MB of memory by default).

The recommended install is the HA-MCP integration, named HA-MCP Custom Component in older releases. It runs the server inside Home Assistant 2026.8.0 or newer. On Home Assistant 2026.11 and newer it comes from the built-in Marketplace, whose default catalog holds it, so no GitHub connection or custom repository is needed. On 2026.8 to 2026.10 it comes from HACS, and it can also be copied in by hand. Setup asks for an administrator access token, or the user name and password of an admin account made for HA-MCP, and for how clients may connect: remote access through Home Assistant, the local network, or both. Both start off. On Home Assistant OS and Supervised it can also run as an app (add-on) that needs no token. Elsewhere it runs from the Docker image or PyPI package with your Home Assistant URL and a long-lived token. Its makers recommend streamable HTTP over the stdio mode of the client snippets here for real use.

Optional settings include Read Only Mode, which hides write tools, per-tool disabling, approval policies, secret redaction, automatic backups before edits, custom instructions and search-based tool discovery for smaller models.

What it needs

RuntimePython 3.13+
Runs onmacOS, Windows, Linux
Home AssistantYour own instanceadmin long-lived access token, or a dedicated admin account for the custom component; the app needs none
Also
  • uv (for uvx) on the PyPI way

For Docker or PyPI, create a token in Home Assistant under your profile, Security, Long-lived access tokens, and set HOMEASSISTANT_URL to your instance's address. Setting HOMEASSISTANT_TOKEN to demo with the public demo URL from the docs connects to a hosted demo instead. The custom component asks for an administrator token or the sign-in of an admin account made for it, then shows the connect URL on its Configure screen under Settings, Devices & Services. The app needs no token and prints its connect URL in its log.

Limits

  • Limit The custom component needs an administrator token, or a dedicated admin account it makes its own token from, and its remote and local-network access both start off until one is chosen.
  • Platform The integration needs Home Assistant 2026.8.0 or newer. Installs from the earlier ha-mcp-integration repository should keep GitHub connected on the Marketplace for update checks.
  • Early release The stdio transport has known connection problems; its makers recommend it for demos and suggest streamable HTTP or the custom component for real setups.
  • Early release File, YAML, dashboard screenshot and code mode tools are off unless ENABLE_BETA_FEATURES and their own flag are set; file and YAML tools also need the custom component.
  • Platform The app (add-on) install needs Home Assistant OS or Supervised; Container and Core installs use the custom component, Docker or PyPI.
  • Limit Run one install method per client: two entries for the same server in one client are a known cause of hangs.
  • Not covered A non-administrator token works on the Docker and PyPI ways, but some tools are limited.
  • Limit Needs Python 3.13 or 3.14 (requires-python >=3.13,<3.15).

Who it suits

Suits people running their own Home Assistant who want a client to set up and troubleshoot it, not just switch devices: it writes automations, dashboards and registry entries and reads logs and traces. Because it can change and restart the whole system, start with Read Only Mode or a dedicated account if you only want to look. For plain voice-style control of a chosen set of entities, Home Assistant's own Model Context Protocol Server integration works through Assist and its exposed entities with Home Assistant sign-in, without a separate install. It is a community project, not published by Home Assistant.

Tools 60 of 87

26 only read, 23 change things, 11 can delete or overwrite. A ? marks an optional parameter.

ha_search
Fuzzy search across entities, automations, scripts and other configurationquery?: stringdomain_filter?: stringarea_filter?: stringsearch_types?: anylimit?: integeroffset?: integerexact_match?: booleaninclude_hidden?: booleaninclude_config?: booleangroup_by_domain?: booleanper_domain_limit?: integerstate_filter?: stringresult_fields?: anyfields?: anyconfig_time_budget?: number
ha_get_overview
Summarise the instance: domains, areas, entity counts and repairsdetail_level?: enumdomains?: anylimit?: integeroffset?: integermax_entities_per_domain?: integerinclude_state?: booleaninclude_entity_id?: booleaninclude_notifications?: booleaninclude_dismissed_repairs?: booleanfields?: any
ha_get_state
Read the current state and attributes of one or more entitiesentity_id: anyfields?: anyattribute_keys?: any
ha_call_service changes
Call any Home Assistant service (action) on chosen targetsdomain?: stringservice?: stringentity_id?: stringdata?: objectreturn_response?: booleanwait?: booleanverbose?: booleanresult_fields?: anyresult_attribute_keys?: anyws_command?: string
ha_bulk_control changes
Run many device operations, or one structural bulk action, in one calloperations?: arrayparallel?: booleanselector?: anyaction?: stringparameters?: objecttimeout_seconds?: numbervalidate_first?: booleandry_run?: boolean
ha_call_event changes
Fire a custom Home Assistant eventevent_type: stringdata?: object
ha_list_services
List the services available, filtered by domain or querydomain?: stringquery?: stringlimit?: integeroffset?: integerdetail_level?: enumservice_fields?: anyfields?: any
ha_config_get_automation
Read an automation's stored config, registry entry, load errors and references, by entity_id or config identity_id: string
ha_config_set_automation changes
Create or update an automationconfig?: objectentity_id?: stringpython_transform?: stringconfig_hash?: stringtake_control_of_blueprint?: booleancategory?: stringwait?: booleanenabled?: booleanrun_actions?: booleanMandatoryBPS?: booleanBestPracticeKey?: any
ha_config_remove_automation deletes
Delete an automation, by entity_id or config identity_id: stringwait?: boolean
ha_config_get_script
Read a script's configurationscript_id: string
ha_config_set_script changes
Create or update a scriptscript_id: stringconfig?: objectpython_transform?: stringconfig_hash?: stringtake_control_of_blueprint?: booleancategory?: stringwait?: booleanrun?: enumvariables?: objectMandatoryBPS?: booleanBestPracticeKey?: any
ha_config_remove_script deletes
Delete a scriptscript_id: stringwait?: boolean
ha_config_get_scene
Read or find scenesscene_id?: stringquery?: stringsearch_in_config?: booleanlimit?: integeroffset?: integer
ha_config_set_scene changes
Create or update a scenescene_id: stringconfig?: objectpython_transform?: stringconfig_hash?: stringcategory?: stringwait?: booleanactivate?: booleanMandatoryBPS?: booleanBestPracticeKey?: any
ha_config_remove_scene deletes
Delete a scenescene_id: stringwait?: boolean
ha_config_get_dashboard
Read a dashboard or list dashboardsurl_path?: stringlist_only?: booleanforce_reload?: booleanentity_id?: stringcard_type?: stringheading?: stringinclude_config?: booleaninclude_screenshot?: booleanview_path?: stringquery?: stringdescribe?: boolean
ha_config_set_dashboard changes
Create or edit a dashboard and its cardsurl_path: stringconfig?: objectpython_transform?: stringconfig_hash?: stringtitle?: stringicon?: stringrequire_admin?: booleanshow_in_sidebar?: booleanMandatoryBPS?: booleanBestPracticeKey?: anyreturn_screenshot?: booleanview_path?: stringpatch?: array
ha_config_delete_dashboard deletes
Delete a dashboardurl_path: string
ha_get_dashboard_screenshot
Render images of a dashboard view, also at phone and tablet sizes (beta, needs a screenshot engine app)dashboard_path?: stringurl_path?: stringview_path?: stringwidth?: integerheight?: anyviewport_presets?: arrayorientation?: anyzoom?: numberwait_ms?: integerfull_page?: booleantheme?: stringdark_mode?: booleanlanguage?: stringimage_format?: anyrender_timeout_seconds?: number
ha_config_list_helpers
List helper entities of a given typehelper_type: anylimit?: integeroffset?: integerdescribe?: booleanmenu_choice?: stringhelper_id?: string
ha_config_set_helper changes
Create or update a helper entityhelper_type: anyname?: stringhelper_id?: stringentry_id?: stringsubentry_type?: stringsubentry_id?: stringshow_advanced_options?: booleanicon?: stringarea_id?: stringlabels?: anymin_value?: numbermax_value?: numberstep?: numberunit_of_measurement?: stringoptions?: anyinitial?: anymode?: stringhas_date?: booleanhas_time?: booleanrestore?: boolean
ha_remove_helpers_integrations deletes
Remove a helper or an integration's config entrytarget: stringhelper_type?: anysubentry_id?: stringconfirm?: booleanwait?: boolean
ha_list_floors_areas
List floors and areasfields?: anyarea_fields?: any
ha_set_area_or_floor changes
Create or update an area or floorkind: enumname?: stringid?: stringfloor_id?: stringlevel?: integericon?: stringaliases?: anypicture?: stringlabels?: anytemperature_entity_id?: stringhumidity_entity_id?: string
ha_remove_area_or_floor deletes
Delete an area or floorkind: enumid: string
ha_get_zone
Read one zone or list all zoneszone_id?: string
ha_set_zone changes
Create or update a zonename?: stringlatitude?: numberlongitude?: numberzone_id?: stringradius?: numbericon?: stringpassive?: booleanwait?: boolean
ha_config_list_groups
List groupslimit?: integeroffset?: integer
ha_config_set_group changes
Create or update a groupobject_id: stringentities?: arrayname?: stringicon?: stringall_on?: booleanadd_entities?: arrayremove_entities?: arraywait?: boolean
ha_config_get_calendar_events
Read events from a calendarentity_id: stringstart?: stringend?: stringmax_results?: integer
ha_config_set_calendar_event changes
Create or update a calendar evententity_id: stringsummary: stringstart: stringend: stringdescription?: stringlocation?: stringrrule?: stringuid?: stringrecurrence_id?: stringrecurrence_range?: enum
ha_get_todo
Read to-do lists and their itemsentity_id?: stringstatus?: any
ha_set_todo_item changes
Add, update or reorder a to-do itementity_id: stringsummary?: stringitem?: stringstatus?: enumdescription?: stringdue_date?: stringdue_datetime?: stringrename?: stringmove_after?: string
ha_manage_blueprints changes
List, read, import and manage blueprintsaction: enumdomain?: stringpath?: stringurl?: stringyaml?: stringsource_url?: stringoverwrite?: booleaninput?: objectconfirm?: boolean
ha_get_device
Read devices from the device registrydevice_id?: stringentity_id?: stringintegration?: stringarea_id?: stringmanufacturer?: stringlimit?: integeroffset?: integerdetail_level?: enum
ha_set_device changes
Update a device's registry entrydevice_id: stringname?: stringarea_id?: stringdisabled_by?: stringlabels?: any
ha_remove_device deletes
Remove a device from the registrydevice_id: string
ha_get_entity
Read entities from the entity registryentity_id?: anyunique_id?: stringdomain?: stringplatform?: string
ha_set_entity changes
Update an entity's registry entry (name, area, labels and so on)entity_id: anyarea_id?: stringname?: stringuse_device_name?: booleanicon?: stringdevice_class?: stringoptions?: objectenabled?: booleanhidden?: booleanaliases?: anyuse_entity_name_alias?: booleancategories?: objectlabels?: anylabel_operation?: enumexpose_to?: objectnew_entity_id?: stringnew_device_name?: string
ha_remove_entity deletes
Remove an entity from the registryentity_id: any
ha_get_history
Read recorded state history or long-term statistics, or a summary of thementity_ids: anysource?: enumstart_time?: stringend_time?: stringminimal_response?: booleansignificant_changes_only?: booleanlimit?: integeroffset?: integerperiod?: stringstatistic_types?: anyorder?: enumsummary?: booleanfields?: anyinclude_schema?: booleancore_options?: object
ha_get_automation_traces
Read automation and script run traces for debuggingautomation_id: stringrun_id?: stringlimit?: integerdeduplicate?: booleandetailed?: booleansections?: stringoffset?: integerorder?: enum
ha_get_logs
Read Home Assistant logs, filtered by entity, device or context if wantedsource?: enumlimit?: integersearch?: stringorder?: enumhours_back?: integerentity_id?: stringdevice_id?: stringcontext_id?: stringend_time?: stringoffset?: anycompact?: booleanlevel?: stringstructured?: booleantop_n?: integerslug?: string
ha_get_camera_image
Fetch a snapshot from a camera entityentity_id: stringwidth?: integerheight?: integer
ha_get_integration
Read integrations and their config entriesentry_id?: stringquery?: stringdomain?: stringintegration_type?: stringinclude_options?: booleaninclude_schema?: booleaninclude_subentries?: booleaninclude_subentry_schema?: booleansubentry_type?: stringsubentry_id?: stringshow_advanced_options?: booleanexact_match?: booleanlimit?: integeroffset?: integerinclude_diagnostics?: booleaninclude_ws_commands?: booleandevice_id?: stringdiagnostics_fields?: anydiagnostics_truncate_at_bytes?: integerdiagnostics_data_path?: string
ha_set_integration changes
Add, enable, disable, reconfigure an integration or send it a commandentry_id?: stringenabled?: booleandomain?: stringconfig?: objectreconfigure?: booleanexpected_device_id?: stringexpected_unique_id?: stringexpected_mac?: stringexpected_entity_ids?: arraylog_level?: enumlog_persistence?: stringmenu_choice?: stringsubentry_type?: stringsubentry_id?: stringflow_id?: stringabort?: booleanws_command?: stringws_data?: object
ha_get_system_health
Read system health and diagnosticsinclude?: stringinclude_dismissed_repairs?: booleanconfig_entry_id?: stringdevice_id?: stringdiagnostics_fields?: anydiagnostics_truncate_at_bytes?: integerdiagnostics_data_path?: stringdiagnostics_data_offset?: integerdiagnostics_data_limit?: integer
ha_manage_backup deletes
Create, list and restore full or partial backups, and per-edit backupsscope: enumaction: enumname?: stringbackup_id?: stringrestore_database?: booleanrestore_addons?: arrayrestore_folders?: arrayinclude_homeassistant?: booleaninclude_database?: booleaninclude_addons?: arrayinclude_all_addons?: booleaninclude_folders?: arraysafety_backup?: booleanconfirm?: booleandomain?: stringentity_id?: stringbackup_name?: stringolder_than_days?: integerlimit?: integer
ha_manage_updates changes
List, install or skip updates and ignore repair issuesaction?: stringentity_ids?: anycategories?: anyinclude_skipped?: booleaninclude_release_notes?: booleanbackup?: booleanrepairs?: array
ha_get_app
Read installed or available apps (add-ons) on HA OS or Supervisedsource?: enumslug?: stringinclude_stats?: booleanrepository?: stringquery?: string
ha_manage_app changes
Start, stop, configure or call an app (add-on)slug?: stringpath?: stringmethod?: stringbody?: anydebug?: booleanport?: integeroffset?: integerlimit?: integerwebsocket?: booleanwait_for_close?: booleanmessage_limit?: integermessage_offset?: integersummarize?: booleanpython_transform?: stringoptions?: objectnetwork?: objectboot?: stringauto_update?: booleanwatchdog?: booleanarray_patch?: object
ha_manage_hacs changes
Search, add and download HACS repositoriesaction: enumrepository_id?: stringversion?: stringrepository?: stringcategory?: stringconfirm_replace_built_in?: booleanconfirm?: boolean
ha_eval_template
Render a Jinja template or test a conditiontemplate?: stringcondition?: objectvariables?: objectstrict?: booleantimeout?: integerreport_errors?: boolean
ha_reload_core changes
Reload core configuration or one config entrytarget?: stringentry_id?: string
ha_restart changes
Restart Home Assistant, optionally in safe mode (asks for confirmation)confirm?: booleansafe_mode?: boolean
ha_manage_radio changes
Manage Z-Wave, Zigbee, Matter and Thread radios, including reading Z-Wave parametersradio: enumaction: stringdevice_id?: stringentity_id?: stringparams?: objectconfirm?: boolean
ha_read_file
Read a file from the config directory (beta, needs the custom component)path: stringtail_lines?: integeryaml_path?: string
ha_write_file deletes
Write a file in allowed directories (beta, needs the custom component)path: stringcontent: stringoverwrite?: booleancreate_dirs?: boolean
ha_config_set_yaml deletes
Add, replace or remove top-level keys in configuration.yaml or packages (beta)yaml_path: stringaction: stringcontent?: stringfile?: stringconfirm_token?: stringMandatoryBPS?: booleanBestPracticeKey?: any

Similar servers