Render and push styled pixel art, text, dashboards, and animations to Divoom Pixoo LED displays.
Render and push styled pixel art, text, dashboards, and animations to Divoom Pixoo LED displays on your local network via MCP. STDIO or Streamable HTTP.
Divoom Pixoo LED matrix displays (Pixoo-64 primary; 16 and 32 also supported) on the local network. Render and push styled text, layered scenes, dashboards, and animations, or control device state, from any MCP client. Runs as a stdio process or a local Streamable HTTP server.
| Tool | Description |
|---|---|
pixoo_display_text | Render styled text (theme, gradient, shadow, outline, auto-fit) onto the display and push it. Returns the rendered frame as an image. |
pixoo_compose_scene | Compose a full scene: layered elements (text, icons, widgets, shapes, bitmaps, images, sprites) with per-element effects and keyframes, static or animated. Returns the rendered scene as an image. |
pixoo_push_image | Load an image (absolute local path or https URL), resize it to the LED grid, and push it. Returns the downsampled result as an image. |
pixoo_overlay_text | Set or clear a device-native scrolling text overlay. Uses device-rendered fonts; overlays persist across channel switches until cleared. |
pixoo_control_device | Read or change device state: brightness, screen on/off, channel, or clock face. Call with no params for a status read. |
pixoo_discover_devices | Find Pixoo devices on the local network via Divoom's cloud discovery endpoint. Run once during setup to find device IPs. |
pixoo_design_brief | Return craft guidance and live device context for a design topic. Covers legibility rules, palette discipline, layout zones, animation budget, and pre-filled next-tool suggestions. |
| Resource | Description |
|---|---|
pixoo://device/status | Live snapshot of the connected Pixoo display: reachable, channel, brightness, screen state, and display size |
pixoo://reference/themes | Theme and palette registry with background gradients, default text palettes, accent colors, and swatch values |
pixoo://reference/icons | Built-in icon names organized by category (weather, arrows, status, media) |
pixoo://reference/design-guide | Long-form 64px craft guide: legibility floors, palette discipline, layout zones, animation budget, and known device behaviors |
All resource data is also reachable via tools. pixoo_design_brief surfaces the design guide content per topic; pixoo_control_device returns live device state equivalent to pixoo://device/status.
pixoo_display_text toolmidnight, ember, claude, ice, neon, forest, mono)ember, ice, neon, fire, lavender, claude, mono) or a custom gradient/flat color, optional drop shadow, 1px outline, integer scale 1–8x: "center", y: "bottom") or absolute pixel coordinates; multi-line text stacks vertically with configurable alignmentlayout[] with an action (shrunk-to-compact, scrolling, wrapped, truncated, clipped)brightness (0–100) applied before push — a failure is a warning via an enrichment notice, not a tool erroroutputFiles is populated only when PIXOO_OUTPUT_DIR is configuredpixoo_compose_scene tooltext, icon, rect, circle, line, progress, sparkline, bitmap, pixels, image, spritefloat, scroll-left, scroll-right, pulse, blink, twinkle, drift, fade-in, fade-out) or raw per-property keyframe arrays — 1–40 frames at 10–2000ms per frame (default 150ms)image and sprite elements accept an absolute local path or an https URL; a supplied output path must be absolute with no traversal segmentsasset_not_found, invalid_color, and unknown_icon, alongside the shared device-error reasonspixoo_push_image toolcontain (letterbox), cover (crop to fill), fill (stretch)nearest for pixel art (default), lanczos3 for photos, mitchell for a balancepixoo_overlay_text toolmode: "set" adds or updates an overlay on one of 20 independent slots (id 0–19); mode: "clear" removes itx/y (0–64), scroll direction (left/right), speed (0–100), and align; color is #RRGGBB hex only — named colors aren't supported herepixoo_display_textpixoo_control_device toolbrightness (0–100), screen (on/off), channel (faces/cloud/visualizer/custom), or clockFaceId to apply changes before the read-backapplied lists which requested settings succeeded; a failed setting is omitted from applied and reported via an enrichment notice instead of failing the callreachable, channel, brightness, screenOn, and clockId (the latter three absent when the device is unreachable)pixoo_discover_devices toolapp.divoom-gz.com) — requires internet access even for local device controlPIXOO_IPPIXOO_IP is already configured, flags whether it matches a discovered device (configuredIpFound) and notes a mismatchtimeoutMs configurable 1000–30000ms (default 5000ms)pixoo_design_brief tooltext, scene, dashboard, animation, pixel-art, troubleshootingdeviceContext snapshotnextToolSuggestions are pre-filled with ready-to-use arguments tailored to the topic and current device state (e.g. suggests pixoo_discover_devices when the device is unreachable)availableThemes and iconCategories for direct use in other toolspixoo://device/status resourcereachable, channel, brightness, screenOn, clockId, displaySize, configuredIpreachable: false instead of erroring when the device is unreachablepixoo_control_device with no paramspixoo://reference/themes resourcethemeNames / paletteNames arrays for direct use in the theme / palette parameterspixoo://reference/icons resourceviewBox, plus a byCategory grouping (weather, arrows, status, media)name from this registry in pixoo_compose_scene icon elementspixoo://reference/design-guide resourcecustom to show pushed content)text/markdown mime type; compile-time constant, cached for 24hpixoo_design_brief surfaces per topic — this resource is the complete reference in one documentBuilt on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Pixoo-specific:
@cyanheads/pixoo-toolkit) — the device receives final RGB frames, never raw drawing commandsAgent-friendly output:
layout[] so agents can inspect and refinepushed reflects the device ACK; deviceState after a push flags visibility issues (screen off, brightness ≤ 10, wrong channel) as enrichment notices rather than failuresAdd the following to your MCP client configuration file. Run pixoo_discover_devices to find your Pixoo's IP, then set PIXOO_IP below.
{
"mcpServers": {
"pixoo-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/pixoo-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"PIXOO_IP": "192.168.1.50"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"pixoo-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/pixoo-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"PIXOO_IP": "192.168.1.50"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"pixoo-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"-e", "PIXOO_IP=192.168.1.50",
"ghcr.io/cyanheads/pixoo-mcp-server:latest"
]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 PIXOO_IP=192.168.1.50 bun run start:http
# Server listens at http://localhost:3010/mcp
push: false) work without a configured device.git clone https://github.com/cyanheads/pixoo-mcp-server.git
cd pixoo-mcp-server
bun install
cp .env.example .env
# edit .env and set PIXOO_IP
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:
| Variable | Description | Default |
|---|---|---|
PIXOO_IP | Device IP address on the local network. Required for device tools (pixoo_display_text, pixoo_compose_scene, pixoo_push_image, pixoo_overlay_text, pixoo_control_device). Discovery and pure-render (push: false) work without it. | — |
PIXOO_SIZE | Display size in pixels: 16, 32, or 64. | 64 |
PIXOO_OUTPUT_DIR | Directory for auto-saving preview PNG and GIF files. When unset, previews are returned in-response only. | — |
PIXOO_PUSH_MIN_INTERVAL_MS | Minimum interval between device pushes in milliseconds. Prevents device freeze from rapid-fire commands. | 1000 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_SESSION_MODE | HTTP session handling: stateful, stateless, or auto (the framework's schema default, which resolves to stateful). The server declares stateless in source — no tool requests input mid-call — and a value set here overrides it. | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry instrumentation (spans, metrics, completion logs). | false |
See .env.example for the full list of optional overrides.
Build and run:
# One-time build
bun run rebuild
# Run the built server
bun run start:stdio
# or
bun run start:http
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against spec
docker build -t pixoo-mcp-server .
docker run --rm -e PIXOO_IP=192.168.1.50 -p 3010:3010 pixoo-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/pixoo-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools/resources and initializes the Pixoo service. |
src/config/ | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools/ | Tool definitions (*.tool.ts). |
src/mcp-server/resources/ | Resource definitions (*.resource.ts). |
src/services/pixoo/ | PixooService — wraps @cyanheads/pixoo-toolkit, handles pacing, result mapping, and device state. |
src/renderer/ | Pure rendering pipeline: element renderers, styled-text engine, themes, icons, effect compiler, preview encoding. No device dependency. |
tests/ | Unit and integration tests mirroring src/. |
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagesrc/renderer/) is pure — no device dependency, testable without hardwarePixooService; every PixooResult is checked — never assume a push succeededIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
npx -y @cyanheads/pixoo-mcp-serverMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-cyanheads-pixoo-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/pixoo-mcp-server"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referenceio.github.cyanheads/pixoo-mcp-server works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.