tuya-local-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@tuya-local-mcpturn on the living room lamp"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
tuya-local-mcp
An MCP server that controls Tuya / Smart Life smart home devices over your local network. Once set up, no request touches Tuya's cloud — commands go straight to the device on your LAN, so they keep working with the internet down and aren't subject to cloud API rate limits.
Built on tinytuya.
The one catch, up front
"Local control" still requires one trip through Tuya's cloud. Each device has a 16-character local_key that's provisioned during pairing and is never broadcast on the network — you can't sniff it, derive it, or guess it. You fetch it once from the Tuya IoT Platform, and after that everything is local, forever.
There is no way around this short of reflashing the hardware with ESPHome or Tasmota. If you'd rather avoid the developer-console setup entirely, use a cloud-based Tuya MCP server instead; this project won't save you that step.
Related MCP server: mcp-server-tuya
Install
Requires Python 3.10+.
git clone https://github.com/ethanj2k/tuya-local-mcp
cd tuya-local-mcp
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .Setup
1. Check your devices are visible
Before touching any credentials, confirm the devices are actually reachable. This listens for the UDP beacons Tuya devices broadcast every few seconds and sends nothing:
python scripts/passive_scan.py 153 device(s):
192.168.1.50 udp/6667 beacons=3 proto=3.3 id=bf0000000000000000aaaa
192.168.1.51 udp/6667 beacons=2 proto=3.4 id=bf0000000000000000bbbb
192.168.1.52 udp/6667 beacons=3 proto=3.3 id=bf0000000000000000ccccNo output? See Troubleshooting discovery — on Windows the usual cause is the firewall, not the devices.
2. Get your local keys
Create an account at iot.tuya.com.
Cloud → Development → Create Cloud Project. Pick the data centre matching your region and "Smart Home" as the industry.
In the project, Devices → Link App Account and scan the QR code with the Smart Life / Tuya Smart app. This imports the devices you already own.
Grab one device's Virtual ID from the app: tap the device → pencil icon → Device Information. tinytuya needs one id to bootstrap the list.
Fetch the keys. Either the stock interactive wizard:
python -m tinytuya wizard…or the non-interactive fetcher bundled here, which takes the same inputs from a .env file. Useful in containers, CI, or anywhere a prompt is awkward:
cp .env.example .env # fill in the four values
python scripts/fetch_keys.pyquerying Tuya Cloud (region us)...
cloud returned 6 device(s), 6 with a local key
listening 20s for LAN addresses (transmitting nothing)...
matched 6 device(s) to a LAN address
wrote devices.json (contains local keys - do not commit)
Living Room Lamp 192.168.1.50 v3.3 key=yes
Desk Plug 192.168.1.51 v3.4 key=yesEither way you end up with devices.json. It contains your local keys — never commit it. This repo's .gitignore already excludes it, along with .env.
3. Point the server at the file
The server looks for snapshot.json then devices.json in the current directory, your home directory, and ~/.tinytuya/. Override with TUYA_DEVICES_FILE.
4. Wire it into your MCP client
{
"mcpServers": {
"tuya-local": {
"command": "/absolute/path/to/.venv/bin/python",
"args": ["-m", "tuya_local_mcp"],
"env": {
"TUYA_DEVICES_FILE": "/absolute/path/to/devices.json"
}
}
}
}On Windows the command is C:\\path\\to\\.venv\\Scripts\\python.exe.
Tools
Tool | Writes? | Description |
| no | Every device in the registry — names, ids, IPs, protocol versions. Local keys are never returned. |
| no | Passively listen for devices broadcasting on the LAN. Flags any not in your registry. |
| no | Read one device's datapoints, plus a decoded reading of the common ones. |
| no | Read every device; per-device errors don't fail the whole call. |
| yes | Turn a device on or off. |
| yes | Set a light's brightness, 0–100%. |
| yes | Set a light's colour from hex ( |
| yes | White mode at a colour temperature, 0 (warm) to 100 (cool). |
| yes | Write a raw datapoint — the escape hatch for fans, curtains, valves, heaters. |
Devices are addressed by friendly name, device id, or IP. Name matching is case-insensitive and accepts unique substrings, so "desk" finds "Desk Plug". Ambiguous matches raise an error listing the candidates rather than picking one.
Read-only mode
Set TUYA_READ_ONLY=1 and every write tool refuses. Discovery and status reads still work. Useful when you want an assistant that can answer "is the garage light on?" without being able to act, or while you're still building trust in a setup.
Configuration
Variable | Default | Meaning |
| auto-detected | Path to |
|
|
|
|
| Per-device socket timeout, seconds. |
|
| Seconds to cache status reads. |
|
| Default listen window for |
Troubleshooting discovery
If passive_scan.py hears nothing, work down this list before concluding the devices are offline.
Windows: allow the base interpreter, not the venv one. This is the single easiest thing to lose an hour to, and the obvious fix is the wrong one.
Windows Firewall allows inbound traffic per program path. A venv's Scripts\python.exe on Windows is only a shim — the process that actually binds the socket is the base interpreter it was created from. So a rule naming .venv\Scripts\python.exe matches nothing, and your scan stays empty with no prompt and no error.
Confirm the real image path of whatever interpreter you're running:
.\.venv\Scripts\python.exe -c "import ctypes,sys; b=ctypes.create_unicode_buffer(1024); ctypes.windll.kernel32.GetModuleFileNameW(None,b,1024); print('reported:',sys.executable); print('actual :',b.value)"reported: C:\...\project\.venv\Scripts\python.exe
actual : C:\Users\you\AppData\Local\Programs\Python\Python313\python.exeWrite the rule against the actual path (elevated PowerShell):
New-NetFirewallRule -DisplayName "Tuya LAN discovery" -Direction Inbound `
-Program "C:\Users\you\AppData\Local\Programs\Python\Python313\python.exe" `
-Protocol UDP -LocalPort 6666,6667,7000 -Action AllowBecause the rule lands on the base interpreter, it applies to every venv built from that install — convenient, but worth knowing you're opening those ports for all of them.
To see which interpreters are already allowed:
Get-NetFirewallApplicationFilter | Where-Object { $_.Program -like '*python*' } |
ForEach-Object { $_.Program }Note this only affects discovery. Device control is outbound TCP on port 6668 and works fine without any inbound rule — so a blocked scan does not mean a broken install. If your registry already has current IPs, everything else works.
Devices on another network segment. Beacons are broadcast and do not cross subnets or VLANs. IoT devices parked on a guest network won't be visible from your main one.
Another listener holds the ports. Home Assistant, a second copy of this script, or tinytuya's own scanner will contend for UDP 6666/6667. passive_scan raises if it can't bind anything.
Beacons are periodic. A 5-second window can genuinely miss a device. Try 30 seconds before worrying.
Notes and known limits
Protocol 3.4 / 3.5 devices use a session-key handshake rather than the local key directly. tinytuya supports them, but they're less battle-tested than 3.3 — if exactly one device misbehaves, check its version first.
Local keys rotate whenever a device is removed and re-paired in the app. Symptom is error 914; fix is re-running the wizard.
One connection at a time. Most Tuya devices accept a single TCP connection, so this server opens and closes a socket per call rather than holding one open. If a call times out, check nothing else (Home Assistant, another script) is polling that device continuously.
Datapoint numbering is per-product. The bulb helpers cover the two common layouts (datapoints 1–5 on older bulbs, 20–24 on newer). For anything else, get_status shows the raw datapoints and set_datapoint writes them.
Discovery is best-effort. Beacons are periodic, so a short listen window may miss devices that are simply between broadcasts. Increase the timeout rather than concluding a device is offline.
Development
pip install -e ".[dev]"
pytestThe test suite runs entirely offline — no device, no network, no credentials. It includes a guard test asserting that passive_scan never calls send, sendto, sendall, or connect on a socket.
License
MIT
Available Tools
9 toolsdiscover_devicesA
Passively listen for Tuya devices broadcasting on the local network.
This transmits nothing - it only receives the beacons devices emit every few seconds. Useful for finding a device whose IP has changed, or for spotting devices that are on the network but missing from the registry.
| Name | Required | Description | Default |
|---|---|---|---|
| timeout | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden. It explicitly states the tool 'transmits nothing' and only receives beacons, which is important safety and side-effect information. However, it does not explain the behavior or purpose of the timeout parameter, which is the tool's only configuration.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-structured: the core action is front-loaded in the first sentence, the passive behavior is clarified in the second, and the practical use cases are given in the third. Every sentence adds distinct value with no redundant wording.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple and has an output schema, so return values are already covered. However, the sole parameter 'timeout' is entirely undocumented in both the schema and the description, leaving a meaningful gap in what the agent needs to know to invoke the tool correctly. The use cases help, but this missing parameter semantics makes it incomplete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides only the name 'timeout' with no description, and schema description coverage is 0%. The description never mentions the timeout parameter at all, so an agent cannot know what it controls, what its units are, or what happens if it is null. This is a critical gap because it is the only parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('listen'), a precise resource ('Tuya devices broadcasting on the local network'), and a distinctly passive mechanism ('it only receives beacons'). This differentiates it clearly from sibling tools like list_devices, which imply a registry query rather than active network discovery.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives concrete use cases: finding a device whose IP changed, or discovering devices missing from the registry. It does not explicitly name an alternative or say when not to use it, but the context strongly implies this is the discovery tool as opposed to the registry-based list_devices.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_all_statusA
Read the state of every device in the registry.
Devices that fail are reported individually rather than failing the call, so one offline device does not hide the rest.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It reveals a key behavior: failures are reported individually rather than failing the call, which is valuable. However, it does not mention response format (though output schema exists), potential latency, or any side effects, leaving the safety profile somewhat implicit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero wasted words. The primary purpose is front-loaded, and the second sentence adds a critical behavioral note. Efficient and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists and there are no parameters, the description covers the core purpose and a key failure mode. It does not explicitly differentiate from list_devices or get_status, but the name and description make the distinction clear enough. The only minor gap is explicit usage routing, which is already scored under usage_guidelines.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, and the input schema is empty. The description correctly focuses on the operation itself. With no params, the baseline is 4, and the description adds no unnecessary parameter information.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Read'), a clear resource ('the state of every device in the registry'), and a scope (all devices). This distinguishes it from siblings like get_status (single device) and list_devices (likely just identifiers) without needing to open schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies its use case: retrieve the state of all devices at once, contrasted with single-device tools. However, it does not explicitly name alternatives or state when NOT to use it, leaving some inference to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_statusA
Read the current state of a device.
device may be a friendly name, a device id, or an IP address. Returns the
raw Tuya datapoints plus a best-effort interpretation of the common ones.
| Name | Required | Description | Default |
|---|---|---|---|
| device | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full disclosure burden. It discloses the read-only nature ('Read'), the return format (raw Tuya datapoints plus best-effort interpretation), and the three accepted device identifier forms. It does not cover error behavior, what 'best-effort' means, or network/auth implications, but this is adequate for a simple read tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the core purpose front-loaded. The code-formatted note packs parameter formats and return behavior with zero filler. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values are already covered; the description adds the raw-vs-interpreted distinction on top. For a single-parameter read tool this is nearly complete — the only gap is explicit routing between get_status and get_all_status.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% — the `device` parameter has no schema description. The description fully compensates by specifying that device may be a friendly name, a device id, or an IP address, adding meaning well beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb+resource pair — 'Read the current state of a device' — which clearly differentiates it from the set_* write siblings. The phrase 'a device' implies single-device scope, distinguishing it from get_all_status, though it doesn't name that sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied: read a specific device's state. However, there is no explicit guidance on when to choose this over get_all_status, and no alternatives or exclusions are named. An agent must infer the single-vs-all distinction from the word 'a device'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_devicesA
List every Tuya device in the local registry.
Returns names, device ids, IPs and protocol versions. Local keys are never
returned. Use the name field when calling the other tools.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations are absent, so the description carries the full burden for behavioral disclosure. It explicitly states that local keys are never returned, which is a security-relevant behavior important for the agent to know. It also mentions the return fields (names, device ids, IPs, protocol versions), but does not mention potential side effects (none likely) or performance implications. Given it is a read-only list operation, this is adequate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is brief (three sentences) and front-loaded with the main purpose. It immediately states what the tool does, then describes the output, and ends with a practical tip for using the results. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has no parameters and an output schema, the description covers all essential aspects: what it lists, what fields are returned, and a crucial privacy note (local keys never returned). It is complete for an agent to invoke correctly without further information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters, and the schema has no properties, so the description has all the responsibility. It does not need to explain parameters, but it does describe the output content, which is a substitute. Since there are no parameters, the description is sufficient, and the baseline of 4 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states what the tool does: 'List every Tuya device in the local registry.' It specifies the resource (devices) and the scope (local registry), and it is distinct from siblings like discover_devices, which likely handles network discovery rather than listing an existing registry.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides clear context for when to use the tool: listing devices from the local registry, and it notes that the returned 'name' field is used when calling other tools, which implicitly suggests this is a prerequisite for other operations. It doesn't explicitly contrast with discover_devices but the mention of 'local registry' vs 'discover' implies the distinction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_brightnessA
Set a light's brightness as a percentage (0-100).
| Name | Required | Description | Default |
|---|---|---|---|
| device | Yes | ||
| percent | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It only states the basic effect, but doesn't mention side effects, failure modes, prerequisites (e.g., device must be a dimmable light), reversibility, or return behavior. This is a significant gap for a mutation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence with no filler. It states the action, target, and value range efficiently, earning its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The output schema exists, so return values are presumably covered. However, the description lacks guidance on edge cases (device not found, non-dimmable device), prerequisites, or when to prefer this over set_datapoint. It is minimally adequate for a simple tool but leaves room for agent error.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description compensates partially: it clarifies that 'percent' is a percentage 0-100 and implies 'device' identifies a light. However, it doesn't explain how device is addressed (e.g., ID vs name) or whether percent accepts any integer outside 0-100.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Set'), resource ('a light's brightness'), and value range (0-100), making it instantly distinguishable from sibling tools like set_power, set_color, and set_color_temp. An agent can understand exactly what this tool does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies use when adjusting brightness ('Set a light's brightness'), but provides no explicit when/when-not guidance or comparison to alternatives. It doesn't mention that this applies only to dimmable lights or that other set_* tools exist for different properties.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_colorA
Set a light's colour from a hex string such as '#FF8800' or 'f80'.
| Name | Required | Description | Default |
|---|---|---|---|
| color | Yes | ||
| device | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure, but it only states the basic mutation 'Set'. It does not mention side effects such as changing color mode, turning the light on, invalid hex handling, device reachability, or reversibility.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no wasted words. The action is stated first, and the format examples are compact and immediately useful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter setter with an output schema, the core call is understandable, but the description is not fully self-contained. It lacks guidance on device identifier provenance and important behavioral caveats, though the low complexity and clear color format keep it minimally viable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema only provides parameter names with no descriptions, so the description adds real value by specifying that color is a hex string and giving examples like '#FF8800' and 'f80'. It also clarifies that device refers to a light, though it doesn't explain where the device identifier comes from.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly names the verb 'Set', the resource 'a light's colour', and the input format 'hex string'. It is immediately distinguishable from siblings like set_brightness, set_power, and set_color_temp because it is specific about color and hex encoding.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no explicit guidance on when to use this tool instead of set_color_temp, set_brightness, or set_power, and no prerequisites are mentioned. Usage is only implied by the action of setting a color, so an agent gets no direction about alternatives or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_color_tempA
Set a light to white mode at a colour temperature percentage (0 warm, 100 cool).
Optionally set brightness in the same call.
| Name | Required | Description | Default |
|---|---|---|---|
| device | Yes | ||
| percent | Yes | ||
| brightness | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It discloses the key behavior: setting white mode and the temperature scale (0 warm, 100 cool). However, it doesn't mention what happens to the light's current color, whether the light must be on, or any side effects. The description is honest but minimal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core action and scale. The optional brightness note is a useful addition without bloat. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 3-parameter tool with an output schema, the description covers the essential semantics. It lacks explicit notes on edge cases (e.g., invalid percent values, behavior when brightness is null) but these are minor given the schema's defaults and the tool's simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explains the 'percent' parameter's meaning (0 warm, 100 cool) and that 'brightness' is optional. It doesn't explain 'device' but that's self-evident from the name and sibling context. The description adds meaningful semantics beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: setting a light to white mode at a color temperature percentage, with a specific range (0 warm, 100 cool). It also mentions an optional brightness parameter. This distinguishes it from siblings like set_color (which likely sets RGB/color) and set_brightness (which only sets brightness).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool: when you want to set a light to white mode with a specific color temperature. It doesn't explicitly state when not to use it or name alternatives, but the sibling list and the clear scope (white mode + temperature) provide enough context. The optional brightness note also clarifies a combined use case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_datapointA
Write a raw Tuya datapoint.
The escape hatch for products whose datapoints the helper tools do not cover - fans, curtains, heaters, valves. Call get_status first to see which datapoints a device exposes and what types they hold.
| Name | Required | Description | Default |
|---|---|---|---|
| dp | Yes | ||
| value | Yes | ||
| device | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must disclose all behavioral traits, but it only states the mutating action ('Write') and gives a prerequisite. It does not mention potential risks, error handling, whether setting an invalid type/value is destructive, or any side effects. The phrase 'escape hatch' hints at advanced use but is not an explicit warning.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is brief and to the point. The core purpose is in the first sentence, and the usage guidance is concise. No extraneous words or redundant details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
It provides the critical prerequisite (get_status) and contextualizes the tool as a fallback, which is helpful. However, it omits details about error handling, what the output schema returns (though an output schema exists), and any cautionary notes about irreversible changes. For a raw write tool, this feels incomplete but not severely lacking.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero description coverage, so the description must compensate. It mentions 'datapoints' and 'types' and advises calling get_status, which implies dp is the datapoint ID and value must match the expected type, but it does not explain the format or acceptable values for dp or value. This is insufficient for an unannotated schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action: 'Write a raw Tuya datapoint.' It also defines the scope by naming the product categories it serves (fans, curtains, heaters, valves) and explicitly positions it as an 'escape hatch' relative to helper tools, which differentiates it from the sibling setter tools like set_power and set_brightness.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly tells when to use this tool ('escape hatch for products whose datapoints the helper tools do not cover') and provides a prerequisite step ('Call get_status first to see which datapoints a device exposes and what types they hold'). This gives clear context and implies the alternative is to use the specialized setters when they apply.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_powerA
Turn a device on or off.
switch_dp overrides the datapoint carrying the relay/switch. Leave it
unset to let tinytuya pick, which is correct for the large majority of
plugs, switches and bulbs.
| Name | Required | Description | Default |
|---|---|---|---|
| on | Yes | ||
| device | Yes | ||
| switch_dp | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses the core effect (power on/off) and an implementation behavior (switch_dp override/default behavior), which goes beyond the bare schema. However, it does not mention permissions, reversibility, edge cases, or failure behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loads the main action in the first sentence. The second paragraph adds necessary parameter nuance without waste. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple three-parameter tool with an output schema, the description covers the core purpose and the one non-obvious parameter. It could briefly mention that 'device' refers to a device identifier from list_devices, but the tool name and sibling context make that inferable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explains switch_dp's override function and the recommended 'unset' default for most devices, but does not clarify the 'device' parameter beyond its name and type. 'on' is self-explanatory but still undocumented in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states an explicit action ('Turn a device on or off') on a clear resource (a device). This is distinct from sibling tools like set_brightness or set_color, which target different aspects of device control.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool by defining its function, but it does not explicitly contrast with alternatives such as set_datapoint, nor does it state when not to use it. The switch_dp guidance is parameter-level, not tool-selection-level.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
9 tool updates
v0.1.0- First observed
discover_devices - First observed
get_all_status - First observed
get_status - First observed
list_devices - First observed
set_brightness - First observed
set_color - First observed
set_color_temp - First observed
set_datapoint - First observed
set_power
TDQS
Scored across 9 tools
Each tool has a clearly distinct purpose: enumeration of registered devices (list_devices), passive network discovery (discover_devices), reading state for one or all devices (get_status/get_all_status), and distinct control actions (power, brightness, color, color temp, raw datapoint). The get_* and set_* families are parallel but not overlapping.
All tool names follow a consistent lowercase snake_case verb_noun pattern: list_devices, discover_devices, get_status, get_all_status, set_power, set_brightness, set_color, set_color_temp, set_datapoint. No mixed conventions or vague verbs.
Nine tools is well-scoped for a Tuya local control server: two device discovery/listing, two status reads, five control operations including a raw escape hatch. Each tool earns its place without redundancy or bloat.
The surface covers the core lifecycle of interacting with local Tuya devices: discovery, listing, status reading, and common control actions. The raw set_datapoint tool fills gaps for unsupported product types. A minor gap is the lack of a tool to add discovered devices to the registry or update device metadata.
Maintenance
Related MCP Connectors
Control a Loxone Miniserver smart home: lights, blinds, climate, scenes and energy.
- mytesla.ioOAuthio.mytesla
Control your Tesla from your AI assistant - climate, charging, access, and security.
Unofficial integration! ## ✨ Key Features ### 💰 Financial Intelligence - **Smart Charging Cost An…
Smart home product intelligence: 1,080+ products with expert consensus scores and compatibility.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables control of smart lights through MQTT messaging protocol, supporting operations like turning lights on/off and adjusting brightness levels from 0-100.-
- AlicenseAqualityDmaintenanceEnables AI assistants to control Tuya/Smart Life smart home devices via tools like on/off, brightness, color, and custom commands.101MIT
- AlicenseAqualityDmaintenanceEnables discovery and control of Philips Hue lighting devices via a local bridge using the CLIP v2 API, without any cloud dependency.10MIT
- FlicenseNot gradedqualityDmaintenanceEnables control of Tuvio/Tuya robot vacuum cleaners via a local hub, supporting commands such as start, pause, home, set mode, suction, water level, and more.-