iaqualink-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@iaqualink-mcp check the pool temperature and set it to 84°F"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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
Tool | What it does | Annotation |
| Systems on the account and their serials | read |
| Temperatures, set points, pumps, heaters, aux/lights, chlorinator, salinity/pH/ORP ( | read |
| Whether a sign-in is configured and accepted | read |
| Pool/spa pump, pool/spa/solar heater; eXO filter pump, production, boost, low, heating — on/off | write, not destructive |
| Aux circuit or light on/off (by number, | write, not destructive |
| Dimmable brightness (0/25/50/75/100) or color effect (iAqua) | write, not destructive |
| Pool and/or spa set point (iAqua °F/°C; eXO °C pool) | write, not destructive |
| eXO chlorinator output % — inferred shape, not in iaqualink-py | write, not destructive |
| RS panel programs via WebTouch (iAqua; iQ20 fallback probe); eXO timers | read |
| Add an RS panel program (circuit, start, stop, run days) via WebTouch | write, not destructive |
| Change an RS panel program's start / stop / run days via WebTouch | write, not destructive |
| Delete an RS panel program via WebTouch — no undo | write, destructive |
| Set / re-time / disable an eXO timer (start–stop, rpm on variable-speed pumps) — eXO only, unverified live | write, not destructive |
| Is 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 disagree | read |
| RS panel variable-speed pump: the named speeds, their RPM and which one runs, via WebTouch | read |
| Run the pump at a named speed via WebTouch | write, not destructive |
| Change a named speed's RPM (600–3450) via WebTouch; a speed that is not running runs briefly while set, then the running speed is restored | write, not destructive |
| RS panel OneTouch scenes (Spa Mode, All OFF, …) and their state, via WebTouch | read |
| Turn a OneTouch scene on/off via WebTouch — toggle not exercised live yet | write, 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).
Related MCP server: iaqualink-mcp
Setup
npm i -g @chrischall/iaqualink-mcpVariable | Required | Meaning |
| for every tool | Your iAqualink app sign-in email |
| for every tool | Your iAqualink password (not trimmed) |
| no | Seconds a status read is reused (default 5; 0 disables) |
| no | Extra hosts (comma-separated) the WebTouch display stream may come from; default only |
| no | Milliseconds a write re-reads to confirm the change before reporting |
| no |
|
| no | confirmToken lifetime (default 600) |
| no |
|
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 withcurl, 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 runsTests run the real client against an in-memory iAqualink
(tests/support/fake-server.ts) built from iaqualink-py's fixtures.
Available Tools
19 toolsiaqualink_add_scheduleA
Add a program to a Jandy AquaLink RS panel’s own schedule (iAqua systems), through iAqualink WebTouch — the panel emulation the iAqualink web app uses. Picks the circuit by its panel label (e.g. "Filter Pump", "Pool Light", "Cleaner"), sets start and stop (24-hour HH:MM; stop may be earlier than start to run overnight) and run days, saves, and re-reads the list to confirm. The preview shows the schedule list before and after. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: days (required), stop (required), start (required), serial (required), +2 more.
iaqualink_check_panelARead-only
Check whether an iAqua (Jandy AquaLink RS) system is reachable and what its panel is showing: the cloud online flag, then — over WebTouch — the current screen, any open dialog, and whether the schedule screen is in Edit mode with unsaved changes. Use it when the app, WebTouch and the other tools disagree, or a schedule/OneTouch tool reports a dialog or a timeout. Sends only the start-up press the WebTouch page sends when it loads (in Edit mode the panel answers it with its "must be saved" dialog); presses nothing else and changes no setting.
Inputs: serial (required).
iaqualink_delete_scheduleADestructive
Delete one program from a Jandy AquaLink RS panel’s schedule (iAqua systems), through WebTouch. The panel stores the deletion immediately, with no undo. Identify the program exactly as iaqualink_list_schedules listed it (page, row, circuit, start, stop, days) — if the panel no longer shows that, nothing is pressed. The preview shows the list before and after; the result re-reads it. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: row (required), days (required), stop (required), start (required), +4 more.
iaqualink_edit_scheduleAIdempotent
Change the start time, stop time and/or run days of one existing program in a Jandy AquaLink RS panel’s schedule (iAqua systems), through WebTouch. Identify the program exactly as iaqualink_list_schedules listed it (page, row, circuit, start, stop, days) — if the panel no longer shows that, nothing is pressed. The circuit itself cannot be changed (delete and add instead). The preview shows the list before and after; the result re-reads it. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: row (required), days (required), stop (required), start (required), +7 more.
iaqualink_get_statusARead-only
Get the current pool/spa status of one iAqualink system: air, pool and spa temperatures, heater set points, pumps, heaters (pool/spa/solar), freeze protection, aux circuits and lights (with names), and — where the system reports them — salt chlorinator output, boost, salinity, pH and ORP. Readings are cached for a few seconds to stay polite to iAqualink.
Inputs: serial (required), view.
iaqualink_healthcheckVerify credentials and upstream reachabilityARead-onlyIdempotent
Resolves the credential the way real tools do, then makes one authenticated request to r-api.iaqualink.net. Reports which source supplied the credential, whether r-api.iaqualink.net accepted it, the round-trip time, and a plain-English hint distinguishing 'no credential' from 'credential rejected' from 'a r-api.iaqualink.net-side problem'. Read-only; never returns the credential itself. Call this when a real tool fails and you want to know which hop broke.
Inputs: no named parameters.
iaqualink_list_onetouchARead-only
List a Jandy AquaLink RS panel’s OneTouch scenes — the panel-defined one-button macros such as "Spa Mode", "All OFF" or "Clean Mode" — with each scene’s number, label and whether it is on, read through iAqualink WebTouch (the panel emulation). Use iaqualink_set_onetouch to run or stop one.
Inputs: serial (required).
iaqualink_list_pump_speedsARead-only
List a Jandy AquaLink RS panel’s variable-speed pump speeds — the named speeds (e.g. Pool, Spa, Cleaner) with each one’s RPM and which one the pump runs at — read through iAqualink WebTouch from the panel’s "VSP Adjust / Set Speed" screen. Use iaqualink_set_pump_speed to switch speeds and iaqualink_set_pump_speed_rpm to change a speed’s RPM.
Inputs: serial (required).
iaqualink_list_schedulesARead-only
List a pool system’s schedules (programs/timers). iAqua (Jandy AquaLink RS) panels: the panel’s own schedule — circuit, start, stop (24-hour, plus the panel’s text) and run days, with the page/row each sits at (what iaqualink_edit_schedule and iaqualink_delete_schedule identify it by) — read through iAqualink WebTouch, the panel emulation. If WebTouch is unavailable it falls back to the iQ20 schedule list (adapter firmware 3+), trying each candidate host once and reporting which answered (probe). eXO salt chlorinators: the pump, chlorinator and aux timers (name, start/stop, enabled, rpm for variable-speed pumps). Returns supported: false with the reason when there are none to read.
Inputs: serial (required).
iaqualink_list_systemsARead-only
List the pool/spa systems (iAqualink / Jandy iAquaLink panels and Zodiac eXO salt chlorinators) on the signed-in iAqualink account, with each serial number needed by the other tools. Other device types (e.g. robotic cleaners) are listed but marked unsupported.
Inputs: view.
iaqualink_set_auxAIdempotent
Turn an auxiliary circuit on or off — cleaner, waterfall, bubbler, landscape or pool/spa lights wired to an aux relay. Identify it by number ("3"), name ("aux_3") or label as shown by iaqualink_get_status. On iAqua, dimmable lights turn on at 100% and color lights at their first color, as the iAqualink app does. Sends nothing if already in that state, then re-reads to confirm. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: on (required), aux (required), serial (required), confirmToken.
iaqualink_set_chlorinatorAIdempotent
Set an eXO salt chlorinator’s output (chlorine production) percentage, 0–100. eXO systems only. Unlike the other controls this write is NOT in the iaqualink-py reference client — its shape is inferred from the reported swc field — so it is confirmed only if a re-read shows the new value. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: serial (required), percent (required), confirmToken.
iaqualink_set_equipmentAIdempotent
Turn pool equipment on or off. iAqua (Jandy iAquaLink) systems: pool_pump, spa_pump, pool_heater, spa_heater, solar_heater. eXO salt chlorinators: filter_pump, production (chlorine generation), boost, low (low-output mode), heating. Reads the current state first and sends nothing if it already matches (iAqua commands are toggles); afterwards re-reads to confirm the change landed. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: on (required), serial (required), equipment (required), confirmToken.
iaqualink_set_lightAIdempotent
Set a pool/spa light’s brightness (dimmable lights: 0, 25, 50, 75 or 100 %) or color/show effect (color lights — Jandy, Pentair, Hayward; the effect names are listed by iaqualink_get_status with view "full"). iAqua systems only. The current color cannot be read back from iAqualink, so an effect change is confirmed only by the light being on. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: aux (required), serial (required), effect, brightness, +1 more.
iaqualink_set_onetouchAIdempotent
Turn a Jandy AquaLink RS panel’s OneTouch scene on or off (by number 1–6, onetouch_, or its label from iaqualink_list_onetouch), through WebTouch. The panel button is a toggle, so it is pressed only when the scene is not already in the requested state; the scenes are re-read afterwards to confirm. A scene switches several pieces of equipment at once, as configured on the panel. The toggle press was not exercised in the live capture. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: on (required), serial (required), onetouch (required), confirmToken.
iaqualink_set_pump_speedAIdempotent
Run a Jandy AquaLink RS panel’s variable-speed pump at one of its named speeds (from iaqualink_list_pump_speeds), through WebTouch — the panel makes a pressed speed the running speed at once. Nothing is pressed if that speed already runs; the speeds are re-read afterwards to confirm. Switch back the same way. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: speed (required), serial (required), confirmToken.
iaqualink_set_pump_speed_rpmAIdempotent
Change the RPM of one of a Jandy AquaLink RS panel’s named pump speeds (600–3450), through WebTouch. The panel stores a typed RPM for the running speed, so a speed that is not running is run for a few seconds while it is set, and the speed that was running is switched back afterwards; the speeds are re-read to confirm. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: rpm (required), speed (required), serial (required), confirmToken.
iaqualink_set_scheduleAIdempotent
Change one eXO salt-chlorinator timer (pump, chlorinator or aux): set its start and stop time (24-hour HH:MM) and enable it, set rpm on a variable-speed pump timer, or disable it (enabled: false clears it to 00:00–00:00, as the app does). Identify the timer by its key (sch3), id (sch_3), name or endpoint (ssp_1) from iaqualink_list_schedules. A chlorinator timer must stay inside its pump timer’s window. eXO systems only — for a Jandy AquaLink RS panel use iaqualink_add_schedule / iaqualink_edit_schedule / iaqualink_delete_schedule. The eXO applies changes asynchronously; the result says whether a re-read confirmed it. Unverified on live hardware (shape from community Home Assistant integrations). Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: serial (required), schedule (required), rpm, stop, +3 more.
iaqualink_set_temperatureAIdempotent
Set the pool and/or spa heater set point (target water temperature), in the system’s own unit (iAqua: °F 34–104 or °C 1–40; eXO: °C within its reported range, pool only). This changes the target only — turning a heater on or off is iaqualink_set_equipment. Re-reads to confirm. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE).
Inputs: serial (required), spa, pool, confirmToken.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 19 tools
Most tools target a distinct resource+action (systems, status, schedules, OneTouch, pump speeds), and descriptions explicitly scope iAqua vs eXO behavior. Two real overlap points remain: iaqualink_set_equipment covers eXO 'production'/'boost' chlorine control while iaqualink_set_chlorinator sets output percentage, and iaqualink_set_aux turns light circuits on/off while iaqualink_set_light sets brightness/color. iaqualink_check_panel vs iaqualink_healthcheck is also a fine distinction an agent must reason about.
All names share the iaqualink_ prefix and snake_case verb_noun structure (list_systems, get_status, set_equipment, add/edit/delete_schedule). The only deviation is iaqualink_healthcheck, which omits a verb, and the schedule tools split awkwardly across set_schedule (eXO) versus add/edit/delete_schedule (iAqua) for what is nominally one concept.
Nineteen tools is on the heavy side, but the server genuinely spans two hardware families plus schedules, OneTouch scenes, VSP speeds, and diagnostics, so most tools earn their place. A few could be collapsed — set_chlorinator largely duplicates the eXO branch of set_equipment, and check_panel/healthcheck are adjacent diagnostics.
Coverage is strong for a control server: discovery, status, equipment/aux/light/temperature writes, full schedule CRUD for iAqua panels, OneTouch and pump-speed management, plus healthcheck and panel diagnostics. Gaps exist on the eXO side, which has list+set schedule but no add or true delete (only a disable-to-00:00), and there is no history/energy/log surface.
Maintenance
Related MCP Connectors
Home energy for AI assistants: live Power flow, Energy history, solar forecast, and device control.
Tesla data for your AI: battery, range, charging, tires, alerts, history. Controls off by default.
Read RemoteLock devices and guests; manage door access and physically lock or unlock doors.
Control your Tesla from your AI assistant - climate, charging, access, and security.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAccess Home Assistant data and control devices (lights, switches, thermostats, etc).6 npm574Apache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to monitor and control Jandy iAqualink pool and spa equipment, including device status, power toggling, temperature settings, and lighting effects.MIT
- AlicenseNot gradedqualityBmaintenanceEnables MCP-compatible assistants to retrieve live data from an iopool pool account, including water temperature, pH, ORP, running mode, and filtration recommendations, and to list the account's pools. Access is authenticated with the user's own iopool API key, via OAuth or a direct bearer header.MIT
- AlicenseNot gradedqualityCmaintenanceReads thermostat status and controls HVAC modes, holds, schedules, comfort sensors, settings, vacations, fan runtime, and on-screen messages for a single thermostat account, hosted remotely on Cloudflare Workers with bearer-protected, stateless access.96 npmMIT