Skip to main content
Glama
homeassistant-ai

Home Assistant MCP Server

Official

Create or Update Script

ha_config_set_script
Destructive

Create or update Home Assistant scripts with sequence actions or blueprint support. Use Python expressions for surgical edits to existing scripts.

Instructions

Create or update a Home Assistant script.

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

PREFER NATIVE ACTIONS OVER TEMPLATES (read this before writing any {{ ... }}): Native actions are validated at config load, fail loudly, and do not bypass HA's schema. Templates in logic positions fail silently and obscure intent.

  • choose / if/then/else instead of template-based service names

  • wait_for_trigger instead of wait_template

  • Native for: field on state conditions inside choose/if, and on state/numeric_state triggers in wait_for_trigger, instead of {{ now() - X.last_changed > timedelta(...) }} duration math.

  • repeat with for_each instead of template loops

  • Hardcode target.entity_id literals — never {{ this.entity_id }}. Templates are appropriate ONLY in data.* fields, notification message/title, event_data, and variables. The reactive best-practice checker on this tool will surface anything in a logic position that should be native; consult the best_practice_warnings field on the response and fix before re-submitting. The relevant skill section is auto-embedded under skill_content on warnings, and the full automation-patterns.md + template-guidelines.md references ship under skill_content proactively by default. For comprehensive guidance beyond that, call ha_get_skill_guide.

Supports two modes: full config replacement OR Python transformation.

WHEN TO USE WHICH MODE:

  • python_transform: RECOMMENDED for edits to existing scripts. Surgical updates.

  • config: Use for creating new scripts or full restructures.

IMPORTANT: python_transform requires 'config_hash' from ha_config_get_script().

PYTHON TRANSFORM EXAMPLES:

  • Update step: python_transform="config['sequence'][0]['data']['message'] = 'Hello'"

  • Add step: python_transform="config['sequence'].append({'delay': {'seconds': 5}})"

  • Remove last step: python_transform="config['sequence'].pop()"

Creates a new script or updates an existing one with the provided configuration. Supports both regular scripts (with sequence) and blueprint-based scripts.

Required config fields (choose one): - sequence: List of actions to execute (for regular scripts) - use_blueprint: Blueprint configuration (for blueprint-based scripts)

Optional config fields: - alias: Display name (defaults to script_id) - description: Script description - icon: Icon to display - mode: Execution mode ('single', 'restart', 'queued', 'parallel') - max: Maximum concurrent executions (for queued/parallel modes) - fields: Input parameters for the script

SCRIPTS vs AUTOMATIONS: Scripts use 'sequence', NOT 'trigger' or 'action'. If you need trigger-based execution, use ha_config_set_automation instead.

EXAMPLES:

Create basic delay script: ha_config_set_script(script_id="wait_script", config={ "sequence": [{"delay": {"seconds": 5}}], "alias": "Wait 5 Seconds", "description": "Simple delay script" })

Create service call script: ha_config_set_script(script_id="blink_light", config={ "sequence": [ {"action": "light.turn_on", "target": {"entity_id": "light.living_room"}}, {"delay": {"seconds": 2}}, {"action": "light.turn_off", "target": {"entity_id": "light.living_room"}} ], "alias": "Light Blink", "mode": "single" })

Create script with parameters: ha_config_set_script(script_id="backup_script", config={ "alias": "Backup with Reference", "description": "Create backup with optional reference parameter", "fields": { "reference": { "name": "Reference", "description": "Optional reference for backup identification", "selector": {"text": None} } }, "sequence": [ { "action": "hassio.backup_partial", "data": { "compressed": False, "homeassistant": True, "homeassistant_exclude_database": True, "name": "Backup_{{ reference | default('auto') }}{{ now().strftime('%Y%m%d%H%M%S') }}" } } ] })

Update script: ha_config_set_script(script_id="morning_routine", config={ "sequence": [ {"action": "light.turn_on", "target": {"area_id": "bedroom"}}, {"action": "climate.set_temperature", "target": {"entity_id": "climate.bedroom"}, "data": {"temperature": 22}} ], "alias": "Updated Morning Routine" })

Create blueprint-based script: ha_config_set_script(script_id="notification_script", config={ "alias": "My Notification Script", "use_blueprint": { "path": "notification_script.yaml", "input": { "message": "Hello World", "title": "Test Notification" } } })

Update blueprint script inputs: ha_config_set_script(script_id="notification_script", config={ "alias": "My Notification Script", "use_blueprint": { "path": "notification_script.yaml", "input": { "message": "Updated message", "title": "Updated Title" } } })

Note: Scripts use Home Assistant's action syntax. Check the documentation for advanced features like conditions, variables, parallel execution, and service call options.

create update modify edit script sequence actions new script write save

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
waitNoWait for script to be queryable before returning. Default: True. Set to False for bulk operations.
configNoScript configuration dictionary. Must include EITHER 'sequence' (for regular scripts) OR 'use_blueprint' (for blueprint-based scripts). Optional fields: 'alias', 'description', 'icon', 'mode', 'max', 'fields'. Mutually exclusive with python_transform.
categoryNoCategory ID to assign to this script. Use ha_config_get_category(scope='script') to list available categories, or ha_config_set_category() to create one.
script_idYesScript identifier — bare storage key ('morning_routine') or entity_id form ('script.morning_routine'); a leading 'script.' prefix is stripped before lookup.
config_hashNoConfig hash from ha_config_get_script for optimistic locking. REQUIRED for python_transform (validates script unchanged). Optional for config updates (validates before full replacement if provided).
MandatoryBPSNo
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.
python_transformNoPython expression to transform existing script config. Mutually exclusive with config. Requires config_hash for validation. WARNING: Expressions with infinite loops will hang the server. Examples: Simple: python_transform="config['sequence'][0]['data']['message'] = 'Hello'" Pattern: python_transform="for step in config['sequence']: if step.get('alias') == 'My Step': step['data']['value'] = 100" 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

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Behavior5/5

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

Annotations already set destructiveHint=true. The description adds significant behavioral context: optimistic locking via config_hash, python transform security restrictions (allowed/forbidden operations), wait parameter for bulk operations, and best-practice checker that surfaces warnings. This exceeds annotation expectations.

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 sections, bullet points, and examples. It is front-loaded with critical usage guidance. Some redundancy exists (e.g., repeated examples), but given tool complexity, the structure is appropriate and earns a 4.

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?

Given 8 parameters, two modes, Python transform security, and integration with best-practice skills, the description covers all necessary aspects. Includes examples for both config and python_transform, references to related tools, and proactive skill content. Output schema exists, so return values are not required.

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?

Schema coverage is 88%, but description adds extensive meaning: explains config sub-keys (sequence, use_blueprint, alias, etc.), python_transform with examples and allowed patterns, wait behavior, category linking to other tools, and BestPracticeKey attestation. Every parameter is well-explained.

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 description clearly states 'Create or update a Home Assistant script', distinguishes two modes (config vs python_transform), and explicitly differentiates from sibling tool ha_config_set_automation via the 'SCRIPTS vs AUTOMATIONS' section. The verb and resource are specific, and examples confirm purpose.

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?

Provides explicit when-to-use guidance: python_transform for edits, config for new/full restructures. Requires config_hash for python_transform. Details prerequisites, best-practice preferences (native over templates), and when to use automation instead. Examples cover multiple scenarios.

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