Skip to main content
Glama
Home Assistant MCP Server

Home Assistant MCP Server

Official

Set Dashboard Resource

ha_config_set_dashboard_resource
Destructive

Create or update a Home Assistant dashboard resource by providing inline JavaScript/CSS code, external URLs, or search/replace edits, so custom cards, HACS modules, and stylesheets load correctly.

Instructions

Create or update a dashboard resource (inline code or external URL).

Provide exactly one of:

  • edits: Search/replace edits on an existing inline resource. Any failing edit (or a config_hash mismatch) aborts the whole call and saves nothing. Prefer this over content= for small changes to a large card: only the changed text is sent.

  • content: Inline JavaScript or CSS code (embedded in the resource URL as a data: URI — no file storage or external hosting involved). Supports 'module' and 'css' types only; URLs are deterministic (same content = same URL); up to ~128KB. Content must be self-contained: a data: URI has no base URL, so relative imports inside a module and relative url() references inside CSS cannot resolve (use fully-qualified URLs instead). If Home Assistant is behind a reverse proxy that injects a Content-Security-Policy without 'data:' in script-src/style-src, the browser blocks these resources: this call still succeeds and the card simply never renders. Register the code as a file and use url='/local/...' on such a deployment. (HA itself ships no CSP.)

  • url: External resource URL — /local/... (/config/www/; Marketplace cards: /local/community/...), /hacsfiles/... (HACS cards) or https://... (CDN). Supports all types: 'module', 'js', 'css', 'html'.

EXAMPLES:

  • Inline: ha_config_set_dashboard_resource(content="class MyCard extends HTMLElement { ... } customElements.define('my-card', MyCard);", resource_type="module")

  • Store cards need no call: in storage mode HACS and the Marketplace register the resource on install (adding it again duplicates it); with YAML-mode resources, list it under lovelace: resources: in configuration.yaml instead.

  • Update: ha_config_set_dashboard_resource(url="/local/my-card-v2.js", resource_type="module", resource_id="abc123")

  • Patch: ha_config_set_dashboard_resource(resource_id="abc123", edits=[{"old": "color: red", "new": "color: blue"}], config_hash="<_config_hash from the list>")

Inline writes return the stored content's config_hash.

After adding a resource, a browser cache clear or hard refresh (Ctrl+Shift+R) is needed to load it.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

Tool call template

This tool declares no required parameters. Add optional parameters from the input schema as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {},
    "name": "ha_config_set_dashboard_resource"
  }
}

Input Schema

NameRequiredDescriptionDefault
urlNoURL of the resource.
editsNoSearch/replace edits for an existing inline resource, applied in order. Requires resource_id; resource_type is ignored and the stored type is kept.
contentNoJavaScript or CSS code to host inline.
config_hashNoWith edits: refuse the patch unless the stored content has this hash when read, just before the write (the list's _config_hash with include_hash=True, or a previous write response's config_hash). A preflight check only: a change made by another client after that read is not detected and can be overwritten.
resource_idNoResource ID to update. If omitted, creates a new resource. Get IDs from ha_config_list_dashboard_resources()
resource_typeNoResource type, validated by Home Assistant: 'module' for ES6 modules (modern cards), 'js' for legacy JavaScript (older custom cards), 'css' for stylesheets (themes, global styles), 'html' for HTML importsmodule

Output Schema

NameRequiredDescriptionDefault

No arguments

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv9.1.2
    • changedInput schema / properties / edits / anyOf
      Previous value: -[
      -  {
      -    "items": {
      -      "additionalProperties": false,
      -      "description": "One exact-match replacement in an inline resource.",
      -      "properties": {
      -        "new": {
      -          "description": "Replacement text (may be empty).",
      -          "type": "string"
      -        },
      -        "old": {
      -          "description": "Exact text to replace. Must occur exactly once in the content at the point this edit is applied; include surrounding context to make it unique.",
      -          "type": "string"
      -        }
      -      },
      -      "required": [
      -        "old",
      -        "new"
      -      ],
      -      "type": "object"
      -    },
      -    "maxItems": 100,
      -    "minItems": 1,
      -    "type": "array"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "items": {
      +      "additionalProperties": false,
      +      "description": "One exact-match replacement.",
      +      "properties": {
      +        "new": {
      +          "description": "Replacement text (may be empty).",
      +          "type": "string"
      +        },
      +        "old": {
      +          "description": "Exact text to replace. Must occur exactly once in the content at the point this edit is applied; include surrounding context to make it unique.",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "old",
      +        "new"
      +      ],
      +      "type": "object"
      +    },
      +    "maxItems": 100,
      +    "minItems": 1,
      +    "type": "array"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
  2. Changed2 schema fields changedv9.1.0
    • addedInput schema / properties / config_hash
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "With edits: refuse the patch unless the stored content has this hash when read, just before the write (the list's _config_hash with include_hash=True, or a previous write response's config_hash). A preflight check only: a change made by another client after that read is not detected and can be overwritten."
      +}
    • addedInput schema / properties / edits
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "additionalProperties": false,
      +        "description": "One exact-match replacement in an inline resource.",
      +        "properties": {
      +          "new": {
      +            "description": "Replacement text (may be empty).",
      +            "type": "string"
      +          },
      +          "old": {
      +            "description": "Exact text to replace. Must occur exactly once in the content at the point this edit is applied; include surrounding context to make it unique.",
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "old",
      +          "new"
      +        ],
      +        "type": "object"
      +      },
      +      "maxItems": 100,
      +      "minItems": 1,
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Search/replace edits for an existing inline resource, applied in order. Requires resource_id; resource_type is ignored and the stored type is kept."
      +}
  3. Changed2 schema fields changedv9.0.0
    • changedInput schema / properties / resource_type / description
      Previous value: -"Resource type: 'module' for ES6 modules (modern cards), 'js' for legacy JavaScript (older custom cards), 'css' for stylesheets (themes, global styles)"New value: +"Resource type, validated by Home Assistant: 'module' for ES6 modules (modern cards), 'js' for legacy JavaScript (older custom cards), 'css' for stylesheets (themes, global styles), 'html' for HTML imports"
    • removedInput schema / properties / resource_type / enum
      Removed value: -[
      -  "module",
      -  "js",
      -  "css"
      -]
  4. Changed3 schema fields changedv8.6.0
    • changedInput schema / properties / content / description
      Previous value: -"JavaScript or CSS code to host inline (max ~128KB). The code is embedded directly in the resource URL as a data: URI - no file storage or external hosting involved. Mutually exclusive with url. Supports 'module' and 'css' types only."New value: +"JavaScript or CSS code to host inline."
    • changedInput schema / properties / resource_type / description
      Previous value: -"Resource type: 'module' for ES6 modules (modern cards, default), 'js' for legacy JavaScript (url mode only), 'css' for stylesheets"New value: +"Resource type: 'module' for ES6 modules (modern cards), 'js' for legacy JavaScript (older custom cards), 'css' for stylesheets (themes, global styles)"
    • changedInput schema / properties / url / description
      Previous value: -"URL of the resource. Can be: /local/file.js (www/ directory), /hacsfiles/component/file.js (HACS), https://cdn.example.com/card.js (external). Mutually exclusive with content."New value: +"URL of the resource."
  5. First observedv7.14.2

TDQS

A4.8/5.0
Behavior5/5

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

Goes well past the destructiveHint/openWorldHint annotations: it discloses that any failing edit or config_hash mismatch aborts the whole call and saves nothing, that config_hash is only a preflight check whose race window can still overwrite another client's change, the ~128KB size cap, the data:-URI consequence for relative imports and url() references, and that a browser hard refresh is needed after adding. It also flags that a CSP deployment lets the call succeed while the card silently never renders.

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?

Front-loaded with the one-line purpose, then a clean bulleted breakdown of the three modes and an EXAMPLES block, so an agent can scan to the relevant mode quickly. It runs long, and the Claude Desktop timeout workaround paragraph is verbose and tangential to the tool's own contract, though it does earn some place as operational guidance.

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 and the description still notes that inline writes return the stored content's config_hash, so return handling is covered. Given a six-parameter mutation tool with a destructive annotation, the atomicity guarantee, the hash-pinning caveat, and the CSP failure mode are all present — nothing an agent needs to call it correctly is missing.

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 100%, so no compensation is required, yet the description still adds real meaning the schema cannot express: the mutual exclusivity of url/content/edits (all six params are optional with no oneOf), which resource_type values apply to which mode, and the 128KB ceiling. Worked call examples tie the parameters to concrete invocations.

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 ('Create or update a dashboard resource') and immediately partitions the operation into three named input modes (edits, content, url) with the resource kinds each supports. An agent can tell this apart from ha_config_set_dashboard and ha_config_delete_dashboard_resource from the description alone.

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 'Provide exactly one of' each mode, when to prefer edits over content= ('small changes to a large card'), and when NOT to call at all ('Store cards need no call: in storage mode HACS and the Marketplace register the resource on install'). It also names the fallback path (register a file and use url='/local/...') for CSP-restricted deployments.

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

Deploy Server

Other Tools