lgtv-control-mcp
v1.1.0
Published
MCP server to control LG webOS TVs from AI clients.
Maintainers
Readme
lgtv-control-mcp
An MCP (Model Context Protocol) server for controlling LG webOS TVs from AI clients like Claude, Codex, GitHub Copilot, and Antigravity. Works with one TV or several: register each TV under a name like "Office" and target it directly, or let commands fall through to a default TV.
Communication uses the webOS SSAP protocol over WebSocket, the same one used by the LG ThinQ app and projects like ColorControl.
Tools
add_tv/remove_tv/list_tvs/set_default_tv: manage your TVs by name (see Multiple TVs)set_backlight: backlight 0-100set_peak_brightness: peak brightnessoff/low/medium/highset_picture_setting/set_picture_mode/get_picture_settings: contrast, brightness, color, and picture modeset_volume/volume_up/volume_down/get_volume/set_mutelist_inputs/set_input: switch HDMI and other inputslist_apps/launch_app/close_app/get_foreground_appchannel_up/channel_down/set_channel/list_channels/get_current_channelmedia_play/media_pause/media_stop/media_rewind/media_fast_forwardpower_off/screen_off/screen_on/get_power_stateset_3d_on/set_3d_offshow_toast: display a notification on the TVsend_button: press a remote button. Compatible names include0-9,HOME,BACK,ENTER,EXIT,UP,DOWN,LEFT,RIGHT,RED,GREEN,YELLOW,BLUE,POWER,VOLUMEUP,VOLUMEDOWN,MUTE,MENU,CC,DASH,CHANNELUP,CHANNELDOWN,LIST,AD,SAP,PROGRAM,PLAY,PAUSE,STOP,REWIND,FASTFORWARD,GUIDE,AMAZON,NETFLIX,MAGNIFIER_ZOOM,LIVE_ZOOM,3D_MODE,ASPECT_RATIO,RECENT,RECORD,SCREEN_REMOTE,MYAPPSget_system_info/get_software_info/get_service_listssap_request: send any raw SSAP command (escape hatch)
Every control tool accepts an optional tv argument with the name of the target TV. Without it, the command goes to the default TV.
Requirements
- Node.js 18+
- An LG webOS TV powered on and on the same local network
- The TV's IP address (Settings > Network)
- Mobile TV On enabled (Settings > Connection > External Devices > On via Wi-Fi)
Installation
Global install
npm install -g lgtv-control-mcpThis puts the lgtv-control-mcp binary in your PATH. Use command: "lgtv-control-mcp" with no args in your client config.
Via npx (no install)
npx -y lgtv-control-mcp@latestThis does not install the package. The MCP client runs this command each time it starts the server; npm caches the package after the first download.
From source
git clone https://github.com/brunofgmag/lgtv-control-mcp.git
cd lgtv-control-mcp
npm install
npm run build
node dist/index.jsPairing
The first time you connect, the TV shows a "Connection Request" prompt on screen. Accept it with the remote.
The client key is saved automatically to ~/.lgtv-control-mcp/keys.json and reused on later connections. You don't need to configure it manually. If you want to pin a specific key, copy the value from that file into LGTV_CLIENT_KEY.
Multiple TVs
You can register any number of TVs by name, without touching config files. Just ask your AI:
- "Add the TV 'Office' with IP 192.168.1.13"
- "Add the TV 'Living Room' with IP 192.168.1.20"
- "Which TVs do I have configured?"
- "Remove the Bedroom TV"
Commands that don't name a TV go to the default TV. The first TV you add becomes the default; to change it, say something like "make the Living Room TV the default". To control a specific TV, name it in the request: "pause the Office TV" or "set the volume to 15 on the Living Room TV".
A few details worth knowing:
- Adding a TV with a name that already exists updates it, so "change the Office TV's IP to 192.168.1.40" works without removing it first.
- Names are matched ignoring case; "office" and "Office" are the same TV.
- Each TV pairs separately. The first command sent to a new TV shows the connection prompt on that screen; accept it with that TV's remote.
- The list is stored in
~/.lgtv-control-mcp/tvs.json, so it survives restarts and is shared by all your MCP clients.
If you only use one TV, you can skip all of this and set LGTV_HOST instead: when no TVs are registered, commands go to that address.
Client configuration
LGTV_HOST is optional in every example below. It gives you a working single-TV setup right away, but you can leave the env block out entirely and register your TVs by chat afterwards, for example "Add the TV 'Office' with IP 192.168.1.13" (see Multiple TVs). If both exist, registered TVs take precedence over LGTV_HOST.
Claude Desktop
Open Settings → Developer → Edit Config. This opens claude_desktop_config.json directly in your editor. Add the entry and restart the app.
{
"mcpServers": {
"lgtv-control": {
"command": "npx",
"args": ["-y", "lgtv-control-mcp@latest"],
"env": { "LGTV_HOST": "192.168.1.50" }
}
}
}If you installed globally, use "command": "lgtv-control-mcp" with "args": [].
Claude Code
The --scope user flag adds the server globally across all your projects:
claude mcp add lgtv-control --scope user --env LGTV_HOST=192.168.1.50 -- npx -y lgtv-control-mcp@latestIf you installed globally, replace npx -y lgtv-control-mcp@latest with just lgtv-control-mcp.
Or add it manually to ~/.claude/settings.json (user-level, global):
{
"mcpServers": {
"lgtv-control": {
"command": "npx",
"args": ["-y", "lgtv-control-mcp@latest"],
"env": { "LGTV_HOST": "192.168.1.50" }
}
}
}Codex CLI
Via CLI:
codex mcp add lgtv-control --env LGTV_HOST=192.168.1.50 -- npx -y lgtv-control-mcp@latestOr in ~/.codex/config.toml:
[mcp_servers."lgtv-control"]
command = "npx"
args = ["-y", "lgtv-control-mcp@latest"]
[mcp_servers."lgtv-control".env]
LGTV_HOST = "192.168.1.50"GitHub Copilot / VS Code
In .vscode/mcp.json or your user MCP settings:
{
"servers": {
"lgtv-control": {
"type": "stdio",
"command": "npx",
"args": ["-y", "lgtv-control-mcp@latest"],
"env": { "LGTV_HOST": "192.168.1.50" }
}
}
}For Copilot clients that expect the mcpServers format:
{
"mcpServers": {
"lgtv-control": {
"type": "local",
"command": "npx",
"args": ["-y", "lgtv-control-mcp@latest"],
"env": { "LGTV_HOST": "192.168.1.50" },
"tools": ["*"]
}
}
}Antigravity
{
"mcpServers": {
"lgtv-control": {
"command": "npx",
"args": ["-y", "lgtv-control-mcp@latest"],
"env": { "LGTV_HOST": "192.168.1.50" }
}
}
}Other MCP clients
Most clients that support local MCP via stdio use the same pattern:
{
"mcpServers": {
"lgtv-control": {
"command": "npx",
"args": ["-y", "lgtv-control-mcp@latest"],
"env": { "LGTV_HOST": "192.168.1.50" }
}
}
}Environment variables
| Variable | Required | Default | Description |
| --- | --- | --- | --- |
| LGTV_HOST | no | - | TV IP address; used when no TVs are registered with add_tv |
| LGTV_PORT | no | 3001 | 3001 = wss (self-signed TLS); use 3000 for plain ws |
| LGTV_CLIENT_KEY | no | - | Pairing key; obtained and saved automatically on first use |
Usage examples
Once configured, try asking your AI:
- "Set the TV backlight to 30"
- "Turn up the volume" / "Switch to HDMI 2"
- "Open Netflix" / "Turn off the TV screen"
- "Show a 'Dinner's ready' notification on the TV"
- "Add the TV 'Office' with IP 192.168.1.13"
- "Open YouTube on the Office TV"
- "Make the Office TV the default"
Troubleshooting
- "pairing timed out": accept the connection prompt on the TV screen and try again.
- "could not connect": check the IP, that the TV is on and on the same network. Try
LGTV_PORT=3000. - Backlight not changing: some firmware versions require the luna path. The server already tries SSAP first and falls back automatically. Also check that your current picture mode allows manual backlight adjustment.
- Command reached the wrong TV: ask "which TVs do I have configured?" to see the registered TVs and the current default, then name the TV in the command or change the default.
- Re-pairing: delete the TV's entry in
~/.lgtv-control-mcp/keys.jsonto force a new pairing prompt.
How it works
The server opens an SSAP WebSocket with the TV, performs the registration handshake (with pairingType: PROMPT), and sends ssap://... requests. Remote control buttons use a separate pointer socket (getPointerInputSocket). Picture adjustments use setSystemSettings; when the direct SSAP path is rejected by the firmware, the server uses the luna trick (creating and closing an alert whose onclose points to luna://com.webos.settingsservice/setSystemSettings).
