Skip to main content
Glama
mahandra

HA Insights MCP

by mahandra

HA Insights MCP

An MCP server that gives LLM agents analytics, diagnostics and guarded actions for Home Assistant.

Status: phase 1 of 4 — read-only discovery tools over stdio. See Roadmap.

Positioning: why another Home Assistant MCP server?

Home Assistant already ships a built-in MCP Server integration, and community servers (e.g. ha-mcp) expose broad control of HA. This project deliberately does not compete with them on "turn on the kitchen light".

Built-in HA MCP Server

HA Insights MCP (this project)

Purpose

Voice/Assist-style control of exposed entities

Understanding and auditing the home

Data

Current state of exposed entities

States joined with area/device/entity registries; history (phase 2)

Analytics

—

Usage patterns, anomalies, energy (phase 2)

Diagnostics

—

Unavailable/flapping devices, low batteries, automation audit (phase 2)

Actions

Direct intents

Guarded: allowlist, value bounds, dry-run, confirmation, audit log (phase 3)

Output

Assist API responses

Compact, typed, token-efficient structured output

Use the built-in server to control your home. Use HA Insights to ask "what is going on in my home, what is broken, and is this change safe?". Both can run side by side.

Related MCP server: Home Assistant MCP Server (HA-mcp)

Features (phase 1)

Tools (all annotated readOnlyHint):

Tool

Purpose

Returns

search_entities(query, domain?, area?, limit=25)

Discover entities by text, domain, area

entity_id, name, state, area; total, truncated

get_entity_state(entity_id)

Live state of one entity

state, unit, area, device, last_changed, domain-relevant attributes

list_areas()

Rooms/zones of the home

area_id, name, entity count; unassigned count

Resource: ha://home/summary — markdown overview: areas with entity counts, entities per domain, number of unavailable entities.

Outputs are pydantic models (MCP structured content with an output schema). Raw HA JSON is never returned: attributes are filtered per domain (no supported_features bitmasks, icons, pictures or GPS coordinates).

Architecture

 MCP client (Claude, Inspector)
        │  JSON-RPC over stdio
┌───────▼──────────────────────────────────────────────┐
│ server.py     MCPServer, lifespan, instructions      │  MCP layer
│ tools.py      search_entities / get_entity_state /   │
│               list_areas  → schemas.py (outputs)     │
│ resources.py  ha://home/summary                      │
│ context.py    AppContext, HAError → ToolError        │
├──────────────────────────────────────────────────────┤
│ snapshot.py   states ⋈ registries, area resolution,  │  domain layer
│               TTL cache, single-flight refresh       │
├──────────────────────────────────────────────────────┤
│ ha/client.py  REST (httpx): states, config           │  HA client
│               WebSocket: area/device/entity registry │  (no MCP imports)
│ ha/errors.py  HAAuthError, HAConnectionError, ...    │
└───────┬──────────────────────────────────────────────┘
        │  HTTP + WebSocket, Bearer token
   Home Assistant

Key decisions:

  • Separate HA client. ha/ knows nothing about MCP, so it is testable on its own and reusable for the HTTP transport (phase 4).

  • REST + WebSocket. REST has no area/device/entity registries; without them you cannot answer "what is in the kitchen". Registries are fetched in one WebSocket session.

  • Area resolution like HA: the entity's own area wins, otherwise the device's area.

  • Snapshot cache (10 s default) shared by tools and the resource; get_entity_state always reads the state fresh.

  • Errors are part of the conversation. HA failures become MCP tool errors with actionable text ("Unknown area 'attic'. Known areas: …"), so the model can self-correct.

  • Security from day one. Token only from env/.env, held as SecretStr, never logged or included in errors. entity_id is validated before it reaches a URL. Phase 1 has no write methods at all — annotations are hints, not enforcement.

  • stdio hygiene. stdout is the JSON-RPC channel; all logs go to stderr.

Setup

Requirements: Python 3.12, uv, Docker (for the dev HA), Node.js (only for MCP Inspector).

make install                 # uv sync
cp .env.example .env         # then set HA_URL and HA_TOKEN

Dev Home Assistant

make dev-ha-up               # HA with the demo integration on http://localhost:8123

Onboard, create a long-lived access token and seed areas — see dev/README.md. Any real HA instance works too: set HA_URL and HA_TOKEN (an admin user's token, required for the registries).

Configuration

Variable

Default

HA_URL

http://localhost:8123

Base URL of Home Assistant

HA_TOKEN

— (required)

Long-lived access token

HA_TIMEOUT_SECONDS

10

Per-request timeout

HA_CACHE_TTL_SECONDS

10

Snapshot cache TTL (0 disables)

LOG_LEVEL

INFO

Logs go to stderr

Usage

MCP Inspector

make inspect

Opens the Inspector in the browser, connected over stdio. Click Connect, then: Tools → List Tools → list_areas → Run; Resources → ha://home/summary. Check the output schema and the structured result of each tool.

Claude Code

claude mcp add ha-insights -- uv run --directory /path/to/ha_mcp ha-insights-mcp
claude mcp list              # should show ha-insights: connected

--directory makes uv run in the repo, so .env is found. In a session, ask "What areas does my home have?" or reference the resource with @ha-insights:ha://home/summary.

Claude Desktop

~/.config/Claude/claude_desktop_config.json (Linux) or ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):

{
  "mcpServers": {
    "ha-insights": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/ha_mcp", "ha-insights-mcp"]
    }
  }
}

Prefer keeping the token in the repo's .env (git-ignored) over an env block in this file.

Development

make test     # pytest, no real HA calls (respx + fake WebSocket + in-memory MCP client)
make lint     # ruff
make fmt

Tool tests run the whole stack: in-memory MCP Client → server → real HAClient → mocked HA. Conventions for contributors and AI agents: CLAUDE.md.

Roadmap

  1. Skeleton + read-only tools over stdio, dev HA in Docker ← current

  2. History analytics, device health (unavailable / flapping / battery), automation audit

  3. Guarded actions: domain allowlist, value bounds, dry-run, confirmation for risky actions, SQLite audit log

  4. Streamable HTTP transport with auth, Docker image, README demo GIF

License

MIT

Available Tools

3 tools
get_entity_stateGet entity stateA
Read-only

Get the live state of one entity with its area, device and relevant attributes.

The state is read fresh from Home Assistant. Attributes are filtered to the ones meaningful for the entity's domain (e.g. temperatures and modes for climate).

NameRequiredDescriptionDefault
entity_idYesExact entity_id, e.g. 'climate.hvac'. Find it with search_entities.

Output Schema

NameRequiredDescription
areaYes
nameYes
unitYesUnit of measurement of the state, if any
stateYes
deviceYesName of the device this entity belongs to
domainYes
entity_idYes
attributesYesRelevant attributes for this domain; noisy/internal attributes are omitted
last_changedYesWhen the state value last changed (UTC)

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, and the description adds genuinely new behavior: values are fetched fresh from Home Assistant rather than cached, and attributes are a filtered subset rather than the raw attribute dict. It does not say what happens when an entity_id is unknown, which is the one remaining behavioral gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the core purpose and followed by meaningful qualifications about freshness and attribute filtering. Slightly padded by the parenthetical climate example, but nothing is genuinely wasteful.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return structure needn't be described; the description instead covers the two things the schema cannot express, data freshness and attribute filtering. Combined with readOnly annotations, that is sufficient for an agent to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter and schema coverage is 100%; the schema already carries the pattern, example ('climate.hvac') and the search_entities discovery hint. The description adds nothing parameter-specific, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Get'), resource ('live state of one entity') and the payload contents (area, device, relevant attributes). It is clearly narrower in scope than sibling tools like search_entities and list_areas, though it never names those siblings to contrast explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: it tells you the state is read fresh and attributes are domain-filtered, so an agent can infer it is for inspecting a known entity. There is no explicit 'use this instead of X when Y' guidance, and the pointer to search_entities lives only in the schema description, not here.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_areasList areasA
Read-only

List all areas (rooms/zones) of the home with how many entities each contains.

    Use area_id or name from here to filter search_entities by area.
    
NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
areasYes
unassigned_entity_countYesEntities that belong to no area

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

readOnlyHint=true and openWorldHint=false already declare this as a safe, closed-domain read, so the safety profile is covered. The description adds only that each area comes back with its entity count and that its identifiers are reusable downstream; it says nothing about empty homes, unnamed areas, or ordering.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, zero filler, with the resource definition first and the follow-on usage hint second. Every clause carries information the agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no parameters, an output schema, and read-only annotations, the description covers purpose and downstream usage adequately. Minor gap: it doesn't mention what happens when no areas exist or how the two identifier forms differ in practice.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes no parameters, so there is nothing to disambiguate and the baseline of 4 applies. The description correctly focuses on the return fields (`area_id`, `name`) that serve as inputs to other tools.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("List all areas") and disambiguates the term with "(rooms/zones) of the home." It also states what each result carries (entity counts), so the agent knows exactly what it gets without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent into the workflow: take `area_id` or `name` from here and pass it to search_entities. There are no exclusions or "don't use this when" cases, but for a zero-arg enumeration tool the intended context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_entitiesSearch entitiesA
Read-only

Find Home Assistant entities and their current states.

    Use this first to discover entity_ids, then call get_entity_state for details.
    Returns entity_id, name, state and area for each match, best matches first.
    
NameRequiredDescriptionDefault
areaNoOnly this area, by area_id or name (see list_areas)
limitNoMaximum results
queryYesCase-insensitive text matched against entity_id and friendly name, e.g. 'kitchen', 'temperature', 'light.bed'. All words must match. Use an empty string to list everything that matches the filters.
domainNoOnly this domain, e.g. 'light', 'sensor', 'climate', 'switch'

Output Schema

NameRequiredDescription
totalYesNumber of matching entities before applying the limit
entitiesYes
truncatedYesTrue if more matches exist; narrow the query or filters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds real value beyond that: the returned fields (entity_id, name, state, area) and the result ordering ('best matches first'). It does not mention limit/pagination behavior or what happens when nothing matches, which is why it stops short of 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short lines, front-loaded with purpose, followed by the workflow hint and the return shape. No filler sentences and nothing repeated from the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Annotations cover read-safety, an output schema covers return structure, and the schema fully documents all four parameters. The description supplies exactly the missing piece — the discovery-then-detail workflow with get_entity_state — so an agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents query matching semantics, area, domain, and limit with a max of 100. The description adds no parameter-level detail (no note that an empty query lists everything, no guidance on combining filters), so this is the baseline for a fully documented schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Find Home Assistant entities and their current states') and immediately distinguishes itself from the sibling read tool by naming get_entity_state for details. An agent can tell what this does and how it differs from adjacent tools without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Use this first to discover entity_ids, then call get_entity_state for details', which gives both the ordering rule and the named alternative. The condition that selects this tool versus get_entity_state is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.0
    • First observedget_entity_state
    • First observedlist_areas
    • First observedsearch_entities

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct role: search_entities discovers entities, list_areas catalogs rooms/zones, and get_entity_state retrieves detail for a single entity. The descriptions explicitly guide sequencing from search to detail, leaving little room for misselection.

Naming Consistency5/5

All tool names follow the same snake_case verb_noun pattern: search_entities, list_areas, get_entity_state. The convention is predictable and readable throughout.

Tool Count5/5

Three tools is minimal but well-matched to this read-only Home Assistant insights server. Each tool serves a distinct discovery, area, or detail purpose, so none feels redundant or missing.

Completeness4/5

The surface covers the core read-only workflow: discover entities, understand areas, and inspect live entity state with relevant attributes. Minor gaps like a dedicated area-detail or history/statistics tool exist, but agents can work around them for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI assistants to interact with Home Assistant to control smart home devices, query entity states, and manage automations using natural language. It provides over 90 tools for comprehensive system management, including dashboard configuration, service execution, and automation debugging.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Gives AI agents scoped, least-privilege access to Home Assistant, with per-token permissions, auditing, and 131 tools for managing smart home devices.
    1
    MIT