浪人
DE | EN
Home Assistant Meets Claude Code: Smart Home Control via MCP
tech

Home Assistant Meets Claude Code: Smart Home Control via MCP

Back to Blog
9 min read

Home Assistant Meets Claude Code: Smart Home Control via MCP

I’ve been talking to my smart home for a while now. Not in that clunky “Hey Alexa, turn on the lights” way, but really - with context, with follow-up questions, with actual analysis. The Model Context Protocol (MCP) Server for Home Assistant makes this possible, connecting the AI assistant directly to the HA API. What happens when you start a new Claude Code project and just ask away - that’s what I’m showing in this article.

What is MCP anyway?

The Model Context Protocol is an open standard that Anthropic released in 2024. The idea behind it is simple: AI models shouldn’t just process text, but actively access external systems - databases, APIs, file systems, and also Home Assistant. Instead of connecting a rigid chatbot, Claude gets a real toolkit via MCP: query entities, call services, create dashboards, set up automations.

The ha-mcp Server is the community implementation for Home Assistant. With currently over 95 tools, it covers everything from simple state queries to backup operations. And it’s picked up serious momentum lately - over 1,000 GitHub stars in a short time speaks for itself.

Architecture: stdio vs. HTTP

Before we get started, a quick word on the most important design decision: How does Claude Code connect to ha-mcp?

There are two transport options:

stdio (Standard I/O) is the simplest approach. Claude Code starts ha-mcp as a subprocess on the same machine and communicates via stdin/stdout. No open port, no network configuration - ha-mcp only runs when Claude Code runs. Ideal when everything is on a single machine.

HTTP is the persistent approach. ha-mcp runs as a permanent HTTP server, Claude Code connects via URL. This makes sense when HA is on a separate host - for example, Home Assistant OS on a Raspberry Pi or mini-PC - and you’re accessing it from another device on the network.

My setup is exactly this case: HA runs on its own host on the local network, Claude Code on my Windows PC. The ha-mcp Server runs as a Supervisor Add-on directly on the HA host and is accessible via HTTP from there on the LAN. Claude Code on Windows connects via URL to the add-on - no local uvx process, no permanently open terminal needed.

Claude Code (Windows)
       ↓  HTTP (local network)
  ha-mcp Add-on (Supervisor, HA Host)
       ↓  internally
  Home Assistant Core

This is the most elegant solution for this setup: the server starts automatically with HA, runs in the background, and is available for any client on the network.

Setup: Installing ha-mcp and Connecting to Claude Code

The setup is divided into two independent parts: the server (ha-mcp add-on on the HA host) and the client (Claude Code configuration on the Windows PC).

Server Side: Installing the HA Add-on

The ha-mcp add-on can be installed directly via the HA Supervisor. The Setup Wizard on the project page under Claude Code → Local Network → HA OS has the complete instructions. Here’s the process in brief:

In Home Assistant, go to Settings → Add-ons → Add-on Store and add the repository https://github.com/homeassistant-ai/ha-mcp. Then “Home Assistant MCP Server” appears in the list - install it, then go to Configuration in the add-on to enter the port (default: 8808) and optionally the allowed hosts.

Before starting the add-on, you need a Long-Lived Access Token: In HA under Profile → Security → Long-Lived Access Tokens → Create token. Copy the token immediately - it’s only shown once. Enter the token in the add-on configuration under HA_TOKEN, then start the add-on.

The add-on now runs at http://<HA-IP>:8808 and is accessible on the local network.

ha-mcp add-on in HA Supervisor with Running status ha-mcp add-on in HA Supervisor Config

Client Side: Configuring Claude Code on Windows

For Windows, uv needs to be installed - this is the Python package tool that ha-mcp uses in the background for local transport. Install via winget:

winget install astral-sh.uv

Now Claude Code needs to know where the MCP server is running. There are two options with an important difference:

User-wide (all projects): claude mcp add without additional flags stores the server in ~/.claude.json - it’s then available in every Claude Code session, regardless of which directory you start in.

claude mcp add ha-mcp --transport http http://192.168.1.x:8808/mcp

Project-specific (recommended): If you prefer a clean, isolated setup, place a .mcp.json directly in your project directory. Claude Code automatically reads this file when starting if you’re in that directory - and only there.

{
  "mcpServers": {
    "ha-mcp": {
      "type": "http",
      "url": "http://192.168.1.x:8808/mcp"
    }
  }
}

The .mcp.json variant can be committed to your Git repository, so the MCP setup remains reproducible. The token is in the add-on on the HA host, not in this file - so nothing sensitive here.

To check if everything worked, run /mcp inside a Claude Code session:

> /mcp
⎿ MCP Server Status

⎿ • ha-mcp: connected (97 tools)

97 tools - that’s something to work with.

/mcp status in Claude Code: ha-mcp connected with 97 tools

Starting a New Project from Scratch

I’m starting a fresh Claude Code project with a clean, project-local MCP configuration - so everything is self-explanatory and nothing depends on global settings.

First, create the project directory and place the .mcp.json in it:

mkdir ha-assistant
cd ha-assistant
{
  "mcpServers": {
    "ha-mcp": {
      "type": "http",
      "url": "http://192.168.1.x:8808/mcp"
    }
  }
}

Then start Claude Code:

claude

On the first start, Claude Code asks for confirmation for the project-local .mcp.json - a security measure so you don’t accidentally accept foreign MCP configs from cloned repos. Confirm once, done. After that, /mcp shows the status:

> /mcp
⎿ MCP Server Status

⎿ • ha-mcp: connected (97 tools)

97 tools - that’s something to work with. If you clone this directory later and run claude, you’ll have the same setup automatically. No “works on my machine” problems.

Query: The Most Productive Day of My Balcony PV

I operate a balcony PV system with four panels, connected via a Hoymiles microinverter and the OpenDTU integration in Home Assistant. The entities I’m interested in:

  • sensor.hoymiles_yieldday - total daily production (in Wh)
  • sensor.hoymiles_yieldtotal - total production since startup (in kWh)
  • sensor.hoymiles_ch1_yieldday to sensor.hoymiles_ch4_yieldday - daily production per panel

The first question:

I want to know which day so far had the highest production from my 
balcony PV. Look at the historical data of sensor.hoymiles_yieldday 
and find the most productive day and the total production on that day 
broken down by the four panels (sensor.hoymiles_ch1_yieldday to 
sensor.hoymiles_ch4_yieldday).

Claude Code calls ha_get_statistics - you see the tool calls appear live in the session. The answer comes in a few seconds:

The most productive day was June 20, 2025 with a 
total production of 11.13 kWh.

Breakdown by panel:
┌────────┬───────────────────────┐
│ Panel  │      Production        │
├────────┼───────────────────────┤
│ CH1    │ 2.722 Wh (2.72 kWh)   │
├────────┼───────────────────────┤
│ CH2    │ 2.495 Wh (2.50 kWh)   │
├────────┼───────────────────────┤
│ CH3    │ 3.011 Wh (3.01 kWh)   │
├────────┼───────────────────────┤
│ CH4    │ 2.906 Wh (2.91 kWh)   │
├────────┼───────────────────────┤
│ Total  │ 11.134 Wh (11.13 kWh) │
└────────┴───────────────────────┘

CH3 was the strongest panel on that day, CH2 the weakest.
The distribution is overall very even.

Top 5 most productive days (for comparison):
┌────────────┬────────────┐
│    Date    │ Production │
├────────────┼────────────┤
│ 20.06.2025 │ 11.13 kWh  │
├────────────┼────────────┤
│ 12.06.2025 │ 10.91 kWh  │
├────────────┼────────────┤
│ 13.06.2025 │ 10.91 kWh  │
├────────────┼────────────┤
│ 30.06.2025 │ 10.89 kWh  │
├────────────┼────────────┤
│ 11.06.2025 │ 10.89 kWh  │
└────────────┴────────────┘

June 2025 was apparently a very sunny month —
all top-5 days are in it.

Two things stand out immediately: 11 kWh in one day is really impressive for a balcony power plant - for comparison, an average household consumes about 8-10 kWh per day. And the top-5 list shows a clear cluster: all June 2025. Claude noted that without me asking.

The panel distribution is very even at 2.5 to 3.0 kWh per unit - no panel drops significantly, indicating a good installation without noticeable shading.

Claude Code session with the PV evaluation: most productive day and top-5 list

What’s conceptually important here: I didn’t write a SQL query, formulate an InfluxDB query, or build a Python evaluation. I asked in plain English, and Claude Code called the right MCP tools in the right order and presented the result cleanly.

That’s the real added value of MCP: not that Claude can do something that was impossible before - but that the barrier to querying data drops to zero.

Creating a Dashboard with Bubble Cards

Bubble Cards is a popular custom card for Home Assistant Lovelace that brings a modern, rounded UI design. Provided Bubble Card is installed via HACS, ha-mcp can create the dashboard directly via the HA API.

Create a new Home Assistant dashboard titled 
"Balcony PV" and add the following Bubble Cards:

1. A Bubble Card with the current daily yield 
   (sensor.hoymiles_yieldday)
2. A Bubble Card with the total yield 
   (sensor.hoymiles_yieldtotal)
3. Four Bubble Cards for individual panels 
   (sensor.hoymiles_ch1_yieldday to ch4_yieldday), 
   each with appropriate icon (mdi:solar-panel)

Use tap_action: more-info for all cards and set 
the theme to dark if available.

Claude Code first calls ha_get_dashboard_guide and ha_get_card_documentation to know the current dashboard syntax - including the Bubble Card version installed in HA. Then it generates the YAML and passes it to Home Assistant via ha_config_set_dashboard. Confirmation comes immediately:

The dashboard has been successfully created. Here's the summary:

Dashboard "Balcony PV" is accessible at /balcony-pv and 
visible in the sidebar.

Configuration:
Section "Overall Overview":
- sensor.hoymiles_yieldday — Daily yield (mdi:solar-power-variant)
- sensor.hoymiles_yieldtotal — Total yield (mdi:counter)

Section "Individual Panels":
- sensor.hoymiles_ch1_yieldday — Panel 1 (mdi:solar-panel)
- sensor.hoymiles_ch2_yieldday — Panel 2 (mdi:solar-panel)
- sensor.hoymiles_ch3_yieldday — Panel 3 (mdi:solar-panel)
- sensor.hoymiles_ch4_yieldday — Panel 4 (mdi:solar-panel)

All cards have tap_action: more-info and the theme is set to dark. 
The layout uses the modern sections type with Bubble Card v3.1.4.

The dashboard is immediately visible in the HA sidebar - no manual YAML editing, no reloading, no navigating through the Lovelace interface. One prompt, done.

Claude Code session: dashboard creation with tool calls and confirmation

What stands out here: Claude didn’t just generate blind YAML, but retrieved the installed Bubble Card version (3.1.4) and uses the modern sections layout type recommended in newer versions. That’s what the ha_get_card_documentation tool call is for.

Iteration: The Unavailable Problem

After the first look at the dashboard, I notice: all six cards show “Unavailable”. Layout and icons are correct, but no values. The obvious suspicion - wrong entity IDs - can be checked immediately:

The entities in the dashboard show "Unavailable". Search for all 
entities related to "hoymiles" and show me the exact entity IDs.

Claude Code calls ha_search_entities and not only provides the entity list, but discovers two insightful sensors in the process:

┌──────────────────────────────────┬───────┐
│            Entity ID             │ State │
├──────────────────────────────────┼───────┤
│ binary_sensor.hoymiles_reachable │ off   │
├──────────────────────────────────┼───────┤
│ binary_sensor.hoymiles_producing │ off   │
└──────────────────────────────────┴───────┘

Diagnosis: The inverter is currently unreachable (reachable = off).
That's why they show "Unavailable" — not wrong entity IDs.
Hoymiles inverters disconnect from the network after sunset.
Historical statistics still work because the data is already 
stored in the HA database.

Claude Code session: diagnosis with binary_sensor.hoymiles_reachable = off

The entity IDs are correct - it’s just nighttime. The inverter is sleeping. But that makes the next problem clear: during the day the dashboard shows live values, at night nothing. The next question:

The entities are unavailable at night because the inverter is offline.
Can you fix it so the cards show the last known value instead of 
"Unavailable"? I want to see what was produced today even at night.

Claude comes up with a clean solution - no workarounds, just Home Assistant native mechanisms:

All set. Here's the summary:

6 input_number helpers (store the last value permanently):
- input_number.hoymiles_yieldday_last_known
- input_number.hoymiles_yieldtotal_last_known
- input_number.hoymiles_ch1_yieldday_last_known to ch4

Automation "hoymiles_save_last_known_value":
- Runs in parallel mode for all 6 sensors simultaneously
- Updates the respective helper as soon as a sensor provides 
  a valid value (not unavailable/unknown)
- Ignores unavailable transitions — the helper retains the last value

The dashboard now shows the input_number helpers instead of 
the direct sensor entities.

The behavior afterwards:

┌────────────────────────────┬──────────────────────────────────────────┐
│         Situation          │                 Display                  │
├────────────────────────────┼──────────────────────────────────────────┤
│ Inverter online (daytime)  │ Live value, updated continuously         │
├────────────────────────────┼──────────────────────────────────────────┤
│ Inverter offline (night)   │ Last value before shutdown               │
├────────────────────────────┼──────────────────────────────────────────┤
│ HA restart                 │ Value remains (input_number is persistent)│
└────────────────────────────┴──────────────────────────────────────────┘

What happened here is more than a dashboard fix: Claude diagnosed the problem itself, created six helper entities, wrote an automation with parallel mode, and updated the dashboard. All without a YAML editor, without the automations assistant, without manually creating helpers via the UI.

That’s the true character of this combination: no single tool is revolutionary, but the conversation as a unit of work - recognize the problem, solve it, refine it, all in context - that’s new.

Finished "Balcony PV" dashboard in HA with actual values from input_number helpers

Bonus: Dashboard Redesign in Plan Mode

Bubble Cards work, but I’m not entirely happy with the aesthetics. So: ask again.

okay this is already seeeeery cool. I'm not happy with the looks 
can you make it more visually appealing? It doesn't have to use 
Bubble Cards.

Instead of jumping straight in, Claude Code activates Plan Mode here - and that deserves its own screenshot. Claude first inventories the available custom cards in the HA instance (Mushroom v5.0.12, layout-card v2.4.7, native statistics-graph), pulls the actual current data values as design reference, and restructures the dashboard into three sections:

Claude Code Plan Mode: dashboard redesign with Mushroom Cards, 3 sections and entity mapping

The plan shows a well-thought-out structure - daily overview with two Mushroom template cards side by side, a 14-day statistics bar chart for production trend, and the four panel cards in a 2×2 grid. Bonus: a badge on the daily yield card that subtly hints at the inverter’s offline status when binary_sensor.hoymiles_reachable = off. The problem from before, elegantly packaged as a feature.

After confirming the plan, Claude implements the YAML directly:

Redesigned Balcony PV dashboard with Mushroom Cards, statistics chart, and panel grid

Ideas: What Else You Can Do With It

The PV example is just the beginning. Ha-mcp has 97 tools - here are a few use cases that can be implemented immediately:

Create automations by voice. “Create an automation that notifies me when the balcony PV produces more than 100W and the dishwasher is off - then it should start automatically.” Claude knows HA automation syntax and writes it directly into the config.

Troubleshooting. “My hallway motion sensor automation isn’t triggering at night. Look at the recent automation traces and tell me why.” Claude calls ha_get_automation_traces and analyzes the trace logs - that often saves 20 minutes of manual debugging.

Energy planning. “Which devices consume the most power during the day? Are there patterns where I could use my PV production better?” With access to history and statistics, Claude can make real optimization suggestions.

Rename and organize devices. After a long installation phase with 40 entities with cryptic names sleeping in HA, “Rename all entities starting with ‘zigbee2mqtt_’ to readable names” is much more pleasant work than manually clicking through.

Scripts for routines. “Create a script called ‘End of Workday’ that: turns off all office lights, sets heating to 21°C, opens the shutters, and sends me a notification.” One prompt, done.

Dashboard iteration. Dashboards in HA are traditionally time-consuming. With Claude as YAML generator, it becomes a conversation: start with a basic structure, then refine, then add cards - and it all lands directly in HA without manual editing.

Conclusion

The ha-mcp Server is one of the most useful things I’ve integrated into my Home Assistant setup lately. Not because it enables things that were previously impossible - HA could always do everything I now use Claude for. But the friction is gone. Analyzing historical data, building dashboards, writing automations: everything now happens in a natural conversational flow instead of in YAML editors and documentation pages.

The stdio vs. HTTP setup takes five minutes, the Hoymiles queries worked right away, and the dashboard was done in a single prompt. For anyone seriously using Home Assistant and already using Claude Code, ha-mcp is a no-brainer.


All entity names used are based on the OpenDTU integration for Hoymiles inverters. Exact names may vary slightly depending on the integration version.