You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: dev mode tools, embedded server update fixes, and version diagnosability (#1780)
* feat: add developer mode with hidden ha_dev_* server management tools
Closes#1775.
A new enable_dev_mode setting (Developer section at the very bottom of
the web settings UI's Server Settings tab, confirm-gated, or
HAMCP_ENABLE_DEV_MODE env var) registers two developer tools. When the
flag is off (default) the tools are never registered, so MCP clients
cannot see or call them.
- ha_dev_manage_server: info / update_source / restart. update_source
drives the ha_mcp_tools in-process server entry's existing options
flow (channel or pip spec, e.g. a GitHub PR tarball URL) so the
server reinstalls and restarts itself; no custom component changes
needed. In embedded mode self-affecting calls are deferred until the
tool response has flushed.
- ha_dev_manage_settings: list / set / reset over the same settings
matrix as the web UI, with origin awareness (env-pinned refused,
addon-synced routed via Supervisor, file overrides written atomically
under the shared override-file lock).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: add destructiveHint annotations and satisfy CodeQL quality gate
The annotations sweep requires every tool to declare readOnlyHint or
destructiveHint explicitly; both dev tools modify server state. Also
make the coercion helper's no-match path an explicit return and retrieve
background-task results in the test drainer (CodeQL mixed-returns /
ineffectual-statement).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: use public reset_global_settings and shared reset helper in dev-mode tests
Applies Gemini review suggestions: the unit tests import the public
reset seam instead of the private one, and the e2e module centralizes
its cache-clear + settings-reset pair in one helper.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: apply server updates on entry reload by purging cached ha_mcp modules
Live-found on a real install: an options save reinstalled the package
(web UI footer showed the new on-disk version) but the new worker thread
silently reused the OLD code — Python resolves imports from the
process-wide sys.modules cache, so installs only took effect after a
full HA core restart. ha_mcp is pure Python with a single controlled
import site (the worker thread), so the manager now purges ha_mcp*
from sys.modules between the install and the thread spawn. Shared
third-party dependencies are deliberately not purged; a post-start
check warns loudly if the running and installed versions still diverge.
Also stop pre-filling the pip-spec override field with the default dist
name: the "leave blank" field always looked populated and showed the
stable dist name even on the dev channel. A saved override still
pre-fills.
Component 1.0.0 -> 1.0.1.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat: truthful version/deployment diagnostics and embedded restart button
Fallout fixes from the live stale-worker hunt:
- ha_report_issue now reports the RUNNING version (__version__, frozen at
import) and the INSTALLED on-disk version separately with an explicit
version_mismatch flag, plus process identity (instance_id/started_at/
uptime) matching /api/settings/info, and the custom component version
read via its get_caller_token bootstrap service.
- Installation-method detection gains an 'embedded' branch checked before
the /.dockerenv probe — in-process installs no longer misreport as
docker (tool, web UI, and update hint all shared the same blind spot).
- get_version() prefers the distribution that owns the imported ha_mcp
package instead of a fixed name order, so leftover channel metadata
can't misreport the version.
- The web settings UI reports deployment_mode and, in embedded mode,
shows a 'Restart HA-MCP Server' button that reloads the server config
entry (shared entry-discovery/reload helpers extracted from the dev
tools); update_command_hint points embedded users at the update entity.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci: derive dev build numbers from the commit count in both publish workflows
publish-dev and addon-publish-dev each used their own github.run_number,
so the same commit produced two unrelated dev numbers (PyPI/Docker at
.dev779 while the dev add-on sat at .dev481) and version reports were
incomparable across install methods. The commit count is identical for
the same commit in every workflow and jumps both counters upward.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: survive a wedged worker during embedded bring-up (HAOS e2e regression)
The purge fix exposed a startup crash cascade on QEMU-slow HAOS: a cold
import outlived the 30s readiness timeout, the stop path's bounded join
gave up on the still-importing thread and nulled the shared stop event,
and the zombie later crashed on the _serve assert while the next
bring-up purged sys.modules out from under its in-flight imports.
- _serve now receives its stop event as a local: async_stop clearing the
published references can no longer crash a wedged worker.
- A timed-out join remembers the orphaned thread; the next start skips
the module purge while that thread may still be importing (loud
warning; the post-start staleness check covers the consequence).
- importlib.invalidate_caches() runs only when modules were actually
purged — the finder-cache flush measurably slows cold imports on slow
disks, which is what tipped HAOS over the readiness budget.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: address review findings and widen embedded readiness budget
- Snapshot sys.modules keys before the purge iteration (concurrent
imports on other HA threads can mutate the dict mid-iteration).
- Run the override-file read and atomic write in executor threads so
ha_dev_manage_settings never blocks the event loop on file I/O.
- Raise the embedded readiness budget 30s -> 90s: QEMU-slow HAOS cold
imports have been observed to exceed 30s and a single readiness
timeout fails bring-up outright (no retry); real deployments only
pay the budget on the failure path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: apply pr-review-toolkit findings
Code review round (four specialist agents, findings verified against
source):
- Entry-probe exception narrowing: find_server_config_entry now skips an
entry only on HomeAssistantAPIError; connection/auth failures propagate
as what they are instead of masquerading as 'no server entry exists'
and steering users toward reinstalling a running component.
- ha_dev_manage_server info degrades ALL entry-probe failures to the
warnings list (a WS hiccup previously hard-failed the whole
diagnostic while the sibling HA-version probe degraded).
- Bug-report rendering keeps probe failures visible: an unverifiable
installed version renders as such instead of reading like a healthy
match, and a missing component version reads 'not detected (not
installed, or probe failed)' instead of 'not installed'.
- Dev version numbers count origin/master, not the checked-out ref — a
workflow_dispatch on an older ref could mint a colliding number and
clobber an existing dev release.
- #restartNotice gets role=status + aria-live=polite (the embedded
branch writes into it; siblings already announce).
- Docstring accuracy: update_source only self-interrupts in embedded
mode; 'most settings' need a restart (matches the tool's own note);
deduplicated the twin stop-event lifecycle comments; docs note reset
refuses env/addon-managed settings.
- ~20 new unit tests covering the previously untested failure branches:
corrupt/unreadable override-file guards, addon-origin set/reset via
Supervisor (success + rejection), entry-discovery error taxonomy,
info degradation warnings, the worker's real running-version capture,
the embedded update hint, null-byte rejection, and end-to-end
presence of the new report fields.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: kingpanther13 <kingpanther13@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: AGENTS.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -470,6 +470,7 @@ src/ha_mcp/
470
470
471
471
**Namespace prefixes**: An optional `<namespace>_` prefix between `ha_` and the verb is allowed for grouped tool families that share a domain. The full shape becomes `ha_<namespace>_<verb>_<noun>`:
-`ha_dev_<verb>_<noun>` — developer-mode tools (`ha_dev_manage_server`, `ha_dev_manage_settings`); registered only when the `enable_dev_mode` setting is on (Developer section at the bottom of the web settings UI's Server Settings tab)
473
474
474
475
**Accepted exceptions**: A small set of tools name a single, distinct operation where forcing a `<verb>_<noun>` shape would read worse than the natural name. These are accepted as-is and should not be flagged:
Developer mode registers two hidden MCP tools intended for people developing
4
+
or testing ha-mcp itself. It is **off by default**, and while it is off the
5
+
tools are never registered — MCP clients cannot see or call them.
6
+
7
+
> **Warning**: with developer mode on, any connected MCP client (i.e. any AI
8
+
> agent using this server) can change server settings and replace the running
9
+
> server version. Enable it only on instances used for development/testing.
10
+
11
+
## Enabling
12
+
13
+
The toggle lives at the **very bottom of the web settings UI**: Server
14
+
Settings tab → **Developer** section (below the beta features). Flip the
15
+
switch, confirm the warning, and restart the server for the tools to
16
+
register. Alternatively set the `HAMCP_ENABLE_DEV_MODE=true` env var.
17
+
18
+
The flag is intentionally absent from the add-on Configuration page.
19
+
20
+
## Tools
21
+
22
+
### `ha_dev_manage_server`
23
+
24
+
| Action | What it does |
25
+
| ------ | ------------- |
26
+
|`info`| Reports server version, deployment mode (embedded / add-on / standalone), Python version, data dir, HA version, and — when the [in-process server](in-process-server.md) entry exists — its current channel and pip spec. |
27
+
|`update_source`| Points the in-process (custom component) server at a release `channel` (`stable` / `dev`) or an explicit `pip_spec` — a version pin or a GitHub tarball URL such as `https://github.com/homeassistant-ai/ha-mcp/archive/refs/pull/<PR>/head.tar.gz` — then reinstalls and restarts it via the component's own options flow. |
28
+
|`restart`| Restarts this server: config-entry reload in embedded mode, Supervisor self-restart in add-on mode. Standalone processes must be restarted externally. |
29
+
30
+
`update_source` makes PR testing a one-call operation on an in-process
31
+
server install: point the pip spec at the PR tarball, wait for the reinstall,
32
+
reconnect, and verify with `info`. No extra repos or add-on rebuilds needed.
33
+
Server-code updates apply on the entry reload itself (component >= 1.0.1
34
+
purges the module cache per worker start); a change that needs *newer
35
+
third-party dependencies* still wants a Home Assistant core restart, since
36
+
shared libraries already loaded by the HA process are not reloaded.
37
+
38
+
### `ha_dev_manage_settings`
39
+
40
+
| Action | What it does |
41
+
| ------ | ------------- |
42
+
|`list`| Returns the full server-settings matrix (the same fields as the web UI's Server Settings tab) with each value's origin: `env` (pinned, read-only), `file` (override file), `addon` (Supervisor-managed), or `default`. |
43
+
|`set`| Validates and persists one setting through the same override layer the web UI uses. Env-pinned settings are refused; beta sub-flags still require the beta master to be on. |
44
+
|`reset`| Removes one setting's override-file entry, returning it to its default. Refused for env-pinned and add-on-managed settings, like `set`. |
45
+
46
+
Changes persist immediately but — like the web UI — most settings only take
47
+
effect after a restart (`ha_dev_manage_server``restart`).
48
+
49
+
Backup settings and per-tool enable/disable state are separate surfaces
50
+
(Backups tab / Tools tab) and are not covered by this tool.
0 commit comments