Skip to main content
Glama
homeassistant-ai

Home Assistant MCP Server

Official

Create or Update Dashboard

ha_config_set_dashboard
Destructive

Create or update a Home Assistant dashboard using full config replacement or Python transformations for targeted edits. Supports new, existing, and strategy-based dashboards.

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.

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.
Behavior5/5

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

Annotations indicate destructiveHint=true, and the description transparently explains creation/update behavior, index shifting after operations, storage-mode vs YAML-mode limitations, and provides detailed security info for python_transform. No contradictions with annotations.

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 well-structured with clear sections, bullet points, and code examples. It's long but every section adds value. Could be slightly condensed, but overall earns its length.

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?

For a complex tool with 12 parameters and no output schema, the description covers usage, parameters, examples, edge cases, security, and limitations comprehensively. No gaps identified.

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

Parameters5/5

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

Despite high schema coverage (92%), the description adds substantial meaning: explains python_transform security, config_hash for optimistic locking, best practice key attestation, and provides numerous examples and patterns. Goes well beyond schema descriptions.

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 title and description clearly state 'Create or Update' a Home Assistant dashboard, with specific verbs and resource. It distinguishes from siblings by mentioning related tools like ha_config_get_dashboard, ha_config_delete_dashboard, and ha_config_set_yaml for YAML dashboards.

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 states prerequisites: 'MUST call ha_get_skill_guide OR refer to your locally installed skills first.' Provides clear guidance on when to use python_transform vs config mode, examples, and importantly clarifies what it does NOT cover (YAML-mode) and suggests alternative tools.

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