FAQ & Troubleshooting

Common questions and solutions for ha-mcp setup.

General Questions

Do I need a Claude Pro subscription?

No. Claude Desktop works with a free Claude account. The MCP integration is available to all users, though free accounts have usage limits.

You can also use ha-mcp with other AI clients. See the Setup Wizard for 15+ supported clients.

Do I need the Home Assistant App?

No. The HA app is just one installation method. Most users run ha-mcp directly on their computer using uvx (recommended for Claude Desktop). To run ha-mcp inside Home Assistant itself, you can install it as the app (Home Assistant OS / Supervised) or via the HA-MCP custom component's in-process server, which works on every installation type.

If you do run the app, you don't also need uvx — that would be a second, separate instance. HTTP-native clients (Codex, Cursor, Windsurf, Claude Code) connect straight to the app's URL, no proxy needed. One caveat: as of early 2026, Codex's HTTP MCP support has a known initialization bug where it loads no tools; if you hit that, run ha-mcp locally over stdio with uvx instead.

Don't run both for the same client. If you switch to the app, remove any local/stdio entry from your client config — a Claude Desktop server running uvx ha-mcp@latest with HOMEASSISTANT_URL / HOMEASSISTANT_TOKEN is the local version and bypasses the app entirely. Pointing both at the same Home Assistant can leave the connection wedged until you restart. The app's Claude Desktop config uses uvx fastmcp-remote with the app's URL and no token.

What's the difference between ha-mcp and Home Assistant's built-in MCP?

FeatureBuilt-in HA MCPha-mcp
Tools~15 basic tools80+ comprehensive tools
FocusDevice controlFull system administration
AutomationsLimitedCreate, edit, debug, trace
DashboardsNoFull dashboard management
CamerasNoScreenshot and analysis

Built-in = operate devices. ha-mcp = administer your system.

How do I open the ha-mcp settings page?

ha-mcp ships a web settings page where you can enable, disable, and pin individual MCP tools, toggle feature flags and advanced (beta) settings, manage automatic backups, and review tool-approval requests. How you reach it depends on how ha-mcp is running:

  • Claude Desktop / Claude Code / any stdio install (uvx ha-mcp): a localhost settings server spawns automatically alongside the MCP process. The easiest way to find the URL is to ask the AI something like "how do I open the ha-mcp settings page?" — the URL is included in ha_get_overview's response. You can also read it directly from ~/.ha-mcp/ui.url (Windows: %USERPROFILE%\.ha-mcp\ui.url). The URL is bound to 127.0.0.1 only and gated by a random secret path generated when the settings server starts.
  • HA Custom Component (in-process server): open the admin-only HA-MCP panel in the Home Assistant sidebar — it serves the settings page through Home Assistant itself, no URL or secret needed.
  • HA App: easiest is the "Open Web UI" button on the app page (served over Home Assistant ingress — no secret needed). For direct or remote access outside the HA UI, the page lives behind the app's secret path: http://<home-assistant-ip>:9583/<secret-path>/settings. Find <secret-path> in the app's Configuration tab ("Secret path override") or in /data/secret_path.txt. The bare :9583/settings without the secret path is rejected for non-ingress callers.
  • ha-mcp-web / Docker (HTTP): append /settings to your MCP secret-path URL. The default MCP_SECRET_PATH is /mcp, so the page is at http://<host>:8086/mcp/settings; if you set a custom secret path, use that instead (e.g. http://<host>:8086/private_xxx/settings).
  • Remote (Cloudflare Tunnel / reverse proxy): same as Docker/HTTP — the page sits under your secret path wherever the MCP endpoint is reachable, e.g. https://<your-host>/<secret-path>/settings.

Changes apply on the next MCP-server restart. To stop the stdio sidecar entirely, click the "Permanently disable settings server" button on the page, set HA_MCP_DISABLE_SETTINGS_UI=1 in your MCP client config, or create an empty ~/.ha-mcp/settings_ui_disabled file.

My settings reset every time I re-create the Docker container

ha-mcp stores its tool configuration, feature flags, backup settings and OAuth client registrations under ~/.ha-mcp — which is /home/mcpuser/.ha-mcp inside the container. That lives in the container's writable layer, so it disappears whenever the container is replaced (docker rm, docker compose down, pulling a new image, or any --rm run). Mount a volume there to keep it:

docker run -d --name ha-mcp -p 8086:8086 \
  -v ha-mcp-data:/home/mcpuser/.ha-mcp \
  -e HOMEASSISTANT_URL=http://homeassistant.local:8123 \
  -e HOMEASSISTANT_TOKEN=your_token \
  ghcr.io/homeassistant-ai/ha-mcp:latest ha-mcp-web

Or in compose:

services:
  ha-mcp:
    volumes:
      - ha-mcp-data:/home/mcpuser/.ha-mcp

volumes:
  ha-mcp-data:
    name: ha-mcp-data

Keep the name: line — without it Compose creates <project>_ha-mcp-data instead, which is not the volume the docker run command above or the docker volume rm below refer to.

A volume mount stays writable even with read_only: true, so keep it when you harden the container — without it ha-mcp can't write to ~/.ha-mcp under a read-only root filesystem and falls back to a temporary directory that's wiped on every restart. To store the data elsewhere, mount your own path and set HA_MCP_CONFIG_DIR to it. This doesn't apply to the HA App (add-on) or the custom component, which persist to Home Assistant's own storage automatically.

Whatever you mount must be writable by the UID the container actually runs as. A named volume is initialised as UID 999 (the image's mcpuser) and needs nothing further; a host bind mount needs chown 999:999 first; and if you run with --user to override the UID, chown the mounted directory to that UID instead — a named volume stays owned by 999 and the overridden user can't write to it. If ha-mcp still can't persist, it says so at startup — look for "Cannot write ha-mcp data to ... data will NOT persist across restarts" in docker logs ha-mcp. A volume created by an older image can be left owned by root; docker volume rm ha-mcp-data and let the current image recreate it.

Try Without Your Own Home Assistant

Want to test before connecting to your own Home Assistant? Use our public demo:

URLhttps://ha-mcp-demo-server.qc-h.net
Tokendemo
Web UILogin with mcp / mcp

The demo environment resets weekly. Your changes won't persist.

Troubleshooting

OAuth stopped working after upgrading to v7.0.0

v7.0.0 removed the Home Assistant URL field from the OAuth consent form to fix security vulnerabilities (SSRF and XSS). Set HOMEASSISTANT_URL as a server-side environment variable before starting ha-mcp.

# Docker
docker run -d -p 8086:8086 \
  -v ha-mcp-data:/home/mcpuser/.ha-mcp \
  -e HOMEASSISTANT_URL=https://your-ha-instance.example.com \
  -e MCP_BASE_URL=https://your-mcp-server.example.com \
  ghcr.io/homeassistant-ai/ha-mcp:latest ha-mcp-oauth

# uvx
HOMEASSISTANT_URL=https://your-ha-instance.example.com \
MCP_BASE_URL=https://your-mcp-server.example.com \
uvx --from=ha-mcp@latest ha-mcp-oauth

The consent form now accepts only the token. See the full migration guide for details.

macOS: "All connection attempts failed" to local Home Assistant

If ha-mcp connects to the demo server but fails to reach your local Home Assistant (192.168.x.x, 10.x.x.x, etc.) on macOS, check the following. See #867 (Local Network Privacy), #630 (env vars), #773 (Python version) for related reports.

1. macOS Local Network Privacy (Sequoia 15+)

macOS Sequoia silently blocks subprocess connections to local network IPs. Claude Desktop spawns uvx as a child process, and macOS may block its outbound LAN connections without showing a permission dialog.

  • Check System Settings → Privacy & Security → Local Network for Claude Desktop
  • If Claude Desktop is not listed, try restarting it to trigger the permission prompt

Workaround — SSH tunnel to localhost:

macOS does not restrict connections to localhost, so an SSH port forward bypasses the restriction:

ssh -N -L 8123:localhost:8123 user@your-ha-server-ip

Then set HOMEASSISTANT_URL to http://localhost:8123 in your config.

2. Firewall software (Little Snitch, Lulu, etc.)

Third-party firewalls may block python or node processes spawned by Claude Desktop. Check your firewall rules and allow connections for these processes. See #780 for an example resolution.

3. http:// vs https://

Home Assistant running in container mode (Docker, K3s) uses HTTP by default. Using https:// causes a TLS handshake error. Use http:// unless you have explicitly configured SSL/TLS or a reverse proxy.

4. Python version too old

ha-mcp requires Python 3.13+. If you are on Python 3.12 or older, uvx installs an outdated version with known bugs (including read-only filesystem errors). Upgrade Python:

brew install python@3.13

Then force a refresh:

uvx --refresh ha-mcp@latest

If uvx still uses the old Python after installing 3.13, explicitly pin it by adding --python 3.13 to your config args:

"args": ["--python", "3.13", "ha-mcp@latest"]

SSL certificate errors (self-signed certificates)

If your Home Assistant uses HTTPS with a self-signed certificate or custom CA, you may see SSL verification errors.

Docker solution:

  1. Create a combined CA bundle:
    cat $(python3 -m certifi) /path/to/your-ca.crt > combined-ca-bundle.crt
  2. Mount it and set SSL_CERT_FILE:
    docker run --rm \
      -e SSL_CERT_FILE=/certs/ca-bundle.crt \
      -v ./combined-ca-bundle.crt:/certs/ca-bundle.crt:ro \
      ...

mcp-proxy fails with ImportError: cannot import name 'request_ctx'

A previously working uvx mcp-proxy config stops connecting and the client shows "Server disconnected". Running the command by hand shows:

from mcp.server.lowlevel.server import request_ctx
ImportError: cannot import name 'request_ctx' from 'mcp.server.lowlevel.server'

Cause: the mcp SDK released version 2.0.0, which removed request_ctx. mcp-proxy depends on mcp without an upper version bound, so uvx installs the incompatible 2.x release. Clearing the uv cache does not help — a fresh install picks the same version.

This only affected clients that reached an HTTP ha-mcp deployment through the mcp-proxy bridge (Claude Desktop and JetBrains, when this FAQ entry was written). The local stdio setup — uvx ha-mcp@latest — is unaffected, and so are the add-on, Docker, and the custom component themselves: ha-mcp already pins the SDK below 2.0.

If your client is JetBrains: drop the bridge entirely rather than switching bridges. JetBrains IDEs support Streamable HTTP natively via the MCP Servers panel. The Setup Wizard now generates a plain {"mcpServers": {"home-assistant": {"url": "..."}}} entry with no command/args at all. The fastmcp-remote fix below still applies to Claude Desktop and other stdio-only clients.

Fix (Claude Desktop and other stdio-only clients): switch the bridge to fastmcp-remote, the stdio bridge published by the FastMCP project. It pins its dependency on the MCP SDK to a bounded range, so an SDK release cannot break it the way it broke mcp-proxy. Replace the whole server entry with:

{
  "mcpServers": {
    "home-assistant": {
      "command": "uvx",
      "args": [
        "fastmcp-remote",
        "http://192.168.1.100:9583/private_your_secret_path"
      ]
    }
  }
}

Keep your own connect URL. No --transport flag is needed: fastmcp-remote defaults to Streamable HTTP, which is what ha-mcp serves. Restart the client after saving (Claude Desktop: File → Exit, then reopen; closing the window is not enough). The Setup Wizard generates this config for stdio-only clients.

Prefer to stay on mcp-proxy? Adding "--with", "mcp<2.0.0" to its args also works. --with is a global uv option, so it must come before the package name. That pin has to be revisited on the next SDK major; switching bridges does not. See #2073.

uvx fails with invalid peer certificate: UnknownIssuer

If uvx can't download ha-mcp (or fastmcp-remote, if you connect to the app through it) and the log shows a certificate error fetching from PyPI, the failure is in uv's package download — it never reaches Home Assistant:

Failed to fetch: https://pypi.org/simple/ha-mcp/
  invalid peer certificate: UnknownIssuer

In Claude Desktop this often shows up as the server briefly connecting, then "transport closed unexpectedly" — uvx exits when it can't fetch the package.

Cause: uv (which backs uvx) ships its own bundled root-certificate store and ignores the operating-system certificate store by default. If anything on your machine intercepts HTTPS — a corporate proxy, Zscaler, or antivirus with HTTPS/SSL scanning (Kaspersky, ESET, Bitdefender, etc.) — it presents a certificate chained to a root your OS trusts but uv's bundled store does not, producing UnknownIssuer. This is most common on Windows.

Fix: point uv at the OS native certificate store by adding UV_NATIVE_TLS=1 to the server's env block:

{
  "mcpServers": {
    "Home Assistant": {
      "command": "uvx",
      "args": ["ha-mcp@latest"],
      "env": {
        "HOMEASSISTANT_URL": "http://homeassistant.local:8123",
        "HOMEASSISTANT_TOKEN": "your_long_lived_token",
        "UV_NATIVE_TLS": "1"
      }
    }
  }
}

Connecting to the HA app through uvx fastmcp-remote instead? Add the same UV_NATIVE_TLS=1 entry to that config's env block. The equivalent --native-tls flag also works, but it is a global uv option, so it must come before the package name. See #1506.

"uvx not found" error

After installing uv, restart your terminal (or Claude Desktop) for the PATH changes to take effect.

Mac:

# Reload shell or restart terminal
source ~/.zshrc
# Or verify with full path
~/.local/bin/uvx --version

Windows:

# Restart PowerShell/cmd after installing uv
# Or use full path
%USERPROFILE%\.local\bin\uvx.exe --version

Claude Desktop note: Claude Desktop does not inherit your shell's PATH. If uvx is not found even after restarting, use the absolute path in your config instead of uvx. Find it with which uvx in your terminal, then set "command": "/Users/<you>/.local/bin/uvx" (macOS/Linux) or the equivalent Windows path.

MCP server not showing in Claude Desktop

  1. Restart Claude completely - Use Cmd+Q (Mac) or Alt+F4 (Windows), not just close the window
  2. Check config file location:
    • Mac: ~/Library/Application Support/Claude/claude_desktop_config.json
    • Windows (traditional installer): %APPDATA%\Claude\claude_desktop_config.json
    • Windows (Microsoft Store): path varies by package — see the Windows setup guide for a detection snippet
  3. Verify JSON syntax - No trailing commas, proper quotes
  4. Check the MCP icon - Bottom left of Claude Desktop shows connected servers

"Token invalid" or authentication errors

  1. Generate a new token:
    • Home Assistant → Click your username (bottom left)
    • Security tab → Long-lived access tokens
    • Create Token → Copy immediately (shown only once)
  2. Check token format - Don't wrap the token in quotes in your config
  3. Token expiration - Tokens don't expire by default, but can be revoked

Claude says it can't see Home Assistant

  1. Open Claude Desktop Settings (gear icon)
  2. Go to the Developer tab
  3. Check Local MCP Servers for any errors
  4. If "Home Assistant" is not listed, check your config file syntax
  5. Try asking Claude: "Can you list your available tools?"

Can't connect remotely? Try the Webhook Proxy app

Using the HA-MCP custom component's in-process server? Remote access is built in — its webhook connect URL already works through Nabu Casa or any reverse proxy pointed at Home Assistant, so you don't need the Webhook Proxy app. The rest of this answer applies to the app (add-on), Docker, and pip installs.

If you're having trouble setting up remote access — TLS errors, Cloudflare configuration issues, or port forwarding problems — the Webhook Proxy app may be a simpler alternative.

Instead of requiring a dedicated tunnel to port 9583, the Webhook Proxy routes MCP traffic through Home Assistant's main port (8123) via a webhook. If you already have Nabu Casa or any reverse proxy pointing at your HA instance, this can be the easiest remote setup.

  1. Install the MCP Server app and the Webhook Proxy app from the app store
  2. Start the webhook proxy and restart Home Assistant when prompted
  3. Copy the webhook URL from the app logs
  4. Use that URL in your MCP client configuration

See #784 for an example where this resolved a TLS connection issue.

Webhook Proxy: securing the URL

By default the Webhook Proxy app registers an unauthenticated webhook endpoint. The webhook URL itself is the shared secret — anyone with the full URL can reach your MCP server, which exposes powerful Home Assistant control. Treat the URL like a password.

Don't share the URL

  • Avoid pasting it into screenshots, log paste-bins, public configs, or chat transcripts.
  • Mask the part after /api/webhook/ if you have to share anything.
  • Anyone with the full URL can call your MCP tools.

Rotating the URL if it leaks

  1. Stop the Webhook Proxy app.
  2. Delete /data/webhook_id.txt from the app's filesystem (e.g. via SSH/Terminal app).
  3. Start the app. A new webhook ID and URL are generated on first launch.
  4. Copy the new URL from the app logs into your MCP client(s). The old URL stops working immediately.

Reinstalling the app also changes the URL. Uninstalling wipes the app's /data (where webhook_id.txt lives), so the next start generates a fresh webhook ID and overwrites /config/.mcp_proxy_config.json with it. Update your MCP client — and re-add the Claude.ai connector — with the new URL afterwards.

Optional: Enable OAuth (Beta)

For a real auth layer on top of the URL secret, the Webhook Proxy app (v1.1.0 and later) ships an optional OAuth 2.1 mode. Toggle Show unused optional configuration options, turn Enable OAuth (Beta) on, leave Client ID and Client Secret blank, and restart the app. The app generates a strong Client ID and Client Secret on first start, persists them at /data/oauth_creds.json, and prints them in the app log.

In Claude.ai, expand the connector's Advanced settings when adding it and paste the Client ID and Client Secret from the app log into the OAuth fields. Claude.ai handles the rest of the OAuth handshake automatically. When the toggle is off, the webhook URL behaves exactly as before with no auth check.

OAuth flow end-to-end

  1. Claude.ai redirects your browser to https://<host>/authorize?... with PKCE parameters.
  2. The app serves a consent page showing the redirect destination — verify it's Claude.ai's callback URL.
  3. Click Allow. The app issues a one-time auth code and redirects back to Claude.ai.
  4. Claude.ai exchanges the code at https://<host>/token using your Client ID + Client Secret + the PKCE verifier. The app returns a 1-hour access token and a 30-day refresh token, both HMAC-signed.
  5. From then on Claude.ai sends every MCP request with Authorization: Bearer <token>; expired access tokens are refreshed automatically.

The Client Secret is the real security boundary

The /authorize consent page is reachable without being logged into Home Assistant or Nabu Casa — that's how OAuth works (the consent page must be reachable from the OAuth client's browser session). What stops an attacker who clicks "Allow" on a phishing authorize URL: the resulting auth code is bound to PKCE and useless without your OAuth Client Secret at the token endpoint. So the Client Secret is the actual gate, not the consent page.

Treat the Client Secret like a password. Don't paste it into screenshots, support threads, or public configs. If you suspect it has leaked — or want a clean slate after sharing logs for debugging — rotate it immediately. After rotation, any tokens issued under the old credentials stop refreshing, forcing the client to redo OAuth.

Rotating OAuth credentials

  • From the app UI (recommended): turn on Regenerate OAuth Credentials on Next Start, save, restart the app. The app wipes the stored credentials, generates fresh ones, prints them in the log, and auto-clears the regenerate toggle. Update your MCP client to match. Takes ~30 seconds.
  • Custom values: type new strings into the Client ID and Client Secret fields and restart — your values override the stored file.
  • Filesystem: stop the app, delete /data/oauth_creds.json, start the app. Equivalent to the UI option but requires SSH/Terminal access.

Getting "Invalid client id" — or OAuth/credential changes not taking effect

The OAuth provider's HTTP views are bound into Home Assistant's HTTP layer when the integration first loads, and HA can't re-register or drop them on a config reload (the webhook endpoint itself re-registers on reload — it's specifically the OAuth views). So toggling OAuth on/off, regenerating credentials, or reinstalling the app only takes effect after a full Home Assistant restart (Settings → System → Restart) — reloading the integration or restarting the app is not enough. After restarting, delete and re-add the Claude.ai connector with the current URL (and current Client ID/Secret, if OAuth is on).

Beta status: the OAuth flow is built against the MCP 2025-06-18 spec and tested with Claude.ai. Other clients' OAuth coverage may vary. Report issues on GitHub.

ChatGPT behind a firewall? Try the community OpenAI Tunnel integration

ChatGPT connectors require a URL reachable from the public internet. If your Home Assistant sits behind a firewall or CGNAT and you don't want to expose it, the community-maintained OpenAI Tunnel for HA-MCP integration by @norpol is an outbound-only alternative:

  • It downloads, verifies, and supervises OpenAI's tunnel-client as a Home Assistant subprocess (installed as a HACS custom repository; Linux amd64/aarch64 on HA OS / Supervised initially).
  • The client connects your MCP server URL to an OpenAI-hosted tunnel, so ChatGPT, Codex, and other OpenAI products can reach it — no port forwarding, reverse proxy, or public URL needed.
  • Create a tunnel on the Tunnels page and a runtime API key with Tunnels Read and Tunnels Use permissions on the API keys page, point the integration at your local ha-mcp URL, and add the ChatGPT connector using the same tunnel ID.

See the integration's README for full setup and #1811 for background. This is a third-party project — report tunnel issues on its tracker, not here.

ChatGPT doesn't show new or newly enabled tools (stale tool list)

ChatGPT (web, including Codex Work Mode) caches a connector's tool list and sometimes keeps serving the stale list even after you enable new tools on the server, restart it, and remove and re-add the connector under the same name. Newly enabled tools (for example the beta filesystem/YAML tools) simply never appear in ChatGPT's tool list, even though the server logs show them registered — and other tools on the stale connection may fail with MCP internal errors.

Solution: delete the connector and create a new one with a different name — ChatGPT then fetches a fresh tool list. Re-adding it under the original name is not enough; the cached list survives the re-add.

Server works but responses are slow

  1. First request is slow - uvx downloads packages on first run
  2. Subsequent requests - Should be faster (packages cached)
  3. Alternative - Use Docker for consistent performance

Antigravity client troubleshooting

  • "Unexpected server output" error: Add FASTMCP_SHOW_SERVER_BANNER=false to your stdio env config. This disables the startup banner that Antigravity misinterprets as unexpected output.
  • "EOF" errors: Use absolute paths for the command, not relative paths.
  • First run timeout: Run uvx ha-mcp@latest --version in your terminal first to download and cache the package before Antigravity tries to start it.
  • Tools load but fail when called: Try switching to stdio mode instead of HTTP. HTTP mode can experience "connection closed" or reconnection errors with this client.
  • Connection issues after config changes: Restart the Agent session in Antigravity after saving any config changes.

Claude.ai connection issues

If tools stop responding or the connector appears disconnected in Claude.ai:

  1. Restart both Claude.ai and the MCP server. Refresh the Claude.ai page in your browser and restart the ha-mcp process (or Docker container). Either side can hold stale connection state. An intermittent connect failure is usually a transient tunnel/relay hiccup, so a restart and retry often clears it.
  2. A 405 Method Not Allowed on a GET in your ha-mcp logs is normal and not the cause of a failed connect. Claude.ai pre-flights with a GET and the Streamable HTTP MCP endpoint only accepts POST (and DELETE), not GET, so a 405 shows up even on a successful connection (the log annotates it NORMAL for most non-SSE connections).
  3. Check that your tunnel (Cloudflare, ngrok, etc.) is still running and the URL has not changed.
  4. Verify the server is reachable by visiting the MCP URL directly in your browser — you should see a response from the server (with OAuth enabled on the webhook proxy, an Unauthorized response is expected and correct).
  5. Reachability from Anthropic's servers: Claude.ai connects from the cloud, not your network — a URL that works in Claude Code or your browser (both on your LAN) can still be unreachable for Claude.ai web. Open the URL on your phone with Wi-Fi off; if it doesn't load, it isn't publicly reachable and Claude.ai can't reach it either.
  6. Don't forget to click Connect on the connector — and, with OAuth enabled, click Allow on the consent page. Adding the connector alone does not complete the connection.
  7. URL works in your browser but the LLM can't connect? Your reverse proxy is filtering the AI client — see Cloudflare: LLM can't connect below (Cloudflare's "Block AI training bots" and geo/country blocking are the usual causes).
  8. Tailscale Funnel: use port 443. Funnel can also serve on the alternate HTTPS ports it offers (8443, 10000), but Claude.ai's connector backend does not reliably reach non-standard ports — the connection fails identically in every auth mode and no request from Anthropic's range (160.79.104.0/21) ever reaches the server. The official Tailscale add-on's "Share Home Assistant with Serve or Funnel" option already exposes Home Assistant on 443 — use that hostname in the connector URL (same webhook path). See #2080.

Cloudflare: LLM can't connect ("Block AI training bots" / geo-blocking)

If you're using Cloudflare and your LLM client can't connect to the MCP server (but visiting the URL in your browser works), Cloudflare's "Block AI training bots" setting is almost certainly the cause. This is the most common connection issue for Cloudflare users. To disable it:

  1. Log in to Cloudflare
  2. In the left sidebar, click Domains, then Overview
  3. Click on the domain you use for connecting to Home Assistant
  4. On the right side of the page, find "Control AI Crawlers"
  5. Under "Block AI training bots", open the dropdown
  6. Select "do not block (allow crawlers)"

Screenshot of the setting — see #783 for more details.

Also check geo / country blocking. This applies to Cloudflare (WAF custom rules) and to any other reverse proxy (NGINX, Traefik, Zoraxy, etc.). Most AI/LLM services connect from US-based cloud infrastructure, so if you block US IP addresses (or only allow your own country), your client cannot connect even with AI-bot blocking disabled. Allow your AI provider's IP ranges — Claude.ai connects from Anthropic's network, 160.79.104.0/21 (see Anthropic's IP ranges). Your proxy's access logs will show the blocked attempts.

Google Gemini Spark: only "legacy" OAuth mode works (for now)

Gemini Spark's custom connected apps are OAuth-only, and they authenticate using a cross-origin redirect URI (a Client ID Metadata Document). Home Assistant core's native OAuth provider doesn't fetch these yet, so it rejects Spark's authorization request with "Invalid redirect URI" — see home-assistant/core#176282 (fix pending in #176286).

Until that's fixed upstream, legacy is the only OAuth mode that works with Spark. It's a self-hosted authorization server built into the HA-MCP Server component, with a static Client ID and Client Secret you paste into Spark's Advanced settings instead of relying on Home Assistant's native OAuth flow. See the Setup Wizard and pick Gemini Spark for the full walkthrough.

Once the core fix lands, this page will be updated to recommend Home Assistant's native OAuth mode for Spark instead.

Copilot CLI: remote OAuth requires legacy mode

Copilot CLI's remote MCP setup requires an OAuth Client ID — its /mcp add form won't accept a blank field — and it tries to get one via dynamic client registration. Home Assistant's default ha_auth mode doesn't advertise a registration endpoint, so that registration fails (MCPOAuthError: Failed to register OAuth client). ha_auth does not work with Copilot CLI.

The fix: in the HA-MCP Server integration's Options, set Authentication mode to legacy and restart Home Assistant when the repair prompts you. Copy the generated Client ID and Client Secret from the Options page (also printed in the Home Assistant log) into Copilot CLI's required Client ID field and its secret field.

This is the same self-hosted authorization path used for Google Gemini Spark, which currently requires it too.

Test ha-mcp without configuring a client

Before setting up a client, you can run a quick smoke test against the public demo server to confirm uvx is installed and ha-mcp launches correctly:

HOMEASSISTANT_URL=https://ha-mcp-demo-server.qc-h.net HOMEASSISTANT_TOKEN=demo uvx ha-mcp@latest

This starts ha-mcp in stdio mode connected to the public demo Home Assistant instance. Press Ctrl+C to stop. If it launches without errors, your environment is ready — replace the URL and token with your own values to connect to your Home Assistant.

Keep ha-mcp-web running in the background

To run the ha-mcp HTTP server detached from the terminal so it survives logout:

nohup uvx --from ha-mcp@latest ha-mcp-web > /dev/null 2>&1 &

nohup detaches the process from the terminal and redirects output to /dev/null. The trailing & sends it to the background. For more robust setups (auto-restart on crash, start on boot), use systemd or the Home Assistant app instead.

Docker: changing the port requires updating both places

When running ha-mcp-web in Docker, the port is set in two independent places and they must match:

  • The second number in -p HOST:CONTAINER — this is the container-side port Docker listens on
  • The MCP_PORT environment variable — this is the port ha-mcp binds inside the container

If these differ, the container starts but requests never reach the server. Example using port 9000:

docker run -d --name ha-mcp \
  -p 9000:9000 \
  -v ha-mcp-data:/home/mcpuser/.ha-mcp \
  -e HOMEASSISTANT_URL=http://homeassistant.local:8123 \
  -e HOMEASSISTANT_TOKEN=your_token \
  -e MCP_PORT=9000 \
  ghcr.io/homeassistant-ai/ha-mcp:latest \
  ha-mcp-web

The first number in -p (the host port) can be anything — only the second number must match MCP_PORT.

Custom Component (ha_mcp_tools)

The HA-MCP Custom Component (ha_mcp_tools) has two config-entry types under one integration: the File & YAML services entry (HA-MCP File & YAML Tools) adds the privileged file and YAML-configuration services described below, and the HA-MCP Server entry runs the full ha-mcp server in-process inside Home Assistant — now the recommended way to install ha-mcp, working on every Home Assistant installation type (HAOS, Supervised, Container, Core). The HA-MCP Server entry is a complete, standalone install that replaces the add-on, Docker, and uvx/stdio methods — run only one ha-mcp server, never two side by side. See the in-process server guide for the full walkthrough.

What is the custom component and why do I need it?

Some tools require a companion custom component installed in Home Assistant. Standard HA APIs do not expose file system access or YAML config editing. This component provides both.

Tools that require the component:

  • ha_config_set_yaml — Safely add, replace, or remove top-level YAML keys in configuration.yaml and package files (automatic backup, validation, and config check)
  • ha_list_files — List files in allowed directories (www/, themes/, custom_templates/)
  • ha_read_file — Read files from allowed paths (config YAML, logs, www/, themes/, custom_templates/, custom_components/)
  • ha_write_file — Write files to allowed directories
  • ha_delete_file — Delete files from allowed directories

All other tools work without the component. These five return an error with installation instructions if the component is missing.

How do I install it?

Using HACS (recommended):

Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.

To add manually: open HACS > Integrations > three-dot menu > Custom repositories > add https://github.com/homeassistant-ai/ha-mcp-integration (category: Integration) > Download.

After installing, restart Home Assistant. Then open Settings > Devices & Services > Add Integration and search for HA-MCP Custom Component, then pick the entry type: HA-MCP Server (the in-process server — the recommended install) or HA-MCP File & YAML Tools (the file/YAML services described above).

Manual install: Copy custom_components/ha_mcp_tools/ from the repository into your HA config's custom_components/ directory. Restart Home Assistant, then add the integration as described above.

Do I also need to enable feature flags?

Yes. The component is required, but the tools are also gated by feature flags for safety:

VariableEnables
HAMCP_ENABLE_FILESYSTEM_TOOLS=trueha_list_files, ha_read_file, ha_write_file, ha_delete_file
ENABLE_YAML_CONFIG_EDITING=trueha_config_set_yaml

The component itself is installed through HACS — add homeassistant-ai/ha-mcp-integration as a custom repository (no feature flag required). An AI agent can drive that install with the generic HACS tools; then add the HA-MCP File & YAML Tools entry from Settings > Devices & Services > Add Integration.

Do I still need the add-on or the webhook proxy if I use the custom component?

No. The custom component's HA-MCP Server entry runs the whole ha-mcp server inside Home Assistant and is completely independent of the Home Assistant App add-on. For remote access it registers its own built-in Home Assistant webhook, so you do not need the separate Webhook Proxy app either.

The add-on remains a fully supported alternative on Home Assistant OS and Supervised — pick whichever install you prefer; you never need to run both.

Configuration Options

Environment Variables

VariableDescriptionRequired
HOMEASSISTANT_URLYour Home Assistant URLYes
HOMEASSISTANT_TOKENLong-lived access token (or demo)Yes
BACKUP_HINTBackup recommendation levelNo
HA_MCP_DISABLE_SETTINGS_UISet to 1 to skip the localhost settings-page sidecar that stdio installs spawn by default (details).No

Backup Hint Modes

ModeBehavior
strongSuggests backup before first modification each day/session
normalSuggests backup only before irreversible operations (recommended)
weakRarely suggests backups
autoSame as normal (future: auto-detection)

Feedback & Help

We'd love to hear how you're using ha-mcp!

Ready to get started? Go to Setup Wizard