| 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.3.0 released on June 2, 2026 |
| Release downloaded: | 5 times |
| Requires: | Indigo v2024.2.0 or higher |
| (Check the Releases tab below for older releases that may have different requirements) | |
| Download latest release |
A Model Context Protocol (MCP) server plugin that enables AI assistants like Claude to interact with your Indigo home automation system through natural language queries.
Search, analyze, and control your Indigo devices using natural language:
npx commandbrew install nodenpx --versionclaude_desktop_config.jsonThe MCP Server Indigo device is what creates the actual MCP Server.
⚠️ IMPORTANT: All MCP connections require authentication using an Indigo API key as a Bearer token.
How to obtain API keys:
secrets.json file
with local secrets
- Location: /Library/Application Support/Perceptive Automation/Indigo [VERSION]/Preferences/secrets.json
- See documentation link above for JSON format details
- Note: Restart Indigo Web Server after creating/modifying this fileRequirements:
- Node.js: Required for MCP client connection (Download)
- Provides npx command used by Claude Desktop configuration
- Install via Homebrew: brew install node
- Or download from nodejs.org
For Claude Desktop -- Add one of the following configurations to
~/Library/Application Support/Claude/claude_desktop_config.json based on your use case:
In all cases, you will need an API Key. For this, you have two choices:
secrets.json file (
see documentation)Use when:
{
"mcpServers": {
"indigo": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://your-reflector-url.indigodomo.net/message/com.vtmikel.mcp_server/mcp/",
"--header",
"Authorization:Bearer YOUR_REFLECTOR_API_KEY"
]
}
}
}
Setup:
your-reflector-url.indigodomo.net with your actual Reflector URLYOUR_REFLECTOR_API_KEY with your Reflector API key{
"mcpServers": {
"indigo": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://your-local-hostname-or-ip:8176/message/com.vtmikel.mcp_server/mcp/",
"--header",
"Authorization:Bearer YOUR_LOCAL_SECRET_KEY"
],
"env": {
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
}
}
}
}
Setup:
/Library/Application Support/Perceptive Automation/Indigo [VERSION]/Preferences/secrets.json
- Restart Indigo Web Server after modifyingyour-local-hostname-or-ip with your Indigo server IP/hostnameYOUR_LOCAL_SECRET_KEY with your generated local secretNODE_TLS_REJECT_UNAUTHORIZED=0 disables certificate validation (required for self-signed certs)If you have HTTPS disabled on your Indigo Web Server.
{
"mcpServers": {
"indigo": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://your-local-hostname-or-ip:8176/message/com.vtmikel.mcp_server/mcp/",
"--allow-http",
"--header",
"Authorization:Bearer YOUR_LOCAL_SECRET_KEY"
]
}
}
}
Setup:
/Library/Application Support/Perceptive Automation/Indigo [VERSION]/Preferences/secrets.json
- Restart Indigo Web Server after modifyingYOUR_LOCAL_SECRET_KEY with your generated local secretyour-local-hostname-or-ip with your server IP/hostname for LAN accessNote: For VS Code, Cursor, or Claude Code CLI, see the "VS Code / Cursor / Claude Code Configuration" section below for direct HTTP configuration.
These clients support direct HTTP transport which is simpler and more reliable than the mcp-remote proxy.
Add to your MCP settings file:
- VS Code: .vscode/mcp.json or VS Code settings
- Cursor: Cursor MCP settings
- Claude Code: ~/.claude.json or project .mcp.json
{
"mcpServers": {
"indigo": {
"type": "http",
"url": "http://localhost:8176/message/com.vtmikel.mcp_server/mcp/",
"headers": {
"Authorization": "Bearer YOUR_LOCAL_SECRET_KEY"
}
}
}
}
{
"mcpServers": {
"indigo": {
"type": "http",
"url": "http://YOUR_INDIGO_IP:8176/message/com.vtmikel.mcp_server/mcp/",
"headers": {
"Authorization": "Bearer YOUR_LOCAL_SECRET_KEY"
}
}
}
}
Replace YOUR_INDIGO_IP with your Indigo server's LAN IP address (e.g., 192.168.1.100).
{
"mcpServers": {
"indigo": {
"type": "http",
"url": "https://your-reflector-id.indigodomo.net/message/com.vtmikel.mcp_server/mcp/",
"headers": {
"Authorization": "Bearer YOUR_REFLECTOR_API_KEY"
}
}
}
}
Why direct HTTP? The
mcp-remoteproxy used by Claude Desktop requests OAuth endpoints that Indigo doesn't implement. Direct HTTP transport avoids this issue entirely.
Important: To handle large Indigo installations, list and search tools support pagination:
limit and offset to paginate through resultstotal_count, offset, has_more for navigationExample:
# Get first 50 devices
list_devices(limit=50, offset=0)
# Get next 50 devices
list_devices(limit=50, offset=50)
# Search with pagination
search_entities("bedroom lights", limit=20)
Tools with Pagination: search_entities, list_devices, list_variables, list_action_groups, get_devices_by_state
Available only when Enable Event Webhooks is turned on in plugin preferences, and require you to run your own webhook receiver. Added in v2026.1.0. See Event Subscriptions & Webhooks for the full guide.
Added in v2026.1.0.
Event subscriptions let an MCP client ask Indigo to notify it the next time something happens — "tell me the next time the front door opens", "alert me if the temperature goes above 80°F", "notify me 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. The plugin is a sender only — there is no built-in receiver. You must run your own always-on HTTP server with a reachable endpoint that accepts that POST and does something with it.
This will not work with stock Claude Desktop (or most off-the-shelf MCP clients). Those clients have no way to receive a proactive, server-initiated notification — enabling webhooks and restarting Claude Desktop does nothing visible. Event subscriptions are intended for custom agents / automation systems that own a persistent HTTP endpoint (for example, OpenClaw). If you don't have a server that can receive a POST, this feature is not for you yet.
The feature is disabled by default. In the plugin's preferences (Plugins → MCP Server → Configure),
check Enable Event Webhooks. The three event-subscription tools
(create_event_subscription, list_event_subscriptions, delete_event_subscription) are hidden
from MCP clients until this is turned on.
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). When multiple conditions are given, they are combined with AND — all must match.
# 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",
)
Conditions are matched 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 |
equal to |
ne |
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 |
Watching variables. Match a variable on its value key. Indigo stores every variable value as a
string, but booleans and numbers in your conditions are coerced automatically, so all of these work:
{ "value": true } // matches the string "true"
{ "value": { "eq": "open" } } // exact string match
{ "value": { "gt": 50 } } // numeric comparison against the string value
Any change (variables only). To fire on every change to a variable's value regardless of what it
becomes, use the any_change sentinel. It is only valid for variables (devices update far too
often), and cannot be combined with duration_seconds:
create_event_subscription(
webhook_url="https://my-server.example.com/indigo-hook",
entity_type="variable",
entity_id=88,
conditions={"any_change": True},
description="House mode changed",
)
Set via the auth parameter. The receiver should validate this so that only your Indigo server can
post to your endpoint.
none (default) — no auth headers added.bearer — adds Authorization: Bearer <token> to each POST.hmac — adds an HMAC-SHA256 signature over the raw request body:
X-Webhook-Signature: sha256=<hexdigest>X-Webhook-Timestamp: <unix-seconds>The signature is computed as HMAC-SHA256(token, raw_body_bytes). Verify it 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.
Each delivery is a POST with Content-Type: application/json and these headers:
X-Event-Id: <event id> # same value as the body's event_id
X-Event-Type: <event type> # device.state_changed | variable.value_changed
X-Subscription-Id: <subscription id>
…plus the auth headers above when configured. The JSON body looks like this:
{
"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": "…" } }.
event_id (or dedupe_key).5xx and network/connection
errors. A 4xx response is treated as a permanent rejection and is not retried.2xx response — have your endpoint return 200 promptly.…/Preferences/Plugins/com.vtmikel.mcp_server/subscriptions.json and reloaded on startup, so they
survive plugin/Indigo restarts and upgrades. The file is written 0600 and contains your webhook
auth tokens (it must, so authenticated webhooks can re-authenticate after a restart) — it lives in
Indigo's protected app-support directory. Delivery stats are saved on each change and on shutdown
(best-effort after an unclean crash). Pending dwell timers are not persisted — a held condition
re-arms on its next matching transition.Added in v2026.3.0. When event webhooks are enabled, the plugin serves a small web page that lists every active subscription with full detail and lets you remove individual ones (it does not create or edit — that stays with the MCP tools). API keys / bearer tokens are never shown.

http://<your-indigo-host>:8176/message/com.vtmikel.mcp_server/events_ui/Any HTTPS endpoint reachable from your Indigo host works — a small Flask app, a serverless function, an automation platform's inbound webhook, etc. Here's a dependency-free Python receiver to test with:
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(length)
# (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()
list_devices({"onState": true}) for state queries vs search_entities("lights")When you first install the plugin and when devices are added or modified, the following device information is sent to OpenAI to create semantic search capabilities:
For Devices:
For Variables:
For Action Groups:
What is NOT sent:
This data is used only to generate embeddings (mathematical representations) that enable natural language search. The embeddings are stored locally on your Indigo server.
NODE_TLS_REJECT_UNAUTHORIZED=0 (see Scenario 3 above)| Released on: | June 2, 2026 |
| Requires: | Indigo v2024.2.0+ |
| Downloaded: | 5 times |
| Download this release | |
Event subscriptions get a management web UI, smarter variable matching, an "any change" trigger, and — most importantly — persistence across restarts.
/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.conditions={"any_change": true} fires the webhook on every change to a variable's value. Variable-only.{"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.…/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).Download MCP Server.indigoPlugin.zip below, unzip, and double-click the .indigoPlugin to install (or update in place).
| Released on: | May 1, 2026 |
| Requires: | Indigo v2024.2.0+ |
| Downloaded: | 12 times |
| Download 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)
| Released on: | March 21, 2026 |
| Requires: | Indigo v2024.2.0+ |
| Downloaded: | 9 times |
| Download this release | |
*/* Accept header — Fixes internal server error when MCP clients send Accept: */* instead of application/json.headers key, causing Indigo Web Server to return generic errors instead of proper error details.| Released on: | Jan. 17, 2026 |
| Requires: | Indigo v2024.2.0+ |
| Downloaded: | 9 times |
| Download this release | |
langgraph, langgraph-checkpoint, langgraph-prebuilt, langgraph-sdk (never imported)influxdb-client (code uses legacy 1.x influxdb only)pydantic-settings, python-dotenv, dicttoxmlopenai >=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)lancedb <0.27.0 (0.26+ deprecates Intel Mac support)langsmith <0.6.0 (0.6+ requires Python 3.10+)matplotlib <4.0.0Full Changelog: https://github.com/mlamoure/indigo-mcp-server/compare/v2025.1.5...v2025.1.6
| Released on: | Dec. 22, 2025 |
| Requires: | Indigo v2024.2.0+ |
| Downloaded: | 12 times |
| Download this release | |
Fixes internal server error when MCP clients send Accept: */* header.
*/* (wildcard) as valid Accept header in addition to application/json and text/event-stream"headers" key to 406 response in mcp_handler.py"headers" key to 500 error response in plugin.pyThe 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)
| Released on: | Nov. 6, 2025 |
| Requires: | Indigo v2024.2.0+ |
| Downloaded: | 11 times |
| Download this release | |
_restart_mcp_server_from_device() method callsFixes https://github.com/mlamoure/indigo-mcp-server/issues/4