Home Assistant and MCP: build with Claude, Codex, and ChatGPT

Connect Home Assistant to Claude, Codex, or ChatGPT with minimal entity exposure, then build local, validated, and reversible automations and dashboards.

01

MCP connects AI to the home, but it does not replace Home Assistant

Home Assistant's native MCP server lets Claude, Codex, or ChatGPT read live context and use Assist API tools for explicitly exposed entities. It helps inventory entity IDs, understand state, and test a command. It is not a general editor: do not assume it can write automations.yaml, modify a dashboard, or administer every integration.

The dependable flow is observe, propose, review, then save in Home Assistant. The final automation runs locally without calling AI on every trigger. Internet downtime or an AI plan limit must not stop a leak alert or room lighting.

NeedNative MCP serverRecommended method
Read states and IDsYes, for exposed entitiesAssist context
Control an entityYes, when enabledAssist tool with approval
Generate YAMLThe model can draftPaste, review, validate
Persist an automationNot a general admin functionHA editor or managed file
Modify a dashboardNot a general admin functionUI editor or YAML dashboard
Use external tools from HAOpposite directionMCP client integration
02

Choose the client and transport

Home Assistant exposes /api/mcp over Streamable HTTP. Codex supports stdio and Streamable HTTP; Claude Code recommends HTTP for remote servers. ChatGPT Web uses a remote MCP app or plugin and does not read local Codex configuration. Availability also depends on plan and workspace policy.

The server exposes Home Assistant to an AI client. The MCP client integration does the reverse: it lets a conversation agent in Home Assistant use an external MCP server.

ClientLocalRemoteMain limit
Claude Desktopstdio proxy to /api/mcpHTTPS connectorRemote connector uses Anthropic cloud
Claude CodeHTTP and OAuthHTTP and OAuthLocal, project, or user scope
Codex CLI/IDEStreamable HTTP and OAuthStreamable HTTP and OAuthGlobal or project configuration
ChatGPTNo direct local Web connectionHTTPS MCP appPlus, Pro, Business, Enterprise/Edu per HA docs
03

1. Prepare Home Assistant with least privilege

The exposed-entities page is the key boundary. /api/mcp/assist explicitly selects Assist; another LLM API requires an administrator user.

  • Create and test a backup.
  • Inventory exact entity IDs and raw states in Developer tools > States.
  • Add Model Context Protocol Server under Devices & services.
  • Expose only required sensors and actuators to Assist.
  • Use a separate non-admin account for /api/mcp/assist where possible.
  • Initially exclude locks, garage doors, alarms, main valves, and sensitive scripts.
04

2. Configure Claude, Codex, or ChatGPT

On Home Assistant OS and Container, add the native server through the UI; no add-on is required. A local proxy normally runs on the client, or in an isolated container. Never put its token in an image, Git, or shared file.

Claude Desktop can use mcp-proxy with a long-lived token on the LAN. Claude Code and Codex can use OAuth directly against a local URL. ChatGPT needs a remotely reachable HTTPS URL: Home Assistant Cloud is simplest; a tunnel requires exact external URL and forwarded-header alignment.

Codex — ~/.codex/config.toml
mcp_oauth_callback_port = 12345

[mcp_servers.homeassistant]
url = "https://ha.example.net/api/mcp/assist"
auth = "oauth"
oauth = { client_id = "http://127.0.0.1:12345" }

# Then: codex mcp login homeassistant
Claude Code — HTTP OAuth
claude mcp add-json "HA" '{
  "type": "http",
  "url": "https://ha.example.net/api/mcp/assist",
  "oauth": {"clientId": "http://localhost:12345", "callbackPort": 12345}
}' --client-secret
05

3. Protect OAuth, tokens, and remote access

Prefer OAuth. Home Assistant uses a Client ID Metadata Document rather than RFC 7591 dynamic registration. The Client ID is https://claude.ai for the remote Claude connector and https://chatgpt.com for ChatGPT; it is never the Home Assistant URL.

A long-lived token remains powerful until revoked. Store it in a secret manager or environment variable. With a tunnel, the hostname must exactly match the external URL and the proxy must forward the correct headers.

  • Valid TLS, one canonical URL, and MFA.
  • No secrets in prompts, YAML, or repositories.
  • Human confirmation for sensitive writes.
  • Logging and a tested revocation procedure.
06

4. Observe before allowing control

Start by listing exposed entities, reading one room, and explaining an automation. Then test one reversible command on a lamp. A text response does not prove a tool call: inspect the client log and Home Assistant state.

Read-only prompt
Read only the exposed Home Assistant context. List the entity IDs for presence, illuminance, energy, and temperature. Flag missing or unavailable entities. Do not control a device or modify configuration.
07

Example 1 — lighting based on presence and illuminance

This draft runs locally after it is saved in Home Assistant. Replace the entity IDs and threshold after observing the real sensor. Triggers start evaluation; conditions then require both presence and low illuminance.

automations.yaml — fictitious example
- id: office_presence_lux_lighting
  alias: Office - lighting from presence and illuminance
  triggers:
    - trigger: state
      entity_id: binary_sensor.office_presence
      to: "on"
      id: presence
    - trigger: numeric_state
      entity_id: sensor.office_illuminance
      below: 80
      id: dark
    - trigger: state
      entity_id: binary_sensor.office_presence
      to: "off"
      for: "00:05:00"
      id: vacant
  actions:
    - choose:
        - conditions:
            - condition: template
              value_template: "{{ trigger.id in ['presence', 'dark'] }}"
            - condition: state
              entity_id: binary_sensor.office_presence
              state: "on"
            - condition: numeric_state
              entity_id: sensor.office_illuminance
              below: 80
          sequence:
            - action: light.turn_on
              target:
                entity_id: light.office_ceiling
        - conditions:
            - condition: template
              value_template: "{{ trigger.id == 'vacant' }}"
          sequence:
            - action: light.turn_off
              target:
                entity_id: light.office_ceiling
  mode: restart
08

Example 2 — water-leak alert without an irreversible action

A leak alert must keep working without AI. Automatic valve closure requires testing action direction, power, unavailable states, and manual override, so this example only alerts.

automations.yaml — local and mobile alert
- id: basement_water_leak_alert
  alias: Basement - water leak alert
  triggers:
    - trigger: state
      entity_id: binary_sensor.basement_water_leak
      to: "on"
  actions:
    - action: persistent_notification.create
      data:
        title: "Water leak detected"
        message: "Check the basement sensor immediately."
    - action: notify.mobile_app_marc_phone
      data:
        title: "Home Assistant alert"
        message: "Water leak detected in the basement."
  mode: single
Review prompt
Review this draft without applying it. Confirm raw states, the notify service, unavailable handling, and the expected trace. Do not close a valve or disable an alarm.
09

Example 3 — energy, temperature, and presence dashboard

A dashboard created in the UI is normally stored by Home Assistant; a YAML dashboard remains a separately managed file. Do not overwrite internal storage with an external tool. Start with native cards before adding a HACS dependency.

Lovelace YAML view — native cards
title: Home
views:
  - title: Overview
    path: home
    cards:
      - type: entities
        title: Presence
        entities:
          - binary_sensor.office_presence
          - person.marc
      - type: gauge
        entity: sensor.home_power_w
        name: Current power
        min: 0
        max: 10000
        severity:
          green: 0
          yellow: 4000
          red: 7000
      - type: history-graph
        title: Temperature - 24 h
        hours_to_show: 24
        entities:
          - sensor.living_room_temperature
          - sensor.basement_temperature
10

8. Save, validate, and test

YAML traces require an id and Home Assistant keeps five by default. numeric_state reacts to crossing a threshold, not merely being below it.

  • Paste through Edit in YAML, save, and reopen the automation.
  • Keep a unique id; automations.yaml must remain a list and must not be edited simultaneously by UI and hand.
  • Run configuration validation under Developer tools > YAML.
  • Test conditions and actions, then cause a real state change.
  • Read the trace: trigger, conditions, choose branch, service, and error.
  • Watch unavailable states, duplicate triggers, and execution mode.
11

9. Rollback and governance

A community MCP server with direct writes or many admin tools increases risk. Verify its primary repository, version, advertised tools, read/write annotations, and authentication; isolate it and keep human approval. MCP is not a security guarantee.

  • Name the backup and record the Home Assistant version.
  • Version manually managed files without secrets.
  • Disable before deleting and preserve the error trace.
  • Revoke OAuth or the token, remove the MCP app, and shrink exposed entities.
  • Document who approves sensitive actions.
12

Quick troubleshooting

SymptomLikely causeCheck
404 at /api/mcpMissing integration or wrong pathAdd integration and use /api/mcp/assist
401 UnauthorizedWrong tokenReauthenticate and revoke old secret
OAuth loopClient ID or URL mismatchCheck Client ID and callback
Tunnel rejectionIssuer or proxy headersAlign external URL and X-Forwarded-*
Missing entityNot exposedCheck Expose and exact entity ID
YAML has no effectCondition or raw stateRead trace and states
Broken dashboardMissing HACS cardReturn to native cards
13

A reliable integration stays local at runtime

Claude, Codex, and ChatGPT accelerate inventory, drafting, and review when MCP gives real context. Quality comes from boundaries: minimal entities, suitable authentication, drafts instead of blind writes, Home Assistant validation, and tested rollback.

This guide offers a method and fictitious examples; it does not replace a security and reliability review of a complex installation.