Skip to main content
Glama
rudy325

rainbird-mcp

by rudy325
README.md
<p align="center">
  <img src="assets/logo.svg" width="128" alt="rainbird-mcp logo">
</p>

<h1 align="center">rainbird-mcp</h1>

<p align="center">
  An <a href="https://modelcontextprotocol.io">MCP</a> server for <b>Rain Bird</b> irrigation
  controllers (ESP-TM2 and compatible) that talk over a local <b>LNK / LNK2 WiFi module</b>.
  <br>Local LAN only — no cloud dependency.
</p>

---

## What it does

Exposes your Rain Bird controller to any MCP client (Claude Code, Claude Desktop, etc.)
so you can ask things like *"is the sprinkler running?"*, *"run zone 3 for 10 minutes"*,
or *"set a 2-day rain delay"* in natural language.

It speaks the controller's local encrypted SIP-command protocol via
[`pyrainbird`](https://github.com/allenporter/pyrainbird) — the same protocol the
Rain Bird mobile app uses on your LAN.

## Tools

| Tool | Purpose |
| --- | --- |
| `list_controllers` | configured controllers, hosts, and detected transport URL |
| `get_controller_info` | model, firmware version, serial number |
| `get_status` | one-shot: irrigating?, active zones, remaining runtime, rain sensor, rain delay, clock |
| `get_zone_states` | per-zone on/off map |
| `get_schedule` | programs, run days, start times, per-zone durations |
| `get_rain_delay` | remaining rain delay in days |
| `get_network_info` | LNK WiFi status and parameters |
| `start_zone` | run one zone for N minutes (validated against available zones) |
| `stop_irrigation` | stop everything now |
| `advance_zone` | skip to the next zone in the running program |
| `set_rain_delay` | set/clear rain delay (0–14 days) |
| `run_program` | start stored program 1–4 (A/B/C on the TM2) |
| `sync_clock` | push this machine's local date/time to the controller |

## Requirements

- Python 3.12+
- [`uv`](https://docs.astral.sh/uv/)
- A Rain Bird controller with an LNK/LNK2 WiFi module on the same reachable network
- The controller's **device password** (see below)

## Install

```bash
git clone https://github.com/rudy325/rainbird-mcp.git
cd rainbird-mcp
uv sync
```

## Configure

The password is the controller's **device password** — set/shown in the Rain Bird app
under the controller's settings. It is **not** your WiFi password and **not** your
Rain Bird account login. If you don't know it, remove and re-add the WiFi module in the
app to set a new one (this keeps your zones and schedules).

Single controller:

```bash
export RAINBIRD_HOST=192.168.1.50
export RAINBIRD_PASSWORD=your-device-password
```

Multiple controllers (each tool then takes an optional `controller` argument, required
when more than one is configured):

```bash
export RAINBIRD_CONTROLLERS='{"front":{"host":"192.168.1.50","password":"pw1"},
                              "back":{"host":"192.168.1.51","password":"pw2"}}'
```

See [`.env.example`](.env.example) for all variables.

## Register with Claude Code

```bash
claude mcp add rainbird \
  --env RAINBIRD_HOST=192.168.1.50 \
  --env RAINBIRD_PASSWORD=your-device-password \
  -- uv --directory /path/to/rainbird-mcp run server.py
```

Or with Claude Desktop, in `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "rainbird": {
      "command": "uv",
      "args": ["--directory", "/path/to/rainbird-mcp", "run", "server.py"],
      "env": {
        "RAINBIRD_HOST": "192.168.1.50",
        "RAINBIRD_PASSWORD": "your-device-password"
      }
    }
  }
}
```

## Use with other clients (OpenAI, local models, etc.)

This is a standard [MCP](https://modelcontextprotocol.io) server — it speaks the open
protocol over stdio and doesn't care which model or client drives it. Anything that
supports MCP works:

- **OpenAI** — the [Agents SDK](https://openai.github.io/openai-agents-python/mcp/) and
  Responses API accept MCP servers. Point them at:
  `command: "uv"`, `args: ["--directory", "/path/to/rainbird-mcp", "run", "server.py"]`,
  with `RAINBIRD_HOST` / `RAINBIRD_PASSWORD` in the environment.
- **Local / open-source models** — via any MCP-capable client (Cline, Continue,
  LibreChat, Open WebUI, Goose, Zed, Cursor) running Ollama, Llama, Qwen, etc.
- **Any other MCP client** — same stdio command as the Claude examples above.

The only requirement is a model that's competent at tool/function calling; the large
hosted models and stronger local ones (Llama 3.1+, Qwen 2.5+) handle it well.

## Transport (HTTP vs HTTPS)

Newer LNK modules (certificate CN `fw-cc20.rainbird.com`) serve the SIP endpoint over
**HTTPS on port 443 and refuse port 80**, with a self-signed Rain Bird certificate.
Older modules are plain HTTP on 80. `pyrainbird` hardcodes `http://`, so this server
probes 443 then 80 per host and rewrites the client URL accordingly. Certificate
verification is disabled — the device is LAN-local, addressed by IP, and its certificate
is self-signed by Rain Bird, so verification cannot succeed.

Skip the probe by forcing it: `RAINBIRD_SCHEME=https` (or `http`).

## Notes & gotchas

- **One connection at a time.** The LNK module accepts a single connection; expect slow
  or failed calls if the Rain Bird mobile app is open against the same controller.
- **WiFi quality matters.** The module is 2.4 GHz WiFi 4, 1×1. A weak signal shows up as
  intermittent timeouts, not clean errors. Check RSSI / TX retries in your AP if calls
  are flaky.
- **`run_program`** uses the `ManuallyRunProgramRequest` SIP command; some firmware
  revisions NACK it. If it fails, drive zones individually with `start_zone`.
- **The controller clock** drifts and has no NTP. `sync_clock` is worth running
  occasionally.
- **Isolated IoT VLANs (UniFi and similar).** If the controller is on an isolated VLAN,
  the router's isolation feature typically drops the controller's *replies* to your LAN,
  which no user "allow" rule reliably overrides. Disabling isolation on that network (and
  optionally re-adding your own outbound-only block rule) is what actually restores access.

## How it fits together

```
MCP client ──stdio──> server.py ──pyrainbird──> HTTP(S) /stick ──> LNK WiFi module ──> controller
```

## Credits

- [`pyrainbird`](https://github.com/allenporter/pyrainbird) — the protocol implementation.
- [Model Context Protocol](https://modelcontextprotocol.io) — the server framework.

## License

[MIT](LICENSE). Not affiliated with or endorsed by Rain Bird Corporation.
"Rain Bird" is a trademark of Rain Bird Corporation.