Skip to content

Repository files navigation

deco-mcp

Manage TP-Link Deco mesh routers from Claude Code. A Claude Code plugin bundling an MCP server, three read-only diagnostic agents, and a skill that carries the operating knowledge.

Talks to the router's local API — no TP-Link cloud account, no outbound traffic, credentials stay on the machine running the server. Zero runtime dependencies: the MCP server and schema validation are vanilla Node, so the shipped bundle imports only node: built-ins — nothing third-party to be compromised in a supply-chain attack.

Developed and verified against a Deco M9 Plus on firmware 1.9.1.

Why

The Deco app is the only supported way to manage these routers, and it is a phone app. This exposes the same local API as MCP tools, so an agent can answer "why is the Wi-Fi slow upstairs" by reading actual mesh state instead of guessing — and so a question like "is there anything on my network I don't recognise" gets an answer grounded in the client table.

Installing in Claude Code

This is a Claude Code plugin (the CLI / desktop app) — it does not apply to claude.ai, the web chat. Installing it brings the MCP server, the three agents, and the deco-network skill together.

As a plugin, from the marketplace (recommended)

In a Claude Code session:

/plugin marketplace add fullo/claude-plugins-marketplace
/plugin install deco-mcp@fullo-plugins

That is everything: the MCP server registers itself, the three agents become available to the Task tool, and the skill is invokable as /deco-mcp:deco-network. If the install summary says Run /reload-plugins to activate, run that once.

Giving it your router credentials

The server reads two environment variables. Set them in your shell before launching Claude Code (or add them to ~/.zshrc / ~/.bashrc):

export DECO_HOST=192.168.68.1          # your Deco's address (this is the default)
export DECO_PASSWORD='your-admin-password'
claude

The plugin's .mcp.json passes them through. DECO_HOST defaults to 192.168.68.1 if unset; DECO_PASSWORD has no default and must be set. Do not commit the password anywhere.

To enable the write tools, also export DECO_ALLOW_WRITE=1 (and DECO_ALLOW_DANGEROUS=1 for node reboots) — see Capability gating.

MCP server only, without the plugin

If you just want the tools (no agents or skill), register the bundled server directly with an absolute path${CLAUDE_PLUGIN_ROOT} only expands for installed plugins, so it will not resolve for a standalone add:

claude mcp add --transport stdio deco \
  --env DECO_HOST=192.168.68.1 \
  --env DECO_PASSWORD='your-admin-password' \
  -- node /absolute/path/to/deco-mcp/bundle/deco-mcp.mjs

Confirm with claude mcp list — it should show deco ✓ Connected.

What you get

  • Tools — every deco_* tool, read-only by default, writes gated.
  • Agentsdeco-netops, deco-security, deco-optimizer, delegated to automatically or invoked with @"deco-netops (agent)".
  • Skill/deco-mcp:deco-network, the operating knowledge for the tools.

Confirm it works by asking Claude something like "give me an overview of my Deco network" — deco_overview should answer with your nodes and clients.

The commands above are current for recent Claude Code; if /plugin behaves differently in your version, check https://code.claude.com/docs.

Running on a TP-Link device

This speaks the Deco local API specifically. How far it carries to other TP-Link hardware depends on how close that hardware's protocol is. The RSA keys are fetched live at each handshake rather than hardcoded, so key differences between models are handled automatically — what varies is the endpoint surface.

Another Deco (M4, M5, X20, X50, X90, …) — supported

The login protocol is the same across the Deco line, so authentication and the core reads work out of the box. What varies is which forms a given model and firmware serves — an M9 Plus on 1.9.1 serves the web form set; a newer unit may serve the app set and expose different endpoints.

  1. Install as above, pointing DECO_HOST at the new Deco.
  2. npm run probe to confirm the credentials.
  3. Call deco_capabilities first thing. It reports the model and firmware and probes every catalogued read form, telling you which this unit actually serves. Endpoints it does not serve degrade cleanly rather than erroring.
  4. If the probe reveals useful forms not yet catalogued, add them to src/deco/catalog.ts with an honest risk tag, then npm run prepare-release. See docs/endpoints.md.

Close to plug-and-play: auth and basic reads immediately, the exact tool set confirmed by the probe.

A TP-Link Archer router — partial, needs work

The login crypto is shared across the TP-Link line — the password RSA key an Archer serves is byte-identical to a Deco's — so authentication is likely to succeed. But the endpoint and form structure differs from the Deco's, so the catalogue would need to be rebuilt against the Archer by probing with deco_call. Expect real work, not a drop-in.

Omada / EAP access points — not supported

The Omada line is managed through a controller, an entirely different model from this local API. This harness does not reach it.

Non-TP-Link (FRITZ!, UniFi, …) — not supported

No compatibility at all. A FRITZ!Box speaks TR-064 (SOAP); UniFi has its own API. Each would need a new transport client written against its protocol. The structure here — the risk-tagged catalogue, capability gating, the agents and skill — would carry over, but the wire layer would not. The project name is honest: it is for Deco.

Capability gating

The server starts read-only. Mutating tools are not merely refused — they are never registered, so an agent cannot discover a capability you did not grant, and the tool list is an accurate statement of what it may do.

Variable Grants
(default) Read everything: nodes, clients, traffic, Wi-Fi config, load
DECO_ALLOW_WRITE=1 DHCP reservations, start a speed test, block/unblock (where the firmware supports it)
DECO_ALLOW_DANGEROUS=1 Reboot nodes, rewrite Wi-Fi settings (needs ALLOW_WRITE too)
DECO_REVEAL_SECRETS=1 Include Wi-Fi passphrases in output

Wi-Fi passphrases are redacted by default. Tool output lands in an agent's context and from there in transcripts, which is the wrong place for them.

Firmware upgrade, factory reset and the cloud-account endpoints are absent from the catalogue entirely. There is no flag that reaches them.

Tools

Readdeco_overview (start here), deco_list_nodes, deco_list_clients, deco_network_status, deco_wifi_settings, deco_performance, deco_client_traffic, deco_blocklist, deco_reservations, deco_leases, deco_topology, deco_node_health, deco_guest_network, deco_band_map, deco_wired_ports, deco_channel_map, deco_qos_priority, deco_bottlenecks, deco_client_signal (per-client Wi-Fi signal), deco_radio_features, deco_network_advanced, deco_speedtest_result, deco_operating_mode (Router vs Access Point), deco_time_settings, deco_show_performance (whether the UI exposes the performance page)

Change trackingdeco_track_clients saves a baseline of connected devices; deco_whats_new reports what has arrived or left since. The automated form of "is there anything on my network I don't recognise". State is stored locally under .deco-state/.

Portabilitydeco_capabilities reports the unit's model and firmware and probes which catalogued endpoints it actually serves. Run it first on an unfamiliar Deco; the catalogue is a superset across models.

All verified against live hardware (M9 Plus, firmware 1.9.1).

Write (DECO_ALLOW_WRITE=1) — deco_reserve_address, deco_modify_reservation, deco_remove_reservation, deco_run_speedtest (starts, waits, returns the result), deco_speedtest_stop, deco_block_client, deco_unblock_client (blocking is app-only on M9 Plus 1.9.1 — see notes)

Disruptive (also DECO_ALLOW_DANGEROUS=1) — deco_reboot_node

Escape hatchdeco_catalog lists every reachable endpoint; deco_call invokes one. Both are gated by the same risk classification.

Agents

Three subagents, all read-only by design — they diagnose and recommend, and hand changes back to you:

  • deco-netops — dropouts, slow Wi-Fi, a device that will not connect. Works outside in, and separates measurement from inference.
  • deco-security — audits who is on the network. Knows that randomised MACs are privacy-conscious phones rather than intruders, which is where naive audits generate their false positives.
  • deco-optimizer — ranks tuning by actual effect: placement and backhaul first, radio settings last.

Skill

skills/deco-network/ carries the operating knowledge: which tool answers which question, when to delegate to an agent versus calling a tool directly, and the constraints that cost real disruption to learn — never retry credentials, one admin session at a time, confirm before rebooting.

What you can do with DHCP

Static reservations — full CRUD, verified. deco_reservations lists the table (64 slots); with writes enabled, deco_reserve_address adds, deco_remove_reservation removes, and deco_modify_reservation moves a reservation to a new IP. The firmware has no native modify, so that one is a remove-then-add composite with rollback — if the add fails, the old reservation is restored. All verified by round trips against the live router.

DHCP server configuration — not manageable, no workaround. The pool range (start/end IP), the DNS servers handed to clients, and the lease time live at /admin/dhcp, which this firmware serves only to the mobile app (it answers No root node was registered locally). There is no local-API path to these; use the Deco app.

Active leases are not exposed as a raw table (lease is app-only), so deco_leases synthesizes one: it merges the connected-client list with the reservation table into a per-IP view marking each address static or dynamic and online or offline. No lease expiry times (the firmware does not expose them), and an offline device appears only if it holds a reservation.

Notes worth knowing

  • One admin session at a time. The firmware evicts the previous session on login, so this server and the Deco app fight over it. Expect HTTP 403 while the app is open.
  • Failed logins lock the account after about ten attempts. A wrong password burns one per call — fix it rather than retrying.
  • deco_block_client does not work on M9 Plus 1.9.1. Verified against a real connected client: every parameter shape is rejected, and this firmware's web form set has no blocking feature — it is app-only. Reading the blocklist works; the writes do not. The tools stay for Deco models that serve the app form set (check with deco_capabilities).
  • Transient timeouts are normal: a laptop roaming between mesh nodes drops the request. The client retries twice with a short backoff.
  • Client throughput counters are KB/s, and are rendered as bit rates.
  • The login encryption is cosmetic. TP-Link hardcodes one RSA keypair across the product line and ships the private half in firmware, which has been public on GitHub for years. Anyone already on your LAN can recover the admin password from a captured login. Do not reuse that password elsewhere. See docs/protocol.md.

Documentation

docs/protocol.md The wire protocol: crypto envelope, handshake, the details reimplementations get wrong
docs/endpoints.md What this firmware serves, what it does not, and how to extend the catalogue
docs/troubleshooting.md Error messages, causes, fixes
docs/distribution.md Installing, local development, releasing

Development

npm run typecheck
npm test                # builds, then runs the unit tests
npm run bundle          # rebuild the shipped bundle
npm run prepare-release # typecheck + test + bundle
npm run probe           # connect to the real router and print the mesh

scripts/verify-envelope.ts proves the crypto against a live router without the real password: it logs in with a deliberately wrong one, and a decryptable -5002 reply means the signature and AES envelope were accepted. It costs one failed login attempt, so do not loop it.

Licence

MIT.

About

Manage TP-Link Deco mesh routers from Claude Code over the local API — MCP server + 3 diagnostic agents + skill. Zero runtime deps.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages