Skip to main content
Glama
README.md
# idotmatrix-mcp

An MCP (Model Context Protocol) server that lets AI assistants draw pixel art on [iDotMatrix](https://www.idotmatrix.com/) LED displays over Bluetooth.

Connect your iDotMatrix display to Claude, ChatGPT, or any MCP-compatible client and ask it to draw pictures, icons, animations, dashboards — anything that fits on a 16x16, 32x32, or 64x64 pixel grid.

## How It Works

The server maintains an in-memory pixel canvas that matches your display's resolution. AI assistants interact with the canvas through MCP tools — drawing shapes, filling colors, rendering text — then push the finished frame to the physical display over BLE.

```
AI Assistant  ──MCP tools──>  idotmatrix-mcp  ──BLE──>  iDotMatrix Display
                              (canvas buffer)
```

**Workflow:**

1. The assistant calls `discover_devices` to find nearby iDotMatrix displays
2. It connects with `connect_device`, specifying the screen size
3. It draws on the canvas using drawing tools (or `draw_batch` for multiple operations at once)
4. It calls `get_preview` to see an ANSI block-art preview in the chat
5. It calls `send_to_display` to push the frame to the physical device

## Prerequisites

- **Node.js** 18+
- **macOS** (BLE support via the `idotmatrix` npm package — uses Noble under the hood)
- An **iDotMatrix LED display** powered on and within Bluetooth range

## Installation

```bash
git clone https://github.com/nailan/idotmatrix-mcp.git
cd idotmatrix-mcp
npm install
npm run build
```

## Configuration

### Claude Desktop

Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "idotmatrix": {
      "command": "node",
      "args": ["/absolute/path/to/idotmatrix-mcp/dist/index.js", "--stdio"]
    }
  }
}
```

### Claude Code

Add to your Claude Code settings (`.claude/settings.json` or global):

```json
{
  "mcpServers": {
    "idotmatrix": {
      "command": "node",
      "args": ["/absolute/path/to/idotmatrix-mcp/dist/index.js", "--stdio"]
    }
  }
}
```

### HTTP mode (other clients)

The server also supports Streamable HTTP transport for clients that don't use stdio:

```bash
node dist/index.js                  # defaults to http://127.0.0.1:8321/mcp
node dist/index.js --port=9000      # custom port
```

## Tools

### Canvas Management

| Tool | Description |
|------|-------------|
| `clear_canvas(color)` | Fill entire canvas with one color and reset |
| `get_preview()` | Return an ANSI block-art preview of the canvas |
| `list_colors()` | List all 48 named colors with hex values |

### Drawing Primitives

| Tool | Description |
|------|-------------|
| `draw_rect(x, y, width, height, color, fill?)` | Rectangle (filled by default) |
| `draw_circle(cx, cy, radius, color, fill?)` | Circle (filled by default) |
| `draw_ellipse(cx, cy, rx, ry, color, fill?)` | Ellipse with independent radii |
| `draw_line(x1, y1, x2, y2, color)` | Line between two points |
| `draw_triangle(x1, y1, x2, y2, x3, y3, color, fill?)` | Triangle (filled by default) |
| `draw_rounded_rect(x, y, width, height, radius, color, fill?)` | Rectangle with rounded corners |
| `draw_polygon(cx, cy, radius, sides, color, fill?, rotation?)` | Regular polygon (3-12 sides) |
| `draw_gradient(x, y, width, height, color_from, color_to, direction?)` | Linear gradient fill (vertical, horizontal, or diagonal) |
| `set_pixel(x, y, color)` | Set a single pixel |
| `flood_fill(x, y, color)` | Paint-bucket fill from a point |
| `draw_text(text, x, y, color, font_size?)` | Bitmap text (3x5 "small" or 5x7 "medium") |

### Batch Drawing

| Tool | Description |
|------|-------------|
| `draw_batch(commands)` | Execute multiple draw commands in one call |

`draw_batch` accepts an array of command objects. Each object has a `command` field plus the same parameters as the corresponding individual tool. This is the most efficient way to compose scenes — one tool call instead of many round-trips.

```json
[
  { "command": "clear", "color": "dark_blue" },
  { "command": "gradient", "x": 0, "y": 0, "width": 64, "height": 32, "color_from": "navy", "color_to": "sky_blue" },
  { "command": "circle", "cx": 48, "cy": 8, "radius": 5, "color": "yellow" },
  { "command": "ellipse", "cx": 20, "cy": 16, "rx": 10, "ry": 5, "color": "white" },
  { "command": "rounded_rect", "x": 10, "y": 40, "width": 44, "height": 16, "radius": 4, "color": "green" },
  { "command": "polygon", "cx": 50, "cy": 10, "radius": 6, "sides": 5, "color": "gold" },
  { "command": "text", "text": "HI", "x": 28, "y": 44, "color": "white" }
]
```

Supported commands: `clear`, `rect`, `circle`, `ellipse`, `line`, `triangle`, `rounded_rect`, `polygon`, `gradient`, `pixel`, `fill`, `text`.

Execution stops on the first error and reports which command failed.

### Device Management

| Tool | Description |
|------|-------------|
| `discover_devices(timeout_seconds?)` | Scan for nearby iDotMatrix BLE devices |
| `connect_device(device_id, screen_size)` | Connect to a device (screen size: 16, 32, or 64) |
| `disconnect_device()` | Disconnect from the current device |
| `send_to_display()` | Push the canvas buffer to the connected display |

## Color Palette

The server includes a curated 48-color palette optimized for LED displays. Use `list_colors` to see all options. Some highlights:

- **Neutrals:** `black`, `white`, `gray`, `dark_gray`, `light_gray`
- **Warm:** `red`, `orange`, `yellow`, `coral`, `salmon`, `pink`, `hot_pink`
- **Cool:** `blue`, `cyan`, `green`, `teal`, `sky_blue`, `purple`, `violet`
- **Earth:** `brown`, `tan`, `sand`, `skin`, `peach`, `dark_brown`
- **Nature:** `forest`, `dark_green`, `lime`, `spring`, `mint`, `olive`

Gradients interpolate between any two palette colors, producing smooth intermediate shades not limited to the 48-color palette.

## Prompts

The server ships a `drawing-guide` prompt that gives the AI assistant context about the coordinate system, available tools, color palette, and pixel art tips. MCP clients that support prompts will make this available automatically.

## Coordinate System

- Origin `(0, 0)` is the **top-left** corner
- X increases rightward, Y increases downward
- Drawing outside bounds is silently clipped

## Development

```bash
npm run dev          # run with tsx (no build step)
npm run build        # compile TypeScript to dist/
npm run clean        # remove dist/
```

## License

MIT