@chrischall/iaqualink-mcp

中文文档
0.3.1发布于 2026/11/04MITES Module构建来源已验证近 30 天下载 1730

iAqualink (Zodiac/Fluidra) pool equipment MCP server for Claude — status plus confirm-gated pump, heater, light, aux and set-point control. Developed and maintained by AI (Claude Code).

原始使用文档
文档目录5 节
  1. Tools
  2. Setup
  3. Hosted (claude.ai)
  4. Skills
  5. Development

iaqualink-mcp

MCP server for iAqualink (Zodiac / Jandy / Fluidra) pool and spa equipment. Read temperatures, set points, pumps, heaters, lights, aux circuits and salt chlorinator state, and switch equipment — every change confirmation-gated and verified by a re-read. It signs in with your own iAqualink account (the same email and password as the iAqualink app); no browser, extension or bridge.

Supports the two system types the reference client supports: iAqua (Jandy iAquaLink panels) and eXO (Zodiac salt chlorinators). Other device types on the account (robotic cleaners, …) are listed but not controlled.

Status: partly verified live. Request shapes come from iaqualink-py 0.7.0 (what Home Assistant uses) and a WebTouch capture (see docs/IAQUALINK-API.md).

  • Seen working on a real iAqua (RS) panel, 2026-10-11/12: sign-in, the system list (devices.json), the iAqua status reads (get_home, get_devices) and WebTouch (location lookup, init, button presses and the display stream).
  • Still derived, not yet exercised live: the iAqua set_* commands (pump, heater, aux, light, temperature), every eXO request (shadow read and writes), iaqualink_set_chlorinator's inferred shape, and the iQ20 schedule fallback. Every write still re-reads to confirm what happened.

This project was developed and is maintained by AI (Claude Code). Use at your own discretion.

Tools

ToolWhat it doesAnnotation
iaqualink_list_systemsSystems on the account and their serialsread
iaqualink_get_statusTemperatures, set points, pumps, heaters, aux/lights, chlorinator, salinity/pH/ORP (view: compact · full · raw)read
iaqualink_healthcheckWhether a sign-in is configured and acceptedread
iaqualink_set_equipmentPool/spa pump, pool/spa/solar heater; eXO filter pump, production, boost, low, heating — on/offwrite, not destructive
iaqualink_set_auxAux circuit or light on/off (by number, aux_<n> or label)write, not destructive
iaqualink_set_lightDimmable brightness (0/25/50/75/100) or color effect (iAqua)write, not destructive
iaqualink_set_temperaturePool and/or spa set point (iAqua °F/°C; eXO °C pool)write, not destructive
iaqualink_set_chlorinatoreXO chlorinator output % — inferred shape, not in iaqualink-pywrite, not destructive
iaqualink_list_schedulesRS panel programs via WebTouch (iAqua; iQ20 fallback probe); eXO timersread
iaqualink_add_scheduleAdd an RS panel program (circuit, start, stop, run days) via WebTouchwrite, not destructive
iaqualink_edit_scheduleChange an RS panel program's start / stop / run days via WebTouchwrite, not destructive
iaqualink_delete_scheduleDelete an RS panel program via WebTouch — no undowrite, destructive
iaqualink_set_scheduleSet / re-time / disable an eXO timer (start–stop, rpm on variable-speed pumps) — eXO only, unverified livewrite, not destructive
iaqualink_check_panelIs an RS system online, and what is its panel showing (screen, open dialog, Edit mode with unsaved changes)? Run it when the app and these tools disagreeread
iaqualink_list_pump_speedsRS panel variable-speed pump: the named speeds, their RPM and which one runs, via WebTouchread
iaqualink_set_pump_speedRun the pump at a named speed via WebTouchwrite, not destructive
iaqualink_set_pump_speed_rpmChange a named speed's RPM (600–3450) via WebTouch; a speed that is not running runs briefly while set, then the running speed is restoredwrite, not destructive
iaqualink_list_onetouchRS panel OneTouch scenes (Spa Mode, All OFF, …) and their state, via WebTouchread
iaqualink_set_onetouchTurn a OneTouch scene on/off via WebTouch — toggle not exercised live yetwrite, not destructive

Systems by name. At start the server lists the account's systems once; when that works, every serial argument advertises the supported systems' names (e.g. "Pool", "Spa") as an enum, and every tool accepts a name or a serial — an unknown name is refused with the list of known systems. If the listing fails (no sign-in yet, iAqualink down, past 5 s), the argument is a plain serial and nothing else changes. Every tool also carries _meta.mint hints (domain home; lookup for reads, turn-on-off for the set_* switches, change for schedule edits) that mcp-host's context groups read and other clients ignore.

Every write has an inverse in this set and reaches no other person — except deleting a panel program, which the panel stores immediately with no undo, so that one is marked destructive.

Schedules and OneTouch on a Jandy AquaLink RS panel go through WebTouch, the panel emulation the iAqualink web app uses: the server opens the panel's display stream, presses the same buttons a person would (checking before every press that the panel is on the expected screen and row, and aborting otherwise), returns to Home, and re-reads to verify. Only one WebTouch session per system runs at a time. The add / edit / delete sequences follow a live capture on an RS panel (2026-10-11) — see docs/IAQUALINK-API.md. If WebTouch is unavailable, iaqualink_list_schedules falls back to iQ20 schedules (adapter firmware 3+), probing r-api.iaqualink.net/v2 (Bearer), p-api.iaqualink.net/v2 (Bearer), p-api.iaqualink.net/v2 (bare token) and prm.iaqualink.net/v1 (bare token) once each and reporting every attempt. iQ20 schedule writes are not built.

How a write works. It reads the current state first and sends nothing if it already matches — iAqua's pump/heater/aux commands are toggles, so a blind send would flip whatever the state happened to be. It then asks you to confirm (an elicitation prompt where the client supports one; otherwise a preview plus a confirmToken, bound to the state it was planned against), sends, and re-reads until the requested value shows up. The result is confirmed, unchanged, or sent-unconfirmed with what was observed (eXO applies changes asynchronously — check again rather than retrying).

Setup

npm i -g @chrischall/iaqualink-mcp
VariableRequiredMeaning
IAQUALINK_EMAILfor every toolYour iAqualink app sign-in email
IAQUALINK_PASSWORDfor every toolYour iAqualink password (not trimmed)
IAQUALINK_STATUS_CACHE_SECONDSnoSeconds a status read is reused (default 5; 0 disables)
IAQUALINK_WEBTOUCH_STREAM_HOSTSnoExtra hosts (comma-separated) the WebTouch display stream may come from; default only prm.iaqualink.net
IAQUALINK_VERIFY_TIMEOUT_MSnoMilliseconds a write re-reads to confirm the change before reporting sent-unconfirmed, for iAqua and eXO alike (positive integer; default 15000 iAqua, 30000 eXO)
MCP_CONFIRM_MODEnoask-user (default) / auto / refuse
MCP_CONFIRM_TTL_SECONDSnoconfirmToken lifetime (default 600)
MCP_CONFIRM_ELICITATIONnooff skips the prompt even on clients that declare elicitation

The server starts without credentials (so hosts can list its tools) and reports them missing on the first call. A rejected password is never retried: the refusal is remembered until the server restarts, so a typo cannot lock the account.

Claude Code: claude mcp add iaqualink -e IAQUALINK_EMAIL=… -e IAQUALINK_PASSWORD=… -- npx -y @chrischall/iaqualink-mcp

Hosted (claude.ai)

mint.yaml declares per-user children with an email/password form on the connector's authorize page (each person signs in as themselves), egress to exactly prod.zodiac-io.com, r-api.iaqualink.net, p-api.iaqualink.net (iQ20 probe only) and prm.iaqualink.net (WebTouch, and the iQ20 probe); the WebTouch display stream is refused on any other host unless it is added to IAQUALINK_WEBTOUCH_STREAM_HOSTS (and egress). No persistent state — the session lives in memory and one sign-in rebuilds it after a cold start.

Skills

  • skills/iaqualink — how to use these tools.
  • skills/iaqualink-curl — the same reads straight from a shell with curl, credentials from the macOS Keychain (the sign-in, system list and iAqua reads are seen live; the eXO shadow read is still derived from iaqualink-py).

Development

npm install
npm run build
npm run test:coverage   # typecheck (src + tests) + vitest, 100% coverage — what CI runs

Tests run the real client against an in-memory iAqualink (tests/support/fake-server.ts) built from iaqualink-py's fixtures.

版本与发布记录

@chrischall/iaqualink-mcp 共发布 8 个版本,首次发布于 2026/10/12;过去 12 个月发布了 8 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.3.1latest2026/11/045 天前
0.3.02026/11/045 天前
0.2.22026/10/1823 天前
0.2.12026/10/1624 天前
0.2.02026/10/1228 天前
0.1.02026/10/1228 天前

关于 @chrischall/iaqualink-mcp 的常见问题

@chrischall/iaqualink-mcp 是什么?

iAqualink (Zodiac/Fluidra) pool equipment MCP server for Claude — status plus confirm-gated pump, heater, light, aux and set-point control. Developed and maintained by AI (Claude Code).

如何安装 @chrischall/iaqualink-mcp?

在项目目录运行 npm install @chrischall/iaqualink-mcp,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 iaqualink-mcp,可以用 npx iaqualink-mcp 直接运行。

@chrischall/iaqualink-mcp 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/chrischall__iaqualink-mcp 是否存在。

@chrischall/iaqualink-mcp 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@chrischall/iaqualink-mcp 可以商用吗?

@chrischall/iaqualink-mcp 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@chrischall/iaqualink-mcp 的下载量有多少?

根据 npm 官方下载统计,@chrischall/iaqualink-mcp 在 2026/10/10 – 2026/11/08 这 30 天内被下载 1,730 次,日均约 58 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@chrischall/iaqualink-mcp 还在维护吗?

最新版本 0.3.1 发布于 2026/11/04(5 天前);至今共发布 8 个版本,其中过去 12 个月发布了 8 个;首次发布于 2026/10/12。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。