Skip to content
Blueprint / referenceLocal-firstPythonMCP

tapo-mcp-server

A local-first MCP server blueprint that exposes your Tapo smart lights to MCP-compatible clients. It keeps device credentials and control on the local network, and ships a clean separation between MCP tools, device adapters, an effects engine, and configuration.

Read the blueprint

This site documents a proposed, reference implementation. It is not a claim of live device connectivity or of support for every Tapo model. Exact library and API compatibility should be verified against your own devices and firmware.

01

Overview

Local-first

The server runs on your machine and talks to lights over your LAN. Credentials and control never leave the local network.

MCP-native

Typed tools are exposed over stdio transport, so any MCP-compatible client can discover and control the lights.

Blueprint

A clean, production-minded reference layout you can adapt, with clear seams between tools, devices, effects, and config.

The goal is a small, solid server you can drop into a local codebase or run directly on a Windows machine. It targets five lights: three LED strips and two bulbs. Everything below is the proposed design - treat it as a starting point, not a finished product.

02

Hardware

The blueprint is scoped to exactly five devices: three L900 LED strips and two L530 bulbs, at the addresses below.

Inventory

Device inventory
DeviceKindHost / IP
L900-3Strip192.168.1.139
L900Strip192.168.1.179
L900-2Strip192.168.1.82
L530-2Bulb192.168.1.129
L530Bulb192.168.1.97

Topology

Local network only

MCP client

Claude, Cursor, etc.

tapo-mcp-server

Python · stdio transport

Tapo devices

3 strips + 2 bulbs

The client talks to the server over stdio (local JSON-RPC). The server talks to the lights over the LAN using the chosen device library. No cloud round-trip for control, and credentials stay on the machine.

03

Architecture

Layers are kept separate so you can swap a backend or extend an effect without touching the rest.

1

MCP tools

FastMCP exposes typed functions as tools over stdio. Thin layer - no device logic here.

2

Controller

Orchestrates devices and effects, validates inputs, and maps errors to clean results.

3

Device adapters

A common adapter interface with swappable backends: kasa, tapo, or an in-memory mock.

4

Effects engine

Runs strobe, pulse, and BPM sync as cancellable tasks with rate limiting.

5

Cross-cutting

Config validation, secret-redacting logs, retries, timeouts, and graceful shutdown.

Every device call passes through a bounded-concurrency limiter, a per-second rate limiter, retries with backoff, and a timeout, so even a fast effect cannot overwhelm the lights or the network.

04

Setup

Example steps for getting the server running locally. IPs and credentials are placeholders - never hardcode secrets.

Create an environment

terminal
python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate

Install dependencies

terminal
pip install -r requirements.txt
# Backend libraries (pick the one you use):
# pip install python-kasa   # or python-tapo

Configure environment

Set device hostnames/IPs and credentials through environment variables. Keep secrets out of committed files.

.env.example
# Copy to .env and fill in your real values
TAPO_USERNAME=you@example.com
TAPO_PASSWORD=change-me

# Device addresses
L900_3_IP=192.168.1.139
L900_IP=192.168.1.179
L900_2_IP=192.168.1.82
L530_2_IP=192.168.1.129
L530_IP=192.168.1.97

Discover devices

The server reads addresses from config. To find them, check your router's DHCP client list, or use the library's discovery helper on the LAN.

terminal
# python-kasa discovery on the local network
python -m kasa discover

Run the server

terminal
python -m tapo_mcp
# Without hardware, try the in-memory mock backend:
python -m tapo_mcp --mock
Compatibility note: exact library and API behavior can vary by your Tapo models and firmware. Verify the adapter against your own devices before relying on it.
05

MCP Tools

The proposed tool contracts. These are reference signatures, not a claim of a shipped client - map them to your five devices by alias.

discover_devicesread
All devices
List the configured lights and their current state and capabilities.
Parameters for discover_devices
ParameterType
refreshbool
get_device_stateread
Any device
Return the live state of a single light: power, brightness, color.
Parameters for get_device_state
ParameterType
device_id *string
set_powerwrite
Any device
Turn a device or group on or off.
Parameters for set_power
ParameterType
device_id *string
on *bool
set_colorwrite
Strips + bulbs
Set HSV color. Applies to devices that support color.
Parameters for set_color
ParameterType
device_id *string
hue *int
saturation *int
value *int
set_brightnesswrite
Any device
Set brightness as a percentage, capped by the configured ceiling.
Parameters for set_brightness
ParameterType
device_id *string
brightness *int
set_effectwrite
Strips
Start a built-in or blueprint effect (strobe, pulse, bpm).
Parameters for set_effect
ParameterType
device_id *string
effect *string
paramsobject
stop_effectwrite
Any device
Stop a running effect, or all effects if none is named.
Parameters for stop_effect
ParameterType
effectstring?

Device aliases (L900-3, L900, L900-2, L530-2, L530) are resolved from configuration, so tools stay readable and never need raw IPs.

06

Party Modes

Three distinct effects. Timing is best-effort on a local network and device capabilities vary - treat these as the blueprint's defaults.

bpm_sync

Beat-synced

Flash on the beat, driven by an external BPM or beat pulses from a local source. No fake audio capture.

Controls

  • bpmBeats per minute (validated range).
  • paletteColor palette for the pulse.
  • brightnessPulse brightness.
  • offsetPhase/beat offset for staggered strips.
while beat := next_beat():
    set_color(palette[beat % len(palette)])
    wait(60 / bpm)

strobe

Fast flash

Rapid on/off flashing at a fixed rate. Intense - use with care.

Controls

  • fpsFlash rate (flashes per second).
  • brightnessFlash brightness.
  • durationMax runtime, then auto-stop.
while running:
    turn_on()
    wait(1 / fps)
    turn_off()
    wait(1 / fps)

Strobe can trigger photosensitivity in some people. Keep rates low, limit duration, and provide an immediate stop.

pulse

Smooth pulse

A slow, smooth breathing effect between two colors or brightness levels.

Controls

  • color_aStart color.
  • color_bEnd color.
  • periodSeconds per full cycle.
  • brightnessPeak brightness.
for t in range(period):
    k = 0.5 * (1 + sin(2 * pi * t / period))
    set_color(lerp(color_a, color_b, k))
    wait(frame)
Accessibility note for this documentation: the docs UI respects prefers-reduced-motion, and no effect is auto-started on page load. The mock telemetry panel animates only a small status indicator.
07

Configuration

A readable example config. Values are placeholders - set your own.

config.yaml
backend: kasa            # kasa | tapo | mock

devices:
  - id: L900-3
    alias: L900-3
    host: 192.168.1.139
    protocol: kasa          # library/adapter for this device
  - id: L900
    alias: L900
    host: 192.168.1.179
    protocol: kasa
  - id: L900-2
    alias: L900-2
    host: 192.168.1.82
    protocol: kasa
  - id: L530-2
    alias: L530-2
    host: 192.168.1.129
    protocol: kasa
  - id: L530
    alias: L530
    host: 192.168.1.97
    protocol: kasa

defaults:
  brightness: 60            # default brightness
  max_brightness: 90        # hard ceiling, never exceeded

party_modes:
  bpm:
    min: 40
    max: 240
  strobe:
    max_fps: 12
    max_duration_s: 30

The brightness ceiling is a safety floor: no tool or effect can exceed it, even if a client requests more.

08

Safety

The blueprint treats safety as part of the design, not an afterthought.

Secrets

Treat Tapo credentials like passwords. Keep them in a git-ignored .env, never in committed config or chat.

LAN-only

The server talks to private addresses only and refuses public IPs. Do not expose it to the internet.

Rate limiting

Bounded concurrency and a per-second cap prevent effects from flooding the network or the devices.

Brightness ceiling

A configured max brightness is enforced server-side as a hard cap for all tools and effects.

Strobe warning

Strobe can trigger photosensitivity. Keep rates low, cap duration, and provide an immediate stop.

No secrets in logs

Logs are scrubbed of credential-looking values before they are written.

09

Roadmap

What comes next for the blueprint, in rough priority order.

01

Adapter verification

Validate kasa and tapo adapters against real devices and firmware.

02

Persistence

Persist device state and preferences across restarts.

03

Richer effects

More effect presets, palettes, and per-device choreography.

04

Beat source integration

Wiring for MIDI clock or DJ software as the beat source.

05

Tests

Expand the suite to cover adapters and effects against mocks.

06

Packaging

Publish as a pip package with a documented entry point.

tapo-mcp-server

Local-first · Python · MCP

Blueprint / reference implementation. This site does not claim live device connectivity and is not affiliated with TP-Link.

Device telemetry

Demo / mock data

Simulated status for illustration only. This panel is not connected to live devices and does not reflect real network telemetry.

  • L900-3

    Strip · 192.168.1.139

    off

    38% · h240

  • L900

    Strip · 192.168.1.179

    on

    82% · h160

  • L900-2

    Strip · 192.168.1.82

    off

    38% · h240

  • L530-2

    Bulb · 192.168.1.129

    off

    38% · h240

  • L530

    Bulb · 192.168.1.97

    on

    82% · h160