Back to Directory/Developer Tools

io.github.cyanheads/pixoo-mcp-server

Render and push styled pixel art, text, dashboards, and animations to Divoom Pixoo LED displays.

Developer ToolsTypeScriptv1.4.0

@cyanheads/pixoo-mcp-server

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.

7 Tools • 4 Resources

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework


Overview

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.

Tools

ToolDescription
pixoo_display_textRender styled text (theme, gradient, shadow, outline, auto-fit) onto the display and push it. Returns the rendered frame as an image.
pixoo_compose_sceneCompose 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_imageLoad 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_textSet or clear a device-native scrolling text overlay. Uses device-rendered fonts; overlays persist across channel switches until cleared.
pixoo_control_deviceRead or change device state: brightness, screen on/off, channel, or clock face. Call with no params for a status read.
pixoo_discover_devicesFind Pixoo devices on the local network via Divoom's cloud discovery endpoint. Run once during setup to find device IPs.
pixoo_design_briefReturn 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.

Resources

ResourceDescription
pixoo://device/statusLive snapshot of the connected Pixoo display: reachable, channel, brightness, screen state, and display size
pixoo://reference/themesTheme and palette registry with background gradients, default text palettes, accent colors, and swatch values
pixoo://reference/iconsBuilt-in icon names organized by category (weather, arrows, status, media)
pixoo://reference/design-guideLong-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.

Capability reference

pixoo_display_text tool

  • Named scene themes set background gradient and default text palette in one parameter (midnight, ember, claude, ice, neon, forest, mono)
  • Style block: palette ramps (ember, ice, neon, fire, lavender, claude, mono) or a custom gradient/flat color, optional drop shadow, 1px outline, integer scale 1–8
  • Semantic positioning (x: "center", y: "bottom") or absolute pixel coordinates; multi-line text stacks vertically with configurable alignment
  • Auto-fit overflow tries standard font, then compact, then scroll; every fit decision is reported in layout[] with an action (shrunk-to-compact, scrolling, wrapped, truncated, clipped)
  • Optional brightness (0–100) applied before push — a failure is a warning via an enrichment notice, not a tool error
  • Returns the rendered frame as an image content block; outputFiles is populated only when PIXOO_OUTPUT_DIR is configured

pixoo_compose_scene tool

  • Up to 50 layered elements rendered back-to-front: text, icon, rect, circle, line, progress, sparkline, bitmap, pixels, image, sprite
  • Background: solid color, gradient (vertical, horizontal, or radial), or named theme
  • Animation via named effect presets (float, 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 segments
  • Static scenes return a PNG preview; animations return a labeled contact-sheet PNG plus a saved GIF (GIF preview is inconsistent across MCP clients)
  • Typed failures for asset_not_found, invalid_color, and unknown_icon, alongside the shared device-error reasons

pixoo_push_image tool

  • Accepts an absolute local file path or an https (not http) URL
  • Three fit modes: contain (letterbox), cover (crop to fill), fill (stretch)
  • Three resize kernels: nearest for pixel art (default), lanczos3 for photos, mitchell for a balance
  • Returns the exact resized result as an image content block before it is pushed

pixoo_overlay_text tool

  • mode: "set" adds or updates an overlay on one of 20 independent slots (id 0–19); mode: "clear" removes it
  • 115 device-rendered font IDs (0–114); overlays persist across channel switches until explicitly cleared
  • Configurable x/y (0–64), scroll direction (left/right), speed (0–100), and align; color is #RRGGBB hex only — named colors aren't supported here
  • Device-rendered, not previewable — for styled, previewable text use pixoo_display_text

pixoo_control_device tool

  • Call with no params to read state only; supply any of brightness (0–100), screen (on/off), channel (faces/cloud/visualizer/custom), or clockFaceId to apply changes before the read-back
  • applied lists which requested settings succeeded; a failed setting is omitted from applied and reported via an enrichment notice instead of failing the call
  • Always returns current reachable, channel, brightness, screenOn, and clockId (the latter three absent when the device is unreachable)

pixoo_discover_devices tool

  • Queries Divoom's cloud discovery endpoint (app.divoom-gz.com) — requires internet access even for local device control
  • Returns each device's name, numeric ID, and LAN IP to set as PIXOO_IP
  • When PIXOO_IP is already configured, flags whether it matches a discovered device (configuredIpFound) and notes a mismatch
  • timeoutMs configurable 1000–30000ms (default 5000ms)

pixoo_design_brief tool

  • Six topics: text, scene, dashboard, animation, pixel-art, troubleshooting
  • Returns markdown craft guidance (legibility floors, palette discipline, layout zones, animation budgets) plus a live deviceContext snapshot
  • nextToolSuggestions 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)
  • Also returns availableThemes and iconCategories for direct use in other tools

pixoo://device/status resource

  • Live snapshot: reachable, channel, brightness, screenOn, clockId, displaySize, configuredIp
  • No cache — every read reaches the device; degrades to reachable: false instead of erroring when the device is unreachable
  • Equivalent to calling pixoo_control_device with no params

pixoo://reference/themes resource

  • Every registered theme (background gradient or solid, default text palette, accent color, shadow flag) and every named palette (gradient stop pair)
  • themeNames / paletteNames arrays for direct use in the theme / palette parameters
  • Compile-time constants — cached for 24h

pixoo://reference/icons resource

  • Every built-in icon name, its category, and its SVG viewBox, plus a byCategory grouping (weather, arrows, status, media)
  • Use a name from this registry in pixoo_compose_scene icon elements
  • Compile-time constants — cached for 24h

pixoo://reference/design-guide resource

  • Long-form markdown: legibility floors, palette discipline, layout zones (top/middle/bottom strip pixel ranges), animation budget, pixel art rules, and known device behaviors (e.g. channel must be custom to show pushed content)
  • text/markdown mime type; compile-time constant, cached for 24h
  • Same content pixoo_design_brief surfaces per topic — this resource is the complete reference in one document

Features

Built 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:

  • Requires a Divoom Pixoo LED matrix display on the local network; primary target is the Pixoo-64 (16 and 32 also supported)
  • All composition happens in an RGBA canvas pipeline on the host (@cyanheads/pixoo-toolkit) — the device receives final RGB frames, never raw drawing commands
  • Styled text engine: gradient palette ramps, drop shadows, outlines, integer scale, semantic alignment — no manual pixel math or bitmap letterforms required
  • Push pacing: device commands serialized with a configurable minimum inter-push interval (default 1000ms) to prevent device freezes
  • Animation capped at 40 frames (device instability beyond this); contact-sheet PNG preview for animations (GIF preview is inconsistent across MCP clients)

Agent-friendly output:

  • Preview-as-content — render tools return the upscaled (8×, 512px) output as an image content block, so the calling model sees exactly what was drawn, before and after push
  • Layout transparency — every silent renderer decision (font fallback, truncation, scroll engaged, element clipped) is reported in layout[] so agents can inspect and refine
  • Device truth — pushed reflects the device ACK; deviceState after a push flags visibility issues (screen off, brightness ≤ 10, wrong channel) as enrichment notices rather than failures
  • Graceful degradation — render succeeds and returns the preview even when the device is unreachable, so the agent keeps its work

Getting started

Add 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

Prerequisites

  • Bun v1.4.0 or higher (or Node.js v24+).
  • A Divoom Pixoo LED matrix display on the local network (Pixoo-64, Pixoo-32, or Pixoo-16). Discovery tools and pure-render tools (push: false) work without a configured device.

Installation

  1. Clone the repository:
git clone https://github.com/cyanheads/pixoo-mcp-server.git
  1. Navigate into the directory:
cd pixoo-mcp-server
  1. Install dependencies:
bun install
  1. Configure environment:
cp .env.example .env
# edit .env and set PIXOO_IP

Configuration

All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:

VariableDescriptionDefault
PIXOO_IPDevice 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_SIZEDisplay size in pixels: 16, 32, or 64.64
PIXOO_OUTPUT_DIRDirectory for auto-saving preview PNG and GIF files. When unset, previews are returned in-response only.—
PIXOO_PUSH_MIN_INTERVAL_MSMinimum interval between device pushes in milliseconds. Prevents device freeze from rapid-fire commands.1000
MCP_TRANSPORT_TYPETransport: stdio or http.stdio
MCP_HTTP_PORTHTTP server port.3010
MCP_SESSION_MODEHTTP 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_MODEAuthentication: none, jwt, or oauth.none
MCP_LOG_LEVELLog level (debug, info, warning, error, etc.).info
LOGS_DIRDirectory for log files (Node.js only).<project-root>/logs
STORAGE_PROVIDER_TYPEStorage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1.in-memory
OTEL_ENABLEDEnable OpenTelemetry instrumentation (spans, metrics, completion logs).false

See .env.example for the full list of optional overrides.

Running the server

Local development

  • 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

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.

Project structure

DirectoryPurpose
src/index.tscreateApp() 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/.

Development guide

See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic
  • Use ctx.log for request-scoped logging, ctx.state for tenant-scoped storage
  • The renderer (src/renderer/) is pure — no device dependency, testable without hardware
  • All device calls go through PixooService; every PixooResult is checked — never assume a push succeeded

Contributing

Issues are welcome. Run checks and tests before submitting:

bun run devcheck
bun run test

License

Apache-2.0 — see LICENSE for details.

Installation

Source-derived launch command. Check the maintainer’s required arguments and credentials before running:

bash
npx -y @cyanheads/pixoo-mcp-server

Set up in your AI client

Merge 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.

json
{
  "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 reference

Package

@cyanheads/pixoo-mcp-servernpm

Compatible MCP Clients

io.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.

  • Claude Desktop~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.
  • Cursor~/.cursor/mcp.jsonRestart Cursor for changes to take effect.
  • VS Code.vscode/mcp.jsonReload VS Code window for changes to take effect.
  • Windsurf~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect.
  • Claude Code.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.

Learn More