Skip to main content
Glama
README.md
# lg-tv-mcp

**עברית:** מדריך למשתמש בעברית [בהמשך העמוד](#שלט-לטלוויזיה--עברית) ומדריך התקנה מלא ב־[docs/client-installation-he.md](docs/client-installation-he.md).

A local [MCP](https://modelcontextprotocol.io) server that turns an AI assistant — Claude Code, Claude Desktop, ChatGPT Work, or any MCP client — into a remote control for LG webOS smart TVs.

Everything runs on your home network: a hand-rolled SSAP websocket client with first-run pairing, the webOS button-input socket, Wake-on-LAN power-on, and mDNS re-discovery when the TV's IP changes. No cloud APIs, no accounts, no telemetry.

## Tools

| Tool | What it does |
|---|---|
| `get_status` | Power, pairing state, current app, volume — no side effects |
| `power_on` | Wake-on-LAN magic packet; TV boots in ~15 s |
| `power_off` | Turn the TV off over SSAP |
| `set_volume` | Set level 0–100, or mute/unmute |
| `press_button` | Remote buttons (arrows, OK, back, play/pause, digits…), with optional repeat |
| `list_apps` / `launch_app` | Enumerate and open apps (Netflix, YouTube, …) |
| `switch_input` | Switch HDMI inputs |
| `set_channel` | Change Live TV channels |
| `type_text` | Type into the focused text field |
| `show_notification` | Toast message on the TV screen |
| `screenshot` | 960×540 JPEG of the current screen (DRM-protected video captures as black; app UI renders fine) |
| `measure_sound_level` | Room loudness via the **laptop** microphone: approximate dB SPL + band (silent/quiet/moderate/loud/very-loud). Loop it with `set_volume` to hit a target level |
| `calibrate_sound_meter` | One-time mic calibration against a phone SPL-meter reading; the offset persists in `config.json` |

## Requirements

- Node.js ≥ 22.13
- An LG webOS TV on the same network as the machine running the server
- For powering on while the TV is off: enable **Settings → General → Turn on via Wi-Fi** on the TV (wording varies by webOS version), and set your TV's MAC address in the config — see [Configuration](#configuration)
- `ffmpeg` for the sound-meter tools (`brew install ffmpeg`); macOS microphone permission is requested from the hosting app on first capture.

## Install

Not yet on npm — install from a clone:

```bash
git clone https://github.com/OmerLapidot/lg-tv-mcp.git
cd lg-tv-mcp
npm ci
```

### Claude Code

```bash
claude mcp add lg-tv-remote --scope user -- node /absolute/path/to/lg-tv-mcp/server/index.js
```

### Claude Desktop / any MCP client

```json
{
  "mcpServers": {
    "lg-tv-remote": {
      "command": "node",
      "args": ["/absolute/path/to/lg-tv-mcp/server/index.js"]
    }
  }
}
```

### ChatGPT Work (desktop plugin)

`npm run plugin:release` builds `dist/plugin/` with the plugin manifest, skill, and icon; the release runtime pins `npx -y @omerlapidot/lg-tv-mcp@<version>` (npm publish is a separate release step). Installation walkthrough (Hebrew): [docs/client-installation-he.md](docs/client-installation-he.md).

## First run — pairing

1. Turn the TV on with the physical remote (first time only) and ask the assistant something harmless like *"what's the TV status?"* — `get_status` works unpaired.
2. The first **control** call (volume, buttons, apps…) pops a pairing prompt on the TV screen. Accept it with the physical remote within a minute.
3. That's it — the TV issues a client key, saved locally. The prompt never appears again unless you revoke the pairing on the TV (**Settings → General → External Devices → Connection Manager**).

## Configuration

State lives in a single JSON file (created and updated automatically):

- macOS: `~/Library/Application Support/lg-tv-mcp/config.json`
- Windows: `%APPDATA%\lg-tv-mcp\config.json`

| Field | Meaning |
|---|---|
| `hostname` | mDNS name tried when the last-known IP stops answering. `LGwebOSTV.local` is the LG factory default, so this usually just works. |
| `ip` | Last-known IPv4 of the TV. Auto-updated whenever discovery finds the TV at a new address. |
| `mac` | The TV's Wi-Fi MAC, used only for Wake-on-LAN. **The repo default is a placeholder — set your own** (shown on the TV under Settings → Network → Wi-Fi Connection → Advanced) or `power_on` cannot wake a TV that is fully off. |
| `clientKey` | Pairing key issued by the TV on first approval; `null` until paired. |
| `micCalibrationOffsetDb` | Optional. dBFS→dB SPL offset stored by `calibrate_sound_meter`; absent until first calibration (a rough default of +100 is used, flagged `calibrated: false`). |

Environment overrides: `LG_TV_DATA_DIR` (config directory), `LG_TV_URL` (skip discovery and connect to a fixed `ws://`/`wss://` URL — used to point at the fake TV in tests), `LG_TV_REGISTER_TIMEOUT_MS` (pairing prompt timeout).

### Security notes

- The client key works only from inside your LAN and can only control this TV; it contains no account credentials.
- The TV serves SSAP and screen captures over TLS with a self-signed certificate, so certificate validation is intentionally disabled for those LAN-only connections.
- Nothing leaves your network; there is no cloud relay.

## Development

```bash
npm ci
npm test                # full suite against an in-process fake TV — no hardware needed
npm run plugin:release  # build dist/plugin for ChatGPT Work
```

Layout: `server/` (config, discovery, SSAP client, input socket, Wake-on-LAN, MCP server), `test/` (node:test suite plus `test/fixtures/fake-tv.mjs`, a scripted SSAP TV), `skills/` (assistant-facing usage skill), `docs/superpowers/` (original design spec and implementation plan).

Quirks worth knowing: the reported model string is a constant (`LG 65NANO80VNA` — the TV this was built for), and user-facing error messages are in Hebrew, since that's the household it serves. PRs welcome.

## Why I built this

I wrote up how this was built and what it taught me:
[English](https://hopala.io/en/blog/mcp-for-my-tv.html) · [עברית](https://hopala.io/blog/mcp-for-my-tv.html)

## License

[MIT](LICENSE) © Omer Lapidot

---

<div dir="rtl">

## שלט לטלוויזיה — עברית

תוסף מקומי שהופך את ChatGPT (או Claude) לשלט רחוק לטלוויזיית LG webOS ברשת הביתית:
הדלקה וכיבוי, ווליום, פתיחת אפליקציות כמו נטפליקס ויוטיוב, החלפת כניסות
HDMI, ערוצים, הקלדת טקסט, הודעות על המסך וצילום של מה שמוצג על המסך.

**הכול מקומי.** התקשורת היא ישירות מהמחשב לטלוויזיה ברשת הביתית
(websocket מקומי + Wake-on-LAN). שום דבר לא עובר בענן.

### התקנה

המדריך המלא: [docs/client-installation-he.md](docs/client-installation-he.md). בקצרה:

1. מתקינים את התוסף **שלט לטלוויזיה** ביישום ChatGPT Work למחשב.
2. מפעילים מחדש את ChatGPT, פותחים משימה וכותבים: **"מה מצב הטלוויזיה?"**.
3. בפקודת השליטה הראשונה יופיע על מסך הטלוויזיה חלון אישור — מאשרים פעם
   אחת עם השלט הפיזי, וזהו.
4. כדי שההדלקה מרחוק תעבוד, מפעילים בטלוויזיה את ההגדרה
   **Turn on via Wi-Fi**.

</div>