ha-mcp-dev 7.1.0.dev286__tar.gz → 7.1.0.dev288__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 (95) hide show
  1. {ha_mcp_dev-7.1.0.dev286/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.1.0.dev288}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/__main__.py +44 -0
  4. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  5. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/LICENSE +0 -0
  6. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/MANIFEST.in +0 -0
  7. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/README.md +0 -0
  8. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/setup.cfg +0 -0
  9. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/__init__.py +0 -0
  10. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/_pypi_marker +0 -0
  11. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/auth/__init__.py +0 -0
  12. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/auth/consent_form.py +0 -0
  13. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/auth/provider.py +0 -0
  14. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/client/__init__.py +0 -0
  15. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/client/rest_client.py +0 -0
  16. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/client/websocket_client.py +0 -0
  17. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/client/websocket_listener.py +0 -0
  18. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/config.py +0 -0
  19. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/errors.py +0 -0
  20. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/py.typed +0 -0
  21. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/card_types.json +0 -0
  22. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/dashboard_guide.md +0 -0
  23. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  24. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  25. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  26. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  27. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  28. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  29. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  30. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  31. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  32. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  33. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  34. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  35. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  36. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  37. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  38. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  39. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/server.py +0 -0
  40. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/smoke_test.py +0 -0
  41. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/__init__.py +0 -0
  42. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/backup.py +0 -0
  43. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  44. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/device_control.py +0 -0
  45. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/enhanced.py +0 -0
  46. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/helpers.py +0 -0
  47. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/registry.py +0 -0
  48. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/smart_search.py +0 -0
  49. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_addons.py +0 -0
  50. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_areas.py +0 -0
  51. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  52. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  53. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_calendar.py +0 -0
  54. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_camera.py +0 -0
  55. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  56. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  57. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
  58. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  59. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_config_info.py +0 -0
  60. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  61. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_entities.py +0 -0
  62. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  63. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_groups.py +0 -0
  64. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_hacs.py +0 -0
  65. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_history.py +0 -0
  66. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_integrations.py +0 -0
  67. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_labels.py +0 -0
  68. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  69. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_registry.py +0 -0
  70. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_resources.py +0 -0
  71. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_search.py +0 -0
  72. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_service.py +0 -0
  73. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_services.py +0 -0
  74. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_system.py +0 -0
  75. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_todo.py +0 -0
  76. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_traces.py +0 -0
  77. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_updates.py +0 -0
  78. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_utility.py +0 -0
  79. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  80. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/tools_zones.py +0 -0
  81. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/tools/util_helpers.py +0 -0
  82. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/utils/__init__.py +0 -0
  83. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/utils/domain_handlers.py +0 -0
  84. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  85. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/utils/operation_manager.py +0 -0
  86. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/utils/python_sandbox.py +0 -0
  87. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp/utils/usage_logger.py +0 -0
  88. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  89. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  90. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  91. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  92. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  93. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/tests/__init__.py +0 -0
  94. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/tests/test_constants.py +0 -0
  95. {ha_mcp_dev-7.1.0.dev286 → ha_mcp_dev-7.1.0.dev288}/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.1.0.dev286
3
+ Version: 7.1.0.dev288
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.1.0.dev286"
7
+ version = "7.1.0.dev288"
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"
@@ -16,6 +16,9 @@ import threading # noqa: E402
16
16
  from collections.abc import Coroutine # noqa: E402
17
17
  from typing import TYPE_CHECKING, Any # noqa: E402
18
18
 
19
+ from starlette.requests import Request # noqa: E402
20
+ from starlette.responses import PlainTextResponse # noqa: E402
21
+
19
22
  if TYPE_CHECKING:
20
23
  from fastmcp import FastMCP
21
24
 
@@ -567,6 +570,45 @@ async def _run_http_with_graceful_shutdown(
567
570
  )
568
571
 
569
572
 
573
+ _registered_landing_paths: set[str] = set()
574
+
575
+
576
+ def register_browser_landing(mcp_instance: "FastMCP", path: str) -> None:
577
+ """Register a GET handler that returns 405 with a helpful message.
578
+
579
+ Browsers and misconfigured clients that send GET instead of POST will see
580
+ a human-readable explanation instead of a bare "Method Not Allowed" error.
581
+ The 405 status and Allow header are set explicitly by this handler so
582
+ automated clients still get the correct HTTP semantics.
583
+
584
+ Args:
585
+ mcp_instance: The FastMCP server to register the route on.
586
+ path: The MCP endpoint path (e.g. "/mcp" or a secret path).
587
+ """
588
+ if path in _registered_landing_paths:
589
+ logger.warning("register_browser_landing: %r already registered, skipping", path)
590
+ return
591
+ _registered_landing_paths.add(path)
592
+
593
+ # Safe because the MCP streamable-http transport claims only POST and DELETE.
594
+ # FastMCP registers custom routes at lowest precedence (after the MCP route),
595
+ # so GET requests fall through here without intercepting MCP traffic.
596
+ @mcp_instance.custom_route(path, methods=["GET"])
597
+ async def _browser_landing(_: Request) -> PlainTextResponse:
598
+ return PlainTextResponse(
599
+ "HA-MCP server is up and running. To connect, please follow the "
600
+ "setup instructions (https://homeassistant-ai.github.io/ha-mcp/), "
601
+ "and paste the URL for this page into your LLM. If using Cloudflare "
602
+ "and you're unable to connect via your LLM, make sure the "
603
+ '"Block AI training bots" setting is set to '
604
+ '"do not block (allow crawlers)".',
605
+ status_code=405,
606
+ # DELETE is included per the MCP Streamable HTTP spec (used for
607
+ # session termination), even though this deployment uses stateless mode.
608
+ headers={"Allow": "POST, DELETE"},
609
+ )
610
+
611
+
570
612
  def _run_http_server(transport: str, default_port: int = 8086) -> None:
571
613
  """Common runner for HTTP-based transports.
572
614
 
@@ -575,6 +617,7 @@ def _run_http_server(transport: str, default_port: int = 8086) -> None:
575
617
  default_port: Default port to use if MCP_PORT env var is not set.
576
618
  """
577
619
  port, path = _get_http_runtime(default_port)
620
+ register_browser_landing(_get_mcp(), path)
578
621
 
579
622
  _run_entrypoint(
580
623
  _run_http_with_graceful_shutdown(transport, port, path),
@@ -699,6 +742,7 @@ async def _run_oauth_server(ha_url: str, base_url: str, port: int, path: str) ->
699
742
  mcp.auth = auth_provider
700
743
 
701
744
  logger.info("Server created with OAuthProxyClient")
745
+ register_browser_landing(mcp, path)
702
746
 
703
747
  tools = await mcp.list_tools()
704
748
  logger.info(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.1.0.dev286
3
+ Version: 7.1.0.dev288
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