
wled-mcp
io.github.descipar/wled-mcp
Unofficial MCP server for WLED LED controllers; not affiliated with the WLED project
Documentation
WLED MCP
An unofficial MCP server that lets an AI agent read and control WLED LED controllers by name: power, brightness, segments, effects, palettes, presets, groups, scenes and zones. It talks to each controller's JSON API on your network, validates every change before sending it and reads it back afterwards. It runs as a subprocess of your MCP host (stdio) or as a separate HTTP service. It is not affiliated with, endorsed by or supported by the WLED project or MCPHub.
Status: early software with 0.x versions that may break between releases
(CHANGELOG.md). Releases are distributed on PyPI as
wled-mcp (the first two releases are Git tags only);
a release that is not listed there installs from its Git tag instead. The server is listed in the
official MCP Registry as io.github.descipar/wled-mcp
(unofficial, not affiliated with the WLED project); whether a particular MCP host or hub shows that
entry was not checked. The container image is not published to GHCR.
Hardware acceptance is partial: one controller on WLED 16.0.1. No support is promised
(Support).
What it does
- Self-hosted: no cloud service, account, MQTT broker or public endpoint is needed.
- Named inventory of controllers in a TOML file. The server and its tools discover
nothing;
wled-mcp discoveris an opt-in command. - Normalized state, capabilities and each device's own effect and palette catalogs.
- Typed changes: master power and brightness, a patch of selected segments, or a
replacement of the complete layout. Advanced segment fields (CCT, 2D) are written only
where the device reports them. Segment tools accept the device's own effect and palette
names (
effect_name,palette_name) in place of IDs; a name is resolved against that device's catalog before any write and an ambiguous or unknown name is refused with candidates (contract). - Effect discovery:
wled_get_effectsparses the firmware's effect metadata and filters by name, 2D and audio reactivity (contract).wled_search_effectsfinds a device's effects by curated properties such as motion, flashing, colour slots and palette use; the catalog is small and an effect it does not list is not searchable (contract). - Named zones: a reviewed zone file maps a physical region to configured devices and LED
ranges;
wled_plan_zonepreviews the exact segments without a write andwled_apply_zonechanges segment fields only inside the zone, otherwise it refuses before any write (contract). - Layout preview (read-only):
wled_preview_layoutreturns a static, bounded SVG of a device's observed segment layout or of a proposed layout checked by the layout planner, with ranges, gaps, overlaps and approximate colours; 1D only, nothing is written and effects are not simulated (contract). - Agent guidance: the server serves safe-lighting instructions at initialization, a prompt
change_lighting_safelyand precise field descriptions, identically over stdio and HTTP. A client has to pass them on to its agent; forwarding by MCPHub was not observed (contract). - Observe and explain (read-only):
wled_get_live_snapshotsamples the LED colours per segment from the controller's live endpoint with explicit missing data and mapping limits (contract);wled_explain_lightinglists observed facts, causes (inferred causes never above medium confidence; only a directly observed blocker may be high), unknowns and next checks for one device whose change seems ineffective (contract). Neither claims colour accuracy, and an explanation is not proof of a cause. - Persistent presets with snapshots, restore, portable bundles and playlists; named device groups and multi-device scenes with a dry-run plan.
- Server-enforced profiles (
read-only,control,full) and, for the HTTP service, a bearer credential with Host and Origin allowlists.
All 34 tools, each with its read-only, write or destructive hint, are listed in the tool contract.
WLED feature coverage: 60 % of the planned scope, 48 % of WLED overall (method and list).
Try it
You need uv, an MCP host that can start a stdio server and
a WLED controller reachable over HTTP; the optional HTTP service also needs Docker with
Docker Compose. Replace <version> with the version of the
latest release (its tag is
v<version>). The commands install that release from
PyPI. If the version is not listed there yet, use the
Git route instead: replace wled-mcp==<version> with
git+https://github.com/descipar/wled-mcp@v<version>, which builds the package from the tag
on your machine; without a tag, uvx takes the current main, which can change at any
time. The commands are for a POSIX shell; Windows is experimental
(docs/DEVELOPMENT.md).
-
Check the installation (no device, no configuration):
uvx --isolated --python 3.13 --from wled-mcp==<version> wled-mcp --version -
Create a data directory and an inventory with one controller (contacts nothing):
mkdir -p "$HOME/wled-mcp" uvx --isolated --python 3.13 --from wled-mcp==<version> wled-mcp config init --config "$HOME/wled-mcp/devices.toml" --device-id desk --device-name "Desk strip" --base-url http://<controller-address> -
Register the server in your MCP host with the command
uvxand these arguments, each one separate, using absolute paths:--isolated --python 3.13 --from wled-mcp==<version> wled-mcp --transport stdio --config <absolute path>/wled-mcp/devices.toml --data-dir <absolute path>/wled-mcpAsk the agent to list your WLED devices (
wled_list_devices). Every write tool acceptsdry_run=trueto preview a change without touching the lights.
Both routes need network access (the Git route to GitHub as well as PyPI). The dependencies
are resolved within the ranges the package declares when uvx first creates the tool
environment, so they can be newer than the set the release was tested with; for that tested
set add the release constraints (dependency policy). For a
checksum-verified wheel, more devices, the
inventory format and the HTTP service, follow the
quickstarts; updates, rollback and removal are in
docs/DEPLOYMENT.md.
Installing from the MCPHub Registry tab
The MCPHub build observed for this project (the Install dialog of a Registry card, under
Packages, for administrators) does not produce a runnable entry from the registry listing: it
prefixes argument names that already start with -- with another --, leaves {config_path}
and {data_dir} unresolved and omits the runtime arguments. Other hosts may handle the listing
differently, and this is a note about that build, not a claim that anything was fixed upstream.
Before saving, edit the dialog: command uvx; arguments, one per field, --isolated,
--python, 3.13, wled-mcp@<version> (the listed version), --transport, stdio, --config,
<absolute path of your devices.toml inside the hub container>, --data-dir and
<writable directory inside the hub container>. Container paths, the uv environment variables
and a complete hub entry are in
docs/DEPLOYMENT.md.
The corrected entry has not been started inside MCPHub yet.
Safety model
- Validate first. A complete request is checked against the current device state before the first write; unknown fields and out-of-range values are rejected. Omitted fields mean "unchanged", never "reset".
- Patch versus replace.
wled_patch_segmentschanges only the named segments; onlywled_replace_layoutremoves segments that are not listed. - Dry run and verification.
dry_run=truereturns the plan without writing. Writes are read back; a write that timed out is reported as possibly applied and is never retried blindly. - Snapshots. Overwriting or deleting a preset first stores a durable snapshot in the
data directory. Restores, imports, supplied-state stores (
wled_store_preset) and playlist saves change the live output before they store, and the previous lighting is not restored. - No hidden reach. No discovery by the server or its tools, no arbitrary endpoints or
caller-supplied hosts, no silent preset overwrite (
overwrite=trueis required). - Authorization. Whether a person may run a tool is the MCP host's job; tool annotations are hints only. The HTTP service also requires its own bearer credential and Host allowlist and must not be exposed to the internet.
Compatibility
What the checks cover; the evidence for each row and the firmware tiers are in docs/contract/compatibility.md. This is not a support commitment (see Support).
| Area | Status |
|---|---|
| Python 3.13 | supported |
| Linux amd64 | supported |
| Linux arm64 | supported |
| HTTP container image, amd64 and arm64 | supported |
| stdio via uvx on Linux | supported |
| Windows | experimental |
| macOS | experimental |
| WLED 16.0.1 | tested |
| WLED 16.x other than 16.0.1 | unknown |
| WLED below 16.0.0, including 0.15.x | unsupported |
Unsupported or unrecognized firmware is served with a warning and never refused;
wled_get_state reports the tier in diagnostics.firmware_support.
Limitations
Automated tests use mocks and synthetic loopback devices. Hardware acceptance covers the
first feature set on one RGB controller, and a live check with an offline controller is
still pending. A short live check of release 0.1.1 over HTTP and stdio covered state
reads, power, brightness and effect changes on that controller
(record). A later run on the same controller
exercised a one-device group and scene, preset store, export, import and restore, and a
playlist, with the controller restored afterwards
(record). Multi-device scenes, profiles, discover, restore
onto an occupied slot, playlist import, restoring a playlist preset and CCT, RGBW and 2D controllers have no hardware run. Of the newest features, only a read-only run
covered the effect metadata and one effect search. One read-only call of the explanation ran
on the controller; the live colour snapshot reported the endpoint as unavailable (HTTP 501), so
no positive snapshot was observed. Zones, name resolution in segment writes and the served
guidance have mocked or local-client tests only.
Other limits:
- No tool deletes a snapshot on request; snapshots are only removed by retention pruning (20 per controller by default).
- Storing, restoring or importing a preset without changing the live output is not possible on WLED 16, and saving a playlist starts it.
- One writer per controller: locks are per process, so a second process or service against the same devices is not coordinated.
- No inventory reload; changes need
wled-mcp config validateand a restart. - No device authentication: WLED has none for its light API ("Anyone with your IP and port can control the lights", WLED docs). The server sends no device credentials and rejects credentials in a device URL, so a controller behind HTTP authentication or a credentialed proxy is not supported. Behavior with a settings PIN or OTA lock is untested; a test is planned (#128).
- No image on GHCR. A live update of a deployed HTTP service was checked once, from an earlier build to release 0.1.1; a rollback has not been checked.
The complete list and the evidence are in docs/VALIDATION.md.
Documentation
| Document | Contents |
|---|---|
| Quickstarts | Release directory, stdio and HTTP setup, inventory format |
| Deployment | Both transports in detail: staging, verification, update, rollback, removal |
| Tool contract | Tools, parameters, results, errors and mutation semantics |
| WLED feature coverage | WLED features with support status, owning issue or decision, and coverage figures |
| Inventory and client | Inventory schema, limits and HTTP client behavior |
| Development | Local checks, build and launch, including PowerShell |
| Validation | Automated checks, opt-in hardware checks, recorded evidence, known limitations |
| Architecture | Components, runtime and design decisions |
| Contract examples | Synthetic request, result and snapshot examples |
Support
There is no support commitment. Questions and problems go to GitHub issues, which are answered best effort, without any commitment to respond or fix. There is no security support; see SECURITY.md.
Project and contributing
Project status, roadmap and the maintainer document index are in docs/PROJECT.md. How to report problems and propose changes is in CONTRIBUTING.md.
How this project is developed
The maintainer develops this project with coding agents that follow a documented
workflow: AGENTS.md holds the project rules,
docs/AGENT-WORKFLOW.md describes the requirements,
implementation, review and completion roles, and the agents/ directory holds the
role definitions. Human contributions do not need this workflow. Design decisions and
their rationale are recorded in docs/DECISIONS.md and, per issue, in
docs/decisions/.
License
Licensed under the Apache License 2.0. Redistributions, including modified versions, must retain the copyright and attribution notice in NOTICE. The project is provided as is, without security support; see SECURITY.md.
wled-mcppip install wled-mcp