ha-mcp-dev 7.5.0.dev531__tar.gz → 7.5.0.dev532__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. {ha_mcp_dev-7.5.0.dev531/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.5.0.dev532}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_config_automations.py +32 -0
  4. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_config_dashboards.py +50 -0
  5. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_config_scripts.py +28 -0
  6. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  7. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/LICENSE +0 -0
  8. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/MANIFEST.in +0 -0
  9. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/README.md +0 -0
  10. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/setup.cfg +0 -0
  11. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/__init__.py +0 -0
  12. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/__main__.py +0 -0
  13. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/_pypi_marker +0 -0
  14. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/_version.py +0 -0
  15. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/auth/__init__.py +0 -0
  16. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/auth/consent_form.py +0 -0
  17. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/auth/provider.py +0 -0
  18. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/client/__init__.py +0 -0
  19. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/client/rest_client.py +0 -0
  20. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/client/supervisor_client.py +0 -0
  21. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/client/websocket_client.py +0 -0
  22. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/client/websocket_listener.py +0 -0
  23. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/config.py +0 -0
  24. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/errors.py +0 -0
  25. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/py.typed +0 -0
  26. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  27. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  28. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  29. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  30. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  31. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  32. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  33. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  34. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  35. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  36. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  37. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  38. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  39. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  40. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  41. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  42. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  43. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  44. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  45. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  46. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/server.py +0 -0
  47. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/settings_ui.py +0 -0
  48. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/smoke_test.py +0 -0
  49. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/__init__.py +0 -0
  50. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/backup.py +0 -0
  51. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  52. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/device_control.py +0 -0
  53. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/enhanced.py +0 -0
  54. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/helpers.py +0 -0
  55. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/reference_validator.py +0 -0
  56. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/registry.py +0 -0
  57. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/smart_search.py +0 -0
  58. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_addons.py +0 -0
  59. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_areas.py +0 -0
  60. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  61. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  62. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_calendar.py +0 -0
  63. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_camera.py +0 -0
  64. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_categories.py +0 -0
  65. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_code.py +0 -0
  66. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
  67. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  68. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  69. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_energy.py +0 -0
  70. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_entities.py +0 -0
  71. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  72. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_groups.py +0 -0
  73. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_hacs.py +0 -0
  74. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_history.py +0 -0
  75. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_integrations.py +0 -0
  76. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_labels.py +0 -0
  77. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  78. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_registry.py +0 -0
  79. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_resources.py +0 -0
  80. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_search.py +0 -0
  81. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_service.py +0 -0
  82. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_services.py +0 -0
  83. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_system.py +0 -0
  84. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_todo.py +0 -0
  85. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_traces.py +0 -0
  86. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_updates.py +0 -0
  87. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_utility.py +0 -0
  88. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  89. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  90. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/tools_zones.py +0 -0
  91. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/tools/util_helpers.py +0 -0
  92. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/transforms/__init__.py +0 -0
  93. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/transforms/categorized_search.py +0 -0
  94. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  95. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/utils/__init__.py +0 -0
  96. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/utils/config_hash.py +0 -0
  97. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/utils/data_paths.py +0 -0
  98. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/utils/domain_handlers.py +0 -0
  99. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  100. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  101. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/utils/operation_manager.py +0 -0
  102. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/utils/python_sandbox.py +0 -0
  103. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp/utils/usage_logger.py +0 -0
  104. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  105. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  106. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  107. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  108. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  109. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/tests/__init__.py +0 -0
  110. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/tests/test_constants.py +0 -0
  111. {ha_mcp_dev-7.5.0.dev531 → ha_mcp_dev-7.5.0.dev532}/tests/test_env_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.5.0.dev531
3
+ Version: 7.5.0.dev532
4
4
  Summary: Home Assistant MCP Server - Complete control of Home Assistant through MCP
5
5
  Author-email: Julien <github@qc-h.net>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ha-mcp-dev"
7
- version = "7.5.0.dev531"
7
+ version = "7.5.0.dev532"
8
8
  description = "Home Assistant MCP Server - Complete control of Home Assistant through MCP"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13,<3.14"
@@ -289,6 +289,21 @@ class AutomationConfigTools:
289
289
  For comprehensive automation documentation, use ha_get_skill_guide.
290
290
  """
291
291
  try:
292
+ # Empty/whitespace identifier would propagate to the internal
293
+ # config lookup and surface as a misleading
294
+ # ``RESOURCE_NOT_FOUND``. Structured ``VALIDATION_INVALID_PARAMETER``
295
+ # naming the parameter is cleaner — extension of the #1312
296
+ # validate_identifier_not_empty pattern to the automations
297
+ # family per #1313.
298
+ validate_identifier_not_empty(
299
+ identifier,
300
+ "identifier",
301
+ suggestions=[
302
+ "Pass an automation entity_id (e.g. 'automation.morning_routine')",
303
+ "Or pass the unique_id of an existing automation",
304
+ "Use ha_search_entities(domain_filter='automation') to list automations",
305
+ ],
306
+ )
292
307
  normalized_config, config_hash = await self._get_automation_config_internal(identifier)
293
308
 
294
309
  # Resolve entity_id and fetch category from entity registry
@@ -542,6 +557,23 @@ class AutomationConfigTools:
542
557
  """
543
558
  bp_warnings: list[str] = []
544
559
  try:
560
+ # ``identifier`` is optional (omit → create new with generated
561
+ # unique_id; pass → update existing). When provided, reject
562
+ # empty/whitespace up-front so the caller gets a structured
563
+ # parameter error instead of a misleading ``RESOURCE_NOT_FOUND``
564
+ # from the downstream lookup. The ``not identifier`` check
565
+ # further down the python_transform branch still handles the
566
+ # explicit ``identifier is None`` case for that mode.
567
+ if identifier is not None:
568
+ validate_identifier_not_empty(
569
+ identifier,
570
+ "identifier",
571
+ suggestions=[
572
+ "Omit identifier to create a new automation",
573
+ "Or pass a valid automation entity_id / unique_id to update",
574
+ ],
575
+ context={"action": "set"},
576
+ )
545
577
  # Validate mutual exclusivity of config and python_transform
546
578
  if config is not None and python_transform is not None:
547
579
  raise_tool_error(
@@ -26,6 +26,7 @@ from .helpers import (
26
26
  extract_tool_error_message,
27
27
  log_tool_usage,
28
28
  raise_tool_error,
29
+ validate_identifier_not_empty,
29
30
  )
30
31
  from .util_helpers import parse_json_param
31
32
 
@@ -605,6 +606,25 @@ def register_config_dashboard_tools(mcp: Any, client: Any, **kwargs: Any) -> Non
605
606
  "count": len(dashboards),
606
607
  }
607
608
 
609
+ # ``url_path`` is optional in this tool (omitted with
610
+ # ``list_only=True`` lists all dashboards — handled above; omitted
611
+ # without ``list_only`` falls back to the default dashboard via
612
+ # the resolver below). When provided, reject empty/whitespace
613
+ # up-front so the caller gets a structured parameter error
614
+ # instead of a misleading ``RESOURCE_NOT_FOUND``. Extension of
615
+ # the #1312 validate_identifier_not_empty pattern to the
616
+ # dashboards family per #1313.
617
+ if url_path is not None:
618
+ validate_identifier_not_empty(
619
+ url_path,
620
+ "url_path",
621
+ suggestions=[
622
+ "Pass a dashboard URL path (e.g. 'lovelace-home')",
623
+ "Omit url_path and pass list_only=True to list dashboards",
624
+ "Use 'default' to target the default dashboard",
625
+ ],
626
+ )
627
+
608
628
  # Search mode — find cards, badges, or header cards
609
629
  if search_mode:
610
630
  get_data: dict[str, Any] = {"type": "lovelace/config", "force": True}
@@ -996,6 +1016,22 @@ def register_config_dashboard_tools(mcp: Any, client: Any, **kwargs: Any) -> Non
996
1016
  are also updated if explicitly provided alongside (or instead of) a config change.
997
1017
  """
998
1018
  try:
1019
+ # ``url_path`` is required (always non-None). Reject empty/
1020
+ # whitespace up-front so the caller gets a structured parameter
1021
+ # error instead of a misleading downstream failure (the
1022
+ # subsequent "default" alias, pre-resolver, and hyphen check
1023
+ # all assume a usable string). Extension of the #1312
1024
+ # validate_identifier_not_empty pattern to the dashboards
1025
+ # family per #1313.
1026
+ validate_identifier_not_empty(
1027
+ url_path,
1028
+ "url_path",
1029
+ suggestions=[
1030
+ "Pass a dashboard URL path (e.g. 'my-dashboard')",
1031
+ "Use 'default' or 'lovelace' for the default dashboard",
1032
+ ],
1033
+ context={"action": "set"},
1034
+ )
999
1035
  # Handle "default" as alias for the default dashboard
1000
1036
  # (matches ha_config_get_dashboard behavior)
1001
1037
  if url_path == "default":
@@ -1490,6 +1526,20 @@ def register_config_dashboard_tools(mcp: Any, client: Any, **kwargs: Any) -> Non
1490
1526
  Note: The default dashboard cannot be deleted via this method.
1491
1527
  """
1492
1528
  try:
1529
+ # ``url_path`` is required. Reject empty/whitespace up-front so
1530
+ # the caller gets a structured parameter error instead of a
1531
+ # misleading "no dashboard found" from the resolver below.
1532
+ # Extension of the #1312 validate_identifier_not_empty pattern
1533
+ # to the dashboards family per #1313.
1534
+ validate_identifier_not_empty(
1535
+ url_path,
1536
+ "url_path",
1537
+ suggestions=[
1538
+ "Pass a dashboard URL path or internal ID (e.g. 'my-dashboard')",
1539
+ "Use ha_config_get_dashboard(list_only=True) to list dashboards",
1540
+ ],
1541
+ context={"action": "delete"},
1542
+ )
1493
1543
  resolved, _ = await _resolve_dashboard(client, url_path)
1494
1544
  if resolved is None:
1495
1545
  raise_tool_error(
@@ -103,6 +103,19 @@ class ConfigScriptTools:
103
103
  For detailed script configuration help, use ha_get_skill_guide.
104
104
  """
105
105
  try:
106
+ # Empty/whitespace script_id would propagate to
107
+ # ``get_script_config`` and surface as a misleading
108
+ # ``RESOURCE_NOT_FOUND``. Extension of the #1312
109
+ # validate_identifier_not_empty pattern to the scripts
110
+ # family per #1313.
111
+ validate_identifier_not_empty(
112
+ script_id,
113
+ "script_id",
114
+ suggestions=[
115
+ "Pass a script identifier (e.g. 'morning_routine')",
116
+ "Use ha_search_entities(domain_filter='script') to list scripts",
117
+ ],
118
+ )
106
119
  config_result = await self._client.get_script_config(script_id)
107
120
  # Extract actual script config body and compute hash before category injection
108
121
  actual_config = config_result.get("config", config_result)
@@ -412,6 +425,21 @@ class ConfigScriptTools:
412
425
  """
413
426
  bp_warnings: list[str] = []
414
427
  try:
428
+ # ``script_id`` is required (always non-None). Reject empty/
429
+ # whitespace up-front so the caller gets a structured parameter
430
+ # error instead of a misleading ``RESOURCE_NOT_FOUND`` from
431
+ # the downstream upsert/fetch. Extension of the #1312
432
+ # validate_identifier_not_empty pattern to the scripts family
433
+ # per #1313.
434
+ validate_identifier_not_empty(
435
+ script_id,
436
+ "script_id",
437
+ suggestions=[
438
+ "Pass a script identifier (e.g. 'morning_routine')",
439
+ "Use ha_search_entities(domain_filter='script') to list scripts",
440
+ ],
441
+ context={"action": "set"},
442
+ )
415
443
  # Validate mutual exclusivity of config and python_transform
416
444
  if config is not None and python_transform is not None:
417
445
  raise_tool_error(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.5.0.dev531
3
+ Version: 7.5.0.dev532
4
4
  Summary: Home Assistant MCP Server - Complete control of Home Assistant through MCP
5
5
  Author-email: Julien <github@qc-h.net>
6
6
  License: MIT