# \[APP\]\[Pro\] MCP AI Bridge: talk to your Homey with Claude, ChatGPT, Gemini, Copilot, Cursor, Mistral, Ollama, LM Studio, n8n, Home Assistant or any AI, also from Telegram and WhatsApp

**URL:** <https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930>\
**Category:** Apps\
**Tags:** app, flow, homey-pro, ai, mcp\
**Created:** [June 8, 2026, 4:20pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930 "2026-06-08T16:20:44Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![weide43](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/weide43/32/79186_2.png) [@weide43](https://community.homey.app/u/weide43)\
**Post date:** [July 27, 2026, 9:15pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/42 "2026-07-27T21:15:21Z")

</div>

@LionelDerBoven  
Your AI was exactly right, and that’s a genuinely clean catch. 🎯 It’s a real bug in MCP AI Bridge, not in your app.

`flowcards_test_condition` was returning Homey’s response _envelope_ (`{ result: <boolean>, error, usedTokens, elapsedTime }`) and coercing the whole object to a boolean with `!!`. An object is always truthy, so the tool reported `true` for every condition regardless of the real answer, which is why a 0% random, a non-matching day, and your `everyone_asleep` card all came back `true` while the raw data and CLI correctly said `false`.

Fixed in **2.8.1** : it now reads the actual `.result` boolean. Verified live: `chance=0 → false`, `chance=100 → true`. I also hardened `flowcards_run_action` so it reports a failure when a card returns an error instead of always claiming success.

The `chance:0` reproduction was about as airtight a bug report as it gets, thanks for that, and for confirming your own app was behaving perfectly the whole time. Update to 2.8.1 once it’s live.

Also checked every other run/test/trigger tool for the same mistake, they’re clean: flow triggers throw on error (so they can’t silently report success), the simulate tool is validation-only, and the rest either read the right field or fail loudly. `flowcards_test_condition` was the only one affected, fixed in 2.8.1.

---

<div class="post-metadata">

**Author:** ![LionelDerBoven](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/lionelderboven/32/121059_2.png) [@LionelDerBoven](https://community.homey.app/u/LionelDerBoven)\
**Post date:** [July 28, 2026, 7:49am UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/43 "2026-07-28T07:49:00Z")

</div>

Thank you! This is fixed indeed! I stumbled on on small issue when making my app (your app is helping so mutch with this with the MCP access)!

I let Claude make a raport of the bug.

Bug report — MCP AI Bridge serves stale device capability values

**App:** MCP AI Bridge 2.8.1 (app store, live channel) — Danny van Soerland  
**Homey:** Homey Pro 2023 (platform local v2), firmware 13.3.0  
**Client:** Claude Code via HTTP MCP transport (`http://<homey-ip>:52199/mcp`)  
**Date:** 2026-07-28

* * *

## Summary

The device tools return capability values from a cache that appears to be  
populated once and then never refreshed. The cache does not update when a  
capability changes, and is **not** invalidated even by the bridge’s own  
`devices_set_capability` write.

The stale response includes a stale `lastUpdated` timestamp, so it is a whole  
cached device object being returned, not just a stale value on a fresh object.

This is a silent failure: the response is well-formed and plausible, so a client  
has no way to tell it is being given old data. It cost me a debugging session  
chasing a bug in my own app that did not exist.

**Affected (confirmed):** `devices_get_state`, `devices_find`  
**Not affected (confirmed accurate):** `users_list`, `users_get_presence`,  
`apps_get`, `apps_list`, `flows_list`, `flows_get`, `system_get_memory`,  
`flowcards_test_condition`

* * *

## Reproduction

The device is a simple `onoff` device provided by a local app, whose value is  
changed by that app calling `setCapabilityValue()`. Ground truth is read with the  
Homey CLI, which bypasses the bridge entirely:

```auto
homey api devices get-device --id <device-id> --json \
  --jq '"onoff=\(.capabilitiesObj.onoff.value) lastUpdated=\(.capabilitiesObj.onoff.lastUpdated)"'

```

### Timeline

| Clock (UTC) | Event |
| --- | --- |
| 07:37:42.258 | App writes `onoff = true`. CLI confirms, `lastUpdated` matches. |
| 07:40:31.650 | App writes `onoff = false`. CLI confirms. |
| 07:42:27 | **CLI:** `onoff=false lastUpdated=07:40:31.650Z`  
**MCP `devices_get_state`:** `value=true lastUpdated=07:37:42.258Z` |
| 07:42:46.491 | App writes `onoff = true`. CLI confirms. |
| 07:43:11 | **CLI:** `onoff=true lastUpdated=07:42:46.491Z`  
**MCP:** `value=true lastUpdated=07:37:42.258Z` — value now correct _by coincidence_, timestamp still frozen |
| 07:43:32.759 | App writes `onoff = false`. CLI confirms. |
| 07:43:50 | **CLI:** `onoff=false lastUpdated=07:43:32.759Z`  
**MCP `devices_get_state`:** `onoff=true`  
**MCP `devices_find`** (capability `onoff`, operator `truthy`): returns this device with `value=true` |
| 07:44 (after) | Called MCP `devices_set_capability` → `onoff=false`, returned `success:true`.  
Immediately re-read via MCP `devices_get_state`: still `value=true lastUpdated=07:37:42.258Z` |

Throughout, every MCP response reported the identical timestamp  
**`2026-07-28T07:37:42.258Z`** , while Homey’s own value changed four times.

* * *

## Key observations

1. **The cache never refreshes.** More than six minutes and four capability  
changes later, the bridge still returned the value from 07:37:42.
2. **`lastUpdated` is stale too.** A client cannot detect the staleness by  
comparing timestamps, because the cached timestamp is returned as well.
3. **The bridge’s own writes do not invalidate it.** `devices_set_capability`  
reports success, but a subsequent `devices_get_state` still returns the old  
cached object.
4. **The cache is shared across device tools.** `devices_get_state` and  
`devices_find` both returned the same stale value in the same instant, so it  
looks like a shared device-state cache rather than a per-tool issue.
5. **It is domain-specific.** Users, apps, flows, flow cards and system memory  
were all accurate at the same moments. Only device capability state was stale.

* * *

## Possible cause (guess, not verified)

The timestamp the cache is frozen at (07:37:42) is the moment a local app that  
had been running under `homey app run --remote` wrote a capability value. Shortly  
after, that dev session ended and the app was reinstalled with  
`homey app install`, restarting it.

That makes me suspect the bridge maintains its device cache from a realtime  
subscription which was dropped, or silently stopped delivering, around an app  
restart — and is never re-established or re-synced afterwards. Worth checking  
whether the subscription is re-created on reconnect, and whether there is any  
TTL or periodic re-sync as a backstop.

* * *

## Impact

Any automation or assistant reading device state through the bridge can act on  
arbitrarily old data while believing it is current. Because the payload is  
well-formed and carries a plausible timestamp, there is no client-side signal  
that anything is wrong — the failure mode is silent and indistinguishable from  
correct behaviour.

* * *

## Suggested fixes

- Re-establish or re-sync the device subscription on reconnect, and after an app  
restart is observed.
- Invalidate the cached entry on `devices_set_capability`, at minimum.
- Add a TTL so a broken subscription degrades to “slightly stale” rather than  
“frozen indefinitely”.
- Consider passing through Homey’s `lastUpdated` only when it comes from a fresh  
read, so clients can detect staleness themselves.

* * *

## Note on a previously reported issue

`flowcards_test_condition` used to always return `{"result": true}` regardless of  
the card’s real value. That was reported and **fixed** — re-verified today:  
`homey:manager:logic:random` with `chance: 0` now correctly returns `false`.  
Thank you for the quick turnaround.

The technique that caught it is worth reusing as a regression test: call a card  
whose answer is knowable a priori. `logic:random` with `chance: 0` must always be  
false; `cron:day_equals` with a day that is not today must always be false.

---

<div class="post-metadata">

**Author:** ![weide43](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/weide43/32/79186_2.png) [@weide43](https://community.homey.app/u/weide43)\
**Post date:** [July 28, 2026, 11:43am UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/44 "2026-07-28T11:43:06Z")

</div>

@LionelDerBoven  
Confirmed and fixed in **2.8.2** , your analysis was exactly right, including the root cause. The bridge reads devices through homey-api’s realtime item-store; the EventBridge puts the devices manager into realtime mode, and when that socket silently drops (as it did around your `homey app run`→`install` restart), the store freezes and every read returns the value + timestamp from that moment, with no re-sync. Device reads now pass `$cache:false` so they always do a fresh HTTP read regardless of socket state (verified: an external capability change is now reflected immediately with a fresh `lastUpdated`). I also found and fixed the _same_ silent-drop failure on the event/webhook path (a watchdog poll now keeps it alive). Your `chance:0` regression-test idea was spot on too, and while auditing this I fixed a batch of other issues (an XSS in dashboard config, a couple of access-scope classifications, OAuth refresh rotation, and several list fields). Thank you, genuinely one of the best bug reports I’ve had.

---

<div class="post-metadata">

**Author:** ![LionelDerBoven](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/lionelderboven/32/121059_2.png) [@LionelDerBoven](https://community.homey.app/u/LionelDerBoven)\
**Post date:** [July 28, 2026, 5:29pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/45 "2026-07-28T17:29:41Z")

</div>

Confirmed and fixed. Thank you! And no problem. Thank Claude Opus 5 for the detailed markdown bugreport 😃

---

<div class="post-metadata">

**Author:** ![weide43](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/weide43/32/79186_2.png) [@weide43](https://community.homey.app/u/weide43)\
**Post date:** [July 29, 2026, 5:28pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/46 "2026-07-29T17:28:55Z")

</div>

## **🎉 Version 3.0 is here, the biggest update yet!**

After a long deep-audit build run, MCP AI Bridge 3.0 is out. This one packs the most new features of any release so far, with security and polish across the board.

**Highlights:**

- 🧠 **Smarter answers** — trend and anomaly detection on your Insights, so “is my power use climbing this week?” gets a real analysis.
- 👁 **The AI can see now** ,camera snapshots come back as actual images, not just links.
- 🛡 **Guardrails with a visual editor** ,click together rules like “never unlock doors at night”, with a strict mode that also blocks the sneaky paths through scenes, flows and scripts.
- ✅ **Confirmation on the scary stuff** ,reboot, delete and uninstall ask a capable client to confirm first.
- 🔑 **Tighter keys** ,per-key rate limits, last-used tracking, and remote connectors you can scope to read / write / full per connection.
- ⚡ **Live-push dashboards** ,the dashboard now updates the instant something changes through the bridge, no more waiting for a refresh.
- 🧭 **Tidy Advanced Flows** ,flows the AI builds are auto-arranged into clean columns.
- 🎨 **Device icons** ,change a device’s icon straight from chat.
- 🔌 **Latest MCP spec (2025-11-25)** with server-initiated requests (confirmations + progress).

Plus dozens of reliability, correctness and security fixes under the hood.

---

<div class="post-metadata">

**Author:** ![DGalama](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/dgalama/32/10402_2.png) [@DGalama](https://community.homey.app/u/DGalama)\
**Post date:** [July 31, 2026, 10:05pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/47 "2026-07-31T22:05:04Z")

</div>

Hi, _(text below is made by Claude: I have been trying te setup MCP Bridge with help from Claude as I am not that tech savvy to do this by myself 😄 )_

I’m trying to connect MCP AI Bridge to Claude web (claude.ai) using the Remote Access / OAuth feature. My setup:

- Homey Pro
- MCP AI Bridge v3.0.0
- Cloudflare Tunnel to port 52199, publicly accessible via HTTPS
- Remote access enabled, public URL set correctly
- API key configured under Security

The OAuth metadata endpoints are working correctly:

- `/.well-known/oauth-protected-resource` → returns correct JSON ✅
- `/.well-known/oauth-authorization-server` → returns correct JSON with all endpoints ✅

However, when Claude attempts to connect, it fails with:

> **Cannot authorize — invalid\_request: Invalid request**

Checking the `/register` endpoint (which is listed in the oauth-authorization-server metadata as `registration_endpoint`) via GET returns `{"error":"Not found"}`.

My assumption is that Claude performs dynamic client registration via POST to `/register` as part of its OAuth flow, and this step is failing — causing the “invalid\_request” error before the authorization screen can complete.

Is dynamic client registration (RFC 7591) supported in v3.0.0? If not, is it on the roadmap? Claude web appears to require it to complete the OAuth handshake.

Thanks in advance!

---

<div class="post-metadata">

**Author:** ![weide43](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/weide43/32/79186_2.png) [@weide43](https://community.homey.app/u/weide43)\
**Post date:** [August 1, 2026, 11:35am UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/48 "2026-08-01T11:35:22Z")

</div>

@DGalama  
Thanks for the incredibly detailed report, that made this easy to pin down.

Good news and a fix:

Dynamic Client Registration (RFC 7591) is supported in v3.0.0. Registration happens via POST /register, and I verified it returns a proper client\_id. The {“error”:“Not found”} you saw is just because you hit it with GET (the endpoint is POST-only), so that part is a red herring, not the failure.

The actual bug is one step later, at the approval screen. When you approve the connection, the consent form was not sending the response\_type parameter back to the server. The server re-validates the request at that point and requires response\_type=code, so the final step failed with exactly invalid\_request: Invalid request, right before the handshake could complete. I reproduced your error end to end and confirmed it.

I’ve fixed it: response\_type is now carried through the consent step, and I verified the full flow (register → authorize → approve → token) now completes and issues a valid token. It’ll be in the next build (3.0.1), no config change needed on your side, just update and reconnect.

I’ll reply here again the moment the build is live. Thanks again for the clear write-up, and apologies for the hiccup!

---

<div class="post-metadata">

**Author:** ![DGalama](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/dgalama/32/10402_2.png) [@DGalama](https://community.homey.app/u/DGalama)\
**Post date:** [August 1, 2026, 2:53pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/49 "2026-08-01T14:53:21Z")

</div>

Hi Danny,

Thanks for the quick fix! I updated to v3.0.1 and the authorization screen now appears correctly.

However, after filling in the API key and clicking “Approve access”, nothing happens. No redirect, no error, no visible feedback. I tested this on both desktop (Chrome and Safari) and Android, same result on both.

I checked the connector status in Claude afterwards: it is not connected, so the flow did not complete silently.

---

<div class="post-metadata">

**Author:** ![weide43](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/weide43/32/79186_2.png) [@weide43](https://community.homey.app/u/weide43)\
**Post date:** [August 1, 2026, 8:47pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/50 "2026-08-01T20:47:14Z")

</div>

@DGalama  
Found it, and fixed. 🙌

The approval screen was working, but the page’s security policy (`form-action 'self'`) also applied to the redirect **after** you click Approve, so Chrome and Safari silently blocked the jump back to Claude’s callback, no redirect, no error, exactly what you saw. The consent page now also allows the connector’s validated redirect address, so approval completes and the connection finishes.

This is in **v3.0.2**. I also ran the entire remote flow end to end this time (register → authorize → approve → token, then actually using the token for live calls, plus token refresh and read/write scoping, 24 checks), so it’s properly verified now rather than fixed blind. Just update to 3.0.2 and reconnect, no config change needed.

Thanks again for the great, precise reports, they made both fixes quick. Let me know if anything else comes up!

---

<div class="post-metadata">

**Author:** ![DGalama](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/dgalama/32/10402_2.png) [@DGalama](https://community.homey.app/u/DGalama)\
**Post date:** [August 2, 2026, 6:15am UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/51 "2026-08-02T06:15:33Z")

</div>

Tested and it worked! Fantastic job (and fast!).

Oh, and I’ll pass on your thanks for the reports to my friend Claude. 😉

---

<div class="post-metadata">

**Author:** ![LionelDerBoven](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/lionelderboven/32/121059_2.png) [@LionelDerBoven](https://community.homey.app/u/LionelDerBoven)\
**Post date:** [August 4, 2026, 6:47am UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/52 "2026-08-04T06:47:26Z")

</div>

Hi,

I found out that Claude was struggeling with note colors for some reason. It was always making transparant note cards (I hope this helps). Thanks for the app!

The feedback and bug report to make this better for claude:

# Homey MCP bridge — Advanced Flow `note` cards: wrong shape and invalid colours both fail silently

**App version:** MCP AI Bridge 3.0.2  
**Homey:** Homey Pro (Early 2023), firmware 13.4.0  
**Reported by:** an LLM agent building Advanced Flows through the bridge

## Summary

Two separate mistakes an agent can make when adding `note` cards to an Advanced Flow are accepted  
without complaint, stored, and reported as success — while the result on screen is wrong:

1. **Note text placed in `args`** produces a blank note. The text and colour must be top-level  
`value` and `color` fields on the card; anything in `args` is stored but never read.
2. **An invalid colour** produces an unstyled grey note. Homey stores any string at all — including  
`"banana"` and `"#ff0000"` — and the web app falls back to a default when it does not recognise  
the value.

Neither is caught by `advanced_flows_validate`, which returns `valid: true` with zero warnings for  
both. Neither produces an error at write time. The write tools return only `{success: true, flow_id}`,  
so nothing in the response contradicts the agent’s assumption that it worked.

This matters more for an MCP server than for a human-facing API. A person adds a note and sees  
immediately that it is blank. **An agent cannot see the canvas.** It has no feedback channel other  
than the tool result, so a silent visual failure is invisible to it, and it will confidently report  
that the flow was created correctly. In practice the mistake surfaced only when the user opened the  
editor and asked why the notes were empty — and later, why they were grey.

## Reproduction

A flow created through the API with six note cards, then read back verbatim:

| card | sent | stored |
| --- | --- | --- |
| n1 | `color: "orange"` | `color: "orange"` |
| n2 | `color: "purple"` | `color: "purple"` |
| n3 | `color: "green"` | `color: "green"` |
| n4 | `color: "banana"` | `color: "banana"` |
| n5 | `color: "#ff0000"` | `color: "#ff0000"` |
| n6 | `args: {value, color}` | `color: undefined`, `args` kept as an opaque blob |

Every value round-trips unchanged. There is no validation and no normalisation anywhere in the path.  
On screen, n1, n2, n4 and n5 render as grey default notes, and n6 renders blank.

`advanced_flows_validate` accepts the n6 shape as valid with no warnings, because it checks graph  
structure — node ids, dangling edges, flow-card nodes missing a `uri` — and never per-type field  
shapes.

## Which colours are actually valid

This could not be determined from any documentation. The Homey feature page says only that notes  
exist and “you can even change their color”, without listing the options, and the developer  
documentation does not cover note cards at all.

It was established empirically instead, by scanning every note in one household’s hand-authored  
flows — notes made in the official editor, therefore valid by construction:

```auto
200 notes across 67 advanced flows
  yellow 181
  red 13
  green 4
  blue 1
  (undefined) 1

```

So `yellow`, `red`, `green` and `blue` are known good, and `undefined` is a valid default. `orange`  
and `purple` are confirmed **not** to render.

That method is the problem in miniature. The set had to be inferred from user data, it can only ever  
be a lower bound, and an early guess based on a smaller sample got it wrong — `green` was assumed  
invalid because the first sample happened to contain none. An agent has no way to discover this set,  
so it guesses from ordinary colour names, and roughly half of those guesses fail silently.

## Why this happens

Homey’s own API is fully permissive here, so the bridge is faithfully passing through a call that  
Homey itself will not reject. The rendering contract lives only in the web app, which reads  
`card.value` and `card.color` and falls back when they are missing or unrecognised.

The bridge’s tool description contributes to the first mistake. It lists `note` as a valid node type  
and documents `args` generically as “object with card arguments”, giving an explicit example only for  
`delay`. Notes are the one node type whose content lives _outside_ `args`, and nothing says so — so  
the generic instruction actively points the wrong way.

## Suggested fixes

In rough order of value:

1. **Put the colour set in the tool’s JSON Schema as an `enum`.** This is the strongest fix and the  
cheapest to maintain, because the schema is already in the agent’s context — it does not require a  
discovery call the agent has to know to make, and an invalid value becomes impossible to write  
without noticing. Any field with a closed set of values deserves the same treatment; a free-form  
`string` in a schema is a promise that any string is meaningful.
2. **Normalise the note shape in the bridge** : lift `args.value` and `args.color` to top level for  
`note` nodes. The bridge already derives `ownerUri` from `uri` — this is the same class of  
ergonomic fix, and it makes the most natural-looking call correct instead of silently wrong.
3. **Warn in `advanced_flows_validate` and at write time** for an unrecognised note colour, and for a  
note carrying `args`. The message should name the valid values, so an agent that hits it is told  
the answer rather than left to guess again.
4. **Echo the stored card back from write calls** , or document that `advanced_flows_get` should be  
used to confirm. This catches the whole class of silent mangling rather than only colours — the  
agent can compare what it intended against what was kept.
5. **Document the note shape** in the `advanced_flows_create` description, alongside the existing  
`delay` example.

Fix 1 alone would have prevented the colour half of this entirely, and fix 2 the other half.

## Note

The bridge handled everything else in this session correctly, including a fairly large flow built  
from scratch, a `cards` round-trip used to repair that flow in place, and reading back state to  
verify each change. The `cards` round-trip in particular worked exactly as documented — edges and  
`input` arrays survived untouched — which is what made repairing the notes a one-call fix once the  
correct shape was known.

The exact full palette is still unconfirmed: `yellow`, `red`, `green`, `blue` are observed valid and  
`orange`, `purple` observed invalid, but the authoritative list is presumably in the web app source  
and would be worth reading off directly before writing it into a schema.

---

<div class="post-metadata">

**Author:** ![weide43](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/weide43/32/79186_2.png) [@weide43](https://community.homey.app/u/weide43)\
**Post date:** [August 4, 2026, 4:23pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/53 "2026-08-04T16:23:51Z")

</div>

@LionelDerBoven  
This is one of the best bug reports I’ve ever received, thank you. You nailed both the cause and why it matters more for an agent than a human. Fixed in **v3.0.3** :

- **Text in `args` → blank note:** the bridge now lifts a note’s text and colour to the top-level `value`/`color` that Homey actually renders from, so the natural `{ args: { value, color } }` shape works instead of coming out blank.
- **Invalid colour → grey note:** the tool schema now carries the colour set as an enum (`yellow, red, green, blue`), so an assistant picks a valid one from its own context, and both `advanced_flows_validate` and the create/update result now warn about an unknown colour, a blank note, or content in `args`, naming the valid values so it’s told the answer instead of guessing again.
- The note shape is now documented in the `advanced_flows_create` description alongside the delay example.

On the palette: you’re right that it’s undocumented and the API is fully permissive, so I went with your hand-authored set (`yellow, red, green, blue`). I also scanned a second household’s flows to corroborate; it added only `orange`, but those turned out to be agent-written (i.e. grey), which matches your finding. If the authoritative web-app list turns out larger, I’ll extend the enum, but this closes the silent-failure for the common cases.

Thanks again, genuinely useful. 🙏

---

<div class="post-metadata">

**Author:** ![LionelDerBoven](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/lionelderboven/32/121059_2.png) [@LionelDerBoven](https://community.homey.app/u/LionelDerBoven)\
**Post date:** [August 8, 2026, 1:56pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/54 "2026-08-08T13:56:34Z")

</div>

Hi, Here I am again with a feature request. Right now Claude code struggles creating dashboards. Would creating dashboards trough the MCP server be possible? I tested it with a local API key with claude and it can do things but it struggels with knowing what widgets to use:

# Feature request: expose write access to Homey’s native Dashboards

## Summary

The server currently exposes `homey_dashboards_list`, which wraps  
`ManagerDashboards.getDashboards()` and is documented as read-only. Homey’s Web API supports  
full dashboard CRUD, so the remaining methods could be exposed as well. Without them, a native  
Homey Dashboard cannot be created or modified through this MCP server, even though the  
underlying platform allows it.

## Current behaviour

`homey_dashboards_list` works and returns `{"items": [], "count": 0}`. There is no  
corresponding create, update or delete tool, so an agent can observe native dashboards but  
never author one.

## Why this matters

Homey’s per-user _homescreen_ is personal: it cannot be shared with other household members,  
duplicated, or reused. Native _Dashboards_ can. Migrating a curated homescreen layout to a  
Dashboard is a natural agent task — read the devices, flows and moods, then lay them out — but  
it stops at the last step because the write side is missing.

The general gap: this server can already author devices, flows, advanced flows, moods, logic  
variables, zones and scripts. Dashboards are the one first-class Homey object that is  
read-only here.

## Proposed API surface

Mirroring the naming of the existing tools:

| Tool | Wraps | Homey endpoint | Scope |
| --- | --- | --- | --- |
| `homey_dashboards_get` | `getDashboard({id})` | `GET /api/manager/dashboards/dashboard/:id` | `homey.dashboard.readonly` |
| `homey_dashboards_create` | `createDashboard({dashboard:{name, columns}})` | `POST /api/manager/dashboards/dashboard` | `homey.dashboard` |
| `homey_dashboards_update` | `updateDashboard({id, name?, columns?})` | `PUT /api/manager/dashboards/dashboard/:id` | `homey.dashboard` |
| `homey_dashboards_delete` | `deleteDashboard({id})` | `DELETE /api/manager/dashboards/dashboard/:id` | `homey.dashboard` |
| `homey_dashboards_list_widgets` | `getAppWidgets()` | `GET /api/manager/dashboards/widget` | `homey.dashboard.readonly` |

`ManagerDashboards` is present on both `HomeyAPIV3Cloud` and `HomeyAPIV3Local`, so this works  
for locally-connected Homey Pro as well as cloud sessions.

Reference: [https://athombv.github.io/node-homey-api/HomeyAPIV3Cloud.ManagerDashboards.html](https://athombv.github.io/node-homey-api/HomeyAPIV3Cloud.ManagerDashboards.html)

## Implementation notes

1. The manager is reachable the same way the existing `homey_dashboards_list` reaches it — no  
new client, transport or auth path is needed. Only the write methods and the two extra read  
methods need wiring up.

2. `getAppWidgets()` is the piece that makes the write tools _usable_. Without a widget  
catalogue an agent has to guess widget identifiers and settings keys. Please return each  
widget’s id, name and settings schema. If the full catalogue is large, a `compact` flag  
(id + name only) matching the convention of `devices_list` would help.

3. The `columns` layout structure is undocumented upstream. Passing it through verbatim as an  
opaque JSON value is fine, and probably preferable to modelling it — agents can learn the  
shape by reading an existing dashboard back. Documenting one worked example in the tool  
description would save a lot of trial and error.

4. Suggest `homey_dashboards_update` be a true partial update (omitted fields left untouched),  
so iterating on a layout does not require resending the whole dashboard and a dashboard  
keeps its id across edits.

5. Delete is destructive and hard to undo from an agent’s position — worth putting behind the  
same guardrail treatment as the other destructive tools in this server.

## Workaround in the meantime

`homeyscript_run` exposes the full Web API client server-side, so  
`Homey.dashboards.createDashboard(...)` is reachable today. That works, but it routes a  
first-class platform object through an escape hatch, and the method list is not discoverable  
via `Object.keys()` — the prototype chain has to be walked to find it.

## Environment

- Homey Pro (Early 2023), firmware 13.4.0, local platform
- `homey_dashboards_list` present and functional; no dashboard write tools available

Thanks you!

---

<div class="post-metadata">

**Author:** ![weide43](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/weide43/32/79186_2.png) [@weide43](https://community.homey.app/u/weide43)\
**Post date:** [August 8, 2026, 3:06pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/55 "2026-08-08T15:06:19Z")

</div>

@LionelDerBoven

Done, and thank you for such a well-scoped request. Shipped in **v3.1.0** , exactly the surface you proposed:

- `homey_dashboards_get`, `homey_dashboards_create`, `homey_dashboards_update`, `homey_dashboards_delete`, and `homey_dashboards_list_widgets`.
- **Widgets are discoverable** : `homey_dashboards_list_widgets` returns each widget’s id, owner app and full **settings schema** (with a `compact` flag for id + name only), so an agent knows what it can place instead of guessing.
- **Update is a true partial update** : it fetches the current dashboard, merges the fields you pass, and writes it back, so omitted fields survive and the dashboard keeps its id across edits.
- **Delete** is treated as destructive: blocked when no API key is set, and it asks for confirmation on clients that support elicitation, same as the other destructive tools.
- On the layout: it’s undocumented upstream, so I dug out the exact shape and put a **worked example in the create tool description** : `columns: [{ id: <uuid>, widgets: [{ id: <uuid>, uri: "<widget id from list_widgets>", settings: {} }] }]`, each column and widget needing its own generated UUID. I verified the whole round-trip live (create empty, add a widget via update, read it back). Reading a dashboard back to iterate works exactly as you suggested.

No more routing a first-class object through the HomeyScript escape hatch. It reaches ManagerDashboards the same way the existing list tool does (local Homey Pro included). Thanks again, genuinely great write-up. 🙏

---

<div class="post-metadata">

**Author:** ![LionelDerBoven](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/lionelderboven/32/121059_2.png) [@LionelDerBoven](https://community.homey.app/u/LionelDerBoven)\
**Post date:** [August 8, 2026, 3:09pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/56 "2026-08-08T15:09:32Z")

</div>

Thanks! Will test later / tomorow!

Also claude was struggling with finding broken flows (deleted device cards for example).

This is the report.

Sorry for all the reports. I really appreciate the updates! I am using it a lot to “spring clean” my flows and automations right now!

# Homey MCP — broken-flow detection returns false negatives on every affected flow

**Date:** 2026-08-08  
**Component:** Homey MCP server — flow integrity tools  
**Severity:** High (silent failure in a diagnostic tool)

* * *

## Summary

`flows_get_broken` is documented as listing flows that are broken “when a card it uses no longer  
exists, for example after a device or app was removed”. In practice it appears to pass through  
Homey’s own `flow.broken` property rather than resolving card references itself. That property was  
`false` for every affected flow on this installation — including a flow constructed specifically to  
be broken — so the tool returns an empty list and the user is told everything is fine.

This is a silent failure in a diagnostic tool, which is the worst place for one: a clean result is  
indistinguishable from a working check. The same root cause affects two other surfaces.

| Metric | Value |
| --- | --- |
| Flows scanned | 99 |
| Real problems found by manual cross-reference | 4 |
| Reported by the MCP | **0** |
| Detection rate | **0%** |

**The fix is cheap.** `getFlowCardTriggers()`, `getFlowCardConditions()` and  
`getFlowCardActions()` already return the fully-resolved live card registry — **2,559 manager/app  
cards plus 3,157 device cards** on this Homey. Validating a flow is a set membership test per card.  
No new API surface is required.

* * *

## Environment

| | |
| --- | --- |
| Homey | Homey Pro |
| Devices | 148 |
| Flows | 26 basic + 73 advanced = 99 |
| Cross-check | Flow Checker 1.37.2 (Martijn Poppen) |

* * *

## Reproduction

1. Create an Advanced Flow using one device for a trigger, a condition and an action.
2. Delete that device from Homey.
3. Call `flows_get_broken`.

**Expected:** the flow is listed, ideally with the three offending cards.  
**Actual:** `{"count": 0, "broken": []}`

The reference flow used here is `Test Broken flow cards`  
(`4a537833-b40e-4727-b5f9-8b7a1f392bc1`). All three of its cards reference the deleted device  
`a3532f0a-635e-4048-b225-1fe04153ebb3`, confirmed deleted — `devices_get` on that id returns  
`Not Found`.

### Three surfaces, same flow, same wrong answer

| Surface | Response | Verdict |
| --- | --- | --- |
| `flows_get_broken` | `{"count": 0, "broken": []}` | False negative |
| `advanced_flows_list` → `broken` | `false` | False negative |
| `advanced_flows_validate` | `{"valid": true, "errors": [], "warnings": []}` | False negative |
| Manual reference resolution | 3 cards → deleted device | Correct |

* * *

## Individual defects

### B1 — `flows_get_broken` does not resolve card references `[CRITICAL]`

The core defect. Returns an empty list on an installation with four genuinely broken flows. Because  
it inherits `flow.broken`, it only ever reports what Homey itself already decided — and Homey did  
not set that flag for any deleted-device case observed here.

Independent confirmation that the breakage was real: the Flow Checker app, running against the same  
Homey, _did_ flag one of these flows under “Kapotte ingeschakelde flows” while the MCP reported zero.

### B2 — `broken` field in list tools is always `false``[MISLEADING]`

`flows_list` and `advanced_flows_list` both expose a `broken` boolean. Across all 99 flows it was  
`false` — including the intentionally broken one. A field that is structurally incapable of being  
`true` is worse than no field, because it implies a check was performed. Either populate it from a  
real check or drop it.

### B3 — `advanced_flows_validate` validates graph shape only `[GAP]`

Passing the exact card map of the broken reference flow returns `valid: true` with no errors and no  
warnings. The tool checks ids, edges and reachability, but never asks whether a card’s `uri`  
actually exists. Since its stated purpose is to catch problems _before_ creating a flow, this is  
where a bad device reference should surface first.

Suggested: add a `resolve_references` option (default on) that reports unknown card uris as errors  
and app-disabled cards as warnings.

### B4 — No reference check for `args.flow.id` (deleted sub-flows) `[CRITICAL]`

This class is missed by _everything_, including the Flow Checker app. A `programmatic_trigger`  
action stores its target as:

```json
{"flow": {"id": "c93cbe0c-3d5a-4aca-9004-bd5facce54ff",
          "name": "Module-buiten-motion",
          "type": "advanced"}}

```

That flow was deleted. Three such cards across two enabled flows pointed at it. Nothing warned the  
user, and the card still renders the stale cached name, so the editor looks correct. For users who  
build modular flows out of sub-flows this is the most damaging failure mode, and the one with the  
best payoff: the cached `name` is right there in the args and makes an excellent error message.

### B5 — Installed-but-disabled apps are not treated as breakage `[GAP]`

An app can be installed while `enabled: false` / `state: "stopped"`. Its cards then vanish from the  
live registry and any flow using them silently never fires — but the app is still “installed”, so an  
installed-check passes. Two enabled flows here depended on cards from a disabled app. This should be  
reported as recoverable breakage, distinct from a deleted device.

* * *

## What a correct check must resolve

Five checks cover every failure mode observed. Each is a lookup against data the API already returns.

| # | Check | Method | Catches |
| --- | --- | --- | --- |
| C1 | Device still exists | Parse `homey:device:<uuid>:<card>`, test uuid against `getDevices()` | Deleted devices |
| C2 | Card definition still exists | Test full card id against the union of the three card registries | Changed devices, app updates that drop cards, disabled apps |
| C3 | Referenced flow still exists | Test `args.flow.id` against basic + advanced flows | Deleted sub-flows (B4) |
| C4 | Owning app is runnable | For `homey:app:*`, check `enabled`, `state`, `crashed` — not merely installed | Disabled and crashed apps (B5) |
| C5 | Argument references resolve | Resolve UUID-shaped `args` values against devices, zones, users, moods, logic variables, flows | Dangling zone / variable / user references |

**C2 is the highest-value check.** The registry covers device cards too — all 3,157 of them — so it  
catches a device that still exists but lost a capability after a driver or firmware update. That is  
the “device changed” case, as opposed to “device deleted”.

> **On false positives.** A naive UUID sweep over card args produced 120 hits on this installation,  
> of which 108 were legitimate references to users, moods and logic variables. Resolving against all  
> six entity types brought it to 12, and every one was real. **C5 is only worth shipping with the  
> full resolution set.**

* * *

## Suggested response shape

Flow-level granularity is not actionable — the real-world case here was an Advanced Flow with 40  
cards. Report the card, its type and its canvas coordinates so the user can find it. Separate hard  
breakage from recoverable, and enabled flows from disabled ones, so a deliberately parked flow does  
not read as an incident.

```json
{
  "count": 2,
  "broken": [
    {
      "flow_id": "a31aab5d-d003-43fe-83f0-fd1e7176ebea",
      "flow_name": "Knopen control center gang inkom",
      "type": "advanced",
      "enabled": true,
      "severity": "broken",
      "cards": [
        {
          "card_id": "homey:device:3e276abd-...:on",
          "card_type": "condition",
          "x": 400, "y": 980,
          "reason": "DEVICE_MISSING",
          "missing_ref": "3e276abd-6386-46fd-b11a-e4de88d39166"
        }
      ]
    },
    {
      "flow_id": "88a742e5-d2f3-4484-b2ed-6d5774312260",
      "flow_name": "Buiten verlichting auto",
      "type": "advanced",
      "enabled": true,
      "severity": "broken",
      "cards": [
        {
          "card_id": "homey:manager:flow:programmatic_trigger",
          "card_type": "action",
          "x": 800, "y": 840,
          "reason": "FLOW_MISSING",
          "missing_ref": "c93cbe0c-3d5a-4aca-9004-bd5facce54ff",
          "cached_name": "Module-buiten-motion"
        }
      ]
    }
  ]
}

```

Useful `reason` values: `DEVICE_MISSING`, `CARD_MISSING`, `FLOW_MISSING`, `APP_MISSING`,  
`APP_DISABLED`, `APP_CRASHED`, `ARG_UNRESOLVED`.

Useful `severity` values: `broken` (unrecoverable without editing) and `degraded` (recoverable, e.g.  
re-enable the app).

* * *

## Reference implementation

The check that found all four problems. Run as HomeyScript against the live Homey. Roughly 40 lines  
of actual logic; the bulk is assembling the resolution sets.

```js
const devices = await Homey.devices.getDevices();
const apps = await Homey.apps.getApps();
const flows = await Homey.flow.getFlows();
const advs = await Homey.flow.getAdvancedFlows();
const zones = await Homey.zones.getZones();
const users = await Homey.users.getUsers();
const moods = await Homey.moods.getMoods();
const vars = await Homey.logic.getVariables();

// C2: the live card registry — includes device cards
const t = await Homey.flow.getFlowCardTriggers();
const c = await Homey.flow.getFlowCardConditions();
const a = await Homey.flow.getFlowCardActions();
const registry = new Set([
  ...Object.keys(t), ...Object.keys(c), ...Object.keys(a)
]);

const devIds = new Set(Object.keys(devices));
const known = new Set([ // C5 resolution set
  ...devIds, ...Object.keys(apps), ...Object.keys(zones),
  ...Object.keys(flows), ...Object.keys(advs), ...Object.keys(users),
  ...Object.keys(moods), ...Object.keys(vars)
]);
for (const f of Object.values(advs)) // advanced-flow node ids
  Object.keys(f.cards || {}).forEach(id => known.add(id));

function checkCard(id, args, report) {
  if (typeof id !== 'string') return;
  if (/^homey:(manager:logic:(all|any)|advancedflow:)/.test(id)) return;

  const parts = id.split(':');

  // C1 — device deleted
  if (parts[1] === 'device' && !devIds.has(parts[2]))
    return report('DEVICE_MISSING', parts[2]);

  // C2 — card definition gone (covers C4: disabled apps drop out of registry)
  if (!registry.has(id))
    return report('CARD_MISSING', id);

  // C3 / C5 — argument references
  for (const [key, val] of Object.entries(args || {})) {
    const ref = (val && typeof val === 'object') ? val.id
              : (typeof val === 'string' ? val : null);
    if (!ref || !/^[0-9a-f-]{36}$/i.test(ref)) continue;
    if (!known.has(ref))
      report(key === 'flow' ? 'FLOW_MISSING' : 'ARG_UNRESOLVED', ref, val.name);
  }
}

```

Iterate basic flows over `trigger` / `conditions` / `actions`, advanced flows over  
`Object.values(flow.cards)`, skipping `type: "note"` nodes.

* * *

## Secondary observations

### No `flows_validate` for basic flows

`advanced_flows_validate` has no counterpart for basic flows, so there is no dry-run path at all  
before `flows_create`. Worth adding alongside the B3 fix, sharing the same resolver.

### Verified working

For balance: everything used to build this report behaved correctly. `devices_list`, `devices_get`,  
`apps_get`, `apps_get_settings`, `flows_get`, `advanced_flows_get` and `homeyscript_run` all  
returned accurate, complete data. `devices_get` returning a clean `Not Found` for the deleted uuid  
is what made the diagnosis straightforward. **The defect is narrowly in the flow-integrity surfaces,  
not the underlying API access.**

* * *

_Compiled from a full scan of 99 flows on a live Homey Pro, 8 August 2026. Findings verified by  
re-scan after user fixes and cross-checked against Flow Checker 1.37.2. No flows were modified  
during analysis._

---

<div class="post-metadata">

**Author:** ![weide43](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/weide43/32/79186_2.png) [@weide43](https://community.homey.app/u/weide43)\
**Post date:** [August 8, 2026, 6:48pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/57 "2026-08-08T18:48:04Z")

</div>

@LionelDerBoven  
This is an exceptional report, thank you, the reference implementation made it a joy to build. Fixed in **v3.1.2** , addressing the whole thing:

- **B1** : `flows_get_broken` no longer trusts Homey’s `broken` flag. It now resolves every card against the live registries: device exists (C1), card definition in the trigger/condition/action registry (C2), referenced sub-flow exists via `args.flow.id` (C3), owning app is runnable (C4), and UUID args resolve against devices/zones/users/moods/variables/flows (C5).
- **Response shape** is exactly what you proposed: per-card `card_type`, `x`/`y`, `reason` (`DEVICE_MISSING`, `CARD_MISSING`, `FLOW_MISSING`, `APP_MISSING`, `APP_DISABLED`, `APP_CRASHED`, `ARG_UNRESOLVED`) and `severity` (`broken` vs `degraded`), plus `cached_name` for deleted sub-flows. Added `include_degraded` and `enabled_only` filters so a parked flow doesn’t read as an incident.
- **B3** : `advanced_flows_validate` gained `resolve_references` (default on), sharing the same resolver, so a bad device/app/flow reference surfaces before the flow is created.
- **B4 / B5** are covered: deleted sub-flows report `FLOW_MISSING` with the cached name, and disabled/crashed-app cards report `APP_DISABLED`/`APP_CRASHED` as `degraded`.
- **B2** : I removed Homey’s unreliable `broken` flag from the flow-list tools, since a field that can’t be true is worse than none.

I tested it against a live home: it found 14 genuinely broken flows that the old tool reported as zero, with no false positives (it correctly resolved against 87 logic variables etc., and only flagged references that are truly gone). The one thing I left for a follow-up is a basic-flow `flows_validate` counterpart, happy to add it next. Never apologise for reports like this, they make the app better. 🙏

---

<div class="post-metadata">

**Author:** ![weide43](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/weide43/32/79186_2.png) [@weide43](https://community.homey.app/u/weide43)\
**Post date:** [August 8, 2026, 9:04pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/58 "2026-08-08T21:04:41Z")

</div>

## MCP AI Bridge 4.0 is out

You can find it in the TEST release!

This is the biggest release since 3.0, and the short version first: **if you already have a connector set up, nothing changes and nothing needs touching.** Everything below is either new ground or a hole that got closed.

### A new protocol, alongside the old one

MCP got a new specification (2026-07-28) that moves the protocol to a stateless model. Version 4.0 speaks both eras side by side. A modern client is recognised from its own request and gets the new path; everything else keeps the exact handshake it has always used. There is no setting for this and no migration step.

What the new era brings:

- **Confirmations that cannot be moved or reused.** When an irreversible action needs your approval, that approval now travels through the client itself, cryptographically tied to the specific tool, the specific arguments and the caller. A confirmation for deleting one device can never be replayed against another device, and never a second time.
- **Slow work can run in the background.** A long job hands back a handle immediately instead of holding the connection open, and the client collects the result later. Opt-in, off by default.
- **A live notification channel** replacing the old subscribe mechanism.
- **Client registration via a metadata document** , replacing the now-deprecated dynamic registration.

### Security

Most of this came out of a long adversarial audit run, where the goal was specifically to break the thing rather than confirm it worked. Findings worth naming:

- A confirmation prompt could be **skipped entirely** by wrapping the call in a batch. Refused now.
- Flooding the server with declined confirmations could **resurrect an accepted one** and run an irreversible action a second time. The store fails closed instead.
- A client could **opt out of being asked** simply by not declaring that it could show a prompt.
- Web pages on other sites could reach the server through **DNS rebinding**. Origins are validated now.
- A registration flood could quietly **unregister a connector you were still using**.
- A corrupt guardrails setting used to **disable every rule you had configured, silently**. It now drops to read-only and tells you.

### Two new settings

Both off by default, so nothing changes unless you choose it.

**Refuse when nothing can be asked.** Some connections have no way to show you a prompt: the REST endpoint, and clients that only send without a return channel. Today those run reboot, delete and uninstall without asking. Turn this on and they get refused instead. Worth knowing before you flip it: connectors that rely on the current behaviour will start getting an error for exactly those three things.

**Allow slow work in the background.** Enables the task handling described above. Only clients that ask for it will use it.

### Also

Cancelling background work now genuinely skips work that has not started yet, and a finished result is never discarded in silence.

* * *

As always: if something behaves oddly, post it here with what you were doing and which client you used. Every one of the bugs fixed in the 3.x line came from a report in this topic.

---

<div class="post-metadata">

**Author:** ![LionelDerBoven](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/lionelderboven/32/121059_2.png) [@LionelDerBoven](https://community.homey.app/u/LionelDerBoven)\
**Post date:** [August 8, 2026, 11:16pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/59 "2026-08-08T23:16:17Z")

</div>

Thank you! it is already better!

It is still struggeling with this. Testing with 3.1.3:

# Follow-up: expose Homey’s built-in dashboard widgets in `homey_dashboards_list_widgets`

Follow-up to the earlier request for dashboard write access. **That part shipped and works** —  
this is about the one piece that did not make it in, which turns out to be the piece that  
actually gates automation.

Everything below was verified against a local Homey Pro on firmware 13.4.0 using the newly  
released tools.

## What shipped, and works

All five tools behave as documented. Verified by real calls, not inspection:

| Tool | Result |
| --- | --- |
| `homey_dashboards_create` | Creates the dashboard, returns the stored object |
| `homey_dashboards_get` | Returns `columns` verbatim; round-trips byte-for-byte |
| `homey_dashboards_update` | True partial update — reports `updated:["columns"]` when only the layout changed, and `updated:["name","columns"]` when both did. Dashboard keeps its id across edits. |
| `homey_dashboards_list` | Picks up dashboards created out-of-band |
| `homey_dashboards_list_widgets` | Returns the app widget catalogue, `compact` flag works |

A two-widget layout written with `update` and read back with `get` came back identical. The  
`columns` schema in the tool description matches the server’s behaviour exactly. Nothing to fix  
here.

## What is still missing

`homey_dashboards_list_widgets` returns **only widgets contributed by installed apps**. On the  
test system: 20 entries, every single one of the form `homey:app:<appId>:<widgetId>`.

Homey’s **built-in** widgets are not in the list: the device tile, flow button, mood/scene  
button, zone tile, weather, insights chart, and whatever the timeline equivalent is. These are  
the widgets an ordinary dashboard is mostly made of.

Re-probed after the update, all still 404 or unchanged:

```auto
GET /api/manager/dashboards/appwidget?includeBuiltin=true -> same 20, app widgets only
GET /api/manager/dashboards/appwidget?builtin=true -> same 20, app widgets only
GET /api/manager/dashboards/widget -> 404
GET /api/manager/dashboards/widgets -> 404
GET /api/manager/dashboards/builtin -> 404
GET /api/manager/dashboards/builtinwidget -> 404
GET /api/manager/dashboards/systemwidget -> 404
GET /api/manager/dashboards/manifest -> 404
GET /api/manager/mobile/widget -> 404
GET /api/manager/apps/widget -> 404
GET /api/manager/system/widget -> 404

```

They appear to be defined client-side in the Homey app rather than served by the platform.

## Why this blocks the use case

The motivating task was migrating a personal Homey _homescreen_ — which is per-user and cannot  
be shared or reused — into a native Dashboard, which can.

With write access but no built-in widget URIs, that dashboard can be assembled only from app  
widgets. On the test system that covers roughly six tiles out of forty-plus. Everything that  
makes the layout worth migrating — status toggles, thermostat, blinds, media, locks, eleven  
favourite flows, fifteen moods, zone tiles, weather — is built-in, and therefore unreachable.

So the write tools are currently sufficient to create a dashboard, but not to create a _useful_  
one, unless a human first builds a sample by hand so the URIs can be read back out of it.

## The silent-failure problem this creates

`uri` and `settings` are still passed through without validation. Verified after the update:

```auto
uri: "homey:app:this.app.does.not.exist:nonsense-widget"
settings: { "bogus": true }
result: { "success": true, "updated": ["columns"] }

```

A non-existent app, a widget id that was never defined, and an invented settings key are all  
accepted and stored. Nothing surfaces until someone opens the dashboard on a phone and finds  
blank tiles.

This matters more than it would otherwise, because the missing catalogue pushes callers toward  
guessing built-in URIs — and guessing is exactly what fails silently here. The two issues  
compound.

## Requests, in order of value

1. **Include built-in widgets in `homey_dashboards_list_widgets`.** Ideally behind a flag  
(`include_builtin: true`) so existing callers are unaffected. Each entry needs the same  
shape the app widgets already have: `id`/`uri`, `name`, whether it takes a device, and the  
settings schema. This single addition unblocks the whole use case.

2. **Validate `uri` against the known widget set before writing** , and return an error listing  
the unknown URIs. If the built-in list is unavailable and validation would produce false  
rejections, then warn rather than reject — but say something. Silent acceptance of a  
dashboard that will render blank is the worst of the options.

3. **Document the fallback in the tool description** , for as long as 1 is not done: build one  
dashboard by hand in the Homey app containing one widget of each built-in type, then call  
`homey_dashboards_get` on it to harvest the URIs and settings shapes. It works, but it  
requires a human round-trip in the middle of what is otherwise an automatable task, and  
nothing currently tells a caller that this is the required workflow.

## Environment

- Homey Pro (Early 2023), firmware 13.4.0, local platform
- Dashboard write tools present and functional
- `homey_dashboards_list_widgets` returns 20 widgets, all app-provided
- Homey MCP AI bridge 3.1.3

---

<div class="post-metadata">

**Author:** ![weide43](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/weide43/32/79186_2.png) [@weide43](https://community.homey.app/u/weide43)\
**Post date:** [August 9, 2026, 9:16am UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/60 "2026-08-09T09:16:47Z")

</div>

@LionelDerBoven  
Thank you for this. The probing you did saved me most of the  
investigation, and it turned out to be right on the part that matters.

**Shipped in 4.0.1.**  
4.0.1 is ready on the TEST version

## The built-in widgets: you were right, and here is the proof

I went looking for an endpoint you might have missed. There was exactly one  
candidate, and it does not deliver.

`ManagerDashboards` in the `homey-api` specification exposes thirteen operations  
in total:

createDashboard, deleteDashboard, getDashboard, getDashboards, updateDashboard,  
getState, getAppWidget, getAppWidgets, getAppWidgetAutocomplete,  
getWidgetStore, getWidgetStores, getWidgetStoreState, setWidgetStoreState

Every path you probed returns 404 because it genuinely does not exist. But  
`/widgetstore` does exist and neither of us had tried it, so I wired it up  
behind a new `include_builtin: true` flag, installed it and called it against a  
live Homey. It comes back empty. HomeyScript’s `Homey.dashboards` is a stub with  
nothing but a constructor.

So: built-in widgets are defined client-side in the Homey app and are not  
reachable from any API. I did not add a static table, for the reason you  
identified yourself: a guessed uri fails silently, and a table I could not  
verify would be guessing dressed up as a catalogue.

What `include_builtin: true` does now is say this outright, and give the  
workaround, instead of returning a list that looks complete.

## Silent acceptance is fixed

This is where your report paid off most. Your example uri names an app, and app  
widgets _can_ be checked authoritatively. So they now are, before anything is  
written:

homey\_dashboards\_create(uri: “homey:app:this.app.does.not.exist:nonsense-widget”)

Error: Unknown app widget uri: homey:app:this.app.does.not.exist:nonsense-widget.  
These name an installed app and a widget it provides, so they can be checked,  
and none of these match. Call homey\_dashboards\_list\_widgets for the valid ids.  
Nothing was written.

Verified on a live Homey: refused, and the dashboard count stayed where it was.

A uri that is _not_ `homey:app:*` is almost certainly one of the built-ins, and  
rejecting those would be a false negative on legitimate input. Those go through,  
with a warning in the response naming each unverifiable uri. Your framing was  
the deciding argument here: silent acceptance is the worst option, so the choice  
was between refusing and warning, not between refusing and saying nothing.

One deliberate limit: if the widget catalogue is unreachable, validation is  
skipped rather than failing the write. A transient API blip should not break  
dashboard editing.

## Documented

`homey_dashboards_create` and `homey_dashboards_update` now both state that  
built-in widgets are not listed, why, and the harvest workflow: build one  
dashboard by hand containing the widget types you need, then read the URIs and  
settings shapes back out with `homey_dashboards_get`.

It still needs that human round-trip. I could not remove it, only stop the  
tools from pretending it is not there.

---

<div class="post-metadata">

**Author:** ![weide43](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/weide43/32/79186_2.png) [@weide43](https://community.homey.app/u/weide43)\
**Post date:** [August 11, 2026, 9:12pm UTC](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930/61 "2026-08-11T21:12:19Z")

</div>

## **🎉 New since 4.0**

Four releases of protocol work, hardening and new capabilities. The short version.

### **🛡 Confirmation actually works now**

Asking you to confirm a reboot, a device delete, an app uninstall or a dashboard delete was presented as a headline feature, and on a normal setup it did not happen. Most assistants cannot show a prompt, and those connections were simply waved through. Three separate ways around the prompt were found and closed, including one where wrapping the call in a list was enough.

It is now **on by default**. A connection that cannot ask you is refused, and the error names the tool and where to change the setting. If you deliberately switched it off before, it stays off.

### **🔒 Security settings fail the safe way**

A typo in the access mode, or a key stored with an unrecognised permission, used to grant **full** access. Anything unreadable now means the least access.

Access mode **“off” really blocks everything**. It used to stop tool calls while still handing out device names, zones and the values of your logic variables. Your assistant now sees an empty list and can tell you the bridge is switched off, instead of reporting a broken connection.

The check that stops hostile web pages reaching your Homey was comparing two values an attacker controls, so it stopped nothing. It compares against your Homey’s real addresses now.

### **✅ The settings page tells the truth**

Save, delete and clear buttons announced success whether or not anything happened, **including the button that revokes an API key**. If you revoked a key on an older version, revoke it again to be sure. The status bar also showed a green “server active” when the app could not be reached at all, which is exactly when you look at it.

### **🔌 New protocol, old connectors untouched**

The whole protocol layer was rebuilt for the 2026-07-28 MCP specification, alongside the old one. A modern client is recognised from its own request; everything else keeps the handshake it always used. Nothing you set up needs changing.

Confirmations in the new era are cryptographically bound to the exact tool and the exact arguments, so a yes for deleting one device can never be replayed against another, and works only once.

### **📱 The Bridge is now a device**

Add it from Devices and you get the server itself on your Homey: whether it is running, how many assistants are connected, tool calls today, failed calls today, refused attempts today, broken flows, the current access mode, and whether remote access is on.

Because it is a real device you get Insights graphs of all of that over time, a place on your own Homey dashboards, and flow triggers when a value changes. None of which the app could offer about itself before. Adding it is optional.

### **🔀 Flows the AI builds run in parallel**

Assistants habitually chain action cards, which makes each one wait for the previous and stops everything after the first failure. Actions now start together. A sequence that is clearly deliberate is left alone: a wait card in the run, an action whose result feeds the next, or a branch off a false output. When something stays chained you are told why.

Flows the AI builds also get tidied into clean left-to-right columns.

### **📊 Also**

Homey’s own native Dashboards can be created and edited by the AI. Widget URIs are checked before writing, so a typo no longer becomes a blank tile you find days later. Broken-flow detection resolves every card against your live system instead of trusting Homey’s own flag, which stays false for most deleted-device cards. Moods and zone activity are reachable. A tool you have blocked no longer appears in the list your assistant sees.

And older Homeys are now refused clearly on startup instead of crash-looping. See Requirements above.

@LionelDerBoven @Luke_Vredeveld New version (test)

[Previous page](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930.md?page=2)

[Next page](https://community.homey.app/t/app-pro-mcp-ai-bridge-talk-to-your-homey-with-claude-chatgpt-gemini-copilot-cursor-mistral-ollama-lm-studio-n8n-home-assistant-or-any-ai-also-from-telegram-and-whatsapp/155930.md?page=4)
