tuya-local-mcp
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
tuya-local-mcp
Zero-cloud LAN controller for Tuya / Smart Life bulbs: an MCP server for Claude Code plus a TrueColor CLI.
$ l focus
[FOCUS] ceiling: off | setup: 85% · temp 90 | bed: 15% · temp 0 312 msLocal only. Commands go straight to the bulbs over your Wi-Fi (TCP 6668). The Tuya cloud is used once, to download each bulb's key, and never again.
A CLI you'll actually use.
ltoggles the room,l bed 20dims the bed lamp,l sleep 30mturns everything off later. Output is painted in the colour the bulb shows.Works in Claude Desktop too, on any plan, including ambient mode.
Claude Code integration. A
/lightcommand that understands "fireplace vibe on the desk in 10 minutes". Lights turn red when your tests fail and flash green when they pass again. An optional ambient mode lets Claude set the mood while it works.
Contents
Related MCP server: io.github.jonnyblankinship/hue-ble-mcp
How it works
One program, two ways in. When you type a command, it's a CLI. When Claude Code starts it (no terminal attached), it's an MCP server. Both share the same engine:
you, in a terminal Claude Code
────────────────── ───────────
l bed night /light "reading in bed"
│ │ │
│ MCP tools (stdio) hooks: test failed / passed
▼ ▼ ▼
┌────────────────────────────────────────────────────────────┐
│ tuya-local-mcp │
│ │
│ cli.py ─┐ ┌─ server.py signals.py │
│ ▼ ▼ │
│ commands.py ── presets.json, devices.json │
│ │ (in ~/.config/tuya-local-mcp) │
│ ▼ │
│ engine.py: one connection per light, all in parallel │
│ • builds the whole change as ONE message │
│ • light unreachable? listen for its LAN broadcast, │
│ save the new IP, retry │
└───────────┬───────────────────────┬────────────────────────┘
│ TCP 6668 │ UDP 6666/6667 (discovery)
▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ ceiling │ │ setup │ │ bed │ your Wi-Fi bulbs
└────────────┘ └────────────┘ └────────────┘Delayed commands (l sleep 30m, or Claude's delay_seconds) run in a small background process, so they still fire after you close the terminal or Claude Code.
Requirements
Tuya-based Wi-Fi bulbs that work with the Smart Life or Tuya Smart app. Many cheap "smart bulbs" are Tuya inside, and the app tells you: if it's Smart Life, it works.
The computer on the same local network as the bulbs.
Python 3.10 or newer and uv.
A free Tuya IoT developer account, used once to download the keys (step 2).
For the Claude Code features: Claude Code.
Setup
1. Install the command
uv tool install git+https://github.com/meow-dot-py/tuya-local-mcpThis puts tuya-local-mcp on your PATH. Check it with tuya-local-mcp help.
To update later, run uv tool upgrade tuya-local-mcp.
2. Get your bulbs' local keys (once)
Each bulb encrypts its local traffic with its own key. The only way to get that key is through Tuya's developer cloud. You do this once, and again only if you re-pair a bulb or add new ones.
a. Create a cloud project
Sign up at platform.tuya.com (free).
Go to Cloud → Development → Create Cloud Project.
Development method: Smart Home.
Data center: the one your app account uses. If you're unsure, it's usually the closest to you: Central Europe, Western America, Eastern America, India or China.
When asked for API services, keep the defaults. Only two are needed: IoT Core and Authorization Token Management. The others the template adds (Smart Home Basic Service, Device Status Notification, ...) are harmless. You can check them later under the project's Service API tab.
On the project's Overview tab, copy the Access ID and Access Secret.
IoT Core is a free trial that expires after about a month. It's only needed while the wizard downloads keys, so the lights keep working after it expires. When you add or re-pair a bulb later, renew it first:Service API → IoT Core → Extend trial period (free, after a short questionnaire).
b. Link your Smart Life account
In the project, open Devices → Link App Account → Add App Account. A QR code appears.
In the Smart Life app, go to Me → the scan icon (top right), and scan it.
Your bulbs now appear under Devices. Copy any one Device ID.
c. Run the wizard
tuya-local-mcp initIt runs the tinytuya wizard inside the config folder (~/.config/tuya-local-mcp) and asks for:
Prompt | Answer |
API Key | the Access ID |
API Secret | the Access Secret |
any Device ID | the Device ID you copied |
Your Region |
|
Download DP Name mappings? | Y. This lets each change go out as a single message |
Poll local devices? | Y. This finds the IPs |
Force-close the Smart Life app on your phone before polling and whenever you use the lights from here. Many bulbs accept only one local connection, and the app may be holding it.
When it finishes, you'll see your lights listed. The wizard also leaves tinytuya.json, tuya-raw.json and snapshot.json in the config folder. They contain secrets: never share or commit them.
Copy devices.example.json to ~/.config/tuya-local-mcp/devices.json and fill in each bulb's id, key, ip and version (3.3, 3.4 or 3.5). Without the wizard's mapping, the first command to each bulb takes one extra round trip to detect its type.
3. Try it
tuya-local-mcp status
tuya-local-mcp presetsThen give it a short name. In PowerShell (notepad $PROFILE):
function light { tuya-local-mcp @args }
Set-Alias -Name l -Value lightIn bash / zsh (~/.bashrc or ~/.zshrc):
alias l='tuya-local-mcp'
alias light='tuya-local-mcp'From here on, the examples use l.
4. Add it to Claude Code
The plugin (recommended) gives you everything: the MCP tools, /light, the test/build signals and ambient mode. Inside Claude Code:
/plugin marketplace add meow-dot-py/tuya-local-mcp
/plugin install tuya-local@tuya-local-mcpThen open /config to adjust the plugin's options (see Claude Code features).
MCP tools only, if you don't want the hooks or skill:
claude mcp add tuya-local -s user -- tuya-local-mcp serveUse one or the other. The plugin already includes the MCP server, so registering both gives Claude every tool twice.
4b. Or add it to Claude Desktop (any plan, including free)
The Claude desktop app can use the MCP server in normal chats, so you can say "make it cosy in here" or "lights off in 20 minutes" without Claude Code.
Find the full path of the command. In PowerShell:
(Get-Command tuya-local-mcp).Source. In bash/zsh:which tuya-local-mcp.In Claude Desktop, open Settings → Developer → Edit Config and add the server to
claude_desktop_config.json:{ "mcpServers": { "tuya-local": { "command": "C:\\Users\\you\\.local\\bin\\tuya-local-mcp.exe", "args": ["serve"], "env": { "TUYA_LOCAL_MCP_AMBIENT": "false" } } } }Use the full path from step 1 (on Windows, double each backslash). The desktop app doesn't always see the same PATH as your terminal.
Can't find the menu? Edit the file directly. Usually it's
%APPDATA%\Claude\claude_desktop_config.jsonon Windows and~/Library/Application Support/Claude/claude_desktop_config.jsonon macOS. Microsoft Store installs may keep it elsewhere, such as%LOCALAPPDATA%\Claude-Data\claude_<id>\. This PowerShell command finds it:Get-ChildItem $env:APPDATA, $env:LOCALAPPDATA -Recurse -Depth 3 -Filter claude_desktop_config.json. AddmcpServersnext to whatever is already in the file.Fully quit Claude Desktop (including from the system tray) and reopen it. tuya-local now appears under + → Connectors.
Make sure its switch is on there, and under + → Connectors → Tool access allow its tools (or choose Always allow the first time Claude uses one). Otherwise every light change, including ambient ones, waits for your approval.
Ambient mode works here too, in two ways:
Always on: set
TUYA_LOCAL_MCP_AMBIENTto"true"in the config above. Every chat starts with the ambient instructions, and Claude reads the local time fromlight_statuswhen the hour matters.For one chat: + → Connectors → Add from tuya-local → Ambient mode attaches the instructions, with the current time, to your message. Use it when the variable is off, or to refresh the time in a long-running chat.
The chat may load connector tools only when something in the conversation points to them, so Claude might not think of the lights unless you hint at them ("set the mood, I'm going to game"). To have it always aware, paste one line into Settings → Profile → personal preferences:
My room lights can be controlled with the tuya-local tools: set the mood on your own when the topic changes (work/study: focus, games: gaming, late night: chill).Using both the plugin and this config entry? The desktop app also hands this server to its Code tab sessions, so the plugin notices it and steps aside there: its own copy of the server registers no tools, and its ambient hook stays quiet if the entry above has ambient on. You get each tool once. The terminal claude CLI doesn't read this file, so it keeps using the plugin's copy.
What you don't get outside Claude Code: the /light shortcut (you don't need it, just ask) and the red/green test signals (there are no commands to watch in a chat).
Using the CLI
l toggle: any light on -> all off, otherwise all on
l [target] on|off|toggle
l [target] <preset> l focus · l bed night
l [target] <bri> [temp] l 40 · l setup 85 90 (brightness 1-100, temp 0 warm - 100 cool)
l [target] rgb R G B [bri] l rgb 255 0 128
l [target] sleep <time> [command] l sleep 30m · l bed sleep 1h night
l timers pending timers, with their ids
l cancel [id] cancel one timer, or all of them
l [target] status
l presets your presets, with colour previews
l lights your lights and every name that targets them
l scan look for lights whose IP changed (also automatic on errors)
l init the one-time key download (step 2)
l signal fail|pass try the red/green build signal by handDurations accept 90, 45s, 10m, 1h30m or 1.5h. Timers survive closing the terminal or Claude, and each one gets a short id you can cancel it by ([TIMER 8ee7] ... cancel: l cancel 8ee7). Out-of-range numbers are clamped with a warning. A mistyped word gets a suggestion ('focsu' ... Did you mean: focus?). The exit code is 0 on success, 1 if any light failed and 2 for a usage error, so the CLI works in scripts.
Colours turn off automatically when the output isn't a terminal or NO_COLOR is set.
Lights, zones and targets
A target picks lights. It can be:
Target | Picks |
| every light |
a zone | lights with that |
a full name |
|
a word of a name |
|
| several, comma-separated |
Matching is whole-word and case-insensitive, so s never matches by accident. An unknown target is an error that lists the valid ones; it never quietly picks some other light.
Give your bulbs short zone names by adding "zone" to their entries in ~/.config/tuya-local-mcp/devices.json:
{ "name": "Lámpara de noche", "zone": "bed", "id": "...", "key": "...", "ip": "192.168.1.52", "version": "3.3" }Presets and scenes
Presets live in ~/.config/tuya-local-mcp/presets.json and are re-read on every command, so edits apply at once. Until you save your own, a built-in set is used (code, chill, night, cyber, red, focus, gaming, movie).
A preset is one setting for whatever you target:
{
"chill": { "temp": 0, "brightness": 20, "description": "Dim, warm and relaxed" },
"cyber": { "rgb": [255, 0, 255], "brightness": 90 }
}A scene gives each target its own setting:
{
"focus": {
"targets": {
"ceiling": { "on": false },
"setup": { "temp": 90, "brightness": 85 },
"bed": { "temp": 0, "brightness": 15 }
}
}
}Settings accept on, brightness (1-100), temp (0-100) and rgb ([r, g, b], 0-255). Use either temp (white) or rgb (colour), not both. A target narrows a scene: l bed focus applies only focus's bed setting. Scene targets that match none of your lights are skipped and reported.
A broken preset is skipped with a warning; it never takes the others down with it. Claude can also create, edit and delete presets for you.
Claude Code features
/light
/light focus
/light bed 20
/light fireplace vibe on the desk
/light apaga todo en media hora
/light save this as "reading": warm, 60%It maps any phrasing, in any language, to a single tool call, with no status lookups first, and replies with one line in the CLI's format. Plugin skills can also be invoked as /tuya-local:light.
Build and test signals
What happens | The lights |
A test or build command Claude runs fails | turn red (their previous state is saved) |
It passes again | flash green for 4 s, then go back to exactly how they were |
It passes and nothing had failed | don't change, so green runs don't flicker |
This uses Claude Code hooks, so it works every time and costs no tokens. Recognised commands include pytest, tox, jest, vitest, npm|pnpm|yarn|bun test/build, cargo, go, make, gradle, mvn, dotnet, tsc, mypy, pyright, swift, xcodebuild and docker build. If a red state is older than 3 hours, the next pass leaves your lights alone instead of restoring something stale.
Ambient mode
When enabled, Claude gets a short instruction at the start of each session: shift to focus during long debugging, to cyber or gaming for creative work, and to chill or night late at night. It does this at most once per task, silently, with at most a [LIGHT: focus] tag at the end of a reply. It's off by default.
Options (/config → tuya-local)
Option | Default | |
Build/test signals | on | turn the red/green signals on or off |
Signal lights |
| which target shows them, e.g. |
Signal commands (regex) | built-in list | your own regular expression for "test or build" commands |
Ambient mood | off | let Claude set the mood on its own |
Outside Claude Code, see Claude Desktop for ambient mode. Without the plugin, set the same options as environment variables: TUYA_LOCAL_MCP_SIGNALS, TUYA_LOCAL_MCP_SIGNAL_TARGET, TUYA_LOCAL_MCP_SIGNAL_COMMANDS and TUYA_LOCAL_MCP_AMBIENT. To use the hooks without the plugin, copy the entries from plugin/hooks/hooks.json into your settings.json.
MCP tools
Tool | Does |
| on / off / group toggle |
| apply a preset or scene, or set values |
| what each light is doing now, plus the local time |
| lights, zones, the names that target them, IPs, presets |
| manage presets.json, with validation |
| see and cancel pending timers |
| find moved lights and save their new IPs |
The server also offers an ambient_mode prompt that switches ambient mode on for one conversation, in any client that supports MCP prompts.
Every result includes a one-line summary and per-light ok/error, so a failure is never reported as success.
Troubleshooting
A light is "unreachable". It's probably one of these:
The Smart Life app is open on a phone and holding the bulb's only local connection. Force-close it.
The bulb is switched off at the wall. Bulbs can't be reached without power.
Its IP changed. This is fixed automatically (the light is found by its broadcast and the new IP saved). You can also run
l scan.Firewall. Allow Python to receive UDP 6666/6667 (discovery) and connect to TCP 6668.
"Check device key or version". The bulb was re-paired in the app, which gives it a new key. Run tuya-local-mcp init again.
The signals don't fire. Check ~/.config/tuya-local-mcp/hook.log. Every signal and every error is logged there. Make sure tuya-local-mcp is on the PATH that Claude Code sees, and try l signal fail / l signal pass by hand.
How fast is it? About 0.3-0.5 s per command, end to end. Most of that is Python starting and the bulb acknowledging the message (~200 ms on typical bulbs). Through the MCP server the process is already running, so only the bulb's time is left.
Security
Bulb keys and Tuya cloud credentials stay in
~/.config/tuya-local-mcp/, outside any repository. SetTUYA_LOCAL_MCP_HOMEto use another folder.Files there are written atomically, so a crash can't corrupt them.
After the one-time setup, nothing talks to the internet. You can even revoke the Tuya cloud project.
This repository's
.gitignoreexcludes every file the wizard creates, in case you run it in the repo by mistake.
Development
git clone https://github.com/meow-dot-py/tuya-local-mcp
cd tuya-local-mcp
uv sync
uv run pytest # uses fake bulbs; no hardware or network needed
uv run ruff check . && uv run ruff format --check .To use your working copy everywhere while you hack on it: uv tool install --editable .
To test the plugin from the repo without installing it: claude --plugin-dir ./plugin.
Each module has one job and a docstring that explains it. Start with src/tuya_local_mcp/__init__.py for the map.
License
MIT © 2026 Johann 'M' Nestorida. Built on tinytuya and the MCP Python SDK. Not affiliated with Tuya.
This server cannot be deployed
Maintenance
Related MCP Connectors
Yeelight device discovery, state, control, and scene execution.
Manage your IoT device fleet directly from Claude. Create device templates with datastreams and events, provision new devices, read live sensor data, and control outputs. The Blynk connector integrates with the Blynk IoT platform, enabling direct configuration and monitoring of connected devices and infrastructure.
Control your existing Philips lights, Sonos speakers, Roborock vacuums and other supported devices through Port OS cloud. Give ChatGPT, Claude and other MCP-compatible assistants access to the devices you connect. Turn off the living room lights, play music on your speakers, adjust the thermostat, run a vacuum in a room, check a camera snapshot or find a connected tracker. Available actions depend on your linked provider accounts and each device’s supported capabilities. Port OS runs in the cloud; no local server is required. You choose the account, device and capability permissions each assistant receives. Device operations require user OAuth; public tool discovery does not grant device access. Port OS is in alpha. Setup: https://portoperatingsystem.com/docs/getting-started/ Support: https://portoperatingsystem.com/contact/
Yeelight home metadata and guarded management workflows.
Related MCP Servers
- AlicenseAqualityFmaintenanceEnables AI assistants to control Tuya/Smart Life smart home devices via tools like on/off, brightness, color, and custom commands.1061 PyPI1MIT
- AlicenseAqualityDmaintenanceEnables control of Philips Hue lights via Bluetooth LE directly from Claude, without requiring a Hue Bridge or internet connection.81MIT
- FlicenseNot gradedqualityDmaintenanceEnables Claude Desktop to control Lutron Caseta smart lighting systems locally, including turning lights on/off, setting dimmer levels, and activating scenes.-
- AlicenseAqualityBmaintenanceEnables local network control of Tuya and Smart Life smart home devices without cloud round-trips, including power, brightness, color, and raw datapoint operations.9MIT