MCP-HA-Connect

A production-ready Model Context Protocol (MCP) server for Home Assistant integration with AI assistants like Claude.

Documentation

MCP-HA-Connect

A production-ready Model Context Protocol (MCP) server for Home Assistant integration with AI assistants like Claude and LM Studio.

npm version Docker Discord

See docs/QUICK_START.md for Docker, HTTP server mode, n8n integration, and more installation options.

Key Features

Core Functionality

  • Smart Device Control
  • Lights: Brightness, color temperature, RGB color, transitions
  • Climate: Temperature, HVAC modes, fan modes, humidity
  • Covers: Position and tilt control
  • Switches: On/off control
  • Sensors & Contacts: State monitoring
  • Media Players: Playback control, volume, source selection
  • Fans: Speed, oscillation, direction
  • Locks: Lock/unlock control
  • Vacuums: Start, stop, return to base
  • Cameras: Motion detection, snapshots

Automation Management

  • List all automations with status
  • Trigger automations manually with variables
  • Enable/disable/toggle automations
  • Create new automations via API
  • Delete automations
  • View automation execution traces
  • Reload automations from configuration

System Features

  • Direct Home Assistant API integration
  • Long-lived access token authentication
  • Entity state management
  • Service call support
  • Advanced entity search
  • AI-powered sensor analysis with Ollama
  • Multiple transport modes (stdio, Streamable HTTP)
  • HTTP server with health checks
  • CORS support for browser-based clients
  • Structured logging (plain, JSON, GCP-JSON formats)
  • Comprehensive configuration validation with Zod
  • Full type safety with TypeScript
  • Stateful and stateless session support
  • JWT authentication with role-based access control
  • MCP Server Instructions for improved LLM tool selection

Network Monitoring & Security (TP-Link Omada)

Bring your home network into the same assistant that runs your home. These are the high-value questions an LLM can actually answer about your network:

  • Internet & WAN status — "Is my internet up? What's my WAN IP and uplink speed?" Live per-WAN status, plus multi-WAN / ISP health and load-balancing for the gateway.
  • Event & alert logs — "What happened on my network?" The site event and alert logs, time-windowed (defaults to the last 7 days), to correlate with Home Assistant history.
  • Wireless security — rogue-AP scan results and (on Omada Pro) wireless intrusion detection (WIDS) for genuine network-security awareness.
  • Controller & device health — dashboard overview plus top devices by CPU and memory usage, HA-style monitoring of your network stack.
  • Speed tests — surface the controller's own speed-test results, pairing with AI-powered analyzeSensors for anomaly detection.
  • Pending devices — "Is there a new device waiting to be adopted?"
  • Firmware awareness — per-device firmware info and a controller-wide critical-upgrade overview, mirroring the Home Assistant checkUpdates philosophy across the network.
  • Client management — list/inspect connected clients, traffic activity, and apply rate-limit profiles, with presence correlation against Home Assistant device trackers.

A discoverable resource-graph mode (MCP_TOOL_REGISTRATION_MODE=graph) exposes all of the above through two tools — omada_browse + omada_read — keeping the tool-schema budget small for low-context models. See the Omada tool tables below for the full eager surface.

Available Tools (69 Total)

Home Assistant Tools (38)

State & Entity Tools

ToolDescription
getStatesGet all entity states (paginated, 50/page default). Use includeAttributes=true for full data
getStateGet the state of a specific entity by entity_id
getEntitiesByDomainGet entities for a domain (paginated, 50/page default). Use includeAttributes=true for full data
searchEntitiesSearch entities by name/entity_id (paginated, 50/page default). Use includeAttributes=true for full data
getAllSensorsGet all sensors (paginated, 50/page default). Use includeAttributes=true for full data
listEntitiesList entities with filtering (domain, state, search, limit). Use includeAttributes=true for full data
getDomainSummaryGet summary statistics for a domain
getHistoryGet historical data for an entity
listPersonsList all household members with location state (home/away)

Service & Control Tools

ToolDescription
callServiceCall any Home Assistant service
entityActionSimple turn_on/turn_off/toggle actions

Device Control Tools

ToolDescription
controlLightControl lights with brightness, color, temperature
controlClimateControl thermostats with temperature, HVAC mode
controlMediaPlayerControl media players with playback, volume
controlCoverControl covers/blinds with position, tilt
controlFanControl fans with speed, oscillation, direction
activateSceneActivate a Home Assistant scene
runScriptRun a Home Assistant script
sendNotificationSend notifications with full mobile app support (actions, priority, images)
listNotificationTargetsDiscover available mobile app notification targets

Owner Questions (approval on the phone)

Ask the owner a question as a phone notification with up to 3 buttons and read back the tap. HTTP mode only; needs an admin Home Assistant token (button taps are admin-only events) and MCP_AUTH_SECRET so open questions survive a restart. Everything except an explicit approving answer counts as NO.

ToolDescription
askOwnerSend the question (plain text, max 256 characters; 1-3 buttons, default Approve / Deny; open up to 7 days) and return a requestId at once
getOwnerAnswerWait up to 50 s per call: answered (button index and label, time, HA user), pending, timeout, cancelled or unknown
cancelOwnerQuestionWithdraw an open question; the notification changes to "Cancelled"

Taps are verified with signed button ids and must come from the mobile app (an automation cannot fake one); set MCP_OWNER_QUESTIONS_HA_USERS so only your HA user can answer. Only the client that asked can read the answer; at most 3 open questions and 30 per hour per client.

Known limit: cancellations and answers are kept in memory. After a restart, someone with a Home Assistant login could re-send an old button id through HA's own API and answer a question that had been cancelled or denied (the phone no longer shows its buttons). That access already allows controlling the house directly.

Automation Tools

ToolDescription
listAutomationsList all automations with status
triggerAutomationManually trigger an automation
enableAutomationEnable a disabled automation
disableAutomationDisable an automation
toggleAutomationToggle automation state
reloadAutomationsReload automations from config
createAutomationCreate a new automation
deleteAutomationDelete an automation
getAutomationTraceRecent runs of an automation, newest first: trigger, result, errors (automations with an id only)

System Tools

ToolDescription
getVersionGet Home Assistant version and config info
restartHomeAssistantRestart the Home Assistant server
getSystemLogGet system log entries from logbook
checkUpdatesCheck for available updates

Calendar Tools

ToolDescription
listCalendarsList all calendar entities
getCalendarEventsGet events from one or all calendars

Omada Network Tools (49)

Site Tools

ToolDescription
omada_listSitesList all sites configured on the Omada controller

Device Tools

ToolDescription
omada_listDevicesList all network devices (APs, switches, gateways) in a site
omada_getDeviceGet detailed information about a specific network device
omada_searchDevicesSearch for devices globally across all sites
omada_getSwitchStackDetailGet detailed information about a switch stack
omada_listDevicesStatsGet statistics for global adopted devices with filtering

Client Tools

ToolDescription
omada_listClientsList all connected clients (devices/users) in a site
omada_getClientGet detailed information about a specific connected client
omada_listMostActiveClientsGet the most active clients sorted by total traffic
omada_listClientsActivityGet client activity statistics over time
omada_listClientsPastConnectionsGet historical client connection data

Rate Limit Tools

ToolDescription
omada_getRateLimitProfilesGet available rate limit profiles for a site
omada_setClientRateLimitSet custom bandwidth limits for a client (download/upload in Kbps)
omada_setClientRateLimitProfileApply a rate limit profile to a client
omada_disableClientRateLimitRemove bandwidth limits from a client

Client and Device Actions

ToolDescription
omada_blockClientBlock a client from the network
omada_unblockClientUnblock a previously blocked client (explains when Omada's API can no longer reach an offline client)
omada_listBlockedClientsList blocked clients, offline ones included
omada_deleteClientDelete a client's record (name, history, block) to clear a block unblock can't reach (needs CONFIGURE)
omada_cyclePoePortPower-cycle PoE switch ports (remote-reboots APs/cameras)
omada_setSsidEnabledTurn an SSID (e.g. guest WiFi) on or off by name

Client Diagnosis and MAC Groups

ToolDescription
omada_diagnoseClientExplain why a device (by MAC) can't get on: block state, MAC groups and the SSID allow/deny lists using them, site MAC filter, IP-MAC binding, DHCP reservation, and for ADMIN callers the audit log (detects an orphaned block). Read-only
omada_listMacGroupsList MAC groups with their entries and which SSIDs use them as allow or deny lists (graph mode: omada_read /profiles/mac-groups)
omada_setMacGroupEntryAdd a MAC to a MAC group, or rename its entry (needs CONFIGURE)
omada_removeMacGroupEntryRemove a MAC from a MAC group (needs CONFIGURE)

Access Control (schedules, groups, gateway ACLs)

Lets the controller enforce a schedule itself (e.g. a curfew) instead of a daily block/unblock loop. All writes need CONFIGURE.

ToolDescription
omada_listAccessControlTime ranges (readable windows), IP groups and gateway ACL rules with names and schedules (graph mode: omada_read /profiles/time-range, /profiles/ip-groups, /network/acls/gateway)
omada_createTimeRange / omada_updateTimeRange / omada_deleteTimeRangeWeekly schedules in quarter hours, e.g. {days:["mon","tue"], start:"14:30", end:"19:00"}; invertWindows turns allowed hours into the blocked ones. At most 7 windows per profile (a curfew needs a morning and an evening profile). Delete is refused while a rule uses it
omada_createGroup / omada_deleteGroupIP groups (ACL sources/destinations) and MAC groups (SSID allow/deny lists); delete is refused for built-in groups and groups in use
omada_setDhcpReservation / omada_removeDhcpReservationFixed IP for a device (so an ACL can match it); refuses an address reserved for another device
omada_createGatewayAcl / omada_updateGatewayAcl / omada_deleteGatewayAcl / omada_moveGatewayAclGateway (router) LAN-to-internet rules: allow/deny a source (IP group, LAN network or SSID), optionally only during a time range; covers wired and Wi-Fi
omada_setSsidMacFilterTurn an SSID's MAC filter on (MAC group as allow or deny list) or off; reports and refuses to disconnect connected clients unless allowLockout; dryRun previews

Security Tools

ToolDescription
omada_getThreatListGet security threat management list

Network Configuration Tools

ToolDescription
omada_getInternetInfoGet internet connection configuration for a site
omada_getPortForwardingStatusGet port forwarding rules (User or UPnP)
omada_getLanNetworkListGet LAN network configuration list
omada_getLanProfileListGet LAN profile configuration list
omada_getWlanGroupListGet WLAN group configuration list
omada_getSsidListGet SSID list for a WLAN group
omada_getSsidDetailGet detailed SSID configuration
omada_getFirewallSettingGet firewall configuration for a site
omada_getSiteNtpStatusGet the site's NTP server configuration and status
omada_setSiteNtpServersReplace the site's NTP server list (needs CONFIGURE; dryRun previews the change)

Vendor-neutral Network Tools (9)

The net_ tools describe networks the same way for every controller vendor: one shared model, with an adapter per vendor (TP-Link Omada today; UniFi and MikroTik are planned). Each adapter says per feature whether it is native, built from several objects, or unsupported (net_capabilities), and refuses what it can't do instead of dropping it. Every change is planned first: dryRun shows the steps, what they mean and which online devices would be cut off; applying refuses if the controller changed in between, or if devices would be cut off without allowLockout. Wi-Fi passwords are never taken or shown: a new or reset Wi-Fi network gets a random temporary password, and the real one is set in the controller's web UI. Reads need QUERY, changes CONFIGURE.

ToolDescription
net_capabilitiesWhat the controller can do, per feature
net_listNetworksNetworks (VLANs): VLAN, gateway, DHCP, IPv6, protected
net_createNetwork / net_updateNetwork / net_deleteNetworkCreate or change a VLAN with its gateway and DHCP range. The network the controller is on is protected; delete is refused while a Wi-Fi network, port profile, reservation or rule uses it
net_listWifiWi-Fi networks: network, bands, security, isolation, MAC filter
net_createWifi / net_updateWifi / net_deleteWifiCreate or change an SSID on a given network (bands, WPA2/WPA3, PMF, isolation, hidden, 802.11r, MAC filter), or reset its password to a random one

On Omada, network isolation, a "guest" network type, switching IPv6 on, and WPA2/WPA3 mixed mode are not available through the API and are refused. Rules arrive in 2.4.6, switch ports and mDNS in 2.4.7.

AI Tools (1)

ToolDescription
analyzeSensorsAnalyze sensor data using AI (Ollama) to detect issues and provide recommendations

MCP Resources

Resource URIDescription
hass://entitiesList all entities grouped by domain
hass://entities/{entity_id}Get state of a specific entity
hass://entities/{entity_id}/detailedGet detailed entity info with all attributes
hass://entities/domain/{domain}Get all entities for a domain
hass://search/{query}/{limit}Search entities with result limit

Prerequisites

  • Node.js 20+ (tested with v20.19.6) - for npm/npx methods
  • npm 10.8+ (tested with v10.8.2) - for npm/npx methods
  • Docker (optional) - for Docker method
  • Home Assistant instance with long-lived access token
  • Network access to your Home Assistant instance
  • (Optional) Ollama for AI-powered analysis

Getting Your Home Assistant Token

  1. Log into your Home Assistant instance
  2. Click on your profile (bottom left)
  3. Scroll down to "Long-Lived Access Tokens"
  4. Click "Create Token"
  5. Give it a name (e.g., "MCP Server")
  6. Copy the token (shown only once!)

Environment Variables

Required

VariableDescriptionExample
HA_URLHome Assistant URLhttp://homeassistant.10.0.0.19.nip.io:8123
HA_TOKENLong-lived access tokeneyJhbGciOiJIUzI1NiIsInR5cCI...

Optional - Home Assistant

VariableDefaultDescription
HA_PLUGIN_ENABLEDtrueEnable Home Assistant plugin
HA_STRICT_SSLtrueValidate SSL certificates
HA_TIMEOUT30000API request timeout (ms)

Optional - MCP Server

VariableDefaultDescription
MCP_SERVER_LOG_LEVELinfoLog level: debug, info, warn, error
MCP_SERVER_LOG_FORMATplainLog format: plain, json, gcp-json
MCP_SERVER_USE_HTTPfalseEnable HTTP mode (vs stdio)
MCP_SERVER_STATEFULfalseEnable stateful sessions in HTTP mode

Optional - HTTP Mode

VariableDefaultDescription
MCP_HTTP_PORT3000HTTP server port
MCP_HTTP_BIND_ADDR127.0.0.1Bind address
MCP_HTTP_PATH/mcpMCP endpoint path
MCP_HTTP_ENABLE_HEALTHCHECKtrueEnable health check endpoint
MCP_HTTP_HEALTHCHECK_PATH/healthHealth check path
MCP_HTTP_ALLOW_CORStrueEnable CORS
MCP_HTTP_ALLOWED_ORIGINS127.0.0.1,localhostAllowed CORS origins

Optional - Chat face (OpenAPI/REST surface)

The server also serves an OpenAPI/REST face (/openapi.json + /api/*) for chat UIs like Open WebUI. By default it exposes the classic 8 Home Assistant tools. Tools marked chat-eligible in code can be activated per category with read/write granularity:

VariableDefaultDescription
MCP_CHAT_TOOLSunset (= legacy 8 HA tools)Category slice, e.g. ha-core:rw,ha-history:r,omada-read:r. Categories: ha-core, ha-history, ha-automations, omada-read, omada-write. Config can only narrow what the code marks chat-eligible; ADMIN tools (invokeAction) can never appear on this face.
MCP_REST_ACTIONSunset (= tool not registered)JSON map of pre-registered REST actions for the invokeAction MCP tool (ADMIN; MCP face only), e.g. {"deploy":{"url":"http://host:8425/v1/update","bearerToken":"...","cooldownMs":300000}}. Each action is rate-limited: min interval between firings = cooldownMs (default 60000; 0 disables) — caps deploy-storm blast radius if a model loops a legitimate action

Activated chat tools appear in the generated /openapi.json as POST /api/tools/<name> and dispatch through the same handlers, validation, and RBAC as the MCP face.

Optional - SSE Events

VariableDefaultDescription
MCP_SSE_EVENTS_ENABLEDtrueEnable real-time SSE events
MCP_OWNER_QUESTIONS_ENABLEDtrueEnable askOwner / getOwnerAnswer / cancelOwnerQuestion (HTTP mode with Home Assistant)
MCP_OWNER_QUESTIONS_HA_USERS(any HA user)Comma-separated Home Assistant user ids allowed to answer owner questions (the answeredBy value of an answer)
MCP_SSE_EVENTS_PATH/subscribe_eventsSSE endpoint path

Optional - Rate Limiting

VariableDefaultDescription
MCP_RATE_LIMIT_ENABLEDfalseEnable rate limiting
MCP_RATE_LIMIT_WINDOW_MS60000Rate limit window (ms)
MCP_RATE_LIMIT_MAX_REQUESTS100Max requests per window

Optional - Authentication

VariableDefaultDescription
MCP_AUTH_METHODnoneAuth method: none or bearer
MCP_AUTH_SECRET-JWT signing secret (min 32 chars, required for bearer method)
MCP_PERMISSIONS_CONFIG-JSON config for user roles and permissions

JWT Authentication

When MCP_AUTH_METHOD=bearer, clients must provide a JWT token in the Authorization header:

Authorization: Bearer <jwt-token>

Generate tokens with your MCP_AUTH_SECRET using HS256 algorithm. The JWT payload should include:

  • sub (subject): User identifier for permission lookup
  • exp (optional): Expiration timestamp

Permission System

The server uses role-based access control with binary permission masks:

PermissionFlagDescription
ADMIN1System operations (restart, updates)
CONFIGURE2Create/modify automations, scripts
CONTROL4Control devices (lights, climate, etc.)
QUERY8Read entity states, history, lists
NOTIFY16Send notifications
AI32Use AI analysis features

Predefined Roles:

RolePermissions
NONENo permissions
READONLYQUERY only
OPERATORQUERY + CONTROL + NOTIFY
CONTRIBUTORQUERY + CONTROL + NOTIFY + CONFIGURE
ADMINAll six permissions (QUERY, CONTROL, NOTIFY, CONFIGURE, AI, ADMIN)
SUPERUSERAll permissions

Configuration Example:

{
  "users": [
    { "sub": "admin@example.com", "role": "admin" },
    { "sub": "user@example.com", "role": "operator" },
    { "sub": "viewer@example.com", "role": "readonly" }
  ],
  "defaultRole": "NONE"
}

Set via environment variable (escape quotes for shell):

MCP_PERMISSIONS_CONFIG='{"users":[{"sub":"admin","role":"admin"}],"defaultRole":"NONE"}'

Recommended: defaultRole: "NONE" plus one users entry per client. defaultRole applies to every validly signed token whose sub is not listed — a non-NONE default silently gives unmapped clients real access. The server logs a warning at startup when defaultRole grants anything. Map each client (Open WebUI, n8n, agents…) explicitly before switching an existing deployment to NONE.

Clients only see the tools they may use: tools/list is filtered by the caller's permissions, so a readonly token is never offered control or admin tools (calls are still checked per tool).

Optional - AI Provider

VariableDefaultDescription
AI_PLUGIN_ENABLEDtrueEnable AI plugin
AI_PROVIDERollamaAI provider: ollama, openai, or none
AI_URLhttp://localhost:11434AI server URL (Ollama)
AI_MODELllama2AI model name
AI_TIMEOUT60000AI request timeout (ms)

Optional - Omada Network Controller

VariableDefaultDescription
OMADA_PLUGIN_ENABLEDfalseEnable Omada plugin
OMADA_BASE_URL-Omada controller URL (e.g., https://10.0.0.1:8043)
OMADA_CLIENT_ID-OAuth2 client ID from Omada controller
OMADA_CLIENT_SECRET-OAuth2 client secret from Omada controller
OMADA_OMADAC_ID-Omada controller ID
OMADA_SITE_ID-Default site ID for operations
OMADA_STRICT_SSLtrueValidate SSL certificates
OMADA_TIMEOUT30000API request timeout (ms)

Advanced Configuration Examples

With AI Analysis (Ollama)

{
  "mcpServers": {
    "homeassistant": {
      "command": "npx",
      "args": ["-y", "@coffeerunhobby/mcp-ha-connect"],
      "env": {
        "HA_URL": "http://homeassistant.10.0.0.19.nip.io:8123",
        "HA_TOKEN": "your_token",
        "AI_PROVIDER": "ollama",
        "AI_URL": "http://ollama.10.0.0.17.nip.io:11434",
        "AI_MODEL": "llama2"
      }
    }
  }
}

Disable AI Features

{
  "mcpServers": {
    "homeassistant": {
      "command": "npx",
      "args": ["-y", "@coffeerunhobby/mcp-ha-connect"],
      "env": {
        "HA_URL": "http://homeassistant.10.0.0.19.nip.io:8123",
        "HA_TOKEN": "your_token",
        "AI_PROVIDER": "none"
      }
    }
  }
}

Docker with Network Configuration

For Linux, you may need to add host.docker.internal:

{
  "mcpServers": {
    "homeassistant": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "--add-host=host.docker.internal:host-gateway",
        "-e", "HA_URL=http://host.docker.internal:8123",
        "-e", "HA_TOKEN=your_token",
        "ghcr.io/coffeerunhobby/mcp-ha-connect:latest"
      ]
    }
  }
}

Usage Modes

Mode 1: MCP Client (Claude Desktop / LM Studio)

Default stdio mode for MCP clients. See Quick Start section for configuration.

For detailed configuration options, see docs/LOCAL_CLIENT.md.

Mode 2: HTTP Server

Start as standalone HTTP server for web applications:

# Using npx
npx @coffeerunhobby/mcp-ha-connect

# Or with environment variables
MCP_SERVER_USE_HTTP=true \
MCP_HTTP_PORT=3000 \
HA_URL=http://homeassistant.10.0.0.19.nip.io:8123 \
HA_TOKEN=your_token \
npx @coffeerunhobby/mcp-ha-connect

Streamable HTTP Transport

Configure your MCP client to use:

  • URL: http://localhost:3000/mcp
  • Transport: Streamable HTTP (MCP 2025-03-26)

SSE Event Subscription

Subscribe to real-time events:

const eventSource = new EventSource(
  'http://localhost:3000/subscribe_events?domain=light&entity_id=light.living_room'
);

eventSource.addEventListener('state_changed', (event) => {
  const data = JSON.parse(event.data);
  console.log('Entity changed:', data.entity_id, data.new_state);
});

See docs/SSE_API.md for complete SSE documentation.

Mode 3: Docker Standalone

# Pull image
docker pull ghcr.io/coffeerunhobby/mcp-ha-connect:latest

# Run in HTTP mode
docker run -d --name mcp-ha-connect \
  -e HA_URL=http://homeassistant.10.0.0.19.nip.io:8123 \
  -e HA_TOKEN=your_token \
  -e MCP_SERVER_USE_HTTP=true \
  -p 3000:3000 \
  ghcr.io/coffeerunhobby/mcp-ha-connect:latest

Mode 4: Docker Compose

version: '3.8'

services:
  mcp-ha-connect:
    image: ghcr.io/coffeerunhobby/mcp-ha-connect:latest
    container_name: mcp-ha-connect
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - HA_URL=http://homeassistant.10.0.0.19.nip.io:8123
      - HA_TOKEN=${HA_TOKEN}
      - MCP_SERVER_USE_HTTP=true
      - MCP_HTTP_BIND_ADDR=0.0.0.0
    networks:
      - home-automation

networks:
  home-automation:
    driver: bridge

Integration Examples

With Claude Desktop

Once configured, you can ask Claude:

  • "Show me all lights in my house"
  • "Turn on the kitchen lights to 50% brightness"
  • "Set the living room temperature to 72 degrees"
  • "Create an automation that turns off all lights at midnight"
  • "What automations are currently enabled?"
  • "Trigger the morning routine automation"
  • "Search for entities with 'bedroom' in their name"
  • "Get all climate entities"
  • "Analyze my sensors for any issues" (requires Ollama)
  • "Check the history of my thermostat"

With n8n Workflows

The server can be integrated with n8n for automated home monitoring. Pre-built workflows are available in the n8n/ directory:

  1. ai-agent-safety-monitor - Critical safety monitoring every 5 minutes

Importing Workflows

Method 1: n8n UI

  1. Open n8n: http://127.0.0.1:5678
  2. Click Workflows → Import from File
  3. Select JSON file from n8n-files/
  4. Activate the workflow

Method 2: Docker CLI

# Copy workflow to n8n container
docker cp "n8n-files/AI Agent Safety Monitor - Updated.json" n8n:/files/workflow.json

# Import using n8n CLI
docker exec -it n8n n8n import:workflow --input=/files/workflow.json

# Verify import
docker exec -it n8n n8n list:workflow

With Web Applications

Use the HTTP transport with your MCP-compatible web client:

  1. Start server in HTTP mode
  2. Configure client to use http://localhost:3000/mcp
  3. Set transport to Streamable HTTP (MCP 2025-03-26)
  4. Enable CORS by adding your origin to MCP_HTTP_ALLOWED_ORIGINS

With Remote MCP Proxy (mcp-remote)

Connect a stdio-only client (Claude Desktop, LM Studio) to a remote HTTP MCP server using mcp-remote. On Windows, launch it through cmd /c and include -y so the first run never blocks on the npx install prompt:

{
  "mcpServers": {
    "homeassistant": {
      "command": "cmd",
      "args": [
        "/c",
        "npx",
        "-y",
        "mcp-remote",
        "https://your-server.example/mcp",
        "--header",
        "Authorization: Bearer <your-jwt-token>"
      ]
    }
  }
}

⚠️ Do not use ${VAR} placeholders in the --header value. A config like "Authorization: Bearer ${MCP_AUTH_TOKEN}" with a matching env block does not work on Windows: cmd /c only expands %VAR% (not ${VAR}), and mcp-remote does not substitute it either. The literal text ${MCP_AUTH_TOKEN} is sent as the token, the server replies 401, and mcp-remote then falls into a failing OAuth flow that surfaces as "Server disconnected". Inline the actual JWT instead. (On macOS/Linux you can instead let your shell expand the variable before the client launches.)

Network Configuration Notes

  • host.docker.internal - Use this to access services on your host machine from Docker
    • Works on Windows and macOS by default
    • On Linux, add --add-host=host.docker.internal:host-gateway to docker args
  • Direct IP - Use your machine's IP address (e.g., http://10.0.0.19:8123)
  • nip.io domains - Use wildcard DNS for easy local development (e.g., http://homeassistant.10.0.0.19.nip.io:8123)

Security Best Practices

Network Security

  • Network Segmentation: Run MCP server on private LAN only
  • Docker Networks: Use Docker networks for container isolation
  • VLAN: Consider VLAN for IoT devices
  • No Internet Exposure: Never expose MCP server directly to internet

Token & Configuration Security

  • Store .env securely (contains access token)
  • Never commit .env to version control
  • Set .env permissions: chmod 600 .env
  • Use HA_STRICT_SSL=true for HTTPS in production
  • Rotate access tokens periodically
  • Restrict MCP_HTTP_ALLOWED_ORIGINS (avoid wildcard *)
  • Bind to 127.0.0.1 for local-only access
  • Enable rate limiting in production (MCP_RATE_LIMIT_ENABLED=true)

MCP Client Configuration Security

⚠️ Important: Storing tokens directly in MCP client config files (Claude Desktop, LM Studio) exposes them to anyone with filesystem access. Consider:

  • Using .env files with restricted permissions for Docker/local deployments
  • Setting file permissions on config files (e.g., chmod 600)
  • Using environment variable substitution if supported by your client
  • Never committing config files with real tokens to version control

Server Instructions

The server provides MCP Server Instructions during initialization to help LLMs understand how to optimally use the available tools. Instructions are dynamically generated based on enabled plugins and include:

  • Entity Queries: Guidance on pagination, attribute inclusion, and using specialized tools like listPersons
  • Device Control: When to use specialized control tools vs generic callService
  • Automation Workflows: Best practices for creating and testing automations
  • Omada Operations: Site context requirements, client vs device distinction, rate limiting safety
  • Cross-Plugin Integration: How HA presence detection correlates with Omada network clients

Instructions follow MCP best practices: concise, actionable, and focused on tool relationships rather than repeating individual tool descriptions.

Troubleshooting

Claude Desktop / LM Studio Not Connecting

  1. Check config file location - Verify you're editing the correct file
  2. Restart the application - Close and reopen after config changes
  3. Check logs - Look for error messages in the application logs
  4. Test connection manually:
# Test npx
npx @coffeerunhobby/mcp-ha-connect

# Test Docker
docker run --rm -i \
  -e HA_URL=http://homeassistant.10.0.0.19.nip.io:8123 \
  -e HA_TOKEN=your_token \
  ghcr.io/coffeerunhobby/mcp-ha-connect:latest

mcp-remote Shows "Server disconnected" (401)

If /health returns 200 but the client shows "Server disconnected", the auth header is almost certainly malformed. Most common cause: a ${VAR} placeholder in the --header value that never got expanded (see the warning under With Remote MCP Proxy). Verify the endpoint accepts your token directly:

curl -i -X POST https://your-server.example/mcp \
  -H "Authorization: Bearer <your-jwt-token>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"diag","version":"1.0"}}}'

A 200 with an initialize result means the server and token are fine — fix the client config (inline the literal token). A 401 means the token itself is wrong.

Docker host.docker.internal Not Working (Linux)

Add host gateway:

{
  "args": [
    "run",
    "--rm",
    "-i",
    "--add-host=host.docker.internal:host-gateway",
    "-e", "HA_URL=http://host.docker.internal:8123",
    ...
  ]
}

Home Assistant Connection Issues

  1. Verify URL - Try accessing http://your-ha-url:8123/api/ in browser
  2. Check token - Ensure it's a valid long-lived access token
  3. Network access - Verify MCP server can reach Home Assistant
  4. SSL issues - Try HA_STRICT_SSL=false for testing

AI Analysis Not Working

  1. Verify Ollama is running - curl http://your-ollama-url:11434/api/tags
  2. Check model is available - Ensure model is pulled: ollama pull llama2
  3. Set AI_PROVIDER - Must be set to ollama (not none)

Development

Setup

# Clone repository
git clone https://github.com/coffeerunhobby/mcp-ha-connect.git
cd mcp-ha-connect

# Install dependencies
npm install

# Copy environment template
cp .env.example .env

# Edit .env with your Home Assistant details
nano .env

# Build
npm run build

# Run
npm start

Available Scripts

npm run build      # Build TypeScript to dist/
npm run dev        # Run in development mode with watch
npm start          # Run built version
npm test           # Run tests
npm run lint       # Run ESLint
npm run format     # Format code with Prettier

License

MIT

Author

Coffee Run Hobby (github.com/coffeerunhobby)

Links

Documentation

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.