Skip to main content
Glama

otolawn-mcp

A Model Context Protocol (MCP) server for OtO Lawn smart sprinkler devices. Control your OtO zones from any MCP client (Claude, Cursor, etc.):

  • List devices, zones, and schedules

  • Start / stop watering on demand, with a water depth or runtime you choose

  • Enable/disable zones, rename them, change their scheduled water amounts

  • Browse irrigation event history (what ran, when, how much water, errors)

  • Enable/disable watering schedules

  • Read the weather data OtO uses for rain/wind skipping, device diagnostics, battery history and notification messages

The protocol was reverse-engineered from the OtO mobile app (v4.0.8, Android build com.oto). See docs/API.md for the full API reference. This is an independent personal-use interoperability project - it is not affiliated with or endorsed by OtO Inc. Trademarks belong to their owners.

This project talks to YOUR devices with YOUR credentials.

How it works

MCP client (Claude, etc.)
    |  (stdio JSON-RPC)
    v
otolawn-mcp server  ──► Firebase Auth (email/password sign-in)  ─► ID token
    |                  https://oto-cloud-service-ems-prod-*.run.app API
    v                  (Bearer ID-token auth)
OtO sprinkler device(s), polled by OtO's cloud
  • Authentication uses the same Firebase auth endpoint the app uses, with an embedded app API key (public information, shipped inside the distributed app).

  • The ID token is cached in memory and refreshed automatically (tokens last ~1 hour).

  • Manual start/stop are executed via the same schedule-execution endpoints the app uses; the physical device picks up the change within ~1-2 minutes.

Related MCP server: hydrawise-mcp

Install

Requires Python 3.11+.

git clone https://github.com/DmitriyAlergant/otolawn-mcp
cd otolawn-mcp
python -m venv .venv
uv pip install -e .        # or: .venv/bin/pip install -e .

Configure credentials

export OTO_EMAIL="you@example.com"
export OTO_PASSWORD="your-oto-app-password"

These are the same email/password you use in the OtO mobile app.

Tool call contract

All tools return flat JSON blobs:

{"ok": true , "...": "payload"}
{"ok": false, "error": "description on failure"}

Water depths are millimetres (wateringQuantity at the API level). Runtimes and water depth are related by a per-zone calibration curve (timeToWater_form); water_zone accepts either.

Available tools

Tool

Description

list_devices

Devices with name + winter mode

get_device_status

Live hardware status: battery mA/V, charge state, comm info

get_battery_history

Daily battery level history

get_device_logs

Device event log (watering starts/stops, errors)

list_zones / get_zone

Zones with water amount, enabled, days, rain/wind skips

set_zone_enabled

Enable / disable a zone

rename_zone

Rename a zone

set_zone_watering

Change a zone's scheduled water depth or runtime

water_zone

Start watering now (returns scheduleId)

stop_watering

Stop a manual run by scheduleId

list_events

Irrigation events (scheduled run instances) with statuses

cancel_event

Cancel an event, or un-cancel a rain-skipped one

list_routines / set_routine_enabled

Watering schedules (routines)

get_weather

Weather used by the rain/wind intelligence

list_messages

Account messages

add_zone

Create an unconfigured zone (path calibration still needs the app)

delete_zone

Delete a zone

Example

You:    "Water the Front Lawn Far zone about 3 mm, then tell me how much it ran."
Claude: calls list_zones() ─► finds zone "Front Lawn Far"
        calls water_zone(device_id, zone_id, water_depth_mm=3)
        calls list_events(only_active=true) ...
        calls stop_watering(scheduleId) when done (or lets it finish)

Registering with Claude Code / other clients

claude mcp add otolawn -- <repo>/venv/bin/otolawn-mcp (with creds in env), or in mcp.json:

{
  "mcpServers": {
    "otolawn": {
      "command": "/path/to/otolawn-mcp/.venv/bin/otolawn-mcp",
      "env": { "OTO_EMAIL": "you@example.com", "OTO_PASSWORD": "..." }
    }
  }
}

Safety notes

  • water_zone triggers real watering within a minute or so.

  • A stopped water_zone run may still have briefly spawned a run - the device applies commands on its next poll, so stopping immediately after starting is also handled (event ends up USER_STOPPED).

  • Rain/wind intelligence is not bypassed by manual starts; use large-enough depth if you expect the forecast to interfere.

  • Deleting zones or devices cannot easily be undone.

Repo contents

  • src/otolawn_mcp/client.py - OtO cloud API client (auth, zones, events, control)

  • src/otolawn_mcp/server.py - MCP tool surface

  • docs/API.md - the full reverse-engineered API reference

Disclaimer

This is an unofficial, independent interoperability implementation, not affiliated with OtO Inc. Endpoints may change without notice. Use at your own risk. Be mindful of local water-use rules and of what you commit to a public repo :).

MIT licensed. See LICENSE.

Available Tools

19 tools
add_zoneA

Create a new unconfigured zone on a device. The device must calibrate the throw path via the app afterwards (cloud-only path mapping is not possible), but the zone appears immediately and is waterable.

Inputs: name (required), device_id (required), enabled, water_depth_mm.

cancel_eventB

Cancel a scheduled irrigation event (or set cancel=false to un-cancel a rain-skipped event and force it to water anyway).

Inputs: schedule_id (required), cancel.

delete_zoneB

Delete a zone. This cannot be undone from this tool; the app keeps deleted zones recoverable for a short period.

Inputs: zone_id (required), device_id (required).

get_device_battery_historyB

Get the device's battery level history (percent values, one per day).

Inputs: device_id (required).

get_device_logsB

Get the device's recent log entries (watering starts/stops, errors, battery and connectivity events), newest first.

Inputs: device_id (required), limit.

get_device_statusB

Get live hardware status for one device: battery voltage/current, charge state, comms info, and any error data.

Inputs: device_id (required).

get_weatherA

Get the local weather used by the OtO weather engine: current conditions, weekly rain/temperature forecast and historical rain.

Inputs: no named parameters.

get_zoneB

Get full details of one zone: paths, nozzle angles, water amounts, bottle/fertilizer state and scheduling info.

Inputs: zone_id (required), device_id (required).

list_devicesB

List all OtO devices on the account with names and winter-mode state.

Inputs: no named parameters.

list_eventsA

List irrigation events. start/end are dates (YYYY-MM-DD), end included; default window is 7 days back through 14 days ahead. Set only_active=true to fetch just events that are scheduled, pending or currently executing.

Inputs: end, start, zone_id, only_active.

list_messagesC

List recent account messages from OtO (announcements, tips).

Inputs: limit.

list_routinesA

List watering schedules (routine definitions): pattern (daily/even/odd/ interval/daysOfWeek), start time, enabled flag and member zones.

Inputs: no named parameters.

list_zonesA

List watering zones (across all devices or for one device), with each zone's name, enabled state, water amount and schedule days.

Inputs: device_id.

rename_zoneC

Rename a watering zone.

Inputs: name (required), zone_id (required), device_id (required).

set_routine_enabledA

Enable or disable a watering schedule. Fetch-current-then-merge is used so other schedule settings are preserved.

Inputs: enabled (required), routine_id (required).

set_zone_enabledB

Enable or disable a zone. A disabled zone is skipped by schedules; manual watering may still be requested.

Inputs: enabled (required), zone_id (required), device_id (required).

set_zone_wateringB

Set the scheduled water amount for a zone. Pass water_depth_mm (the depth of water the zone should receive per watering day) or minutes. Example: 9.5 mm is a typical summer day for turf grass.

Inputs: zone_id (required), device_id (required), minutes, water_depth_mm.

stop_wateringA

Stop an active manual watering run. Get the scheduleId from water_zone or from the device's event list.

Inputs: schedule_id (required).

water_zoneA

START WATERING a zone now, manually. Give water_depth_mm (water depth in millimetres, e.g. 0.5-10) or minutes (runtime). The device begins its run within a couple of minutes. Returns the event scheduleId needed to stop it. If allow_conflicts is false the request fails when the device is already due to water at this time.

Inputs: zone_id (required), device_id (required), minutes, water_depth_mm, +1 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 19 tools

    Disambiguation4/5

    Most tools target clearly distinct resources and actions (zones vs routines vs events vs devices). A few pairs could be momentarily confused—cancel_event vs stop_watering, and water_zone (manual) vs set_zone_watering (scheduled amount)—but the descriptions explicitly clarify the manual/scheduled distinction.

    Naming Consistency5/5

    Every tool follows a consistent snake_case verb_noun pattern (list_zones, get_zone, set_zone_enabled, water_zone, cancel_event, etc.). No mixed conventions or vague verbs appear.

    Tool Count4/5

    19 tools is on the heavier side but the domain is genuinely broad (zones, routines, events, devices, weather, messages), and each tool maps to a distinct operation. Slightly heavy but not bloated.

    Completeness4/5

    Zones have full lifecycle coverage (add/get/list/rename/enable/delete/set-watering) and devices/events are well covered. The main gap is routines: they can only be listed and enabled/disabled, with no create/edit, though zone-level scheduling partially compensates.

    Maintenance

    ActivitySlowing
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      F
      maintenance
      Enables managing OpenSprinkler irrigation controllers via Claude Desktop, including starting/stopping stations, setting rain delays, and viewing controller status.
      -
    • F
      license
      Not graded
      quality
      D
      maintenance
      MCP server for Hunter Hydrawise irrigation controllers, exposing the Hydrawise REST API as tools for AI agents to manage watering schedules and controller settings.
      -
    • F
      license
      A
      quality
      D
      maintenance
      Query and control Orbit B-Hyve irrigation systems from MCP-compatible clients like Claude Code and Cursor.
      12
      1
      -
    • A
      license
      A
      quality
      C
      maintenance
      MCP server for full control of Rachio sprinkler controllers via the reverse-engineered internal gRPC API, enabling schedule management, manual zone runs, rain delays, and weather data retrieval.
      24
      8
      MIT