# Larnitech MCP **Version 1.3.2 Beta** · [Changelog](CHANGELOG.md) · MIT licensed An [MCP](https://modelcontextprotocol.io) server that lets an AI agent read and control a [Larnitech](https://larnitech.com) smart-home installation over the API2 protocol — lights, climate, blinds, sensors, meters. It ships with a documented device-type reference built from live testing against real controllers, so the agent looks up how a widget actually behaves instead of guessing from key names. That matters more than it sounds: on this platform writing `state: "closed"` to a gate is acknowledged with `success: true` and then silently ignored, and several climate types drop half of any two-key write. Those traps are documented, checked before every write, and listed in this README's own safety section. --- ## What it does **Reading** — open, no configuration beyond the API key. | Tool | What it does | |---|---| | `list_objects` | configured controllers (never returns keys) | | `check_connection` | connect, authorize, report device count | | `list_devices` | full snapshot, filterable by area / type / name | | `get_device` | status of one device by address | **Understanding what came back** — statuses are type-specific and occasionally not key/value at all. | Tool | What it does | |---|---| | `get_docs()` | overview of every documented device type | | `get_docs("AC")` | full detail for one type: status keys, enums, XML attributes, script byte layout, quirks | | `get_docs("bugs")` | numbered registry of confirmed vendor bugs | | `get_docs("protocol")` | API2 protocol reference | Responses flag statuses that need care: an opaque `hex` blob, a `malfunction` fault code in place of a normal reading, an all-`null` payload from a meter that missed its poll cycle — which means *no data*, not zeros — or a bare `state: "undefined"`, which is how a device that is physically offline still answers. **Watching** — non-blocking, for "press the switch and tell me what moved". | Tool | What it does | |---|---| | `watch_start` | begin watching; returns immediately | | `watch_read` | drain what changed since the last read, per key `from`/`to` | | `watch_stop` / `watch_list` | stop one / list active | A watch keeps its own connection alive, so it survives the controller's 5-minute idle timeout and can stay open across a long conversation. **Writing** — off by default, two-phase, and never a single tool call. | Tool | What it does | |---|---| | `set_device` | validate, preview the change, return a token — **does not write** | | `confirm_set` | execute, then wait for the device to settle and report what actually landed | **Learning** — findings survive the session. | Tool | Writes to | |---|---| | `add_docs_note` | that device type's own doc file | | `add_preference` | `preferences.md`, served with every `get_docs` | **Saving data** — a snapshot is worth more than scrollback. | Tool | What it does | |---|---| | `save_snapshot` | keep a slice of controller data as a file | | `list_snapshots` | what has been saved, per controller | | `read_snapshot` | read one back, to compare against now | Files land in `data//_