Skip to main content

deco-local

Local control of TP-Link Deco mesh routers: no cloud, no app. A Python library, a small CLI, and an MCP server so Claude (or any MCP client) can look at your mesh and, carefully, change it.

(an illustration)
You:     Which of my Deco nodes is on wireless backhaul, and how good is its link?
Claude:  (mesh_overview) One node is: "Attic", an M5 hanging off "Hallway" over 5 GHz and
         2.4 GHz, both at signal 2 of 3. The other four are wired. Attic has 3 clients...

What it does that others don't

  • Two interfaces, one answer. The Deco has a control port (the TMP protocol the app uses, SSH on port 20001) and a local web interface on port 80. The control port can do far more, but it locks up: for 60-90 s after every write, and sometimes much longer. When it does, the reads the web interface also offers (nodes, clients, WAN, CPU/memory) come from there instead, reshaped into the same names and fields. Every read says which interface answered.
  • Writes are graded by evidence. Each write is verified (proven live with a before/after read-back), upstream (seen in real app captures by pydeco-tmp, not re-tested), noop (proven to ACK and do nothing, like HomeShield's toggle) or inferred (an opcode-numbering guess). Anything not verified is refused unless you opt in, and every write returns the router's read-back, not just its ACK.
  • It knows the router's moods. After a write the router drops the control port for ~60-90 s. Connecting during that window keeps it shut longer, so a shared lockout makes every caller on the machine (MCP server, scripts) wait instead of hammering it.
  • Safe to hand to an AI. Secrets are redacted by default, refusals say why (so the model asks you instead of guessing), and DECO_MCP_READONLY=1 gives a server with no write tools at all, for anything unattended.

Tested on

  • Deco X55 (hardware 1.0, firmware 1.11.1) as the main router, with M5 satellites.

The control port is on the main Deco only; it reports the whole mesh. Other Deco models very likely speak the same protocol (the app is the same), but they haven't been tried. If you try one, please open an issue with what worked.

Credentials

The control port logs in with your TP-Link account email and password, the ones you use in the Deco app. The Deco checks them itself, locally; nothing is sent to TP-Link's cloud. The web interface uses the same password on app-managed Decos (DECO_WEB_PASSWORD if yours differs).

Variable
DECO_HOST the main Deco's LAN address (default 192.168.68.1, the Deco default)
DECO_EMAIL TP-Link account email
DECO_PASSWORD TP-Link account password
DECO_WEB_PASSWORD optional, if the web interface password differs
DECO_MCP_READONLY 1 for a read-only MCP server
DECO_STATE_DIR optional; lockout state and the web session (default ~/.local/state/deco-local)

Use it with Claude

Needs uv (uvx runs it without installing anything permanently).

Claude Code:

claude mcp add deco -e DECO_HOST=192.168.68.1 -e DECO_EMAIL=you@example.com -e DECO_PASSWORD='...' \
  -- uvx --from git+https://github.com/ukbodypilot/deco-local deco-mcp

Add -e DECO_MCP_READONLY=1 for a read-only server.

Claude Desktop: Settings, Developer, Edit Config, and add:

{
  "mcpServers": {
    "deco": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/ukbodypilot/deco-local", "deco-mcp"],
      "env": {
        "DECO_HOST": "192.168.68.1",
        "DECO_EMAIL": "you@example.com",
        "DECO_PASSWORD": "...",
        "DECO_MCP_READONLY": "1"
      }
    }
  }
}

Leave out DECO_MCP_READONLY if you want Claude to be able to change settings. It will still refuse unverified writes unless you say so.

Things to ask:

  • "Give me an overview of my mesh." / "Which node is my laptop on, and how's its signal?"
  • "Is any node on wireless backhaul? How strong is it?"
  • "What firmware are my Decos on?" / "Show my DHCP reservations and port forwards."
  • "Which clients are on 2.4 GHz?" / "What DNS servers is the router using?"
  • "Turn the LED night mode on." (a verified write: Claude reads the setting, changes one field, writes it, and shows you the read-back)

Tools

Tool
mesh_overview nodes (online, backhaul, signal, upstream, firmware, client count) and online clients (node, band, signal)
get_router_data one named read, secrets redacted; falls back to the web interface where it can
list_reads every read name, and which the web fallback covers
lockout_status whether the router is still applying a write (no router contact)
get_router_data_unredacted a read with secrets included (not in read-only mode)
router_snapshot every read in one paced pass, over a minute (not in read-only mode)
list_writes every write with its tier and note (not in read-only mode)
write_router_setting a write, with the read-back (not in read-only mode)

Library

from deco_local import DecoClient, WRITE

with DecoClient("192.168.68.1", "you@example.com", "password") as deco:
    nodes = deco.get("device_list")["device_list"]
    led = deco.get("led_schedule")
    deco.set("led_set", dict(led, enable_night_mode=True), confirm=True)  # verified write
    print(deco.get("led_schedule")["enable_night_mode"])                  # read it back
# the control port is now locked ~60-90 s; deco_local.busy.wait() blocks until it is back

from deco_local import web
reads = web.snapshot("192.168.68.1", "password", ["device_list", "client_list"])  # web interface

DecoClient.set needs confirm=True, and allow_unverified=True for anything but a verified write. Reads come back in the router's own shapes; deco_local/tmp.py lists every read and write.

CLI

deco reads                      # every read name
deco writes                     # every write and its tier
deco read device_list wps       # over the control port (JSON)
deco read --web client_list     # over the web interface
deco status                     # post-write lockout (no router contact)

The CLI only reads. Writes go through the library or the MCP server.

Writes: what's known

Only led_set is verified so far. 12 more are upstream (seen in app captures, including UPnP, DoH, DHCP reservations, DDNS, IPv6, WPS, 802.11r, DNS servers), one is a proven no-op, and the rest are guesses from the opcode numbering. Verifying one is simple and the most useful contribution: read the setting, write a harmless change, read it back, write the original back, and open an issue or PR moving it to verified, with your model and firmware. Avoid WAN-affecting ones (ipv6_set, internet_backup_set, mac_clone_set, operation_mode_set) unless you can get to the router another way if it goes wrong.

The lockout

Measured on the X55: a write ACKs and reads back within ~3 s; then the control port closes ~5-14 s later and stays closed until ~64-95 s after the write. Probing every 0.5 s kept it shut longer, so the watcher probes every 5 s. The control port has also been seen to stay closed for 45+ min after a node reboot from the app, while the web interface kept working; that is what the fallback is for. The lock is a small state file, so every process on the machine respects it. A short-lived script's watcher dies with it; the lock then simply expires after 150 s.

No warranty

This talks to your router with undocumented protocols. Reads are harmless; writes change real settings, and unverified ones may do something unexpected. MIT licensed, as is.

Credits

Built on two projects' protocol work. No code from either is used here; the clients are reimplementations from their descriptions:

  • mthsg/pydeco-tmp (MIT): the Deco TMP protocol (SSH transport, framing, login, opcode tables) and the app-capture list behind the upstream tier.
  • tplinkrouterc6u (GPL-3.0): the encrypted login of TP-Link's local web interface. Compared line by line: no code in common, only the protocol.

License

MIT

Metadata

Release files for deco-local 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for deco-local 0.1.0
File Size Uploaded Provenance
deco_local-0.1.0.tar.gz 24.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for deco-local 0.1.0
File Interpreter ABI Platform
deco_local-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 51.8 kB

Release files / deco_local-0.1.0.tar.gz

Download URL deco_local-0.1.0.tar.gz
Size 24.5 kB
Tags Source
SHA-256 checksum
How to use checksums
607259f26c0ca2a61f17241620320ffbab9f16c6bc7454ffe4bfa86da7bcd0d0
BLAKE2b-256 checksum
How to use checksums
78bd3cade09896a87da23d0d78e70f06b3c563e08b376989f6cffdf216ae00d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / deco_local-0.1.0-py3-none-any.whl

Download URL deco_local-0.1.0-py3-none-any.whl
Size 27.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bda515c21806ccdd3baec11f364a1ca205f4855aa3abce3146b9ab206303d206
BLAKE2b-256 checksum
How to use checksums
328dd43a3d8d92e8a473ce2ca92ede527a558a8b8540de22beb13cb7b22cbd6b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Security for deco-local 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for deco_local-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page