Skip to main content
Glama
homeassistant-ai

Home Assistant MCP Server

Official

Create or Update Dashboard

ha_config_set_dashboard
Destructive

Create or update Home Assistant dashboards using full config replacement or Python-based surgical transformations, enabling precise edits to views and cards without rebuilding from scratch.

Instructions

Create or update a Home Assistant dashboard.

MUST call ha_get_skill_guide OR refer to your locally installed skills first.

Creates a new dashboard or updates an existing one with the provided configuration. Supports two modes: full config replacement OR Python transformation.

Use 'default' or 'lovelace' to target the built-in default dashboard. New dashboards require a hyphenated url_path (e.g., 'my-dashboard').

WHEN TO USE WHICH MODE:

  • python_transform: RECOMMENDED for edits. Surgical/pattern-based updates, works on all platforms.

  • config: New dashboards only, or full restructure. Replaces everything.

IMPORTANT: After delete/add operations, indices shift! Subsequent python_transform calls must use fresh config_hash from ha_config_get_dashboard() to get updated structure. Chain multiple ops in ONE expression when possible.

TIP: Use ha_config_get_dashboard(entity_id=...) to get the path for any card.

TIP: return_screenshot=True bundles rendered image(s) with the write result (beta feature); for visual re-checks after the write, use the dedicated ha_get_dashboard_screenshot tool instead of re-sending config.

PYTHON TRANSFORM EXAMPLES (RECOMMENDED):

  • Update card icon: 'config["views"][0]["cards"][0]["icon"] = "mdi:thermometer"'

  • Add card: 'config["views"][0]["cards"].append({"type": "button", "entity": "light.bedroom"})'

  • Delete card: 'del config["views"][0]["cards"][2]'

  • Pattern-based update: 'for card in config["views"][0]["cards"]: if "light" in card.get("entity", ""): card["icon"] = "mdi:lightbulb"'

  • Multi-operation: 'config["views"][0]["cards"][0]["icon"] = "mdi:a"; config["views"][0]["cards"][1]["icon"] = "mdi:b"'

MODERN DASHBOARD BEST PRACTICES:

  • Use "sections" view type (default) with grid-based layouts

  • Use "tile" cards as primary card type (replaces legacy entity/light/climate cards)

  • Use "grid" cards for multi-column layouts within sections

  • Create multiple views with navigation paths (avoid single-view endless scrolling)

  • Use "area" cards with navigation for hierarchical organization

DISCOVERING ENTITY IDs FOR DASHBOARDS: Do NOT guess entity IDs - use these tools to find exact entity IDs:

  1. ha_get_overview(include_entity_id=True) - Get all entities organized by domain/area

  2. ha_search(query, domain_filter, area_filter, search_types) - Find entities and config-body references in one call

If unsure about entity IDs, ALWAYS use one of these tools first.

DASHBOARD DOCUMENTATION:

  • dashboard-guide.md and dashboard-cards.md ship in this response under skill_content by default — layout patterns, card-type taxonomy, and worked examples.

  • ha_get_skill_guide — deeper card-type and configuration guidance.

EXAMPLES:

Create empty dashboard: ha_config_set_dashboard( url_path="mobile-dashboard", title="Mobile View", icon="mdi:cellphone" )

Create dashboard with modern sections view: ha_config_set_dashboard( url_path="home-dashboard", title="Home Overview", config={ "views": [{ "title": "Home", "type": "sections", "sections": [{ "title": "Climate", "cards": [{ "type": "tile", "entity": "climate.living_room", "features": [{"type": "target-temperature"}] }] }] }] } )

Create strategy-based dashboard (auto-generated): ha_config_set_dashboard( url_path="my-home", title="My Home", config={ "strategy": { "type": "home", "favorite_entities": ["light.bedroom"] } } )

Note: Strategy dashboards cannot be converted to custom dashboards via this tool. Use the "Take Control" feature in the Home Assistant interface to convert them.

Update existing dashboard config: ha_config_set_dashboard( url_path="existing-dashboard", config={ "views": [{ "title": "Updated View", "type": "sections", "sections": [{ "cards": [{"type": "markdown", "content": "Updated!"}] }] }] } )

Note: When updating an existing dashboard, title/icon/require_admin/show_in_sidebar are also updated if explicitly provided alongside (or instead of) a config change.

STORAGE-MODE vs YAML-MODE DASHBOARDS: This tool only manages storage-mode dashboards (created via UI/API and stored in Home Assistant's storage backend). It does NOT touch YAML-defined dashboards. Two distinct YAML cases exist and this tool covers neither:

  • "YAML-mode" dashboards: written in their own .yaml file referenced from configuration.yaml under lovelace: dashboards:. The dashboard itself lives in a separate YAML file but its registration is in configuration.yaml.

  • Dashboards inlined directly in configuration.yaml under the lovelace: key (legacy single-dashboard mode). For either YAML case, edit the dashboard's .yaml file directly. ha_config_set_yaml can update the lovelace: registration entry in configuration.yaml but does NOT touch the dashboard body in the referenced .yaml file.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
iconNoMDI icon name (e.g., 'mdi:home', 'mdi:cellphone'). Defaults to 'mdi:view-dashboard'
titleNoDashboard display name shown in sidebar
configNoDashboard configuration with views and cards. Omit or set to None to create dashboard without initial config. Mutually exclusive with python_transform.
url_pathYesDashboard URL path (e.g., 'my-dashboard'). Use 'default' or 'lovelace' for the default dashboard. New dashboards must use a hyphenated path.
view_pathNoWith return_screenshot: stable Lovelace views[].path to render.
config_hashNoConfig hash from ha_config_get_dashboard for optimistic locking. REQUIRED for python_transform (validates dashboard unchanged). Optional for config (validates before full replacement if provided).
MandatoryBPSNo
require_adminNoRestrict dashboard to admin users only. For existing dashboards, only updated when explicitly provided.
BestPracticeKeyNoRead-receipt for the home-assistant-best-practices skill; required when strict best-practices mode is enabled. Not a secret or credential: the current value is an attestation phrase published openly at the top of the skill content served by ha_get_skill_guide. Read that content, then pass the value back verbatim — this round-trip is the server's designed protocol confirming the practices were read before writing.
show_in_sidebarNoShow dashboard in sidebar navigation. For existing dashboards, only updated when explicitly provided.
python_transformNoPython expression to transform existing dashboard config. Mutually exclusive with config. Requires config_hash for validation. See PYTHON TRANSFORM SECURITY below for allowed operations. Examples: Simple: python_transform="config['views'][0]['cards'][0]['icon'] = 'mdi:lamp'" Pattern: python_transform="for card in config['views'][0]['cards']: if 'light' in card.get('entity', ''): card['icon'] = 'mdi:lightbulb'" Multi-op: python_transform="config['views'][0]['cards'][0]['icon'] = 'mdi:lamp'; del config['views'][0]['cards'][2]" PYTHON TRANSFORM SECURITY: ✅ ALLOWED: - Dictionary/list access: config['views'][0]['cards'][1] - Slicing: config['views'][0]['cards'][1:3] - Assignment: config['key'] = 'value' - Deletion: del config['key'] or config.pop('key') - List methods: append, insert, pop, remove, clear, extend - Dict methods: update, get, setdefault, keys, values, items - Loops: for, if/else, pass, break, continue - Comprehensions: [x for x in ...], {k: v for ...}, (x for x in ...) - Ternary: x if condition else y - Iterable unpacking (* in calls/literals): f(*xs), [*xs, y] - Dict unpacking (**) in calls and dict literals: {**d, 'k': v} - Keyword arguments: func(key=value) - Lambdas (e.g. for `key=`): sorted(items, key=lambda x: x['score']) - String methods: startswith, endswith, lower, upper, strip, split, join, replace - Safe builtins: isinstance, len, range, enumerate, zip, sorted, reversed, min, max, sum, abs, any, all, round, str, int, float, bool, list, dict, tuple, set ❌ FORBIDDEN: - Imports: import, from, __import__ - File operations: open, read, write - Dunder access: __class__, __bases__, __subclasses__ - Dangerous builtins: eval, exec, compile, getattr, setattr, delattr, hasattr - Function definitions: def, class - Exception handling: try/except (validate with isinstance/in/.get() instead) - While loops: use bounded for loops or comprehensions instead 🎯 PATTERNS: - Filter cards: cards = [c for c in cards if keep(c)] - Skip in a loop: prefer `continue` over an empty `pass` branch (clearer) - Conditionally include: build a new list and `.append(x)` only the cards you want, instead of iterating the original and using if/pass branches to drop entries - Modify in place when possible (single pass, fewer surprises) over reconstructing the entire list
return_screenshotNoAfter writing, also return rendered image(s) of the dashboard so you can see what it looks like in a single call (the dashboard creation/iteration loop). Requires the 'dashboard screenshot' beta feature + engine add-on/sidecar; if unavailable, the write result is returned with a warning. For visual re-checks after the write (no config round-trip), use the dedicated ha_get_dashboard_screenshot tool instead.

Schema Changelog

Changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. Changed1 schema field changedv8.4.1
    • changedInput schema / properties / return_screenshot / description
      Previous value: -"After writing, also return rendered image(s) of the dashboard so you can see what it looks like in a single call (the dashboard creation/iteration loop). Requires the 'dashboard screenshot' beta feature + engine add-on/sidecar; if unavailable, the write result is returned with a warning."New value: +"After writing, also return rendered image(s) of the dashboard so you can see what it looks like in a single call (the dashboard creation/iteration loop). Requires the 'dashboard screenshot' beta feature + engine add-on/sidecar; if unavailable, the write result is returned with a warning. For visual re-checks after the write (no config round-trip), use the dedicated ha_get_dashboard_screenshot tool instead."
  2. First observedv7.14.2

TDQS

A4.7/5.0
Behavior5/5

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

No contradiction with the destructiveHint annotation - the description openly states 'Replaces everything,' 'After delete/add operations, indices shift!,' and shows deletion expressions, so the destructive profile is consistent. It adds substantial behavioral context beyond the annotation: optimistic locking via config_hash, the index-shift gotcha requiring fresh hashes, the storage-mode vs YAML-mode scope boundary, the strategy-dashboard conversion limitation, and the rule that title/icon/require_admin/show_in_sidebar only update when explicitly provided.

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?

The description is long but well-structured with headers, scannable bullets, code examples, and front-loaded critical information (mode selection, index-shift warning, default-dashboard targeting). It carries some redundancy - the python_transform examples overlap with the schema's own extensive examples, and the MODERN DASHBOARD BEST PRACTICES section is content guidance arguably better placed in the skill guide.

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?

For a destructive 12-parameter tool with no output schema, the description is unusually complete: prerequisites, mode semantics, optimistic locking, YAML-mode exclusion, strategy-dashboard limitation, and entity-discovery workflow are all covered. Remaining gaps are minor but real - MandatoryBPS is never explained, and the write-result/return format is not described.

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?

Schema coverage is 92%, so the baseline is 3, but the description adds genuine value beyond the schema: the hyphenated url_path rule for new dashboards, the mode-selection semantics mapping python_transform to edits and config to full replacement, and the rationale for always fetching a fresh config_hash after structural changes. The one gap is MandatoryBPS, which remains unexplained in both the schema and the description.

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?

The opening sentence 'Create or update a Home Assistant dashboard' pairs specific verbs (create/update) with a concrete resource, and the two-mode breakdown (config vs python_transform) makes the operation unambiguous. It is easily distinguished from siblings like ha_config_get_dashboard (read), ha_config_delete_dashboard (delete), and ha_config_set_scene (scenes).

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?

Gives explicit when-to-use guidance: 'python_transform: RECOMMENDED for edits... config: New dashboards only, or full restructure.' It also names alternatives for adjacent tasks - ha_config_get_dashboard for fetching structure/hashes, ha_get_overview/ha_search for entity discovery, ha_get_dashboard_screenshot for visual re-checks, and ha_config_set_yaml with a clear exclusion for YAML-mode dashboards. The MUST-call ha_get_skill_guide prerequisite is also stated up front.

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

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/homeassistant-ai/ha-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server