refactor: extract shared Supervisor httpx client helper (#1130)#1203
Conversation
…t-ai#1130) Three direct-Supervisor httpx call sites all built fresh AsyncClients with the same boilerplate (base URL http://supervisor, Authorization: Bearer $SUPERVISOR_TOKEN). Move that into a single factory in client/supervisor_client.py and have the call sites pass relative paths instead of full URLs: - client/rest_client.py:_supervisor_logs_get - tools/tools_bug_report.py:_fetch_addon_logs - settings_ui.py:_restart_addon Per-call clients (vs. a singleton) preserved — these endpoints are low-frequency, connection-pool reuse is negligible, and singleton lifecycle adds shutdown/reload coupling that the issue's homeassistant-ai#1126 G2 review already declined for the same reason. verify and timeout stay caller-supplied so each site keeps its existing settings-source choice (instance snapshot vs. live read). Token is read from env in the helper at construction time, matching the original sites; the absent-token policy stays at the call site (rich exception, silent empty string, or 400 JSONResponse — these don't share a common shape and the helper shouldn't dictate one). Tests: new tests/src/unit/test_supervisor_client.py covers the factory contract (base_url, env override, Bearer header, timeout/verify forwarding, absent-token graceful degradation). Two existing tests in test_tools_utility_supervisor_logs.py updated to the new contract: URL passed to .get() is now relative; Authorization header asserted on the constructor kwargs instead of the per-call kwargs. Closes homeassistant-ai#1130.
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request consolidates redundant Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request centralizes Home Assistant Supervisor API interactions by introducing a make_supervisor_httpx_client factory. It refactors call sites in the REST client, settings UI, and bug reporting tools to use this helper, ensuring consistent handling of base URLs, timeouts, and authentication. New unit tests were added to validate the factory's logic. Feedback suggests improving robustness when the supervisor token is missing to avoid malformed headers and recommends aligning configuration access with project standards.
Implementation SummaryChoices Made:
Problems Encountered:
Suggested Improvements:
|
kingpanther13
left a comment
There was a problem hiding this comment.
Refactor is mechanically clean — wire-level behaviour, exception flow, and per-site absent-token policies are preserved byte-for-byte across the three migrated call sites. A few changes before this merges.
1. Empty Bearer shouldn't be a documented contract
make_supervisor_httpx_client silently emits Authorization: Bearer when SUPERVISOR_TOKEN is unset, and test_supervisor_client.py::test_authorization_uses_supervisor_token_env pins that as supported behaviour. The three current call sites guard before calling, so it's latent today, but the framing inverts the upstream _supervisor_logs_get posture (fast-fail with a distinct message so operators don't read 401 as "token rejected"). A future direct caller that forgets the guard turns "env var missing" into "Supervisor rejected our token" — exactly the silent-failure mode rest_client.py was written to avoid.
Pick one:
- Raise inside the factory on empty token (preferred — pushes detection to construction time, matches the upstream design).
- Downgrade the docstring + test from "contract" to "hazard," log a warning when the empty-Bearer path is taken.
2. Two call-site test files don't pin the new wire shape
test_tools_bug_report.py (_fetch_addon_logs tests) and test_settings_ui.py (_restart_addon tests) patch httpx.AsyncClient at module scope and pass through transitively after the refactor, but never assert that the relative URL (/addons/self/logs, /addons/self/restart) or the Authorization header actually reach the client. A regression that broke the relative-path conversion or the ctor-set header at either site wouldn't be caught here — only test_tools_utility_supervisor_logs.py:257 pins it for _supervisor_logs_get. Add one call_args assertion per site for parity.
3. Header layering is untested
_supervisor_logs_get passes per-call headers={"Accept": "text/plain"} on top of the factory's ctor-level Authorization. httpx layers these correctly today, but no unit test in test_supervisor_client.py covers the case — a regression that moved Authorization to per-call defaults would silently strip it. Add a test that constructs the factory client, overlays a per-call Accept header, and asserts both headers reach the outbound request.
4. Drop issue/PR refs from code and test comments
Per AGENTS.md, comments shouldn't reference ephemeral context like PR numbers — they rot once the PR is merged and the call sites move. Locations:
src/ha_mcp/client/supervisor_client.py:8-13— drop#1116, #1126tests/src/unit/test_supervisor_client.py:7-8, 64, 119, 142— drop(#1128)and "three call sites" framingtests/src/unit/test_tools_utility_supervisor_logs.py:254-256, 579-580— drop "after the supervisor_client refactor (#1130)"; replace with neutral statements about what the code does now
While you're in there
supervisor_client.py:65— env read happens at construction, frozen into the header. Fine for today's short-livedasync withcallers, latent footgun for any future long-lived/reused client across token rotations. One-line note in the function docstring, or move the env read into an httpx event hook.supervisor_client.py:36—verify: boolnarrows httpx'sbool | str | ssl.SSLContextsurface. Intentional? If yes, leave; if not, broaden.supervisor_client.py:19-22vs:59-62— the token-handling paragraph is duplicated almost verbatim in module + function docstrings. Pick one.supervisor_client.py:47-51— theverifyrationale ("SUPERVISOR_BASE_URLenv-var overrides that may be HTTPS in non-add-on test rigs") is worth spot-checking thatget_supervisor_base_urlactually permits HTTPS overrides; otherwise the justification is misleading.- Across the migrated sites — pinning "no caller-supplied
Authorizationin per-call kwargs" with anassert "Authorization" not in kwargs.get("headers", {})(already done attest_tools_utility_supervisor_logs.py:259) is worth replicating at the other two test sites while you're adding the URL assertions.
- Raise RuntimeError on absent/empty SUPERVISOR_TOKEN at the factory so the malformed Bearer header never reaches Supervisor. - Add wire-shape unit tests for _fetch_addon_logs and _restart_addon asserting relative URLs, ctor-set Authorization, and no per-call Authorization kwarg. - Add a header-layering test pinning per-call Accept overlay on the ctor-set Authorization. - Drop ephemeral PR/issue refs from code and test comments per AGENTS.md. - Broaden the verify parameter type to httpx's full surface, add an env-read-at-construction Note to the docstring, dedup the token-handling paragraph. - Sibling: test_config_toggles_section_renders_in_templates now delenv's SUPERVISOR_TOKEN so the SimpleNamespace fake (missing verify_ssl) doesn't hit the addon-logs path on containers with the env var set.
Patch76
left a comment
There was a problem hiding this comment.
Round-2 fixes pushed. Walkthrough of each item from the review:
1. Empty Bearer contract → Option A (raise in factory). make_supervisor_httpx_client now raises RuntimeError if SUPERVISOR_TOKEN is unset or empty. The existing test_authorization_header_with_absent_token is rewritten as test_raises_on_absent_token; a sibling test_raises_on_empty_token covers the empty-string case. All three call sites already guard before invoking the factory, so the raise is a pure future-proof defensive — no current caller reaches it.
2. Wire-shape asserts on the two call-site test files. New tests test_passes_relative_url_with_ctor_authorization (test_tools_bug_report.py) and test_posts_relative_url_with_ctor_authorization (test_settings_ui.py) mirror the pattern at test_tools_utility_supervisor_logs.py:253-266: relative path on call, Authorization absent from per-call kwargs, base_url + Authorization on ctor kwargs.
3. Header-layering test. test_per_call_headers_layer_over_ctor_authorization in test_supervisor_client.py constructs a real client, calls client.build_request("GET", "/addons/self/logs", headers={"Accept": "text/plain"}), and asserts both ctor-Authorization and per-call Accept reach the merged request headers.
4. Drop PR/issue refs. All #1116, #1126, #1128, #1130 framing dropped from supervisor_client.py, test_supervisor_client.py, and the cited blocks in test_tools_utility_supervisor_logs.py. Remaining #1126 review item N / #1116 refs in that file are regression-test descriptions tied to those prior PRs' findings, predate this PR, and stay scoped to their own fixes.
"While you're in there"
:65env-read frozen at construction: added aNote:paragraph to the function docstring covering the long-lived/reused-client footgun.:36verify narrowing: broadened tobool | str | ssl.SSLContextto match httpx's full surface; docstring updated.:19-22vs:59-62docstring dedup: module-level token-handling paragraph removed; function-docstringRaises:block carries the policy.:47-51verify rationale spot-check:get_supervisor_base_urlat_version.py:69returnsos.environ.get("SUPERVISOR_BASE_URL", "http://supervisor")without protocol restriction, so HTTPS overrides flow through unchanged. Rationale stands.- Cross-site
Authorization-not-in-kwargs asserts: bundled into the new wire-shape tests in finding 2.
Sibling fix
test_config_toggles_section_renders_in_templates (test_tools_bug_report.py) now delenvs SUPERVISOR_TOKEN before invoking ha_report_issue_func. The SimpleNamespace fake settings carry only the toggle fields (no verify_ssl); without the delenv, the addon-logs path runs on containers with the token set and the fake hits an AttributeError. Pre-existing on master; CI passed because the runner has no token. In scope per the boy-scout rule since the file is touched by this PR.
kingpanther13
left a comment
There was a problem hiding this comment.
Round-2 fixes verified. All four review findings addressed: factory now raises RuntimeError on absent/empty SUPERVISOR_TOKEN (loud fail-fast replaces the empty-Bearer footgun); wire-shape pinned at all three call sites; header layering test exercises the Accept-over-Authorization merge through client.build_request; PR/issue refs neutralised in the right places. "While you're in there" items all picked up: verify type broadened to the full httpx surface, module-docstring dedup, long-lived-caller footgun noted, verify rationale spot-checked. Sibling delenv fix in test_config_toggles_section_renders_in_templates correctly addresses a pre-existing latent AttributeError.
🧪 Your changes are now in the dev channel!Your PR has been merged to master and is available for testing in the dev channel. Test your changes before the next stable release (biweekly Wednesday): Quick start# Run dev version
uvx ha-mcp-dev
# Check version
uvx ha-mcp-dev --versionDocker: docker pull ghcr.io/homeassistant-ai/ha-mcp:dev
docker run --rm -i \
-e HOMEASSISTANT_URL=http://your-ha:8123 \
-e HOMEASSISTANT_TOKEN=your_token \
ghcr.io/homeassistant-ai/ha-mcp:devFound an issue? Please open a new bug report and mention this PR for context. |
…→ 7.5.0) (#455) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/homeassistant-ai/ha-mcp](https://github.com/homeassistant-ai/ha-mcp) | minor | `7.4.0` → `7.5.0` | --- >⚠️ **Warning** > > Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/3) for more information. --- ### Release Notes <details> <summary>homeassistant-ai/ha-mcp (ghcr.io/homeassistant-ai/ha-mcp)</summary> ### [`v7.5.0`](https://github.com/homeassistant-ai/ha-mcp/blob/HEAD/CHANGELOG.md#v750-2026-05-13) [Compare Source](homeassistant-ai/ha-mcp@v7.4.0...v7.5.0) ##### Added - Add ENABLE\_LITE\_DOCSTRINGS beta toggle ([#​1259](homeassistant-ai/ha-mcp#1259)) - Add ha\_call\_event tool for publishing events on the HA event bus ([#​996](homeassistant-ai/ha-mcp#996)) ([#​1239](homeassistant-ai/ha-mcp#1239)) - Pinpoint backslash-escape mistake in python\_sandbox errors ([#​1204](homeassistant-ai/ha-mcp#1204)) - Reject empty-trigger automations targeting scene.create ([#​1187](homeassistant-ai/ha-mcp#1187)) - Add scene config tools — ha\_config\_get/set/remove\_scene ([#​1168](homeassistant-ai/ha-mcp#1168)) - **addon**: Optional OAuth 2.1 mode for webhook proxy (beta) ([#​1184](homeassistant-ai/ha-mcp#1184)) - Surface helper schema inline in ha\_config\_set\_helper validation errors ([#​1149](homeassistant-ai/ha-mcp#1149)) ([#​1179](homeassistant-ai/ha-mcp#1179)) - Emit progress via FastMCP Context in long-running tools ([#​1124](homeassistant-ai/ha-mcp#1124)) - Broaden python\_transform AST allowlist + improve error UX ([#​1163](homeassistant-ai/ha-mcp#1163)) - Add ha\_manage\_custom\_tool — sandboxed code execution escape hatch ([#​854](homeassistant-ai/ha-mcp#854)) - Always-on skills; rename list/read resource tools with ha\_ prefix ([#​1136](homeassistant-ai/ha-mcp#1136)) - Expose device\_class + options on ha\_set\_entity / ha\_get\_entity (Show As) ([#​1135](homeassistant-ai/ha-mcp#1135)) - **site**: Inline wizard data into setup.astro, migrate setup nuggets, drop content collections ([#​1120](homeassistant-ai/ha-mcp#1120)) - Add "Advanced debug logging" toggle for kill-signal diagnostics ([#​1117](homeassistant-ai/ha-mcp#1117)) - **yaml**: Scoped lovelace.dashboards.\<url\_path> support (issue [#​1034](homeassistant-ai/ha-mcp#1034)) ([#​1103](homeassistant-ai/ha-mcp#1103)) - Add HA\_VERIFY\_SSL toggle to disable TLS verification ([#​1104](homeassistant-ai/ha-mcp#1104)) - Per-top-level-key config\_hash for ha\_manage\_energy\_prefs ([#​1049](homeassistant-ai/ha-mcp#1049)) ([#​1098](homeassistant-ai/ha-mcp#1098)) - **site**: Add gemini-cli setup notes + compose hardening to wizard ([#​1027](homeassistant-ai/ha-mcp#1027)) ([#​1087](homeassistant-ai/ha-mcp#1087)) - Add convenience modes to ha\_manage\_energy\_prefs ([#​1050](homeassistant-ai/ha-mcp#1050)) ([#​1073](homeassistant-ai/ha-mcp#1073)) - Surface integration log levels in ha\_get\_logs/integration/addon ([#​956](homeassistant-ai/ha-mcp#956)) ([#​1003](homeassistant-ai/ha-mcp#1003)) - Expose allowlist\_external\_dirs in ha\_get\_overview full system\_info ([#​1053](homeassistant-ai/ha-mcp#1053)) - **dashboards**: Unify identifier handling in ha\_config\_\*\_dashboard tools ([#​981](homeassistant-ai/ha-mcp#981)) ([#​1075](homeassistant-ai/ha-mcp#1075)) - Include addon container logs in bug reports ([#​934](homeassistant-ai/ha-mcp#934)) - Add WebSocket response-shaping controls to ha\_manage\_addon ([#​1009](homeassistant-ai/ha-mcp#1009)) - Web-based settings UI for per-tool enable/disable/pin ([#​960](homeassistant-ai/ha-mcp#960)) - **site**: Add OpenCode support to setup wizard ([#​1080](homeassistant-ai/ha-mcp#1080)) ##### Changed - Clarify standard-mode HTTP deployment guidance ([#​1185](homeassistant-ai/ha-mcp#1185)) - Add Cloudflared add-on hostname alternative for tunnel service ([#​1183](homeassistant-ai/ha-mcp#1183)) - Align tool naming convention between AGENTS.md and styleguide ([#​943](homeassistant-ai/ha-mcp#943)) ([#​1174](homeassistant-ai/ha-mcp#1174)) - **addon**: Note tool-list ([#​985](homeassistant-ai/ha-mcp#985 divergence; fix [#​1139](https://github.com/homeassistant-ai/ha-mcp/issues/1139)/[#​1162](https://github.com/homeassistant-ai/ha-mcp/issues/1162) test conflict ([#​1172](homeassistant-ai/ha-mcp#1172)) - Add brew install option for mcp-proxy on macOS ([#​1171](homeassistant-ai/ha-mcp#1171)) - Update contributors list \[contributors-updated] ([`aba01a1`](homeassistant-ai/ha-mcp@aba01a1)) - Warn against enable\_tool\_search on Claude Sonnet/Opus ([#​1088](homeassistant-ai/ha-mcp#1088)) ([#​1140](homeassistant-ai/ha-mcp#1140)) - Address [#​1094](homeassistant-ai/ha-mcp#1094) review nits on OpenCode mirror comments ([#​1105](homeassistant-ai/ha-mcp#1105)) ##### Fixed - **integrations**: Surface ConfigEntry.options via OptionsFlow probe ([#​1245](homeassistant-ai/ha-mcp#1245)) - **backup**: Discover local agent at call time instead of hardcoding hassio.local ([#​1244](homeassistant-ai/ha-mcp#1244)) - Triage all 10 ha\_search\_entities behaviors from [#​1170](homeassistant-ai/ha-mcp#1170) ([#​1195](homeassistant-ai/ha-mcp#1195)) - Replace cron with systemd for demo server (prevents process leak) ([#​1110](homeassistant-ai/ha-mcp#1110)) - Improve ha\_manage\_addon discoverability (BM25 keywords + slug examples) ([#​1200](homeassistant-ai/ha-mcp#1200)) - Route Supervisor 401s to structured tool errors + add E2E coverage ([#​1129](homeassistant-ai/ha-mcp#1129)) ([#​1192](homeassistant-ai/ha-mcp#1192)) - Harden \_validate\_category\_id gate to cover dict-promoted category ([#​1190](homeassistant-ai/ha-mcp#1190)) - Broaden template anti-pattern detection + skill discoverability ([#​1011](homeassistant-ai/ha-mcp#1011)) ([#​1181](homeassistant-ai/ha-mcp#1181)) - Return newest automation traces, add offset+order pagination ([#​1177](homeassistant-ai/ha-mcp#1177)) ([#​1178](homeassistant-ai/ha-mcp#1178)) - **security**: Write YAML backups outside www/ (GHSA-g39v-cvjh-8fpf) ([#​1180](homeassistant-ai/ha-mcp#1180)) - **search**: Apply domain\_filter when area\_filter is set ([#​1162](homeassistant-ai/ha-mcp#1162)) ([#​1165](homeassistant-ai/ha-mcp#1165)) - **resources**: Reject HA-config YAML in dashboard resource content ([#​1160](homeassistant-ai/ha-mcp#1160)) - Close 19 bugs in ha\_config\_set\_helper (issue [#​1150](homeassistant-ai/ha-mcp#1150)) ([#​1151](homeassistant-ai/ha-mcp#1151)) - Route addon log fetches directly to supervisor on addon installs ([#​1126](homeassistant-ai/ha-mcp#1126)) - Survive read-only filesystems at startup ([#​1138](homeassistant-ai/ha-mcp#1138)) - **helpers**: Clarify name-required-on-create for ha\_config\_set\_helper ([#​1143](homeassistant-ai/ha-mcp#1143)) - Resolve disabled entities via entity\_registry in helper deletion ([#​1119](homeassistant-ai/ha-mcp#1119)) - Allow unary operators in python\_transform sandbox ([#​1118](homeassistant-ai/ha-mcp#1118)) - **site**: Add github-copilot-agents wizard branch + delete unreferenced data/clients.ts ([#​1108](homeassistant-ai/ha-mcp#1108)) - **addons**: Route addon API calls through HA Core ingress proxy ([#​1069](homeassistant-ai/ha-mcp#1069)) - **webhook-proxy**: Surface webhook registration failures instead of silently loading ([#​1101](homeassistant-ai/ha-mcp#1101)) - **site**: Resolve client display-order collisions and anchor OpenCode shape ([#​1094](homeassistant-ai/ha-mcp#1094)) ##### Performance Improvements - Dedupe lovelace/dashboards/list in ha\_config\_set\_dashboard ([#​1085](homeassistant-ai/ha-mcp#1085)) ([#​1191](homeassistant-ai/ha-mcp#1191)) ##### Refactoring - Drop obsolete ha\_mcp\_tools defensive ruamel.yaml imports ([post-#​1268](https://github.com/post-/ha-mcp/issues/1268)) ([#​1269](homeassistant-ai/ha-mcp#1269)) - Extract shared Supervisor httpx client helper ([#​1130](homeassistant-ai/ha-mcp#1130)) ([#​1203](homeassistant-ai/ha-mcp#1203)) - Surface client identity, AI model, config toggles, and prompt context in ha\_report\_issue ([#​1189](homeassistant-ai/ha-mcp#1189)) - Harden Context injection with safe-emit + branch coverage ([#​1173](homeassistant-ai/ha-mcp#1173)) - Consolidate area/floor set+remove tools (revisit of [#​813](homeassistant-ai/ha-mcp#813)) ([#​1139](homeassistant-ai/ha-mcp#1139)) - Pass verify\_ssl to remaining direct-Supervisor httpx callers ([#​1128](homeassistant-ai/ha-mcp#1128)) - Validate only new entries on convenience-mode writes ([#​1086](homeassistant-ai/ha-mcp#1086)) ([#​1100](homeassistant-ai/ha-mcp#1100)) *** <details> <summary>Internal Changes</summary> ##### Fixed - **ci**: Align pr.yml E2E with --dist loadscope ([#​1206](homeassistant-ai/ha-mcp#1206)) ([#​1247](homeassistant-ai/ha-mcp#1247)) - **ci**: Switch Renovate to a GitHub App token to allow workflow-file pushes ([#​1229](homeassistant-ai/ha-mcp#1229)) - **ci**: Break gemini-triage retrigger loop and bump turn budget ([#​1131](homeassistant-ai/ha-mcp#1131)) - **ci**: Harden gemini-triage so failures stop spamming user issues ([#​1122](homeassistant-ai/ha-mcp#1122)) - **ci**: Unbreak hotfix-release semantic-release run ([#​1091](homeassistant-ai/ha-mcp#1091)) ##### Chores - **addon**: Publish dev addon version 7.4.1.dev299 \[skip ci] ([`397aa6d`](homeassistant-ai/ha-mcp@397aa6d)) - **addon**: Publish dev addon version 7.4.1.dev298 \[skip ci] ([`942b7e0`](homeassistant-ai/ha-mcp@942b7e0)) - Sync tool docs after merge \[skip ci] ([`6823c47`](homeassistant-ai/ha-mcp@6823c47)) - **addon**: Publish dev addon version 7.4.1.dev297 \[skip ci] ([`6eac062`](homeassistant-ai/ha-mcp@6eac062)) - **addon**: Publish dev addon version 7.4.1.dev296 \[skip ci] ([`b2afe93`](homeassistant-ai/ha-mcp@b2afe93)) - **addon**: Publish dev addon version 7.4.1.dev295 \[skip ci] ([`4f4c4f3`](homeassistant-ai/ha-mcp@4f4c4f3)) - **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.1 ([#​1236](homeassistant-ai/ha-mcp#1236)) - **addon**: Publish dev addon version 7.4.1.dev294 \[skip ci] ([`fd24991`](homeassistant-ai/ha-mcp@fd24991)) - **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.13 ([#​1233](homeassistant-ai/ha-mcp#1233)) - **addon**: Publish dev addon version 7.4.1.dev293 \[skip ci] ([`fcc6496`](homeassistant-ai/ha-mcp@fcc6496)) - **addon**: Publish dev addon version 7.4.1.dev292 \[skip ci] ([`2961650`](homeassistant-ai/ha-mcp@2961650)) - **addon**: Publish dev addon version 7.4.1.dev291 \[skip ci] ([`5703112`](homeassistant-ai/ha-mcp@5703112)) - **addon**: Publish dev addon version 7.4.1.dev290 \[skip ci] ([`19b2f65`](homeassistant-ai/ha-mcp@19b2f65)) - **addon**: Publish dev addon version 7.4.1.dev289 \[skip ci] ([`e5a1365`](homeassistant-ai/ha-mcp@e5a1365)) - Sync tool docs after merge \[skip ci] ([`d2ff93b`](homeassistant-ai/ha-mcp@d2ff93b)) - **addon**: Publish dev addon version 7.4.1.dev288 \[skip ci] ([`0f62400`](homeassistant-ai/ha-mcp@0f62400)) - Sync tool docs after merge \[skip ci] ([`c7e2066`](homeassistant-ai/ha-mcp@c7e2066)) - **addon**: Publish dev addon version 7.4.1.dev287 \[skip ci] ([`c1133d4`](homeassistant-ai/ha-mcp@c1133d4)) - **addon**: Publish dev addon version 7.4.1.dev286 \[skip ci] ([`1ae790e`](homeassistant-ai/ha-mcp@1ae790e)) - **addon**: Publish dev addon version 7.4.1.dev285 \[skip ci] ([`2387d0c`](homeassistant-ai/ha-mcp@2387d0c)) - **addon**: Publish dev addon version 7.4.1.dev284 \[skip ci] ([`dd3a4a5`](homeassistant-ai/ha-mcp@dd3a4a5)) - **addon**: Publish dev addon version 7.4.1.dev283 \[skip ci] ([`78af8eb`](homeassistant-ai/ha-mcp@78af8eb)) - Sync tool docs after merge \[skip ci] ([`093fd74`](homeassistant-ai/ha-mcp@093fd74)) - **addon**: Publish dev addon version 7.4.1.dev282 \[skip ci] ([`2141e15`](homeassistant-ai/ha-mcp@2141e15)) - Sync tool docs after merge \[skip ci] ([`7810c95`](homeassistant-ai/ha-mcp@7810c95)) - **addon**: Publish dev addon version 7.4.1.dev281 \[skip ci] ([`7d79ec2`](homeassistant-ai/ha-mcp@7d79ec2)) - Sync tool docs after merge \[skip ci] ([`a73dc81`](homeassistant-ai/ha-mcp@a73dc81)) - **addon**: Publish dev addon version 7.4.1.dev280 \[skip ci] ([`c858ce3`](homeassistant-ai/ha-mcp@c858ce3)) - Sync tool docs after merge \[skip ci] ([`a587be0`](homeassistant-ai/ha-mcp@a587be0)) - **addon**: Publish dev addon version 7.4.1.dev279 \[skip ci] ([`b78ddb2`](homeassistant-ai/ha-mcp@b78ddb2)) - Sync tool docs after merge \[skip ci] ([`1210725`](homeassistant-ai/ha-mcp@1210725)) - **addon**: Publish dev addon version 7.4.1.dev278 \[skip ci] ([`a282c17`](homeassistant-ai/ha-mcp@a282c17)) - **addon**: Publish dev addon version 7.4.1.dev277 \[skip ci] ([`1081768`](homeassistant-ai/ha-mcp@1081768)) - Sync tool docs after merge \[skip ci] ([`e03f5d2`](homeassistant-ai/ha-mcp@e03f5d2)) - **addon**: Publish dev addon version 7.4.1.dev276 \[skip ci] ([`c4ef680`](homeassistant-ai/ha-mcp@c4ef680)) - **addon**: Publish dev addon version 7.4.1.dev275 \[skip ci] ([`780422d`](homeassistant-ai/ha-mcp@780422d)) - Sync tool docs after merge \[skip ci] ([`8a2bd1a`](homeassistant-ai/ha-mcp@8a2bd1a)) - **addon**: Publish dev addon version 7.4.1.dev274 \[skip ci] ([`f0f09de`](homeassistant-ai/ha-mcp@f0f09de)) - **addon**: Publish dev addon version 7.4.1.dev273 \[skip ci] ([`cb49f68`](homeassistant-ai/ha-mcp@cb49f68)) - **addon**: Publish dev addon version 7.4.1.dev272 \[skip ci] ([`5097186`](homeassistant-ai/ha-mcp@5097186)) - **addon**: Publish dev addon version 7.4.1.dev271 \[skip ci] ([`4714342`](homeassistant-ai/ha-mcp@4714342)) - **addon**: Publish dev addon version 7.4.1.dev270 \[skip ci] ([`217982a`](homeassistant-ai/ha-mcp@217982a)) - **addon**: Publish dev addon version 7.4.1.dev269 \[skip ci] ([`a65dd5f`](homeassistant-ai/ha-mcp@a65dd5f)) - Sync tool docs after merge \[skip ci] ([`0e6b54f`](homeassistant-ai/ha-mcp@0e6b54f)) - **addon**: Publish dev addon version 7.4.1.dev268 \[skip ci] ([`60ba1f2`](homeassistant-ai/ha-mcp@60ba1f2)) - **addon**: Publish dev addon version 7.4.1.dev267 \[skip ci] ([`13412aa`](homeassistant-ai/ha-mcp@13412aa)) - Sync tool docs after merge \[skip ci] ([`2702a0f`](homeassistant-ai/ha-mcp@2702a0f)) - **addon**: Publish dev addon version 7.4.1.dev266 \[skip ci] ([`77abe0b`](homeassistant-ai/ha-mcp@77abe0b)) - **addon**: Publish dev addon version 7.4.1.dev265 \[skip ci] ([`08b69db`](homeassistant-ai/ha-mcp@08b69db)) - Sync tool docs after merge \[skip ci] ([`c1f24b5`](homeassistant-ai/ha-mcp@c1f24b5)) - **addon**: Publish dev addon version 7.4.1.dev264 \[skip ci] ([`f2583f6`](homeassistant-ai/ha-mcp@f2583f6)) - Sync tool docs after merge \[skip ci] ([`c2ed2d3`](homeassistant-ai/ha-mcp@c2ed2d3)) - **addon**: Publish dev addon version 7.4.1.dev263 \[skip ci] ([`9d43e54`](homeassistant-ai/ha-mcp@9d43e54)) - **addon**: Publish dev addon version 7.4.1.dev262 \[skip ci] ([`a7355c8`](homeassistant-ai/ha-mcp@a7355c8)) - Sync tool docs after merge \[skip ci] ([`085bd8a`](homeassistant-ai/ha-mcp@085bd8a)) - Convert agents to skills ([#​1084](homeassistant-ai/ha-mcp#1084)) - **addon**: Publish dev addon version 7.4.1.dev261 \[skip ci] ([`0d1af36`](homeassistant-ai/ha-mcp@0d1af36)) - **addon**: Publish dev addon version 7.4.1.dev260 \[skip ci] ([`29397dc`](homeassistant-ai/ha-mcp@29397dc)) - **addon**: Publish dev addon version 7.4.1.dev259 \[skip ci] ([`4bbc74b`](homeassistant-ai/ha-mcp@4bbc74b)) - Sync tool docs after merge \[skip ci] ([`0f6d41e`](homeassistant-ai/ha-mcp@0f6d41e)) - **addon**: Publish dev addon version 7.4.1.dev258 \[skip ci] ([`6751d08`](homeassistant-ai/ha-mcp@6751d08)) - **addon**: Publish dev addon version 7.4.1.dev257 \[skip ci] ([`2213c89`](homeassistant-ai/ha-mcp@2213c89)) - **addon**: Publish dev addon version 7.4.1.dev256 \[skip ci] ([`18a366e`](homeassistant-ai/ha-mcp@18a366e)) - **addon**: Publish dev addon version 7.4.1.dev255 \[skip ci] ([`0e9b18d`](homeassistant-ai/ha-mcp@0e9b18d)) - **addon**: Publish dev addon version 7.4.1.dev254 \[skip ci] ([`39fc65b`](homeassistant-ai/ha-mcp@39fc65b)) - Sync tool docs after merge \[skip ci] ([`9fa0aea`](homeassistant-ai/ha-mcp@9fa0aea)) - **addon**: Publish dev addon version 7.4.1.dev253 \[skip ci] ([`0dcc59e`](homeassistant-ai/ha-mcp@0dcc59e)) - Sync tool docs after merge \[skip ci] ([`ec7413f`](homeassistant-ai/ha-mcp@ec7413f)) - **addon**: Publish dev addon version 7.4.1.dev252 \[skip ci] ([`345640c`](homeassistant-ai/ha-mcp@345640c)) - **addon**: Publish dev addon version 7.4.1.dev251 \[skip ci] ([`bab9d49`](homeassistant-ai/ha-mcp@bab9d49)) - Sync tool docs after merge \[skip ci] ([`726f0a5`](homeassistant-ai/ha-mcp@726f0a5)) - **addon**: Publish dev addon version 7.4.1.dev250 \[skip ci] ([`ded04ea`](homeassistant-ai/ha-mcp@ded04ea)) - **addon**: Publish dev addon version 7.4.1.dev249 \[skip ci] ([`37d5628`](homeassistant-ai/ha-mcp@37d5628)) - **addon**: Publish dev addon version 7.4.1.dev248 \[skip ci] ([`530786a`](homeassistant-ai/ha-mcp@530786a)) - Sync tool docs after merge \[skip ci] ([`36719c3`](homeassistant-ai/ha-mcp@36719c3)) - **addon**: Publish dev addon version 7.4.1.dev247 \[skip ci] ([`4dc47b5`](homeassistant-ai/ha-mcp@4dc47b5)) - **addon**: Publish dev addon version 7.4.1.dev246 \[skip ci] ([`6ffbd6a`](homeassistant-ai/ha-mcp@6ffbd6a)) - Sync tool docs after merge \[skip ci] ([`add66e3`](homeassistant-ai/ha-mcp@add66e3)) - **addon**: Publish dev addon version 7.4.1.dev245 \[skip ci] ([`d0114af`](homeassistant-ai/ha-mcp@d0114af)) - Sync tool docs after merge \[skip ci] ([`0ca41af`](homeassistant-ai/ha-mcp@0ca41af)) - **addon**: Publish dev addon version 7.4.1.dev244 \[skip ci] ([`d052dd0`](homeassistant-ai/ha-mcp@d052dd0)) - **addon**: Publish dev addon version 7.4.0.dev243 \[skip ci] ([`827bc65`](homeassistant-ai/ha-mcp@827bc65)) - Bump package version to 7.4.1 to match released addon ([`4f65497`](homeassistant-ai/ha-mcp@4f65497)) - **addon**: Publish dev addon version 7.4.0.dev242 \[skip ci] ([`8ba80ae`](homeassistant-ai/ha-mcp@8ba80ae)) - **addon**: Publish hotfix version 7.4.1 ([`bda75e6`](homeassistant-ai/ha-mcp@bda75e6)) - **addon**: Publish dev addon version 7.4.0.dev241 \[skip ci] ([`2126428`](homeassistant-ai/ha-mcp@2126428)) ##### Continuous Integration - **deps**: Bump renovatebot/github-action in the github-actions group ([#​1218](homeassistant-ai/ha-mcp#1218)) - **deps**: Bump renovatebot/github-action in the github-actions group ([#​1111](homeassistant-ai/ha-mcp#1111)) ##### Refactoring - Extract \_fetch\_dashboards\_list helper ([#​1193](homeassistant-ai/ha-mcp#1193)) ([#​1207](homeassistant-ai/ha-mcp#1207)) ##### Testing - **e2e**: Module-scope bulk\_automations + bulk\_scripts fixtures (refs [#​366](homeassistant-ai/ha-mcp#366)) ([#​1275](homeassistant-ai/ha-mcp#1275)) - **e2e**: Lower INPUT\_BOOLEAN\_WAIT from 30s to 10s (refs [#​366](homeassistant-ai/ha-mcp#366)) ([#​1273](homeassistant-ai/ha-mcp#1273)) - **e2e**: Generalize readiness-gate diagnostics helper (closes [#​1267](homeassistant-ai/ha-mcp#1267)) ([#​1271](homeassistant-ai/ha-mcp#1271)) - **e2e**: Narrow except clauses in e2e polling helpers (closes [#​1266](homeassistant-ai/ha-mcp#1266)) ([#​1270](homeassistant-ai/ha-mcp#1270)) - **e2e**: Drop ha\_mcp\_tools retry-path + pre-install manifest requirements ([#​1268](homeassistant-ai/ha-mcp#1268)) - **e2e**: Instrument and retry ha\_mcp\_tools readiness wait ([#​1262](homeassistant-ai/ha-mcp#1262)) - Use time.monotonic() in UAT runner and test\_env\_manager ([#​1254](homeassistant-ai/ha-mcp#1254)) - **e2e**: Detect partial/corrupt hacs\_frontend dir in fast-path guard ([#​1253](homeassistant-ai/ha-mcp#1253)) - **e2e**: Remove unused wait/assert helpers ([post-#​1249](https://github.com/post-/ha-mcp/issues/1249) audit) ([#​1256](homeassistant-ai/ha-mcp#1256)) - **e2e**: Clear stale .hacs\_frontend.lock from prior crashed runs ([#​1252](homeassistant-ai/ha-mcp#1252)) - **e2e**: Use time.monotonic() in workflow polling loops ([#​1258](homeassistant-ai/ha-mcp#1258)) - **e2e**: Use time.monotonic() for duration polling ([#​1234](homeassistant-ai/ha-mcp#1234)) ([#​1249](homeassistant-ai/ha-mcp#1249)) - **e2e**: Close ARM ha\_mcp\_tools readiness race under loadscope ([#​1208](homeassistant-ai/ha-mcp#1208)) - **hacs**: Tighten is\_hacs\_unavailable to not match legitimate "Repository not found" ([#​1246](homeassistant-ai/ha-mcp#1246)) - **seed**: Unblock 3 silent-skip pagination/state tests via baked recorder DB ([#​1240](homeassistant-ai/ha-mcp#1240)) - **seed**: Register a writable local\_calendar to unblock event-creation test ([#​1243](homeassistant-ai/ha-mcp#1243)) - **addon**: Fix base64 padding-bit flake in token tamper tests ([#​1238](homeassistant-ai/ha-mcp#1238)) ([#​1241](homeassistant-ai/ha-mcp#1241)) - **seed**: Add a writable scene for test\_call\_service\_scene\_turn\_on ([#​1231](homeassistant-ai/ha-mcp#1231)) - **seed**: Assign demo device to living\_room area for filter test ([#​1230](homeassistant-ai/ha-mcp#1230)) - **e2e**: Drop nonexistent sun service from session readiness wait ([#​1227](homeassistant-ai/ha-mcp#1227)) - **e2e**: Self-contain dashboard register/remove to fix ARM xdist race ([#​1196](homeassistant-ai/ha-mcp#1196)) ([#​1201](homeassistant-ai/ha-mcp#1201)) - Fix EN dash in docstring causing RUF002 lint failure ([`eac5916`](homeassistant-ai/ha-mcp@eac5916)) - Address Gemini review feedback on host detection and port allocation ([`960305e`](homeassistant-ai/ha-mcp@960305e)) - Fix three categories of E2E test flakiness ([`39417ff`](homeassistant-ai/ha-mcp@39417ff)) - **e2e**: Pin config\_hash stability for dashboards ([#​1132](homeassistant-ai/ha-mcp#1132)) </details> </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19--> Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/455
….0 ) (#26) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/homeassistant-ai/ha-mcp](https://github.com/homeassistant-ai/ha-mcp) | minor | `7.4.0` → `7.5.0` | --- ### Release Notes <details> <summary>homeassistant-ai/ha-mcp (ghcr.io/homeassistant-ai/ha-mcp)</summary> ### [`v7.5.0`](https://github.com/homeassistant-ai/ha-mcp/blob/HEAD/CHANGELOG.md#v750-2026-05-13) [Compare Source](homeassistant-ai/ha-mcp@v7.4.0...v7.5.0) ##### Added - Add ENABLE\_LITE\_DOCSTRINGS beta toggle ([#​1259](homeassistant-ai/ha-mcp#1259)) - Add ha\_call\_event tool for publishing events on the HA event bus ([#​996](homeassistant-ai/ha-mcp#996)) ([#​1239](homeassistant-ai/ha-mcp#1239)) - Pinpoint backslash-escape mistake in python\_sandbox errors ([#​1204](homeassistant-ai/ha-mcp#1204)) - Reject empty-trigger automations targeting scene.create ([#​1187](homeassistant-ai/ha-mcp#1187)) - Add scene config tools — ha\_config\_get/set/remove\_scene ([#​1168](homeassistant-ai/ha-mcp#1168)) - **addon**: Optional OAuth 2.1 mode for webhook proxy (beta) ([#​1184](homeassistant-ai/ha-mcp#1184)) - Surface helper schema inline in ha\_config\_set\_helper validation errors ([#​1149](homeassistant-ai/ha-mcp#1149)) ([#​1179](homeassistant-ai/ha-mcp#1179)) - Emit progress via FastMCP Context in long-running tools ([#​1124](homeassistant-ai/ha-mcp#1124)) - Broaden python\_transform AST allowlist + improve error UX ([#​1163](homeassistant-ai/ha-mcp#1163)) - Add ha\_manage\_custom\_tool — sandboxed code execution escape hatch ([#​854](homeassistant-ai/ha-mcp#854)) - Always-on skills; rename list/read resource tools with ha\_ prefix ([#​1136](homeassistant-ai/ha-mcp#1136)) - Expose device\_class + options on ha\_set\_entity / ha\_get\_entity (Show As) ([#​1135](homeassistant-ai/ha-mcp#1135)) - **site**: Inline wizard data into setup.astro, migrate setup nuggets, drop content collections ([#​1120](homeassistant-ai/ha-mcp#1120)) - Add "Advanced debug logging" toggle for kill-signal diagnostics ([#​1117](homeassistant-ai/ha-mcp#1117)) - **yaml**: Scoped lovelace.dashboards.\<url\_path> support (issue [#​1034](homeassistant-ai/ha-mcp#1034)) ([#​1103](homeassistant-ai/ha-mcp#1103)) - Add HA\_VERIFY\_SSL toggle to disable TLS verification ([#​1104](homeassistant-ai/ha-mcp#1104)) - Per-top-level-key config\_hash for ha\_manage\_energy\_prefs ([#​1049](homeassistant-ai/ha-mcp#1049)) ([#​1098](homeassistant-ai/ha-mcp#1098)) - **site**: Add gemini-cli setup notes + compose hardening to wizard ([#​1027](homeassistant-ai/ha-mcp#1027)) ([#​1087](homeassistant-ai/ha-mcp#1087)) - Add convenience modes to ha\_manage\_energy\_prefs ([#​1050](homeassistant-ai/ha-mcp#1050)) ([#​1073](homeassistant-ai/ha-mcp#1073)) - Surface integration log levels in ha\_get\_logs/integration/addon ([#​956](homeassistant-ai/ha-mcp#956)) ([#​1003](homeassistant-ai/ha-mcp#1003)) - Expose allowlist\_external\_dirs in ha\_get\_overview full system\_info ([#​1053](homeassistant-ai/ha-mcp#1053)) - **dashboards**: Unify identifier handling in ha\_config\_\*\_dashboard tools ([#​981](homeassistant-ai/ha-mcp#981)) ([#​1075](homeassistant-ai/ha-mcp#1075)) - Include addon container logs in bug reports ([#​934](homeassistant-ai/ha-mcp#934)) - Add WebSocket response-shaping controls to ha\_manage\_addon ([#​1009](homeassistant-ai/ha-mcp#1009)) - Web-based settings UI for per-tool enable/disable/pin ([#​960](homeassistant-ai/ha-mcp#960)) - **site**: Add OpenCode support to setup wizard ([#​1080](homeassistant-ai/ha-mcp#1080)) ##### Changed - Clarify standard-mode HTTP deployment guidance ([#​1185](homeassistant-ai/ha-mcp#1185)) - Add Cloudflared add-on hostname alternative for tunnel service ([#​1183](homeassistant-ai/ha-mcp#1183)) - Align tool naming convention between AGENTS.md and styleguide ([#​943](homeassistant-ai/ha-mcp#943)) ([#​1174](homeassistant-ai/ha-mcp#1174)) - **addon**: Note tool-list ([#​985](homeassistant-ai/ha-mcp#985 divergence; fix [#​1139](https://github.com/homeassistant-ai/ha-mcp/issues/1139)/[#​1162](https://github.com/homeassistant-ai/ha-mcp/issues/1162) test conflict ([#​1172](homeassistant-ai/ha-mcp#1172)) - Add brew install option for mcp-proxy on macOS ([#​1171](homeassistant-ai/ha-mcp#1171)) - Update contributors list \[contributors-updated] ([`aba01a1`](homeassistant-ai/ha-mcp@aba01a1)) - Warn against enable\_tool\_search on Claude Sonnet/Opus ([#​1088](homeassistant-ai/ha-mcp#1088)) ([#​1140](homeassistant-ai/ha-mcp#1140)) - Address [#​1094](homeassistant-ai/ha-mcp#1094) review nits on OpenCode mirror comments ([#​1105](homeassistant-ai/ha-mcp#1105)) ##### Fixed - **integrations**: Surface ConfigEntry.options via OptionsFlow probe ([#​1245](homeassistant-ai/ha-mcp#1245)) - **backup**: Discover local agent at call time instead of hardcoding hassio.local ([#​1244](homeassistant-ai/ha-mcp#1244)) - Triage all 10 ha\_search\_entities behaviors from [#​1170](homeassistant-ai/ha-mcp#1170) ([#​1195](homeassistant-ai/ha-mcp#1195)) - Replace cron with systemd for demo server (prevents process leak) ([#​1110](homeassistant-ai/ha-mcp#1110)) - Improve ha\_manage\_addon discoverability (BM25 keywords + slug examples) ([#​1200](homeassistant-ai/ha-mcp#1200)) - Route Supervisor 401s to structured tool errors + add E2E coverage ([#​1129](homeassistant-ai/ha-mcp#1129)) ([#​1192](homeassistant-ai/ha-mcp#1192)) - Harden \_validate\_category\_id gate to cover dict-promoted category ([#​1190](homeassistant-ai/ha-mcp#1190)) - Broaden template anti-pattern detection + skill discoverability ([#​1011](homeassistant-ai/ha-mcp#1011)) ([#​1181](homeassistant-ai/ha-mcp#1181)) - Return newest automation traces, add offset+order pagination ([#​1177](homeassistant-ai/ha-mcp#1177)) ([#​1178](homeassistant-ai/ha-mcp#1178)) - **security**: Write YAML backups outside www/ (GHSA-g39v-cvjh-8fpf) ([#​1180](homeassistant-ai/ha-mcp#1180)) - **search**: Apply domain\_filter when area\_filter is set ([#​1162](homeassistant-ai/ha-mcp#1162)) ([#​1165](homeassistant-ai/ha-mcp#1165)) - **resources**: Reject HA-config YAML in dashboard resource content ([#​1160](homeassistant-ai/ha-mcp#1160)) - Close 19 bugs in ha\_config\_set\_helper (issue [#​1150](homeassistant-ai/ha-mcp#1150)) ([#​1151](homeassistant-ai/ha-mcp#1151)) - Route addon log fetches directly to supervisor on addon installs ([#​1126](homeassistant-ai/ha-mcp#1126)) - Survive read-only filesystems at startup ([#​1138](homeassistant-ai/ha-mcp#1138)) - **helpers**: Clarify name-required-on-create for ha\_config\_set\_helper ([#​1143](homeassistant-ai/ha-mcp#1143)) - Resolve disabled entities via entity\_registry in helper deletion ([#​1119](homeassistant-ai/ha-mcp#1119)) - Allow unary operators in python\_transform sandbox ([#​1118](homeassistant-ai/ha-mcp#1118)) - **site**: Add github-copilot-agents wizard branch + delete unreferenced data/clients.ts ([#​1108](homeassistant-ai/ha-mcp#1108)) - **addons**: Route addon API calls through HA Core ingress proxy ([#​1069](homeassistant-ai/ha-mcp#1069)) - **webhook-proxy**: Surface webhook registration failures instead of silently loading ([#​1101](homeassistant-ai/ha-mcp#1101)) - **site**: Resolve client display-order collisions and anchor OpenCode shape ([#​1094](homeassistant-ai/ha-mcp#1094)) ##### Performance Improvements - Dedupe lovelace/dashboards/list in ha\_config\_set\_dashboard ([#​1085](homeassistant-ai/ha-mcp#1085)) ([#​1191](homeassistant-ai/ha-mcp#1191)) ##### Refactoring - Drop obsolete ha\_mcp\_tools defensive ruamel.yaml imports ([post-#​1268](https://github.com/post-/ha-mcp/issues/1268)) ([#​1269](homeassistant-ai/ha-mcp#1269)) - Extract shared Supervisor httpx client helper ([#​1130](homeassistant-ai/ha-mcp#1130)) ([#​1203](homeassistant-ai/ha-mcp#1203)) - Surface client identity, AI model, config toggles, and prompt context in ha\_report\_issue ([#​1189](homeassistant-ai/ha-mcp#1189)) - Harden Context injection with safe-emit + branch coverage ([#​1173](homeassistant-ai/ha-mcp#1173)) - Consolidate area/floor set+remove tools (revisit of [#​813](homeassistant-ai/ha-mcp#813)) ([#​1139](homeassistant-ai/ha-mcp#1139)) - Pass verify\_ssl to remaining direct-Supervisor httpx callers ([#​1128](homeassistant-ai/ha-mcp#1128)) - Validate only new entries on convenience-mode writes ([#​1086](homeassistant-ai/ha-mcp#1086)) ([#​1100](homeassistant-ai/ha-mcp#1100)) *** <details> <summary>Internal Changes</summary> ##### Fixed - **ci**: Align pr.yml E2E with --dist loadscope ([#​1206](homeassistant-ai/ha-mcp#1206)) ([#​1247](homeassistant-ai/ha-mcp#1247)) - **ci**: Switch Renovate to a GitHub App token to allow workflow-file pushes ([#​1229](homeassistant-ai/ha-mcp#1229)) - **ci**: Break gemini-triage retrigger loop and bump turn budget ([#​1131](homeassistant-ai/ha-mcp#1131)) - **ci**: Harden gemini-triage so failures stop spamming user issues ([#​1122](homeassistant-ai/ha-mcp#1122)) - **ci**: Unbreak hotfix-release semantic-release run ([#​1091](homeassistant-ai/ha-mcp#1091)) ##### Chores - **addon**: Publish dev addon version 7.4.1.dev299 \[skip ci] ([`397aa6d`](homeassistant-ai/ha-mcp@397aa6d)) - **addon**: Publish dev addon version 7.4.1.dev298 \[skip ci] ([`942b7e0`](homeassistant-ai/ha-mcp@942b7e0)) - Sync tool docs after merge \[skip ci] ([`6823c47`](homeassistant-ai/ha-mcp@6823c47)) - **addon**: Publish dev addon version 7.4.1.dev297 \[skip ci] ([`6eac062`](homeassistant-ai/ha-mcp@6eac062)) - **addon**: Publish dev addon version 7.4.1.dev296 \[skip ci] ([`b2afe93`](homeassistant-ai/ha-mcp@b2afe93)) - **addon**: Publish dev addon version 7.4.1.dev295 \[skip ci] ([`4f4c4f3`](homeassistant-ai/ha-mcp@4f4c4f3)) - **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.1 ([#​1236](homeassistant-ai/ha-mcp#1236)) - **addon**: Publish dev addon version 7.4.1.dev294 \[skip ci] ([`fd24991`](homeassistant-ai/ha-mcp@fd24991)) - **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.13 ([#​1233](homeassistant-ai/ha-mcp#1233)) - **addon**: Publish dev addon version 7.4.1.dev293 \[skip ci] ([`fcc6496`](homeassistant-ai/ha-mcp@fcc6496)) - **addon**: Publish dev addon version 7.4.1.dev292 \[skip ci] ([`2961650`](homeassistant-ai/ha-mcp@2961650)) - **addon**: Publish dev addon version 7.4.1.dev291 \[skip ci] ([`5703112`](homeassistant-ai/ha-mcp@5703112)) - **addon**: Publish dev addon version 7.4.1.dev290 \[skip ci] ([`19b2f65`](homeassistant-ai/ha-mcp@19b2f65)) - **addon**: Publish dev addon version 7.4.1.dev289 \[skip ci] ([`e5a1365`](homeassistant-ai/ha-mcp@e5a1365)) - Sync tool docs after merge \[skip ci] ([`d2ff93b`](homeassistant-ai/ha-mcp@d2ff93b)) - **addon**: Publish dev addon version 7.4.1.dev288 \[skip ci] ([`0f62400`](homeassistant-ai/ha-mcp@0f62400)) - Sync tool docs after merge \[skip ci] ([`c7e2066`](homeassistant-ai/ha-mcp@c7e2066)) - **addon**: Publish dev addon version 7.4.1.dev287 \[skip ci] ([`c1133d4`](homeassistant-ai/ha-mcp@c1133d4)) - **addon**: Publish dev addon version 7.4.1.dev286 \[skip ci] ([`1ae790e`](homeassistant-ai/ha-mcp@1ae790e)) - **addon**: Publish dev addon version 7.4.1.dev285 \[skip ci] ([`2387d0c`](homeassistant-ai/ha-mcp@2387d0c)) - **addon**: Publish dev addon version 7.4.1.dev284 \[skip ci] ([`dd3a4a5`](homeassistant-ai/ha-mcp@dd3a4a5)) - **addon**: Publish dev addon version 7.4.1.dev283 \[skip ci] ([`78af8eb`](homeassistant-ai/ha-mcp@78af8eb)) - Sync tool docs after merge \[skip ci] ([`093fd74`](homeassistant-ai/ha-mcp@093fd74)) - **addon**: Publish dev addon version 7.4.1.dev282 \[skip ci] ([`2141e15`](homeassistant-ai/ha-mcp@2141e15)) - Sync tool docs after merge \[skip ci] ([`7810c95`](homeassistant-ai/ha-mcp@7810c95)) - **addon**: Publish dev addon version 7.4.1.dev281 \[skip ci] ([`7d79ec2`](homeassistant-ai/ha-mcp@7d79ec2)) - Sync tool docs after merge \[skip ci] ([`a73dc81`](homeassistant-ai/ha-mcp@a73dc81)) - **addon**: Publish dev addon version 7.4.1.dev280 \[skip ci] ([`c858ce3`](homeassistant-ai/ha-mcp@c858ce3)) - Sync tool docs after merge \[skip ci] ([`a587be0`](homeassistant-ai/ha-mcp@a587be0)) - **addon**: Publish dev addon version 7.4.1.dev279 \[skip ci] ([`b78ddb2`](homeassistant-ai/ha-mcp@b78ddb2)) - Sync tool docs after merge \[skip ci] ([`1210725`](homeassistant-ai/ha-mcp@1210725)) - **addon**: Publish dev addon version 7.4.1.dev278 \[skip ci] ([`a282c17`](homeassistant-ai/ha-mcp@a282c17)) - **addon**: Publish dev addon version 7.4.1.dev277 \[skip ci] ([`1081768`](homeassistant-ai/ha-mcp@1081768)) - Sync tool docs after merge \[skip ci] ([`e03f5d2`](homeassistant-ai/ha-mcp@e03f5d2)) - **addon**: Publish dev addon version 7.4.1.dev276 \[skip ci] ([`c4ef680`](homeassistant-ai/ha-mcp@c4ef680)) - **addon**: Publish dev addon version 7.4.1.dev275 \[skip ci] ([`780422d`](homeassistant-ai/ha-mcp@780422d)) - Sync tool docs after merge \[skip ci] ([`8a2bd1a`](homeassistant-ai/ha-mcp@8a2bd1a)) - **addon**: Publish dev addon version 7.4.1.dev274 \[skip ci] ([`f0f09de`](homeassistant-ai/ha-mcp@f0f09de)) - **addon**: Publish dev addon version 7.4.1.dev273 \[skip ci] ([`cb49f68`](homeassistant-ai/ha-mcp@cb49f68)) - **addon**: Publish dev addon version 7.4.1.dev272 \[skip ci] ([`5097186`](homeassistant-ai/ha-mcp@5097186)) - **addon**: Publish dev addon version 7.4.1.dev271 \[skip ci] ([`4714342`](homeassistant-ai/ha-mcp@4714342)) - **addon**: Publish dev addon version 7.4.1.dev270 \[skip ci] ([`217982a`](homeassistant-ai/ha-mcp@217982a)) - **addon**: Publish dev addon version 7.4.1.dev269 \[skip ci] ([`a65dd5f`](homeassistant-ai/ha-mcp@a65dd5f)) - Sync tool docs after merge \[skip ci] ([`0e6b54f`](homeassistant-ai/ha-mcp@0e6b54f)) - **addon**: Publish dev addon version 7.4.1.dev268 \[skip ci] ([`60ba1f2`](homeassistant-ai/ha-mcp@60ba1f2)) - **addon**: Publish dev addon version 7.4.1.dev267 \[skip ci] ([`13412aa`](homeassistant-ai/ha-mcp@13412aa)) - Sync tool docs after merge \[skip ci] ([`2702a0f`](homeassistant-ai/ha-mcp@2702a0f)) - **addon**: Publish dev addon version 7.4.1.dev266 \[skip ci] ([`77abe0b`](homeassistant-ai/ha-mcp@77abe0b)) - **addon**: Publish dev addon version 7.4.1.dev265 \[skip ci] ([`08b69db`](homeassistant-ai/ha-mcp@08b69db)) - Sync tool docs after merge \[skip ci] ([`c1f24b5`](homeassistant-ai/ha-mcp@c1f24b5)) - **addon**: Publish dev addon version 7.4.1.dev264 \[skip ci] ([`f2583f6`](homeassistant-ai/ha-mcp@f2583f6)) - Sync tool docs after merge \[skip ci] ([`c2ed2d3`](homeassistant-ai/ha-mcp@c2ed2d3)) - **addon**: Publish dev addon version 7.4.1.dev263 \[skip ci] ([`9d43e54`](homeassistant-ai/ha-mcp@9d43e54)) - **addon**: Publish dev addon version 7.4.1.dev262 \[skip ci] ([`a7355c8`](homeassistant-ai/ha-mcp@a7355c8)) - Sync tool docs after merge \[skip ci] ([`085bd8a`](homeassistant-ai/ha-mcp@085bd8a)) - Convert agents to skills ([#​1084](homeassistant-ai/ha-mcp#1084)) - **addon**: Publish dev addon version 7.4.1.dev261 \[skip ci] ([`0d1af36`](homeassistant-ai/ha-mcp@0d1af36)) - **addon**: Publish dev addon version 7.4.1.dev260 \[skip ci] ([`29397dc`](homeassistant-ai/ha-mcp@29397dc)) - **addon**: Publish dev addon version 7.4.1.dev259 \[skip ci] ([`4bbc74b`](homeassistant-ai/ha-mcp@4bbc74b)) - Sync tool docs after merge \[skip ci] ([`0f6d41e`](homeassistant-ai/ha-mcp@0f6d41e)) - **addon**: Publish dev addon version 7.4.1.dev258 \[skip ci] ([`6751d08`](homeassistant-ai/ha-mcp@6751d08)) - **addon**: Publish dev addon version 7.4.1.dev257 \[skip ci] ([`2213c89`](homeassistant-ai/ha-mcp@2213c89)) - **addon**: Publish dev addon version 7.4.1.dev256 \[skip ci] ([`18a366e`](homeassistant-ai/ha-mcp@18a366e)) - **addon**: Publish dev addon version 7.4.1.dev255 \[skip ci] ([`0e9b18d`](homeassistant-ai/ha-mcp@0e9b18d)) - **addon**: Publish dev addon version 7.4.1.dev254 \[skip ci] ([`39fc65b`](homeassistant-ai/ha-mcp@39fc65b)) - Sync tool docs after merge \[skip ci] ([`9fa0aea`](homeassistant-ai/ha-mcp@9fa0aea)) - **addon**: Publish dev addon version 7.4.1.dev253 \[skip ci] ([`0dcc59e`](homeassistant-ai/ha-mcp@0dcc59e)) - Sync tool docs after merge \[skip ci] ([`ec7413f`](homeassistant-ai/ha-mcp@ec7413f)) - **addon**: Publish dev addon version 7.4.1.dev252 \[skip ci] ([`345640c`](homeassistant-ai/ha-mcp@345640c)) - **addon**: Publish dev addon version 7.4.1.dev251 \[skip ci] ([`bab9d49`](homeassistant-ai/ha-mcp@bab9d49)) - Sync tool docs after merge \[skip ci] ([`726f0a5`](homeassistant-ai/ha-mcp@726f0a5)) - **addon**: Publish dev addon version 7.4.1.dev250 \[skip ci] ([`ded04ea`](homeassistant-ai/ha-mcp@ded04ea)) - **addon**: Publish dev addon version 7.4.1.dev249 \[skip ci] ([`37d5628`](homeassistant-ai/ha-mcp@37d5628)) - **addon**: Publish dev addon version 7.4.1.dev248 \[skip ci] ([`530786a`](homeassistant-ai/ha-mcp@530786a)) - Sync tool docs after merge \[skip ci] ([`36719c3`](homeassistant-ai/ha-mcp@36719c3)) - **addon**: Publish dev addon version 7.4.1.dev247 \[skip ci] ([`4dc47b5`](homeassistant-ai/ha-mcp@4dc47b5)) - **addon**: Publish dev addon version 7.4.1.dev246 \[skip ci] ([`6ffbd6a`](homeassistant-ai/ha-mcp@6ffbd6a)) - Sync tool docs after merge \[skip ci] ([`add66e3`](homeassistant-ai/ha-mcp@add66e3)) - **addon**: Publish dev addon version 7.4.1.dev245 \[skip ci] ([`d0114af`](homeassistant-ai/ha-mcp@d0114af)) - Sync tool docs after merge \[skip ci] ([`0ca41af`](homeassistant-ai/ha-mcp@0ca41af)) - **addon**: Publish dev addon version 7.4.1.dev244 \[skip ci] ([`d052dd0`](homeassistant-ai/ha-mcp@d052dd0)) - **addon**: Publish dev addon version 7.4.0.dev243 \[skip ci] ([`827bc65`](homeassistant-ai/ha-mcp@827bc65)) - Bump package version to 7.4.1 to match released addon ([`4f65497`](homeassistant-ai/ha-mcp@4f65497)) - **addon**: Publish dev addon version 7.4.0.dev242 \[skip ci] ([`8ba80ae`](homeassistant-ai/ha-mcp@8ba80ae)) - **addon**: Publish hotfix version 7.4.1 ([`bda75e6`](homeassistant-ai/ha-mcp@bda75e6)) - **addon**: Publish dev addon version 7.4.0.dev241 \[skip ci] ([`2126428`](homeassistant-ai/ha-mcp@2126428)) ##### Continuous Integration - **deps**: Bump renovatebot/github-action in the github-actions group ([#​1218](homeassistant-ai/ha-mcp#1218)) - **deps**: Bump renovatebot/github-action in the github-actions group ([#​1111](homeassistant-ai/ha-mcp#1111)) ##### Refactoring - Extract \_fetch\_dashboards\_list helper ([#​1193](homeassistant-ai/ha-mcp#1193)) ([#​1207](homeassistant-ai/ha-mcp#1207)) ##### Testing - **e2e**: Module-scope bulk\_automations + bulk\_scripts fixtures (refs [#​366](homeassistant-ai/ha-mcp#366)) ([#​1275](homeassistant-ai/ha-mcp#1275)) - **e2e**: Lower INPUT\_BOOLEAN\_WAIT from 30s to 10s (refs [#​366](homeassistant-ai/ha-mcp#366)) ([#​1273](homeassistant-ai/ha-mcp#1273)) - **e2e**: Generalize readiness-gate diagnostics helper (closes [#​1267](homeassistant-ai/ha-mcp#1267)) ([#​1271](homeassistant-ai/ha-mcp#1271)) - **e2e**: Narrow except clauses in e2e polling helpers (closes [#​1266](homeassistant-ai/ha-mcp#1266)) ([#​1270](homeassistant-ai/ha-mcp#1270)) - **e2e**: Drop ha\_mcp\_tools retry-path + pre-install manifest requirements ([#​1268](homeassistant-ai/ha-mcp#1268)) - **e2e**: Instrument and retry ha\_mcp\_tools readiness wait ([#​1262](homeassistant-ai/ha-mcp#1262)) - Use time.monotonic() in UAT runner and test\_env\_manager ([#​1254](homeassistant-ai/ha-mcp#1254)) - **e2e**: Detect partial/corrupt hacs\_frontend dir in fast-path guard ([#​1253](homeassistant-ai/ha-mcp#1253)) - **e2e**: Remove unused wait/assert helpers ([post-#​1249](https://github.com/post-/ha-mcp/issues/1249) audit) ([#​1256](homeassistant-ai/ha-mcp#1256)) - **e2e**: Clear stale .hacs\_frontend.lock from prior crashed runs ([#​1252](homeassistant-ai/ha-mcp#1252)) - **e2e**: Use time.monotonic() in workflow polling loops ([#​1258](homeassistant-ai/ha-mcp#1258)) - **e2e**: Use time.monotonic() for duration polling ([#​1234](homeassistant-ai/ha-mcp#1234)) ([#​1249](homeassistant-ai/ha-mcp#1249)) - **e2e**: Close ARM ha\_mcp\_tools readiness race under loadscope ([#​1208](homeassistant-ai/ha-mcp#1208)) - **hacs**: Tighten is\_hacs\_unavailable to not match legitimate "Repository not found" ([#​1246](homeassistant-ai/ha-mcp#1246)) - **seed**: Unblock 3 silent-skip pagination/state tests via baked recorder DB ([#​1240](homeassistant-ai/ha-mcp#1240)) - **seed**: Register a writable local\_calendar to unblock event-creation test ([#​1243](homeassistant-ai/ha-mcp#1243)) - **addon**: Fix base64 padding-bit flake in token tamper tests ([#​1238](homeassistant-ai/ha-mcp#1238)) ([#​1241](homeassistant-ai/ha-mcp#1241)) - **seed**: Add a writable scene for test\_call\_service\_scene\_turn\_on ([#​1231](homeassistant-ai/ha-mcp#1231)) - **seed**: Assign demo device to living\_room area for filter test ([#​1230](homeassistant-ai/ha-mcp#1230)) - **e2e**: Drop nonexistent sun service from session readiness wait ([#​1227](homeassistant-ai/ha-mcp#1227)) - **e2e**: Self-contain dashboard register/remove to fix ARM xdist race ([#​1196](homeassistant-ai/ha-mcp#1196)) ([#​1201](homeassistant-ai/ha-mcp#1201)) - Fix EN dash in docstring causing RUF002 lint failure ([`eac5916`](homeassistant-ai/ha-mcp@eac5916)) - Address Gemini review feedback on host detection and port allocation ([`960305e`](homeassistant-ai/ha-mcp@960305e)) - Fix three categories of E2E test flakiness ([`39417ff`](homeassistant-ai/ha-mcp@39417ff)) - **e2e**: Pin config\_hash stability for dashboards ([#​1132](homeassistant-ai/ha-mcp#1132)) </details> </details> --- ### Configuration 📅 **Schedule**: (in timezone America/New_York) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNjAuNyIsInVwZGF0ZWRJblZlciI6IjQzLjE2MC43IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19--> Co-authored-by: todd <tpunderson@greyrock.io> Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/26
What does this PR do?
Closes #1130. Extracts the shared boilerplate from the three direct-Supervisor
httpx.AsyncClientcall sites into a single factory in a newsrc/ha_mcp/client/supervisor_client.py. Resolves theneeds-choiceslabel by picking the simplest sensible answer for each design question raised in the issue body.Sites consolidated
src/ha_mcp/client/rest_client.py:_supervisor_logs_get— carries the addon-logs and system-service-logs branches landed in fix: route addon and HA core log fetches directly to Supervisor on addon installs #1126 (the_get_addon_logs_via_supervisornamed in the issue body now delegates to this lower-level helper)src/ha_mcp/tools/tools_bug_report.py:_fetch_addon_logssrc/ha_mcp/settings_ui.py:_restart_addonWire-level behaviour preserved:
base_url=http://supervisor+ relative path on.get/.postjoins to the samehttp://supervisor/<path>URL the originals built by f-string.Authorization: Bearer ${SUPERVISOR_TOKEN}moves from per-call kwargs onto the constructor.verifyandtimeoutstay caller-supplied so each site keeps its existing settings-source choice.Design decisions on the three open questions
src/ha_mcp/client/supervisor_client.pyclient/already housesrest_client.py+websocket_client.py+websocket_listener.py— all external-service clients.utils/is for cross-cutting helpers; a Supervisor-specific wrapper isn't one.verify/timeoutparameters, notget_global_settings()inside the helperself.verify_sslsnapshot forRESTClient, liveget_global_settings()for the module-level helper,server.settings.verify_sslfor the closure). Helper stays a pure factory with no settings coupling — easier to test, no behaviour change at any site.Token-absent policy stays at the call sites
SUPERVISOR_TOKENis read in the helper at construction time (matching the originals), but each site keeps its own absent-token branch:_supervisor_logs_getraisesHomeAssistantAuthErrorwith the richf"Supervisor token absent at call time for /{path}/logs ..."message_fetch_addon_logsreturns""silently (matching the docstring's failure contract)_restart_addonreturns 400 +CONFIG_VALIDATION_FAILEDThese three don't share a common shape, so the helper deliberately doesn't dictate one.
Type of change
Testing
uv run pytest)uv run ruff check)New tests
tests/src/unit/test_supervisor_client.py— 8 tests covering the factory contract:httpx.AsyncClientreturnedbase_url == "http://supervisor"SUPERVISOR_BASE_URLenv override flows through (the path E2E tests use to point at a local mock without/etc/hostshacks)Authorization: Bearer <token>read from env at construction timeSUPERVISOR_TOKENproduces a literal"Bearer "— graceful-degradation contract for any future direct caller that forgets to guardtimeoutforwarded as plainfloat(connect/read both carry the value)timeoutforwarded ashttpx.Timeout(...)instance (the rich form_supervisor_logs_getpasses)verify=True/Falsekwarg forwarded — patcheshttpx.AsyncClientand asserts both values, since httpx doesn't exposeverifyon the public clientExisting tests updated
Two tests in
tests/src/unit/test_tools_utility_supervisor_logs.pyupdated for the post-refactor wire shape:client.get()is now relative (/addons/.../logsinstead of the full URL)Authorizationheader moves from per-call kwargs onto the constructor kwargsctor_kwargs["base_url"]so a regression that drops the base_url surfaces here tooLocal: 166 passed across the 4 affected test files (
test_supervisor_client,test_tools_utility_supervisor_logs,test_tools_bug_report,test_settings_ui); ruff check + format clean.Future improvements
Checklist