MCP Server  

Developer: VTMikel's Plugins     Like this plugin? Show your appreciation!
Category: Hubs and Protocol Bridges
Github: Github Repo
Assistance: Get help!   
Plugin ID: com.vtmikel.mcp_server
Latest release: v2026.6.0 released on July 3, 2026
Release downloaded: 4 times
Requires: Indigo v2024.2.0 or higher
(Check the Releases tab below for older releases that may have different requirements)
  Download release v2026.3.0

Indigo MCP Server Plugin

A Model Context Protocol (MCP) server plugin that lets AI assistants like Claude search, understand, and control your Indigo home automation system through natural language.

  • "Find all light switches in the bedroom"
  • "What devices are currently on?"
  • "Turn on the garage lights" / "Execute the bedtime scene"
  • "What trigger turned off the porch light last night?"

Requirements

  • Indigo Domotics 2025.2 or later (ships Python 3.13)
  • macOS 10.15 (Catalina) or later
  • Apple Silicon (M-series) only — LanceDB 0.30+ no longer ships Intel Mac wheels
  • OpenAI API key for semantic search (get one). Only device names, types, and descriptions are sent, to generate embeddings (minimal cost) — see Privacy & Security.
  • Node.js (for Claude Desktop only, which connects via npx mcp-remote): brew install node

Installation

  1. Install the MCP Server plugin in Indigo via the Plugin Manager.
  2. Enter your OpenAI API key in the plugin's preferences.
  3. Add a new MCP Server device in Indigo (this creates the actual server; one per install).
  4. Wait for the plugin to index your database — the first run takes a while.
  5. Connect an MCP client — see below.

Optional integrations, all off by default:

  • InfluxDB — required for the analyze_historical_data tool.
  • Event Webhooks — real-time outbound push notifications; requires a server you run, not stock Claude Desktop. See Event Subscriptions & Webhooks. (v2026.1.0)
  • LangSmith — AI prompt tracing for debugging; most people don't need it.

Connecting an MCP Client

1. Get an API key

Every connection authenticates with an Indigo API key sent as Authorization: Bearer <key>. Two kinds:

  • Reflector API key — from your Indigo Reflector settings. Use for remote/HTTPS access.
  • Local secret — for local/LAN access. Add one to /Library/Application Support/Perceptive Automation/Indigo <VERSION>/Preferences/secrets.json (format), then restart the Indigo Web Server.

2. Pick your endpoint URL

The endpoint path is always /message/com.vtmikel.mcp_server/mcp/. Choose the base by where you connect from (default Web Server port is 8176):

Access Endpoint URL Key
Same machine as Indigo http://localhost:8176/message/com.vtmikel.mcp_server/mcp/ Local secret
Another machine on your LAN http://<indigo-ip>:8176/message/com.vtmikel.mcp_server/mcp/ Local secret
Remote (outside your network) https://<your-reflector>.indigodomo.net/message/com.vtmikel.mcp_server/mcp/ Reflector key

For HTTPS on the LAN with a self-signed certificate, use the https://<indigo-host>:8176/... URL and see the self-signed note in the client examples below.

3. Configure your client

VS Code, Cursor, Claude Code support direct HTTP transport — simpler and more reliable. Add to your MCP settings (.vscode/mcp.json, Cursor MCP settings, or ~/.claude.json / project .mcp.json):

{
  "mcpServers": {
    "indigo": {
      "type": "http",
      "url": "http://localhost:8176/message/com.vtmikel.mcp_server/mcp/",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    }
  }
}

Swap the url for the LAN or Reflector variant from the table above.

Claude Desktop does not support direct HTTP, so it proxies through mcp-remote. Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "indigo": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "https://your-reflector.indigodomo.net/message/com.vtmikel.mcp_server/mcp/",
        "--header", "Authorization:Bearer YOUR_API_KEY"
      ]
    }
  }
}
  • Plain HTTP (local/LAN): add "--allow-http" to args.
  • Self-signed HTTPS (LAN): add "env": { "NODE_TLS_REJECT_UNAUTHORIZED": "0" } to the server block.

Why the difference? mcp-remote requests OAuth endpoints that Indigo doesn't implement; direct HTTP transport avoids that entirely, so prefer it whenever your client supports it.

HTTP transport notes

The endpoint uses the MCP streamable-HTTP transport over the Indigo Web Server: POST carries all messages, GET returns 405 (no server→client SSE stream), and sessions expire after 2 hours idle (current Indigo Web Server versions reject the DELETE teardown before it reaches the plugin).

Available Tools

Most list and search tools paginate with limit (default 50, max 500) and offset, and return total_count / has_more for navigation.

Search and query

  • search_entities — natural-language search across devices, variables, action groups, triggers, and schedules
  • list_devices — all devices, with optional state filtering
  • list_variables / list_variable_folders — variables (with values) and their folders
  • list_action_groups — action groups / scenes
  • get_devices_by_state — devices matching state conditions
  • get_devices_by_type — devices of a type (dimmer, relay, sensor, …)
  • get_device_by_id / get_variable_by_id / get_action_group_by_id — exact lookups

Automation introspection (v2026.6.0)

Inspect triggers, schedules, and action groups in full — including the action steps and condition trees that Indigo's scripting API does not expose (read from the server's database file, refreshed within minutes of a change).

  • list_triggers — triggers with a one-line summary of what each watches; filter by name/type/enabled/folder
  • list_schedules — schedules with next execution time and a timing summary
  • get_trigger_details / get_schedule_details / get_action_group_details — the full explanation of one automation: its event/timing, condition tree, and every action step (device commands, variable writes, nested action groups, embedded Python, plugin actions with config), IDs resolved to names
  • find_automation_references — reverse lookup: which automations watch, act on, set, or condition-read a device/variable/action group — including indirect paths through nested action groups, cross-checked against Indigo's own dependency graph

Investigation (v2026.6.0)

  • investigate_event — "what caused this?" Finds a device's state-change in the log, collects the automations that fired around it, and ranks candidate causes by structural evidence (does it actually act on that device, directly or through action-group chains?) plus temporal proximity.
  • query_event_log — read the event log, newest first. With no filters it returns the recent tail from Indigo's live log; add query/regex/types/start_time/end_time to scan the full historical daily log files instead. Each entry is {timestamp, type, message}.

Automation control (v2026.6.0)

  • control_trigger / control_schedule / control_action_group — lifecycle actions: enable/disable (with a duration_seconds auto-revert — "disable this trigger for 2 hours"), execute, duplicate, move_to_folder, remove_delayed_actions, and delete. (Action groups support execute/duplicate/move/delete only.) Delete requires confirm=true and the Allow AI to delete automations preference (off by default); every other action is always available.
  • update_trigger — edit a trigger's name/description and its event settings (watched device/variable, comparison, value), returning a before/after diff.
  • update_schedule / update_action_group — edit name/description only.

Action steps, conditions, and schedule timing are read-only in Indigo's scripting API — change those in the Indigo UI. Since there's no API to author actions from scratch, duplicate (via control_trigger) followed by update_trigger is the supported way to make a trigger variant.

Device control

  • device_turn_on / device_turn_off — power state
  • device_set_brightness — dimmer level (0–100 or 0–1)
  • device_set_rgb_color / device_set_rgb_percent / device_set_hex_color / device_set_named_color (954 XKCD colors + aliases) / device_set_white_levels — RGB / RGBW control
  • thermostat_set_heat_setpoint / thermostat_set_cool_setpoint / thermostat_set_hvac_mode / thermostat_set_fan_mode — thermostat control

Variables, actions, and system

  • variable_create / variable_update — create or update variables
  • action_execute_group — run an action group / scene
  • list_plugins / get_plugin_by_id / get_plugin_status / restart_plugin — plugin management
  • analyze_historical_data — AI analysis of device/variable history (requires InfluxDB)

Event subscriptions (v2026.1.0, only when webhooks are enabled)

  • create_event_subscription — POST a JSON event to your webhook URL when device/variable conditions match
  • list_event_subscriptions — active subscriptions with delivery health stats (or one by ID)
  • delete_event_subscription — delete a subscription (cancels pending dwell timers)

See Event Subscriptions & Webhooks for the full guide.

Event Subscriptions & Webhooks

Added in v2026.1.0. Event subscriptions let an MCP client ask Indigo to notify it the next time something happens — "the next time the front door opens", "if the temperature goes above 80°F", "if the garage door stays open for 10 minutes".

⚠️ This is an outbound webhook — you must run your own server

When a subscription's conditions match, the plugin sends an HTTP POST to a URL you provide. It is a sender only — there is no built-in receiver. This will not work with stock Claude Desktop or most off-the-shelf MCP clients, which have no way to receive a proactive notification. It's meant for custom agents / automation systems that own a persistent HTTP endpoint (for example, OpenClaw).

Enable it under Plugins → MCP Server → Configure → Enable Event Webhooks (the three tools are hidden until then).

Creating a subscription

create_event_subscription accepts:

Parameter Type Required Description
webhook_url string yes HTTP(S) endpoint you run that events are POSTed to.
entity_type "device" | "variable" yes What kind of entity to watch.
conditions object yes State conditions that trigger the webhook (see operators below).
entity_id integer no A specific device/variable ID, or omit to watch all entities of that type.
auth object no { "mode": "none"\|"bearer"\|"hmac", "token": "…", "verify_ssl": true } (see Authentication).
duration_seconds integer (≥1) no Dwell time — the condition must stay matched this long before firing. If it reverts first, nothing is sent.
max_fires integer (≥1) no Auto-delete the subscription after this many successful deliveries. Use 1 for a one-shot notification. Omit for unlimited.
description string no Human-readable label for the subscription.

A webhook fires on the transition into a matching state (not repeatedly while it stays matched). Multiple conditions are combined with AND.

# Notify me once, the next time the front door opens
create_event_subscription(
    webhook_url="https://my-server.example.com/indigo-hook",
    entity_type="device", entity_id=12345,
    conditions={"onState": True}, max_fires=1,
    description="Front door opened",
)

# Alert me if the garage door stays open for 10 minutes
create_event_subscription(
    webhook_url="https://my-server.example.com/indigo-hook",
    entity_type="device", entity_id=67890,
    conditions={"onState": True}, duration_seconds=600,
    description="Garage left open",
)

Condition operators

Conditions match against device/variable state keys (including third-party plugin states). Use simple equality, or an operator object per key:

{ "onState": true }                                    // equality
{ "brightness": { "gt": 50 } }                         // single operator
{ "temperatureInput1": { "gt": 80 }, "onState": true } // AND of multiple keys
Operator Meaning
eq / ne equal to / not equal to
gt / gte greater than / greater than or equal
lt / lte less than / less than or equal
contains substring is contained in the value
regex value matches the regular expression

Variables match on their value key. Indigo stores every value as a string, but booleans and numbers in your conditions are coerced automatically, so { "value": true }, { "value": { "eq": "open" } }, and { "value": { "gt": 50 } } all work. To fire on every change regardless of the new value, use { "any_change": true } — variables only, and not combinable with duration_seconds.

Authentication

Set via the auth parameter; your receiver should validate it so only your Indigo server can post to your endpoint.

  • none (default) — no auth headers.
  • bearer — adds Authorization: Bearer <token>.
  • hmac — adds X-Webhook-Signature: sha256=<hexdigest> (HMAC-SHA256(token, raw_body_bytes)) and X-Webhook-Timestamp: <unix-seconds>. Verify on the receiver:

    python import hmac, hashlib expected = "sha256=" + hmac.new(SECRET.encode(), raw_body, hashlib.sha256).hexdigest() ok = hmac.compare_digest(expected, request.headers["X-Webhook-Signature"])

Set "verify_ssl": false only if your receiver uses a self-signed certificate.

The webhook payload

Each delivery is a POST with Content-Type: application/json, the headers X-Event-Id, X-Event-Type (device.state_changed | variable.value_changed), and X-Subscription-Id (plus any auth headers), and a body like:

{
  "event_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
  "schema_version": "1.0",
  "dedupe_key": "indigo:device:12345:state:onState:True",
  "source": { "system": "indigo", "plugin": "com.vtmikel.mcp_server", "host": "my-indigo-mac" },
  "timestamp": "2026-06-01T15:30:45.123456+00:00",
  "event_type": "device.state_changed",
  "entity": { "kind": "device", "id": 12345, "name": "Front Door", "device_type": "…" },
  "state": { "changed_keys": ["onState"], "old": { "onState": false }, "new": { "onState": true } },
  "trigger": { "subscription_id": "…", "conditions_matched": { "onState": true } },
  "human": { "title": "Front Door state changed", "summary": "Front Door: onState=true" }
}

Variable changes use event_type: "variable.value_changed", entity.kind: "variable", and a state of { "changed_keys": ["value"], "old": { "value": "…" }, "new": { "value": "…" } }.

Delivery behavior

  • At-least-once — retries mean an event can arrive more than once; your receiver must deduplicate by event_id (or dedupe_key).
  • Retries — up to 4 attempts (1 + 3 retries), 10s timeout each, exponential backoff (~1s/2s/4s), on 5xx and network errors. A 4xx is a permanent rejection and is not retried. Success is any 2xx — return 200 promptly.
  • Persisted across restarts — subscriptions are saved (0600) to …/Preferences/Plugins/com.vtmikel.mcp_server/subscriptions.json and reloaded on startup, so they survive restarts and upgrades. The file contains your webhook auth tokens (required so authenticated webhooks can re-authenticate). Pending dwell timers are not persisted — a held condition re-arms on its next matching transition.

Managing subscriptions in a browser (v2026.3.0)

When webhooks are enabled, the plugin serves a page that lists active subscriptions and lets you remove them (create/edit stays with the MCP tools; auth tokens are never shown).

Event Subscriptions web UI

  • URL: http://<your-indigo-host>:8176/message/com.vtmikel.mcp_server/events_ui/ — served by the Indigo Web Server under the same authentication as the rest of IWS (open it from a browser logged into Indigo).
  • Plugins → MCP Server → Print Event Subscriptions Web UI URL prints the local/LAN/Reflector URLs to the log.

Minimal example receiver

Any HTTPS endpoint reachable from your Indigo host works. A dependency-free Python receiver to test with:

from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
        # (Optional) verify X-Webhook-Signature here if using HMAC auth.
        event = json.loads(body)
        # Dedupe by event_id — at-least-once delivery means retries can repeat.
        print(f"{event['event_type']} {event['event_id']}: {event['human']['summary']}")
        self.send_response(200)   # any 2xx = success
        self.end_headers()

HTTPServer(("0.0.0.0", 8888), Handler).serve_forever()

Tips for Better Results

  • Be specific — include location and device type in queries.
  • Use device Notes — descriptions in the Notes field are included in the AI's context.
  • State vs. search — use list_devices({"onState": true}) for state queries, search_entities("lights") for discovery.

Privacy & Security

Sent to OpenAI (only to generate search embeddings, stored locally on your Indigo server): device name/description/model/type/address, variable name/description, and action-group name/description — sent on install and when entities are added or changed. Never sent: device states or values, credentials, URLs, IP/network configuration, or historical/usage data.

Network — every MCP connection requires Bearer-token authentication. Local HTTP stays on your LAN; use the Indigo Reflector for encrypted remote access. For self-signed HTTPS on the LAN, set NODE_TLS_REJECT_UNAUTHORIZED=0 (Claude Desktop) as shown above.

Support

Release details
Released on: July 3, 2026
Requires: Indigo v2024.2.0+
Downloaded: 4 times 
Changes in this release

v2026.6.0 — Automation Introspection, Investigation & Control

Major release: triggers, schedules, and action groups are now first-class citizens of the MCP server. Eight new tools close the gap Indigo's scripting API leaves around understanding and managing automations.

Understand your automations

  • list_triggers / list_schedules — every trigger/schedule with a one-line summary; schedules include next execution times
  • get_trigger_details / get_schedule_details / get_action_group_details — full explanation of one automation: the event or timing that fires it, its condition tree, and every action step (device commands, variable writes, nested action groups, embedded Python scripts, plugin actions with configuration). Sourced by merging the live Indigo Object Model with a read-only parse of the server's database file — the only place action steps and conditions exist.
  • find_automation_references — reverse lookup: what watches, acts on, sets, or condition-reads a device/variable/action group, including indirect paths through nested action-group chains, cross-checked against Indigo's own dependency graph
  • search_entities now also finds triggers and schedules semantically

Investigate behavior

  • query_event_log (existing tool, now much more capable) — with no filters it returns the recent tail from Indigo's live event log; add query/regex/types/start_time/end_time and it scans the full historical daily log files instead. One tool, filters optional, consistent {timestamp, type, message} output.
  • investigate_event — "what caused this device change?": locates the change in the log and ranks the automations that fired around it by structural evidence plus temporal proximity, with the evidence spelled out

Control

  • control_trigger / control_schedule / control_action_group — lifecycle: enable/disable (with duration_seconds auto-revert: "disable this trigger for 2 hours"), execute, duplicate, move to folder, remove delayed actions, delete. Deletion requires confirm=true and the Allow AI to delete automations preference (off by default); every other action is always available.
  • update_trigger — edit a trigger's name/description and event settings (watched device/variable, comparison, value), with a before/after diff. update_schedule / update_action_group edit name/description only. Schedule timing, action steps, and conditions are read-only in Indigo's scripting API — duplicate-and-modify is the supported way to make a trigger variant.

Notes

  • Automation tools are per entity type (e.g. control_trigger, get_schedule_details) rather than one tool with an entity_type parameter — clearer, self-documenting names.
  • Only deletion is permission-gated (the Allow AI to delete automations preference, off by default, plus confirm=true). Reading, control, and editing are always available.
  • Field editing was verified on a live server: replaceOnServer() preserves action steps and conditions exactly.
  • Plugin tools now report the real PluginVersion instead of CFBundleVersion.
  • 44 tools total (47 with event webhooks enabled); the vector store now indexes triggers and schedules.
  • query_event_log covers both the recent live tail and filtered historical search behind one interface.
Release details
Released on: June 2, 2026
Requires: Indigo v2024.2.0+
Downloaded: 24 times 
Changes in this release

Event subscriptions get a management web UI, smarter variable matching, an "any change" trigger, and — most importantly — persistence across restarts.

New

  • Event Subscriptions web UI — list every active subscription with full detail (auth tokens are never shown) and remove individual ones from a browser. Served by the Indigo Web Server at /message/com.vtmikel.mcp_server/events_ui/ (behind the same auth as the rest of IWS). A new plugin menu item, Print Event Subscriptions Web UI URL, prints the link.
  • Persistence — subscriptions are now saved to disk and restored on startup, so they survive plugin restarts, Indigo restarts, and upgrades. (Previously they were in-memory only and lost on every restart.)
  • "Any change" subscriptions (variables)conditions={"any_change": true} fires the webhook on every change to a variable's value. Variable-only.

Fixed

  • Variable condition matching — Indigo stores variable values as strings, so {"value": true} never matched (bool ≠ string) and numeric operators like {"value": {"gt": 50}} silently failed. Conditions now coerce booleans and numbers, so these work as expected. The fix is in the shared filter, so it also hardens list_devices / search / get_devices_by_state.

Notes

  • The persisted subscriptions file (…/Preferences/Plugins/com.vtmikel.mcp_server/subscriptions.json) contains your webhook auth tokens — required so authenticated webhooks can re-authenticate after a restart. It is written 0600 inside Indigo's protected app-support directory. Pending dwell timers are not persisted (they re-arm on the next matching transition).
  • Requires Indigo 2025.2+ (Python 3.13), Apple Silicon.

Install

Download MCP Server.indigoPlugin.zip below, unzip, and double-click the .indigoPlugin to install (or update in place).

Release details
Released on: May 1, 2026
Requires: Indigo v2024.2.0+
Downloaded: 32 times 
Changes in this release

Dependency bump to fix Indigo 2025.2 (Python 3.13) startup crash.

Impact: - Now requires Indigo 2025.2 or later (Python 3.13) - Apple Silicon only — Intel Mac (x86) is no longer supported (lancedb 0.27+ dropped x86 wheels)

What changed: - lancedb: 0.25.x → 0.30.2 - pyarrow: 23.0.x → 23.0.x (range widened)

Release details
Released on: March 21, 2026
Requires: Indigo v2024.2.0+
Downloaded: 30 times 
Changes in this release

Bug Fixes

  • Fix LLM keyword cache returning failures instead of cached results — Cache hits during vector store sync were being discarded and misinterpreted as failures, causing misleading "Even small batch of size 1 failed" warnings. Cached keywords are now correctly returned.
  • Support multiple MCP protocol versions (2025-11-25 and 2025-06-18) — Fixes compatibility with MetaMCP and other clients that connect using the older protocol version.
  • Accept wildcard */* Accept header — Fixes internal server error when MCP clients send Accept: */* instead of application/json.
  • Add missing headers to error responses — 406 and 500 error responses were missing the headers key, causing Indigo Web Server to return generic errors instead of proper error details.

Improvements

  • Update default OpenAI models from GPT-5/GPT-5-mini to GPT-5.4/GPT-5.4-mini
  • Add VS Code, Cursor, and Claude Code CLI direct HTTP transport configuration docs

Dependencies

  • Update LangSmith to >=0.7.3,<0.8.0
  • Update PyArrow to v23
Release details
Released on: Jan. 17, 2026
Requires: Indigo v2024.2.0+
Downloaded: 34 times 
Changes in this release

What's Changed

Dependency Cleanup

  • Removed 8 unused packages:
    • langgraph, langgraph-checkpoint, langgraph-prebuilt, langgraph-sdk (never imported)
    • influxdb-client (code uses legacy 1.x influxdb only)
    • pydantic-settings, python-dotenv, dicttoxml

Version Updates

  • openai >=2.15.0 (was >=2.3.0)
  • tiktoken >=0.12.0 (was >=0.11.0)
  • pydantic >=2.12.5 (was >=2.12.2)
  • jinja2 >=3.1.5 (was >=3.1.0)

Stability Constraints Added

  • lancedb <0.27.0 (0.26+ deprecates Intel Mac support)
  • langsmith <0.6.0 (0.6+ requires Python 3.10+)
  • matplotlib <4.0.0

Full Changelog: https://github.com/mlamoure/indigo-mcp-server/compare/v2025.1.5...v2025.1.6

Release details
Released on: Dec. 22, 2025
Requires: Indigo v2024.2.0+
Downloaded: 31 times 
Changes in this release

Bug Fix

Fixes internal server error when MCP clients send Accept: */* header.

Changes

  • Accept */* (wildcard) as valid Accept header in addition to application/json and text/event-stream
  • Add missing "headers" key to 406 response in mcp_handler.py
  • Add missing "headers" key to 500 error response in plugin.py

Root Cause

The missing "headers" key in error responses caused Indigo Web Server to return a generic "internal server error" instead of the proper error response. Clients like mcp-remote send Accept: */* which was incorrectly rejected.

Related to #5 (investigation ongoing)

Release details
Released on: Nov. 6, 2025
Requires: Indigo v2024.2.0+
Downloaded: 33 times 
Changes in this release

Enhancements and Bug Fixes

Fixed

  • Configuration Save Error: Fixed AttributeError when saving plugin configuration (#4)
    • Removed obsolete server restart calls from when MCP ran as separate process
    • MCP server now runs via Indigo Web Server and doesn't require restart on config changes
    • Configuration changes take effect on next MCP request

Technical Details

  • Removed non-existent _restart_mcp_server_from_device() method calls
  • Updated success messages to clarify config behavior
  • Environment variables are updated immediately without server restart

Fixes https://github.com/mlamoure/indigo-mcp-server/issues/4