[APP][Pro] MCP AI Bridge - Control Homey with any AI assistant (Claude, ChatGPT, Gemini, Copilot or Cursor) via the Model Context Protocol

:robot: MCP AI Bridge

Control your Homey Pro with any AI assistant. Claude, ChatGPT, Gemini, Copilot or Cursor.
Just ask in plain language.

Talk to your Homey like you talk to a person. “Turn off the lights.” “Is the door still open?” “Set the heating to 21.” “Build me a flow for the porch light at sunset.” MCP AI Bridge lets your favorite AI assistant control your Homey Pro directly, in any language you speak. It runs locally on your Homey, works with every major assistant through the open MCP standard, comes with a full interactive home dashboard, and you stay in full control.

:link: Links


:sparkles: What It Is

Your Homey already runs your home. Now you can just talk to it.

MCP AI Bridge turns your Homey Pro into something any modern AI assistant can talk to directly. No middleman cloud, no separate integration per assistant. The app runs a local Model Context Protocol (MCP) server on your Homey, and any MCP-compatible AI connects straight to it over your own network.

MCP is the open standard Anthropic, OpenAI and Google are building their assistants around. Because the bridge speaks that standard, the same Homey endpoint works in Claude, ChatGPT, Gemini, Cursor, Windsurf and more. No lock-in.


:rocket: Why This MCP App

  • :unlocked: Works with every assistant, not one. One open-standard endpoint for Claude, ChatGPT, Gemini, Cursor, Windsurf and any MCP client.
  • :toolbox: Covers the whole Homey. Over a hundred actions across devices, zones, flows, advanced flows, logic, energy, insights, alarms, notifications, apps and system.
  • :bar_chart: A full interactive dashboard, built in. Auto-generated or AI-built, with real tile control, in any browser on your network.
  • :puzzle_piece: You build your own AI commands in the flow editor and send live answers back.
  • :house: Local first. The AI connects to your Homey’s own address. Nothing routed through an extra cloud.
  • :locked: Real security. Scoped keys, an access switch, a tool blocklist, rate limits and a security log with source IPs.

:speech_balloon: Just Ask

:light_bulb: Lights and climate: “Turn off all the lights downstairs.” · “Dim the living room to 30 percent.” · “Set the bedroom to 19 tonight.”
:magnifying_glass_tilted_left: Check on things: “Is the garage door still open?” · “Which devices have a low battery?” · “Anything offline right now?”
:high_voltage: Energy and history: “What used the most power this week?” · “Average power use over the last 7 days?”
:hammer: Automations: “Make a flow that turns on the porch light at sunset.” · “Watch the front door and tell me when it opens.”
:broom: Housekeeping: “Did anything fail in the last hour?” · “Restart the Hue app.” · “Are any of my flows broken?”

You talk normally. The assistant works out which devices and capabilities you mean and does it.


:toolbox: What It Can Reach

  • :electric_plug: Devices and every capability they have
  • :house: Zones and rooms
  • :shuffle_tracks_button: Basic flows and Advanced Flows, including creating and editing them
  • :1234: Logic variables
  • :alarm_clock: Alarms and the alarm clock
  • :high_voltage: Energy, live and historical
  • :chart_increasing: Insights, with one-number summaries
  • :bell: Notifications
  • :package: Installed apps (enable, disable, restart, settings)
  • :busts_in_silhouette: Users and presence
  • :desktop_computer: System info, memory, storage and reboot

Over a hundred actions in total, so the assistant can both understand the state of your home and act on it.


:bar_chart: The Home Dashboard

Beyond chat, the app serves a complete, interactive dashboard in any browser on your network, at http://YOUR-HOMEY-IP:52199/dashboard.

Two ways to get one

  • :magic_wand: One-tap auto-generate (no AI needed). The app reads your devices and builds a clean, tabbed dashboard grouped by what you have.
  • :robot: Build it with any AI. A structured config mode means Claude, ChatGPT, Gemini etc. all produce the same clean result. Just ask, or copy the ready-made prompt from the settings.

What you get

  • :control_knobs: Real control from tiles: tap to toggle a light, long-press to dim, set a thermostat (temperature + mode), play or pause a speaker, lock the door, or run a one-tap scene like “all off”. Everything stays in sync with the live state.
  • :card_index_dividers: Organised tabs: a live Overview (who is home, lights on, what’s playing, what needs attention, weather, live energy flow), Lights per room, Climate, Energy (electricity, water and gas for today/yesterday/month/year plus savings), Media, Security, a dedicated Vehicles tab for EVs (battery, range, lock, charge status, odometer), and a fallback Devices tab so nothing gets left off.
  • :counterclockwise_arrows_button: Self-updating: add or remove a device in a category and an open dashboard refreshes on its own.
  • :camera: Camera friendly: a plain <img> shows live snapshots and a <video> plays a stream (for formats the browser supports natively) on a custom HTML dashboard.
  • :window: Multiple dashboards: keep several side by side (each at /dashboard/<name>) and choose which one opens by default.
  • :locked: Safe by design: controls use a separate dashboard token, are limited to the devices the dashboard shows, and can never delete or reboot anything.

:gear: How It Works

Under the hood it is a standard MCP server speaking JSON-RPC over local HTTP, using the StreamableHTTP transport from the MCP spec. Prefer to script against it? There is a REST shortcut at POST /tools/{name} and a full OpenAPI 3.1 spec at GET /openapi.json, so it drops right into n8n, Make, or your own code. Everything stays on your network.


:electric_plug: Connect a Local Assistant

Desktop and CLI assistants run on your own machine, so they reach your Homey directly. Every one connects to the same address:

http://YOUR-HOMEY-IP:52199/mcp

Open MCP AI Bridge → Settings → Connection for the exact URL and a ready-to-paste snippet. The examples use <homey-ip>.

:key: API key. If you set one in Settings → Security, add an Authorization: Bearer YOUR_KEY header (shown per client). Without a key the server is open on your local network only.

Claude Desktop — Settings → Developer → Edit Config, then restart:

{ "mcpServers": { "homey": { "type": "http", "url": "http://<homey-ip>:52199/mcp" } } }

Claude Code (CLI)

claude mcp add --transport http homey http://<homey-ip>:52199/mcp

Cursor — Settings → MCP → Add new server (or ~/.cursor/mcp.json):

{ "mcpServers": { "homey": { "url": "http://<homey-ip>:52199/mcp" } } }

Windsurf~/.codeium/windsurf/mcp_config.json:

{ "mcpServers": { "homey": { "serverUrl": "http://<homey-ip>:52199/mcp" } } }

GitHub Copilot (VS Code).vscode/mcp.json (note: servers, not mcpServers), then Agent mode:

{ "servers": { "homey": { "type": "http", "url": "http://<homey-ip>:52199/mcp" } } }

Gemini CLI~/.gemini/settings.json:

{ "mcpServers": { "homey": { "httpUrl": "http://<homey-ip>:52199/mcp" } } }

Antigravity CLI (replaces gemini-cli) — ~/.gemini/antigravity-cli/mcp_config.json, uses serverUrl:

{ "mcpServers": { "homey": { "serverUrl": "http://<homey-ip>:52199/mcp" } } }

Fallback: mcp-remote (for stdio-only clients, needs Node.js):

{ "mcpServers": { "homey": { "command": "npx", "args": ["-y", "mcp-remote", "http://<homey-ip>:52199/mcp", "--allow-http"] } } }

Quick check: ask “List my zones.” If that works, you are good to go.


:globe_with_meridians: Remote Access for Cloud & Mobile Assistants (v2.6, opt-in)

Cloud assistants (the ChatGPT and Claude web/phone apps) run on the provider’s servers, so they cannot see a private 192.168.x.x address. As of 2.6.0 the bridge is a full remote MCP server with standard OAuth 2.1, so you can use it from your phone, no desktop needed.

Step by step

  1. Set an API key in Settings → Security (you use it to approve the connection).
  2. Make your Homey reachable over HTTPS, e.g. a free Cloudflare Tunnel to port 52199. Never expose a bare port-forward without HTTPS.
  3. In the app, open the new Settings → Remote tab: enter your public URL, turn remote access on, and save.
  4. In the Claude or ChatGPT app, add a custom connector with that URL + /mcp. The app runs the OAuth login itself.
  5. You get an approval screen: enter your API key once to confirm. Done, your Homey now works inside the AI app.

Secure by default: remote access is off until you enable it. With the switch off, the app stays local-network only, exactly as before, with no OAuth endpoints exposed. When on, it uses PKCE, single-use authorization codes and tokens that expire automatically.

:mobile_phone: GitHub Copilot on mobile still needs to add custom-MCP-server support on their side. The moment it does, this works with it too, since the bridge is now a standard remote MCP server.


:puzzle_piece: Build Your Own AI Commands with Flow Cards

The app ships flow cards so your AI and your flows work together both ways.

  • :studio_microphone: Give the AI its own command. Trigger “An AI agent calls a custom tool”, run any logic, and reply with “Return a response to the AI agent” using live device values.
  • :eye: See what the AI does. Trigger “The AI controls a device” with name, capability and value as tokens.
  • :police_car_light: Catch problems early. Triggers for a flow becomes broken, an AI tool call fails, a security event occurs, plus a “there is a broken flow” condition.
  • :brain: Give the AI memory. Action “Remember a value for the AI” and condition “A remembered value is”.

You design your own AI commands in the flow editor.


:bullseye: Real World Examples

  • :bar_chart: Answer with live data. Trigger An AI agent calls a custom toolReturn a response with the current power usage. Now “how much power am I using right now” gets the real number from your flow.
  • :person_running: Let the AI know nobody is home. Your presence flow writes nobody_home = true; the assistant checks that context later.
  • :wrench: Get told when a flow breaks. Trigger A flow becomes broken → send yourself a notification with the flow name.

:locked: You Stay in Control

  • :green_circle: Access mode switch: full, write only, read only, or off in one click.
  • :key: Scoped API keys: each assistant its own key with read, write or full rights.
  • :prohibited: Tool blocklist: disable risky tools entirely, even for a full key.
  • :shield: IP whitelist and rate limits, with a tighter limit for destructive actions.
  • :memo: Security log: every denied or unauthorized attempt, with its source IP.
  • :satellite: Active connections view. Argument values are never logged.

By default, with nothing configured, it stays open on your trusted local network. The controls are there when you want them.


:bar_chart: See What Is Happening

The settings page is organized into tabs: Status, Connection, Commands, Dashboard, Security, Remote, Memory, Schedules, Events, Diagnostics, Bug report and About. Browse what the AI remembers and schedules, which devices it watches, recent activity, broken flows and the security log.


:white_check_mark: Works With

Claude (Desktop, Code, web, mobile), ChatGPT, Google Gemini, GitHub Copilot, Cursor, Windsurf, and any other MCP client. Text-to-speech and LED ring tools work on Homey Pro (Early 2019) and older models.


:inbox_tray: Get It

  1. :mobile_phone: Install: MCP AI Bridge | Homey
  2. :test_tube: Or the test build: MCP AI Bridge | Homey
  3. :gear: Open the app settings and run the connect wizard.
  4. :speech_balloon: Paste the config into your assistant and start talking to your home.

Questions, ideas and bug reports are very welcome in this topic. :folded_hands:


:scroll: Changelog

v2.6.0  Remote access for cloud AI apps (opt-in). New "Remote" tab: OAuth 2.1
        so Claude/ChatGPT apps connect over the internet. Off by default; when
        on, connector registers, you approve once with your API key, tokens
        expire automatically. PKCE, single-use codes, hashed tokens. With the
        switch off the app stays LAN-only, exactly as before.

v2.5.4  Dashboards can play external video/audio (media-src): a plain <video>/
        <audio> to an http/https stream works directly. Scripts/connections
        stay restricted to the app.

v2.5.3  Dashboards can show external images (img-src): a plain <img> from any
        http/https source works directly (camera snapshots, weather graphics).

v2.5.2  Electric cars get their own Vehicles tab (battery, range, lock, charge,
        odometer); home battery stays on Energy. Every device type gets a home
        (fans->Climate, TV/amp->Media, garage/camera->Security) + a Devices
        fallback. Auto dashboards self-refresh on device add/remove. Charge/
        lock/contact shown as readable text; several frozen rows now live.

v2.5.1  Dashboard hardening: page token limited to shown devices + honours the
        access mode; long-press dimmer fixes; no more "NaN"; flow-create
        validates + requires a trigger; no double-run on device error; logic
        type fix; 0-100 volume; alarm repeat-days apply; webhook SSRF block;
        settings survive restart; malformed requests handled.

v2.5.0  Full interactive dashboard: one-tap auto-generate or AI-built, live
        control from tiles, tabs for lights/climate/energy/media/security,
        multiple dashboards, separate dashboard token.

v2.4.0  Moods & scenes, weather + forecast, zone activity, realtime events,
        AI-generated dashboard at /dashboard, modern MCP (structured output,
        resource links, subscriptions, paging).

v2.3.0  ~93% smaller full-home overview, compact-by-default reads, control by
        name, short read cache, MCP resources & prompts, expanded Connect tab.

v2.2.x  Connect-tab guides (Gemini/Antigravity, Copilot, ChatGPT, Claude web),
        auto Authorization header, Advanced Flow create/edit fixes, token
        session fallback for privileged actions, my.homey.app settings fixes,
        constant-time key compare, Commands tab.

v2.1.x  New flow cards (AI controls a device, flow broken, tool fails, security
        event, AI memory), Bug report tab + tool, stricter-client compatibility,
        deep security & reliability audit.

v2.0.0  AI memory, device health/find/batch, insight summaries, scheduling,
        events & webhooks, templates + flow validator, access modes, scoped
        keys, blocklist, rate limits, security log, rebuilt NL/EN settings.

v1.x    Renamed to MCP AI Bridge, custom-tool flow cards + response callback,
        API key auth, REST + OpenAPI, Gemini support. v1.0.0: first release,
        control Homey Pro from any AI agent over MCP.

Where can I add Gemini ?

@Mark1541
A quick heads up: the regular Gemini app (gemini.google.com and the phone app) cannot add a custom MCP server. The consumer app has no custom connector feature yet. MCP works with the Gemini CLI (below), with Gemini Enterprise as a custom data store, or through the Gemini API in your own code. For most people the CLI is the way.

I have everything in working order with Gemini-cli on MacBook and the MCP-server app. I have made a personal acces token to be able to write flows to my homey. But writing doesn’t work. Gemini helped to troubleshoot but without success. I asked Gemini to make a bug report for me:

 Bug Report: Flow Write Operations Unavailable (even with Full Access PAT)

  Device: Homey Pro (2026)
  Firmware: v13.2.1
  App Version: MCP AI Bridge (latest)
  Issue: The bridge consistently reports that flow write operations are unavailable, despite using a Personal Advisory Token (PAT) with all possible scopes/permissions enabled.

  Steps taken to resolve:
   1. Created multiple new PAT tokens with "Full Access" (all scopes checked).
   2. Removed and re-added the token in the app configuration.
   3. Restarted the MCP AI Bridge app multiple times (with 10+ seconds wait time).
   4. Tested with both Basic Flows (flows_create) and Advanced Flows (advanced_flows_create).
   5. Verified the user account is the Owner/Admin of the Homey.

  Error Message received via MCP:
  Error executing tool "flows_create": Flow schrijfoperaties zijn niet beschikbaar. Controleer of het PAT token correct is ingesteld en herstart de app (Homey → MCP AI Bridge →
  Uitschakelen/Inschakelen).

  Additional Technical Observation:
  List-based tools (like flows_list, devices_list, zones_list) are also failing with a Zod-like type validation error:
  Invalid input: expected record, received array at path: ["structuredContent"]. This suggests a potential issue in how the bridge serializes data or how the schema is defined for the MCP output.

  Expected behavior:
  With a valid Admin PAT token, the bridge should allow the creation and modification of flows and correctly parse list-responses as records.

@Luke_Vredeveld

Thanks for the detailed report, it was really helpful. Both problems are fixed in v2.1.0 (now in test/review).

The list-tool error. The error expected record, received array at path ["structuredContent"] was a real bug on our side. The list tools (devices, flows, zones, etc.) returned a bare JSON array, and strict MCP clients like Gemini CLI reject that during structured-content validation, they expect an object. List results are now returned as an object, so reads work again in Gemini CLI and other strict clients.

The flow-write problem. This was not your token, and not the scopes. On recent firmware the bridge’s separate token-based session fails to initialize, which blocked all flow writes no matter how many PATs you created or which scopes you checked. Flow create and edit now go through the app’s own API (which already has the required permission), so a Personal Access Token is no longer needed at all. If the token session still cannot start, the real error is now surfaced instead of the generic message.

Update to v2.1.0 and it should just work.

While I was at it I also hardened the server for all AI clients: safe serialization (no more crashes on circular or empty results), protocol-version echoing, a session id for POST-based clients like ChatGPT and Cursor, and read-only/destructive hints on every tool.

One more thing that should make future reports easier: there is now a Bug report tab in the app settings that builds a diagnostic report with no tokens included, and you can also just ask your AI assistant to “create a bug report”. It builds the same report, saves it in the app, and returns it in the chat, so the exact diagnostics (app version, firmware, flow-write status, recent errors) are one click away.

Changelog:

v2.1.2

  • New flow cards: AI controls a device, a flow becomes broken, an AI tool fails, a security event occurs, remember a value for the AI, check a remembered value, and is any flow broken.
  • New Bug report tab in the app settings that builds a diagnostic report with no tokens, plus a system_create_bug_report tool so you can ask your AI to create one straight from the chat. Both copies stay identical.
  • Better compatibility with strict clients like Gemini CLI: list results are objects, safe serialization, protocol-version echo, a session id for POST-based clients (ChatGPT, Cursor, Windsurf), and read-only/destructive tool hints.
  • Flow create and edit no longer need a Personal Access Token; they use the app’s own API on modern firmware.
  • Fixed the app settings API so all management tabs load their data, and fixed the Generate report button.
  • Security and reliability fixes from a deep audit: destructive tools are blocked until you set an API key (with an in-app warning), the energy price tools use the correct Homey API, webhooks are no longer revealed to the AI, a memory namespace limit, a scheduler cancel fix, and corrections to the Claude Code mcp-remote command and the insights time range.

While the latest update fixed the reading of large lists (no more array errors!), I am completely blocked from creating flows.

I get ‘Missing Scopes’ every time. I’ve tried a clean reinstall and followed the release notes regarding the PAT being unnecessary, but it still won’t let me write. It seems like the new firmware

might have different requirements for the app’s internal API session.

Bug Report: Persistent "Missing Scopes" on Flow Write Operations (Homey Pro 2026)

  Environment:
   * Device: Homey Pro (2026)
   * Firmware: v13.2.1
   * App: MCP AI Bridge (latest version, post-array-fix)

  The Issue:
  Despite the latest update (which successfully fixed the "expected record, received array" error for read operations), the bridge is still unable to perform any flow write operations (flows_create or
  advanced_flows_create). Every attempt returns a "Missing Scopes" error.

  Summary of Findings:
   * Read Operations: WORKING. Tools like zones_list and devices_get_all_states return full, valid JSON structures.
   * Write Operations: FAILING. Any attempt to create a flow results in Error executing tool "flows_create": Missing Scopes.
   * Internal API Route: According to the release notes, the app should now use its own internal API permissions for flows, making a PAT unnecessary. However, on this firmware (v13.2.1), this internal
     session initialization still seems to be blocked or unauthorized.

  Steps Taken (All failed to resolve the issue):
   1. Created multiple new PAT tokens with "Full Access".
   2. Verified the user is the Homey Owner/Admin.
   3. Restarted the MCP AI Bridge app multiple times.
   4. Clean Reinstall: Fully uninstalled the app and reinstalled it from the App Store.
   5. Attempted write operations both with and without a PAT configured.

  Technical Observation:
  The bridge successfully authenticates for the general Web API (reading), but the authorization specifically for the homey.flow and homey.advancedflow scopes seems to be lost or not correctly requested
  when the bridge attempts to use the app's internal API on the newest Homey Pro 2026 firmware.

  Expected Behavior:
  The app should be able to create or edit flows using its internal permissions (as stated in the release notes) without requiring an external PAT, or it should correctly pass the PAT's scopes if one is
  provided.

@Luke_Vredeveld
Thanks again, this was a different root cause than the array fix, and your “Missing Scopes” observation pointed straight at it.

I verified it against the Homey API specification:

  • Reading flows (getFlows, getFlow, getAdvancedFlows) needs the homey.flow.readonly scope.
  • Creating or editing flows (createFlow, createAdvancedFlow, updateFlow, deleteFlow) needs the full homey.flow scope.

The app’s own API token (from the homey:manager:api permission) only carries the readonly scope, so reads work but writes return “Missing Scopes”. There is no app permission that grants the homey.flow write scope, so an app simply cannot create flows with its own token. My earlier “PAT no longer required” note was wrong, and the app-API fallback is exactly what produced the error.

On top of that, the token session that does have the right scope was connecting to a hand-built local address that fails on the Homey Pro 2026 firmware. It now uses the same local URL the app’s own API uses (homey.api.getLocalUrl()), so the token session initializes correctly.

What to do in v2.1.7 (now in test/review):

  1. Keep your Full-Access PAT in the app settings (Flow scope is the part that matters).
  2. Restart the app once (Homey, MCP AI Bridge, disable/enable).
  3. Open the Bug report tab and check the “Flow write” line: it should say “PAT session active”.
  4. flows_create and advanced_flows_create should then work.

If it still does not show an active session, generate a bug report and look at the flow_api_info patError field, it will contain the real error from the token session so we can pin down whether it is the address, the token scope, or something else. Thanks for the thorough testing.

v2.1.7

  • Flow create and edit require a Personal Access Token with the Flow scope. The app’s own API can only read flows, not write them (which caused “Missing Scopes”), and no app permission grants flow-write access.
  • The token session now uses the same local address the app API uses, so it initializes correctly on Homey Pro 2026 firmware.
  • If no token is set, you now get a clear message explaining what to do instead of a cryptic “Missing Scopes” error. The Bug report tab shows whether the token session is active.

I’ve updated the app, but there is no such information in the bug report tab visible

@Luke_Vredeveld
Thanks again for reporting this and for sticking with it. Here is a summary of everything that changed since 2.1.7, ending in the real fix.

  • 2.1.8 The Bug report now clearly states whether flow writing is enabled (active token session, the real error, or no token set) instead of a misleading label.
  • 2.1.9 The Status tab also lists recent connections, since most AI clients connect with stateless requests that hold no live session.
  • 2.2.0 to 2.2.3 First round of fixes for saving the Personal Access Token: route the save through a reliable path, rebuild and verify the flow session the moment you save (no restart), validate the token (a session is created even for a wrong token, so I added a real check), and version the settings scripts so an update always loads the fresh page instead of a cached one.
  • 2.2.4 (the actual root cause) On the Homey web app (my.homey.app) the settings page runs in a sandboxed frame, and the current web SDK there no longer exposes the methods the page was using. The fallback network request was blocked by the browser (CORS, null origin with credentials). That is why saving the token and loading the tabs silently failed in the browser, while the mobile app kept working. The page now talks to the app over the channel the web SDK does support, so saving and all tabs work in the browser again.
  • 2.2.5 Reliable feedback: once the token is stored you get an immediate confirmation, and a slow flow check can no longer flip a successful save back into a false “saving failed”. It still shows flow writing active, or the exact error if the token was rejected.
  • 2.2.6 The Connection tab now shows a masked preview of the saved token, so you can see which one is active.

What to do: update to 2.2.6. If your settings page was already open, do a hard refresh (Ctrl+Shift+R) so it loads the new version. Then on the Connection tab paste a Personal Access Token created at my.homey.app, Settings, API, with the Flow scope, and save. The page will confirm whether flow writing is active. Reading flows and everything else works without a token; only flow create/edit needs that Flow-scoped token.

Hi there, still checking out the server-app, awesome development!

I can conform the write acces works. But now, the AI can only create empty advanced flows. Once again, I asked Gemini CLI to make me a bug report.

 Bug Report: advanced_flows_create silently drops nodes/edges (while flows_create works perfectly)

  Environment:
   * Device: Homey Pro (2026)
   * Firmware: v13.2.1
   * App: MCP AI Bridge (latest version, PAT session active & working)

  The Issue:
  Following the latest updates, write permissions via the PAT session are successfully established. Standard flows (flows_create) are now created flawlessly, including all nested triggers, conditions,
  and actions. 
  However, when using advanced_flows_create, the bridge successfully creates the flow object (it appears in the Homey app with the correct name and ID), but the flow canvas is completely empty. Homey
  silently drops or rejects the entire nodes and edges payload provided in the API call.

  Steps Taken & Observations:
   1. Basic Flows (Success): Called flows_create with a cron trigger and a HomeyScript action. Result: Flow created perfectly with all cards intact.
   2. Advanced Flows (Failure): Called advanced_flows_create with a minimal payload (1 trigger node, 1 action node, 1 edge).
       * The MCP tool returns {"success": true, "flow_id": "..."}.
       * Upon fetching the created flow via advanced_flows_get, the cards object is completely empty: { ..., "cards": {} }.
   3. Formatting Attempts: Tried alternative formatting strategies for the nodes (using strict UUIDs for node IDs, verifying ownerUri and cardId mapping), but all resulted in the same silent dropping of
      cards by the Homey validation engine.

  Conclusion & Request:
  The bridge's connection and token authorization are now rock solid. The issue lies entirely in the schema translation/validation for the advanced_flows_create payload. It appears the Homey Pro 2026
  firmware requires a highly specific internal formatting or nesting structure for Advanced Flow nodes/edges that differs from how the bridge currently serializes them. 

  Could you investigate the exact payload structure expected by the homey.advancedflow endpoint on firmware v13.2+?

@Luke_Vredeveld

Fixed in v2.2.7. Thanks for the excellent bug report, your diagnosis was spot on.

You were exactly right: the bridge was passing the nodes/edges payload straight through, but Homey’s advancedflow endpoint does not use nodes/edges. It stores an advanced flow as a cards map (the same structure advanced_flows_get returns), where each card carries its ownerUri, id, type, args, and its connections as output arrays on the source card. Because the payload had no cards, Homey accepted the flow but dropped the whole graph, hence the empty canvas.

What changed in 2.2.7:

  • advanced_flows_create and advanced_flows_update now translate the node graph into Homey’s card structure: ownerUri is derived from the full card id, ports map to the right outputs (output to outputSuccess, true/false to outputTrue/outputFalse, error to outputError), any/all join nodes get their input arrays, and delay nodes keep their delay args.
  • You can also pass a native cards object (exactly what advanced_flows_get returns) for a clean round-trip: get an example, tweak it, write it back.
  • A start node type is now supported, so the AI can build advanced flows that are manually triggerable.
  • Bonus, found while testing: triggering a flow (basic or advanced) used to fail with “Missing Scopes” because it went through the app’s own API token. It now uses the token session, like the writes. Same fix applied to reading/deleting notifications and restarting apps.

Tips for building one with the AI:

  • For trigger/condition/action nodes, set uri to the FULL flowcard id, for example homey:manager:notifications:create_notification or homey:device:<deviceId>:onoff_true. The bridge derives ownerUri.
  • Edges: sourcePort is output for triggers/actions, or true/false for conditions.
  • Add a start node (no uri) if you want to trigger the flow on demand.

Verified end to end on a Homey Pro: the AI created an advanced flow (start node to a notification action), it triggered, and the notification showed up. Let me know how it works on your side.

Can confirm it can write advanced flows now! Great job done :ok_hand:

@Luke_Vredeveld
Just to show I haven’t been sitting still, here’s what landed in v2.2.8:

  • Privileged actions now fall back to the token session when the app’s own permissions come up short, so writes no longer fail with a scopes error. This covers devices, zones, variables, notifications, presence, alarms, apps and system settings.
  • Setting a capability now auto-corrects a wrong value type (for example the text true for an on/off switch) and retries, so those calls don’t fail anymore.
  • New tool devices_get_flowcards returns the trigger, condition and action cards for a single device.
  • New tool advanced_flows_validate dry-runs a flow graph and catches mistakes before the flow gets created.
  • Flow-card lists now report when results were truncated, with limit/offset paging.
  • The Connect tab automatically adds the Authorization header to the generated config when you’ve set an API key.
  • New Commands tab with example questions you can ask your AI.
  • Security: unknown discovery probes get a 404 instead of cluttering the security log, and API keys are now compared in constant time.

This response was brought to you by Gemini :smile:

Hi @weide43,

Thanks again for this awesome app!

Since Google has recently replaced gemini-cli with antigravity-cli ( antigravity / agy ), there are a few changes regarding the MCP server configuration that might be useful to update in the startup post for other Gemini users:

### 1. New Config File Location

The configuration file has moved.

Old (gemini-cli): ~/.gemini/settings.json

New (antigravity-cli): ~/.gemini/antigravity-cli/mcp_config.json

### 2. Config Key Change ( serverUrl vs httpUrl )

antigravity uses the key “serverUrl” (or “url” ) for HTTP/SSE connections instead of “httpUrl” . If you use

httpUrl , the server won’t be discovered.

### Updated Config Example for ~/.gemini/antigravity-cli/mcp_config.json :

{                                                                                                                

  "mcpServers": {                                                                                                

    "homey": {                                                                                                   

      "serverUrl": "http://<homey-ip>:52199/mcp"                                                                 

    }                                                                                                            

  }                                                                                                              

}                                                                                                                

Or with an API key/token:

{                                                                                                                

  "mcpServers": {                                                                                                

    "homey": {                                                                                                   

      "serverUrl": "http://<homey-ip>:52199/mcp",                                                                

      "headers": {                                                                                               

        "Authorization": "Bearer YOUR_API_KEY"                                                                   

      }                                                                                                          

    }                                                                                                            

  }                                                                                                              

}                                                                                                                

Once updated, restarting the CLI and running /mcp will reload the server and show the Homey tools successfully.

Hope this helps other users transitioning to the new CLI!

How to Build an Autonomous Homey Pro Telegram AI Bot on a Synology NAS

Here’s how I built a personal, autonomous Telegram Bot powered by Google’s Gemini AI, connected to my Homey Pro with MCP-server, and hosted entirely on my Synology NAS via Docker.

The Architecture

  • Homey Pro: Runs the community app MCP AI Bridge, which exposes an unauthenticated local API on port 52199 for fetching device states and setting capabilities.
  • Google Gemini (2.5 Flash): Acts as the brain. It natively understands text and voice (multimodal) and has a massive context window to ingest the entire state of the house.
  • Synology NAS: Runs the Node.js script via Docker (Container Manager) 24/7 without needing a laptop.
  • Telegram: The user interface.

Prerequisites

  1. Telegram Bot Token: Request one from @BotFather on Telegram.
  2. Google Gemini API Key: Generate a free key via Google AI Studio.
  3. Homey Pro IP: Find your Homey’s local IP (e.g., 192.168.1.xxx).

The 3 Files You Need

Create a folder on your computer (e.g., homey-telegram-bot). You only need three simple files in this folder.

1. docker-compose.yml

Lesson Learned: Synology’s Container Manager strongly prefers standard docker-compose.yml files over raw Dockerfiles. By using the official Node image and mounting our local directory, we avoid the need to build an image entirely.

version: '3'
services:
  homey-telegram-bot:
    image: node:20-alpine
    container_name: homey-telegram-bot
    restart: unless-stopped
    working_dir: /app
    volumes:
      - .:/app
    command: sh -c "npm install && npm start"

2. package.json

Lesson Learned: Always use "latest" for the @google/generative-ai SDK. Older versions (like 0.2.x) lack support for modern features like responseMimeType, which causes crash loops in the bot.

{
  "name": "homey-telegram-bot",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "@google/generative-ai": "latest",
    "telegraf": "latest"
  }
}

3. index.js (The Bot Logic)

Lessons Learned:

  • Markdown Stripping: Even when instructed to return raw JSON, Gemini sometimes wraps its output in Markdown blocks (json ... ), especially when processing voice input. Always strip markdown backticks before JSON.parse().
  • Speaker Playback: Models instinctively try to toggle speakers using the onoff capability. You must explicitly prompt it to use speaker_playing.
  • Volume Scaling: If you ask for “volume 2”, the AI often calculates 2 / 10 = 0.20 (20%). Since Homey uses a strict 0.0 to 1.0 scale, explicitly instruct the model to treat user numbers as percentages out of 100.
const { Telegraf } = require('telegraf');
const { GoogleGenerativeAI } = require('@google/generative-ai');

const TELEGRAM_TOKEN = 'YOUR_TELEGRAM_BOT_TOKEN_HERE';
const GEMINI_API_KEY = 'YOUR_GEMINI_API_KEY_HERE';
const HOMEY_IP = '192.168.1.XXX'; // e.g. 192.168.1.27

const bot = new Telegraf(TELEGRAM_TOKEN);
const genAI = new GoogleGenerativeAI(GEMINI_API_KEY);

const model = genAI.getGenerativeModel({
  model: 'gemini-2.5-flash',
  systemInstruction: `You are a virtual smarthome assistant.
When you receive a message (text or voice), decide if you need to control devices.
ALWAYS respond strictly with a JSON object. DO NOT return markdown.
Format:
{
  "response_text": "The answer to the user in Telegram (informal and helpful)",
  "actions": [
    {
      "url": "http://${HOMEY_IP}:52199/tools/devices_set_capability",
      "body": { "device_id": "ID", "capability": "CAPABILITY", "value": "VALUE (boolean, string, or number)" }
    }
  ]
}
Important rules:
- For volume_set, the scale is ALWAYS 0.0 to 1.0. If the user says a number (e.g., 2 or 20), divide it by 100 ("volume 2" = 0.02).
- For lights/plugs, use the capability "onoff" with true/false.
- For Sonos/Speakers to play/pause, use the capability "speaker_playing" with true/false.
- If no action is needed, leave the "actions" array empty: [].`
});

let deviceListCache = "";

// Pull live state of all devices on boot
async function updateDeviceList() {
    try {
        const res = await fetch(`http://${HOMEY_IP}:52199/tools/devices_get_all_states`, {
            method: "POST", headers: {"Content-Type": "application/json"}, body: "{}"
        });
        const data = await res.json();
        const resultObj = JSON.parse(data.result);
        
        let devicesFlat = [];
        for (const zone in resultObj) {
            devicesFlat.push(...resultObj[zone]);
        }
        
        deviceListCache = devicesFlat.map(d => {
            let caps = [];
            if (d.state) {
                for (const cap in d.state) {
                    caps.push(`${cap}: ${d.state[cap].value}`);
                }
            }
            return `Name: ${d.name}, ID: ${d.id}, Status: [${caps.join(", ")}]`;
        }).join("\n");
        console.log("Device list (with live states) loaded!");
    } catch(e) {
        console.error("Failed to load devices:", e.message);
    }
}

updateDeviceList();

// Listen to text and voice notes
bot.on(['text', 'voice'], async (ctx) => {
    try {
        await ctx.sendChatAction('typing');
        const parts = [];
        
        if (ctx.message.voice) {
            console.log("[Voice message received]");
            const fileLink = await ctx.telegram.getFileLink(ctx.message.voice.file_id);
            const audioResponse = await fetch(fileLink.href);
            const arrayBuffer = await audioResponse.arrayBuffer();
            const base64Audio = Buffer.from(arrayBuffer).toString('base64');
            
            parts.push({
                inlineData: {
                    mimeType: ctx.message.voice.mime_type || 'audio/ogg',
                    data: base64Audio
                }
            });
            parts.push({ text: `Device list:\n${deviceListCache}\n\nThe user sent this voice note. What are they asking? Output JSON:` });
        } 
        else if (ctx.message.text) {
            console.log(`Received text: "${ctx.message.text}"`);
            parts.push({ text: `Device list:\n${deviceListCache}\n\nThe user says: "${ctx.message.text}"\nOutput JSON:` });
        } else {
            return;
        }

        const result = await model.generateContent({
            contents: [{ role: 'user', parts: parts }]
        });
        
        // Strip markdown backticks to prevent JSON.parse crashes
        let rawText = result.response.text();
        rawText = rawText.replace(/```json/gi, '').replace(/```/g, '').trim();
        const responseJson = JSON.parse(rawText);
        
        // Execute Homey commands
        if (responseJson.actions && responseJson.actions.length > 0) {
            for (const action of responseJson.actions) {
                console.log("Executing Homey action:", action.body);
                await fetch(action.url, {
                    method: "POST",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify(action.body)
                });
            }
        }

        await ctx.reply(responseJson.response_text);

    } catch (error) {
        console.error("Error:", error);
        await ctx.reply("Sorry, something went wrong internally!");
    }
});

bot.launch().then(() => console.log('Telegram Bot running!'));
process.once('SIGINT', () => bot.stop('SIGINT'));
process.once('SIGTERM', () => bot.stop('SIGTERM'));

Deployment on Synology

Important Lesson: Do not use the “Import” button under the “Images” tab for text files. Synology expects a compressed .tar file there, not a script.

You have two options depending on your Synology version:

Option A: Using Container Manager (DSM 7.2+)

  1. Copy the folder containing these three files to your Synology NAS (e.g., into your /docker shared folder).
  2. Open Container Manager.
  3. Go to ProjectsCreate.
  4. Name it homey-bot, set the Path to your copied folder, and follow the wizard. It will automatically read the docker-compose.yml.

Option B: Using the older Docker GUI (DSM 6 / 7.1)
If you don’t have “Projects” or the YAML file throws an invalid format error:

  1. Delete the docker-compose.yml (you only need index.js and package.json).
  2. Go to Registry, search for node, and download the 20-alpine or latest tag.
  3. Go to Images, select the Node image, and click Launch/Run.
  4. Volume Settings: Mount your NAS folder /docker/homey-telegram-bot to the path /app inside the container.
  5. Environment/Command: In the Execution Command field, type: sh -c "cd /app && npm install && npm start".
  6. Start the container.

Enjoy your entirely local, highly autonomous AI smarthome butler!

Which do you actually prefer, Gemini Claude ChatGPT? Which works better, or is there not much difference in practice?

@weide43 Io now see me Gemini Clio at connections but if I ask something via Gemini nothing happens what am I doing wrong

Can you ask telegram for making flows or whatever

no, with the telegram bot you cannot make flows. It can tell you the status of your devices and change them.

Did you install antigravity instead of gemini-cli? See my post