@cyanheads/pixoo-mcp-server 1.1.4 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +11 -7
- package/CLAUDE.md +11 -7
- package/Dockerfile +30 -10
- package/README.md +61 -85
- package/changelog/1.2.x/1.2.0.md +28 -0
- package/changelog/1.2.x/1.2.1.md +35 -0
- package/dist/mcp-server/resources/definitions/pixoo-design-guide.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/pixoo-design-guide.resource.js +1 -0
- package/dist/mcp-server/resources/definitions/pixoo-design-guide.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.d.ts +77 -11
- package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.js +69 -59
- package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-design-brief.tool.d.ts +3 -3
- package/dist/mcp-server/tools/definitions/pixoo-design-brief.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-design-brief.tool.js +57 -45
- package/dist/mcp-server/tools/definitions/pixoo-design-brief.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.js +121 -32
- package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-overlay-text.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-overlay-text.tool.js +17 -3
- package/dist/mcp-server/tools/definitions/pixoo-overlay-text.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.js +9 -8
- package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.js.map +1 -1
- package/dist/mcp-server/tools/device-push.d.ts +24 -0
- package/dist/mcp-server/tools/device-push.d.ts.map +1 -0
- package/dist/mcp-server/tools/device-push.js +50 -0
- package/dist/mcp-server/tools/device-push.js.map +1 -0
- package/dist/renderer/icons.d.ts +14 -4
- package/dist/renderer/icons.d.ts.map +1 -1
- package/dist/renderer/icons.js +30 -22
- package/dist/renderer/icons.js.map +1 -1
- package/dist/renderer/keyframes.d.ts +35 -3
- package/dist/renderer/keyframes.d.ts.map +1 -1
- package/dist/renderer/keyframes.js +85 -52
- package/dist/renderer/keyframes.js.map +1 -1
- package/dist/renderer/preview.d.ts +17 -19
- package/dist/renderer/preview.d.ts.map +1 -1
- package/dist/renderer/preview.js +55 -34
- package/dist/renderer/preview.js.map +1 -1
- package/dist/renderer/remote-image.d.ts +10 -2
- package/dist/renderer/remote-image.d.ts.map +1 -1
- package/dist/renderer/remote-image.js +13 -1
- package/dist/renderer/remote-image.js.map +1 -1
- package/dist/renderer/scene-renderer.d.ts +14 -9
- package/dist/renderer/scene-renderer.d.ts.map +1 -1
- package/dist/renderer/scene-renderer.js +166 -137
- package/dist/renderer/scene-renderer.js.map +1 -1
- package/dist/renderer/text-engine.d.ts +14 -1
- package/dist/renderer/text-engine.d.ts.map +1 -1
- package/dist/renderer/text-engine.js +22 -4
- package/dist/renderer/text-engine.js.map +1 -1
- package/dist/services/pixoo/pixoo-service.js +1 -1
- package/dist/services/pixoo/pixoo-service.js.map +1 -1
- package/package.json +6 -5
- package/server.json +3 -3
package/AGENTS.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** pixoo-mcp-server
|
|
4
|
-
**Version:** 1.1
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 1.2.1
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.9`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/server` ^2.
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/server` ^2.1.0 (protocol revision 2026-07-28 alongside the 2025 era)
|
|
8
8
|
**Zod:** ^4.6.5
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
@@ -166,7 +166,7 @@ Handlers receive a unified `ctx` object. Key properties used by this server:
|
|
|
166
166
|
| `ctx.enrich` | Success-path agent context — `.notice()` / `.total()` / `.echo()` / `.truncated()`. Lands only when the definition declares an `enrichment` block. |
|
|
167
167
|
| `ctx.fail` | Typed throw against the definition's `errors[]` reason union — auto-populates `data.reason`. |
|
|
168
168
|
| `ctx.recoveryFor` | `{ recovery: { hint } }` for a declared reason, resolved from the contract. Pass it as `ctx.fail`'s data argument (or spread it in) to put the declared hint on the wire. |
|
|
169
|
-
| `ctx.state` | Tenant-scoped KV — `.get`, `.set(key, value, { ttl? })`, `.delete`, `.getMany`, `.list`. Keys are validated; colons are not legal separators. |
|
|
169
|
+
| `ctx.state` | Tenant-scoped KV — `.get`, `.set(key, value, { ttl? })`, `.delete`, `.getMany`, `.list`. Accepts any JSON-serializable value; reads return its JSON form (a `Date` comes back as an ISO string). Keys are validated; colons are not legal separators. |
|
|
170
170
|
| `ctx.requestInput` / `ctx.inputs` | Multi-round-trip input. `return ctx.requestInput(...)`; read the answers with `ctx.inputs.accepted(key, schema)` on re-entry. Unused by this server. |
|
|
171
171
|
| `ctx.signal` | `AbortSignal` for cancellation. Pass it to any long-running I/O. |
|
|
172
172
|
| `ctx.requestId` | Unique request ID. |
|
|
@@ -195,6 +195,8 @@ Pixoo-specific error reasons declared on tools:
|
|
|
195
195
|
|
|
196
196
|
A contract's `retryable` reaches the wire only through `ctx.fail`; a service throw carries it only when the service writes `data.retryable` itself. `classifyDeviceFailure` (in `pixoo-service.ts`) is the one place a failed device call becomes a reason and a retryability — `PixooService` writes both on its push-path throws, and `pixoo_overlay_text` passes the retryability into `ctx.fail` so it overrides the contract default per occurrence.
|
|
197
197
|
|
|
198
|
+
The three push tools (`pixoo_display_text`, `pixoo_compose_scene`, `pixoo_push_image`) share one post-render path in `src/mcp-server/tools/device-push.ts`. `pushKeepingPreview` rethrows a failed push's error with its code, `reason`, `retryable`, and recovery untouched, adding `data.outputFiles` (the file the call already saved, else a copy in a fresh `os.tmpdir()` directory) and naming the path in the message. The framework drops `ctx.content` blocks from error results, so the file path is how the render survives. On success, `visibilityNotice` turns the post-push `DeviceStateSnapshot` into one `ctx.enrich.notice` (screen off, brightness ≤ 10, not on the custom channel). `ctx.enrich.notice` is last-wins, so a tool with a second notice source composes them into one string.
|
|
199
|
+
|
|
198
200
|
```ts
|
|
199
201
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
200
202
|
|
|
@@ -233,8 +235,10 @@ src/
|
|
|
233
235
|
scene-renderer.ts # Element vocabulary, layout resolver, frame rendering
|
|
234
236
|
keyframes.ts # Keyframe interpolation + animation preset compiler
|
|
235
237
|
preview.ts # PNG/contact-sheet/GIF encoding
|
|
236
|
-
remote-image.ts # https image fetch to a temp file for the toolkit loader
|
|
238
|
+
remote-image.ts # https image fetch to a temp file for the toolkit loader; stops on ctx.signal
|
|
237
239
|
mcp-server/
|
|
240
|
+
tools/
|
|
241
|
+
device-push.ts # Shared post-render push: preview kept on failure, visibility notice
|
|
238
242
|
tools/definitions/
|
|
239
243
|
pixoo-display-text.tool.ts
|
|
240
244
|
pixoo-compose-scene.tool.ts
|
|
@@ -328,7 +332,7 @@ Available skills:
|
|
|
328
332
|
| `bun run audit:fix` | `bun audit fix` — upgrade vulnerable packages to the lowest safe version within existing ranges (`--dry-run` previews, `--latest` rewrites ranges). First response when `devcheck` flags a transitive advisory; then `bun update <name>`, then `bun dedupe` |
|
|
329
333
|
| `bun run audit:refresh` | Delete `bun.lock` and reinstall. Last resort after `audit:fix`, `bun update <name>`, and `bun dedupe` — re-resolves every ranged dep (the framework pin included) and rewrites the lockfile as `lockfileVersion: 2` |
|
|
330
334
|
| `bun run lint:mcp` | Run the MCP definition linter standalone (rule catalog: `api-linter` skill) |
|
|
331
|
-
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity, MCPB `user_config` wiring, plugin manifests, README version
|
|
335
|
+
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity, MCPB `user_config` wiring, plugin manifests, manifest and README version parity, Dockerfile build platform (run by devcheck) |
|
|
332
336
|
| `bun run list-skills` | Print the skill registry |
|
|
333
337
|
| `bun run tree` | Generate directory structure doc |
|
|
334
338
|
| `bun run format` | Auto-fix formatting (safe fixes only) |
|
|
@@ -348,7 +352,7 @@ Available skills:
|
|
|
348
352
|
|
|
349
353
|
`bun run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies and strips dependency-shipped agent docs and platform-specific native bindings that root-anchored `.mcpbignore` patterns cannot reach. MCPB is stdio-only — HTTP deployments are unaffected.
|
|
350
354
|
|
|
351
|
-
`lint:packaging` verifies that `server.json` and `manifest.json` declare the same env var names, that every `manifest.json` `user_config` option is wired into `mcp_config.env` as `"X": "${user_config.<key>}"` (the host substitutes nothing else), that an optional string option carries `"default": ""`, that no plugin manifest writes an empty `env` value, and
|
|
355
|
+
`lint:packaging` verifies that `server.json` and `manifest.json` declare the same env var names, that every `manifest.json` `user_config` option is wired into `mcp_config.env` as `"X": "${user_config.<key>}"` (the host substitutes nothing else), that an optional string option carries `"default": ""`, that no plugin manifest writes an empty `env` value, that `manifest.json` and the README `Version-` badge carry the `package.json` version, and that the Dockerfile stage running `bun run build` starts `FROM --platform=$BUILDPLATFORM` (a multi-arch build otherwise runs it under QEMU, where Bun aborts).
|
|
352
356
|
|
|
353
357
|
---
|
|
354
358
|
|
package/CLAUDE.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** pixoo-mcp-server
|
|
4
|
-
**Version:** 1.1
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 1.2.1
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.9`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/server` ^2.
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/server` ^2.1.0 (protocol revision 2026-07-28 alongside the 2025 era)
|
|
8
8
|
**Zod:** ^4.6.5
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
@@ -166,7 +166,7 @@ Handlers receive a unified `ctx` object. Key properties used by this server:
|
|
|
166
166
|
| `ctx.enrich` | Success-path agent context — `.notice()` / `.total()` / `.echo()` / `.truncated()`. Lands only when the definition declares an `enrichment` block. |
|
|
167
167
|
| `ctx.fail` | Typed throw against the definition's `errors[]` reason union — auto-populates `data.reason`. |
|
|
168
168
|
| `ctx.recoveryFor` | `{ recovery: { hint } }` for a declared reason, resolved from the contract. Pass it as `ctx.fail`'s data argument (or spread it in) to put the declared hint on the wire. |
|
|
169
|
-
| `ctx.state` | Tenant-scoped KV — `.get`, `.set(key, value, { ttl? })`, `.delete`, `.getMany`, `.list`. Keys are validated; colons are not legal separators. |
|
|
169
|
+
| `ctx.state` | Tenant-scoped KV — `.get`, `.set(key, value, { ttl? })`, `.delete`, `.getMany`, `.list`. Accepts any JSON-serializable value; reads return its JSON form (a `Date` comes back as an ISO string). Keys are validated; colons are not legal separators. |
|
|
170
170
|
| `ctx.requestInput` / `ctx.inputs` | Multi-round-trip input. `return ctx.requestInput(...)`; read the answers with `ctx.inputs.accepted(key, schema)` on re-entry. Unused by this server. |
|
|
171
171
|
| `ctx.signal` | `AbortSignal` for cancellation. Pass it to any long-running I/O. |
|
|
172
172
|
| `ctx.requestId` | Unique request ID. |
|
|
@@ -195,6 +195,8 @@ Pixoo-specific error reasons declared on tools:
|
|
|
195
195
|
|
|
196
196
|
A contract's `retryable` reaches the wire only through `ctx.fail`; a service throw carries it only when the service writes `data.retryable` itself. `classifyDeviceFailure` (in `pixoo-service.ts`) is the one place a failed device call becomes a reason and a retryability — `PixooService` writes both on its push-path throws, and `pixoo_overlay_text` passes the retryability into `ctx.fail` so it overrides the contract default per occurrence.
|
|
197
197
|
|
|
198
|
+
The three push tools (`pixoo_display_text`, `pixoo_compose_scene`, `pixoo_push_image`) share one post-render path in `src/mcp-server/tools/device-push.ts`. `pushKeepingPreview` rethrows a failed push's error with its code, `reason`, `retryable`, and recovery untouched, adding `data.outputFiles` (the file the call already saved, else a copy in a fresh `os.tmpdir()` directory) and naming the path in the message. The framework drops `ctx.content` blocks from error results, so the file path is how the render survives. On success, `visibilityNotice` turns the post-push `DeviceStateSnapshot` into one `ctx.enrich.notice` (screen off, brightness ≤ 10, not on the custom channel). `ctx.enrich.notice` is last-wins, so a tool with a second notice source composes them into one string.
|
|
199
|
+
|
|
198
200
|
```ts
|
|
199
201
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
200
202
|
|
|
@@ -233,8 +235,10 @@ src/
|
|
|
233
235
|
scene-renderer.ts # Element vocabulary, layout resolver, frame rendering
|
|
234
236
|
keyframes.ts # Keyframe interpolation + animation preset compiler
|
|
235
237
|
preview.ts # PNG/contact-sheet/GIF encoding
|
|
236
|
-
remote-image.ts # https image fetch to a temp file for the toolkit loader
|
|
238
|
+
remote-image.ts # https image fetch to a temp file for the toolkit loader; stops on ctx.signal
|
|
237
239
|
mcp-server/
|
|
240
|
+
tools/
|
|
241
|
+
device-push.ts # Shared post-render push: preview kept on failure, visibility notice
|
|
238
242
|
tools/definitions/
|
|
239
243
|
pixoo-display-text.tool.ts
|
|
240
244
|
pixoo-compose-scene.tool.ts
|
|
@@ -328,7 +332,7 @@ Available skills:
|
|
|
328
332
|
| `bun run audit:fix` | `bun audit fix` — upgrade vulnerable packages to the lowest safe version within existing ranges (`--dry-run` previews, `--latest` rewrites ranges). First response when `devcheck` flags a transitive advisory; then `bun update <name>`, then `bun dedupe` |
|
|
329
333
|
| `bun run audit:refresh` | Delete `bun.lock` and reinstall. Last resort after `audit:fix`, `bun update <name>`, and `bun dedupe` — re-resolves every ranged dep (the framework pin included) and rewrites the lockfile as `lockfileVersion: 2` |
|
|
330
334
|
| `bun run lint:mcp` | Run the MCP definition linter standalone (rule catalog: `api-linter` skill) |
|
|
331
|
-
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity, MCPB `user_config` wiring, plugin manifests, README version
|
|
335
|
+
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity, MCPB `user_config` wiring, plugin manifests, manifest and README version parity, Dockerfile build platform (run by devcheck) |
|
|
332
336
|
| `bun run list-skills` | Print the skill registry |
|
|
333
337
|
| `bun run tree` | Generate directory structure doc |
|
|
334
338
|
| `bun run format` | Auto-fix formatting (safe fixes only) |
|
|
@@ -348,7 +352,7 @@ Available skills:
|
|
|
348
352
|
|
|
349
353
|
`bun run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies and strips dependency-shipped agent docs and platform-specific native bindings that root-anchored `.mcpbignore` patterns cannot reach. MCPB is stdio-only — HTTP deployments are unaffected.
|
|
350
354
|
|
|
351
|
-
`lint:packaging` verifies that `server.json` and `manifest.json` declare the same env var names, that every `manifest.json` `user_config` option is wired into `mcp_config.env` as `"X": "${user_config.<key>}"` (the host substitutes nothing else), that an optional string option carries `"default": ""`, that no plugin manifest writes an empty `env` value, and
|
|
355
|
+
`lint:packaging` verifies that `server.json` and `manifest.json` declare the same env var names, that every `manifest.json` `user_config` option is wired into `mcp_config.env` as `"X": "${user_config.<key>}"` (the host substitutes nothing else), that an optional string option carries `"default": ""`, that no plugin manifest writes an empty `env` value, that `manifest.json` and the README `Version-` badge carry the `package.json` version, and that the Dockerfile stage running `bun run build` starts `FROM --platform=$BUILDPLATFORM` (a multi-arch build otherwise runs it under QEMU, where Bun aborts).
|
|
352
356
|
|
|
353
357
|
---
|
|
354
358
|
|
package/Dockerfile
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
# is architecture-independent — emulating this stage buys nothing, and Bun 1.4
|
|
10
10
|
# aborts with MemoryExhaustion under QEMU x86_64 when it is emulated.
|
|
11
11
|
# ==============================================================================
|
|
12
|
-
FROM --platform=$BUILDPLATFORM oven/bun:1.4.
|
|
12
|
+
FROM --platform=$BUILDPLATFORM oven/bun:1.4.2 AS build
|
|
13
13
|
|
|
14
14
|
WORKDIR /usr/src/app
|
|
15
15
|
|
|
@@ -35,7 +35,7 @@ RUN bun run build
|
|
|
35
35
|
# application. It uses a slim base image and only includes production
|
|
36
36
|
# dependencies and build artifacts.
|
|
37
37
|
# ==============================================================================
|
|
38
|
-
FROM oven/bun:1.4.
|
|
38
|
+
FROM oven/bun:1.4.2-slim AS production
|
|
39
39
|
|
|
40
40
|
WORKDIR /usr/src/app
|
|
41
41
|
|
|
@@ -51,8 +51,15 @@ LABEL org.opencontainers.image.licenses="Apache-2.0"
|
|
|
51
51
|
LABEL org.opencontainers.image.version="${APP_VERSION}"
|
|
52
52
|
LABEL org.opencontainers.image.source="https://github.com/cyanheads/pixoo-mcp-server"
|
|
53
53
|
|
|
54
|
-
# Copy dependency manifests
|
|
55
|
-
|
|
54
|
+
# Copy dependency manifests. `bunfig.toml` rides along so every install below
|
|
55
|
+
# passes its release-age gate and security scanner, as a local install does.
|
|
56
|
+
COPY package.json bun.lock bunfig.toml ./
|
|
57
|
+
|
|
58
|
+
# The scanner bunfig.toml names is a devDependency, and Bun installs a missing
|
|
59
|
+
# scanner through the same production-filtered install, which omits it and
|
|
60
|
+
# aborts. Seed it from the build stage's full install instead. Remove this line
|
|
61
|
+
# together with the scanner if bunfig.toml stops naming one.
|
|
62
|
+
COPY --from=build /usr/src/app/node_modules/@socketsecurity/bun-security-scanner ./node_modules/@socketsecurity/bun-security-scanner
|
|
56
63
|
|
|
57
64
|
# Install only production dependencies, ignoring any lifecycle scripts (like 'prepare')
|
|
58
65
|
# that are not needed in the final production image.
|
|
@@ -65,21 +72,35 @@ RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
|
65
72
|
bun install --production --omit=peer --frozen-lockfile --ignore-scripts
|
|
66
73
|
|
|
67
74
|
# Conditionally install OpenTelemetry optional peer dependencies (Tier 3).
|
|
68
|
-
#
|
|
69
|
-
# with: docker build --build-arg OTEL_ENABLED=
|
|
75
|
+
# Installed by default. Omit them for a leaner image at build time
|
|
76
|
+
# with: docker build --build-arg OTEL_ENABLED=false
|
|
77
|
+
# Each package is requested at the range the installed framework declares in
|
|
78
|
+
# `peerDependencies`, so the resolution stays inside the framework's tested
|
|
79
|
+
# peer range; a name with no declared range fails the build.
|
|
70
80
|
ARG OTEL_ENABLED=true
|
|
71
81
|
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
72
82
|
if [ "$OTEL_ENABLED" = "true" ]; then \
|
|
73
|
-
bun
|
|
74
|
-
|
|
83
|
+
specs=$(bun -e ' \
|
|
84
|
+
const { peerDependencies: peers } = await Bun.file("node_modules/@cyanheads/mcp-ts-core/package.json").json(); \
|
|
85
|
+
const names = process.argv.slice(1); \
|
|
86
|
+
const missing = names.filter((name) => !peers?.[name]); \
|
|
87
|
+
if (missing.length > 0) throw new Error(`no peerDependencies range for ${missing.join(", ")}`); \
|
|
88
|
+
console.log(names.map((name) => `${name}@${peers[name]}`).join(" ")); \
|
|
89
|
+
' \
|
|
90
|
+
@hono/otel \
|
|
91
|
+
@opentelemetry/api-logs \
|
|
92
|
+
@opentelemetry/exporter-logs-otlp-http \
|
|
75
93
|
@opentelemetry/exporter-metrics-otlp-http \
|
|
76
94
|
@opentelemetry/exporter-trace-otlp-http \
|
|
95
|
+
@opentelemetry/instrumentation-http \
|
|
77
96
|
@opentelemetry/instrumentation-pino \
|
|
78
97
|
@opentelemetry/resources \
|
|
98
|
+
@opentelemetry/sdk-logs \
|
|
79
99
|
@opentelemetry/sdk-metrics \
|
|
80
100
|
@opentelemetry/sdk-node \
|
|
81
101
|
@opentelemetry/sdk-trace-node \
|
|
82
|
-
@opentelemetry/semantic-conventions
|
|
102
|
+
@opentelemetry/semantic-conventions) \
|
|
103
|
+
&& bun add --omit=dev --omit=peer --ignore-scripts $specs; \
|
|
83
104
|
fi
|
|
84
105
|
|
|
85
106
|
# Copy the compiled application code from the build stage
|
|
@@ -123,7 +144,6 @@ ENV MCP_TRANSPORT_TYPE="http"
|
|
|
123
144
|
ENV MCP_SESSION_MODE="stateless"
|
|
124
145
|
ENV MCP_LOG_LEVEL="info"
|
|
125
146
|
ENV LOGS_DIR="/var/log/pixoo-mcp-server"
|
|
126
|
-
ENV MCP_FORCE_CONSOLE_LOGGING="true"
|
|
127
147
|
|
|
128
148
|
# Expose the port the server listens on
|
|
129
149
|
EXPOSE ${MCP_HTTP_PORT}
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/pixoo-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/pixoo-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -23,129 +23,109 @@
|
|
|
23
23
|
|
|
24
24
|
## Overview
|
|
25
25
|
|
|
26
|
-
Divoom Pixoo LED matrix displays
|
|
26
|
+
Divoom Pixoo LED matrix displays on the local network, with the Pixoo-64 as the primary target and the 16 and 32 also supported. Render and push styled text, layered scenes, dashboards, and animations, or read and change device state. Runs as a stdio process or a local Streamable HTTP server.
|
|
27
27
|
|
|
28
28
|
### Tools
|
|
29
29
|
|
|
30
30
|
| Tool | Description |
|
|
31
|
-
|
|
32
|
-
| `pixoo_display_text` | Render styled text
|
|
33
|
-
| `pixoo_compose_scene` | Compose
|
|
34
|
-
| `pixoo_push_image` |
|
|
35
|
-
| `pixoo_overlay_text` | Set or clear a device-
|
|
36
|
-
| `pixoo_control_device` | Read or change
|
|
37
|
-
| `pixoo_discover_devices` | Find Pixoo devices
|
|
38
|
-
| `pixoo_design_brief` |
|
|
31
|
+
|:---|:---|
|
|
32
|
+
| `pixoo_display_text` | Render styled text with themes, gradients, shadows, and auto-fit, static or animated, and push it |
|
|
33
|
+
| `pixoo_compose_scene` | Compose layered scenes of text, icons, widgets, shapes, bitmaps, images, and sprites, static or animated |
|
|
34
|
+
| `pixoo_push_image` | Resize a local or https image to the LED grid and push it |
|
|
35
|
+
| `pixoo_overlay_text` | Set or clear a device-rendered scrolling text overlay |
|
|
36
|
+
| `pixoo_control_device` | Read or change brightness, screen state, channel, or clock face |
|
|
37
|
+
| `pixoo_discover_devices` | Find Pixoo devices and their LAN IPs through Divoom's cloud discovery |
|
|
38
|
+
| `pixoo_design_brief` | Craft guidance for a design topic, with live device state and pre-filled next calls |
|
|
39
39
|
|
|
40
40
|
### Resources
|
|
41
41
|
|
|
42
42
|
| Resource | Description |
|
|
43
43
|
|:---|:---|
|
|
44
|
-
| `pixoo://device/status` | Live snapshot
|
|
45
|
-
| `pixoo://reference/themes` | Theme and palette registry
|
|
46
|
-
| `pixoo://reference/icons` | Built-in icon names
|
|
47
|
-
| `pixoo://reference/design-guide` | Long-form
|
|
44
|
+
| `pixoo://device/status` | Live device snapshot: reachability, channel, brightness, screen state, display size |
|
|
45
|
+
| `pixoo://reference/themes` | Theme and palette registry |
|
|
46
|
+
| `pixoo://reference/icons` | Built-in icon names by category |
|
|
47
|
+
| `pixoo://reference/design-guide` | Long-form craft guide for the 64px display |
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Tools cover the same ground for tool-only clients: `pixoo_control_device` reads the live device state, and `pixoo_design_brief` returns craft guidance, theme names, and icon names.
|
|
50
50
|
|
|
51
51
|
## Capability reference
|
|
52
52
|
|
|
53
53
|
### `pixoo_display_text` <sub>tool</sub>
|
|
54
54
|
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
- 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`)
|
|
59
|
-
- Optional `brightness` (0–100) applied before push — a failure is a warning via an enrichment notice, not a tool error
|
|
60
|
-
- Returns the rendered frame as an image content block; `outputFiles` is populated only when `PIXOO_OUTPUT_DIR` is configured
|
|
55
|
+
- `text` as a string or an array of lines; `theme` (`midnight`, `ember`, `claude`, `ice`, `neon`, `forest`, `mono`) sets the background and default palette. `style` takes a `palette` ramp (`ember`, `ice`, `neon`, `fire`, `lavender`, `claude`, `mono`) or a custom `{ from, to }`, plus `shadow`, `outline`, and `scale` 1–8; `position` is semantic or in pixels, and `align` lines up multi-line text
|
|
56
|
+
- `layout[]` reports every fit decision as an `action` (`shrunk-to-compact`, `scrolling`, `truncated`, …). Single-line text falls back from the standard to the compact font unless `font` is set, and text still too wide only scrolls under `effect: "auto"` or `"scroll"`
|
|
57
|
+
- `effect`: `scroll` makes one pass in up to 40 frames, `auto` scrolls only on overflow, and `float` and `pulse` loop over 20 frames; `frames` reports the count, and the animation pushes as one device animation
|
|
61
58
|
|
|
62
59
|
---
|
|
63
60
|
|
|
64
61
|
### `pixoo_compose_scene` <sub>tool</sub>
|
|
65
62
|
|
|
66
|
-
- Up to 50
|
|
67
|
-
-
|
|
68
|
-
- Animation
|
|
69
|
-
- `image` elements accept an absolute local path or an https URL; `sprite` elements take an absolute local path; a supplied `output` path must be absolute with no traversal segments
|
|
70
|
-
- `opacity` (0–100) blends any element, images included, over the layers beneath it
|
|
71
|
-
- Static scenes return a PNG preview; animations return a labeled contact-sheet PNG plus a saved GIF (GIF preview is inconsistent across MCP clients)
|
|
72
|
-
- Typed failures for `asset_not_found`, `invalid_color`, and `unknown_icon`, alongside the shared device-error reasons
|
|
63
|
+
- Up to 50 `elements` drawn back-to-front: `text`, `icon`, `rect`, `circle`, `line`, `progress`, `sparkline`, `bitmap`, `pixels`, `image` (absolute path or https URL), `sprite` (absolute path). The `background` is a solid color, a `v` / `h` / `r` gradient, or a `theme`
|
|
64
|
+
- Returns `layout[]`: each element's placed box and whether it `fits` on the panel. An absolute `output` path saves the first frame as a PNG in place of the `PIXOO_OUTPUT_DIR` auto-save. Typed failures: `asset_not_found`, `invalid_color`, `unknown_icon`, `invalid_output_path`
|
|
65
|
+
- Animation through per-element `effect` presets (`float`, `scroll-left`, `scroll-right`, `pulse`, `blink`, `twinkle`, `drift`, `fade-in`, `fade-out`) or raw `animate` keyframes over `dx`, `dy`, `opacity` (numbers or numeric strings), `visible` (`true`/`false`), and `color` (interpolated through RGB on any element with a `color`), each track holding at least one keyframe; `frames` 1–40, `speed` 10–2000 ms per frame (default 150). An effect's `amplitude` sets the movement of `float`, `scroll-*`, and `drift`, and the 0–1 depth of the `pulse` and `twinkle` opacity dip
|
|
73
66
|
|
|
74
67
|
---
|
|
75
68
|
|
|
76
69
|
### `pixoo_push_image` <sub>tool</sub>
|
|
77
70
|
|
|
78
|
-
-
|
|
79
|
-
-
|
|
80
|
-
- Three resize kernels: `nearest` for pixel art (default), `lanczos3` for photos, `mitchell` for a balance
|
|
81
|
-
- Returns the exact resized result as an image content block before it is pushed
|
|
71
|
+
- `source` is an absolute local path or an https URL, with downloads capped at 10 MB; `fit` is `contain` (default), `cover`, or `fill`, and `kernel` is `nearest` (default, for pixel art), `lanczos3` (photos), or `mitchell`
|
|
72
|
+
- An unreadable path or URL fails as `asset_not_found`; the preview is the exact resized frame the device receives
|
|
82
73
|
|
|
83
74
|
---
|
|
84
75
|
|
|
85
76
|
### `pixoo_overlay_text` <sub>tool</sub>
|
|
86
77
|
|
|
87
|
-
- `mode: "set"`
|
|
88
|
-
-
|
|
89
|
-
- Configurable `x`/`y` (0–64), scroll `direction` (`left`/`right`), `speed` (0–100), and `align`; color accepts hex (`#RRGGBB` or `#RGB`) or a named color, the same as the render tools
|
|
90
|
-
- Device-rendered, not previewable — for styled, previewable text use `pixoo_display_text`
|
|
78
|
+
- `mode: "set"` or `"clear"` on one of 20 slots (`id` 0–19). `set` requires `text` and takes a device `font` ID (0–114), `x` / `y` within `PIXOO_SIZE`, `color`, `speed` (0–100), `direction`, `align`, and `width`
|
|
79
|
+
- Returns `acknowledged`, `mode`, and `id`. The device renders the overlay, so there is no preview, and it persists across channel switches until cleared
|
|
91
80
|
|
|
92
81
|
---
|
|
93
82
|
|
|
94
83
|
### `pixoo_control_device` <sub>tool</sub>
|
|
95
84
|
|
|
96
|
-
-
|
|
97
|
-
- `
|
|
98
|
-
- Always returns current `reachable`, `channel`, `brightness`, `screenOn`, and `clockId` (the latter three absent when the device is unreachable)
|
|
85
|
+
- No params reads state; any of `brightness` (0–100), `screen` (`on` / `off`), `channel` (`faces` / `cloud` / `visualizer` / `custom`), or `clockFaceId` is applied before the read-back
|
|
86
|
+
- Returns `reachable`, `channel`, `brightness`, `screenOn`, and `clockId` (absent when unreachable) plus `applied`; a failed setting is left out of `applied` and named in the notice instead of failing the call
|
|
99
87
|
|
|
100
88
|
---
|
|
101
89
|
|
|
102
90
|
### `pixoo_discover_devices` <sub>tool</sub>
|
|
103
91
|
|
|
104
|
-
- Queries Divoom's cloud
|
|
105
|
-
- Returns each device's name
|
|
106
|
-
- When `PIXOO_IP` is already configured, flags whether it matches a discovered device (`configuredIpFound`) and notes a mismatch
|
|
107
|
-
- `timeoutMs` configurable 1000–30000ms (default 5000ms)
|
|
92
|
+
- Queries Divoom's cloud endpoint (`app.divoom-gz.com`), so it needs internet access; `timeoutMs` 1000–30000 (default 5000)
|
|
93
|
+
- Returns each device's `name`, `id`, and `ip`; with `PIXOO_IP` set, `configuredIpFound` says whether it matched. An unreachable endpoint fails as `discovery_failed`
|
|
108
94
|
|
|
109
95
|
---
|
|
110
96
|
|
|
111
97
|
### `pixoo_design_brief` <sub>tool</sub>
|
|
112
98
|
|
|
113
|
-
-
|
|
114
|
-
- Returns markdown
|
|
115
|
-
- `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)
|
|
116
|
-
- Also returns `availableThemes` and `iconCategories` for direct use in other tools
|
|
99
|
+
- `topic`: `text`, `scene`, `dashboard`, `animation`, `pixel-art`, or `troubleshooting`; works without a reachable device
|
|
100
|
+
- Returns markdown `craftGuidance`, a live `deviceContext`, `nextToolSuggestions` as `{ toolName, reason, args }` with arguments pre-filled for the topic and device state, plus `availableThemes` and `iconCategories`
|
|
117
101
|
|
|
118
102
|
---
|
|
119
103
|
|
|
120
104
|
### `pixoo://device/status` <sub>resource</sub>
|
|
121
105
|
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
- Equivalent to calling `pixoo_control_device` with no params
|
|
106
|
+
- Uncached live read: `reachable`, `channel`, `brightness`, `screenOn`, `clockId`, `displaySize`, `configuredIp`
|
|
107
|
+
- Returns `reachable: false` rather than an error when the device can't be reached or `PIXOO_IP` is unset
|
|
125
108
|
|
|
126
109
|
---
|
|
127
110
|
|
|
128
111
|
### `pixoo://reference/themes` <sub>resource</sub>
|
|
129
112
|
|
|
130
|
-
- Every
|
|
131
|
-
-
|
|
132
|
-
- Compile-time constants — cached for 24h
|
|
113
|
+
- Every theme (background, `textPalette`, `accent`, `shadow`) and palette (`from` / `to` stops), plus `themeNames` and `paletteNames` for the `theme` and `palette` parameters
|
|
114
|
+
- Static registry, cached for 24h
|
|
133
115
|
|
|
134
116
|
---
|
|
135
117
|
|
|
136
118
|
### `pixoo://reference/icons` <sub>resource</sub>
|
|
137
119
|
|
|
138
|
-
-
|
|
139
|
-
-
|
|
140
|
-
- Compile-time constants — cached for 24h
|
|
120
|
+
- Each icon's `name`, `category`, and `viewBox`, plus a `byCategory` grouping (weather, arrows, status, media); a `name` goes in a `pixoo_compose_scene` icon element
|
|
121
|
+
- Static registry, cached for 24h
|
|
141
122
|
|
|
142
123
|
---
|
|
143
124
|
|
|
144
125
|
### `pixoo://reference/design-guide` <sub>resource</sub>
|
|
145
126
|
|
|
146
|
-
-
|
|
147
|
-
- `
|
|
148
|
-
- Same content `pixoo_design_brief` surfaces per topic — this resource is the complete reference in one document
|
|
127
|
+
- `text/markdown`: legibility floors, palette discipline, layout zones, animation budget, effect presets, pixel art rules, push pacing, and known device behaviors
|
|
128
|
+
- The whole guide in one document, where `pixoo_design_brief` returns guidance per topic; cached for 24h
|
|
149
129
|
|
|
150
130
|
## Features
|
|
151
131
|
|
|
@@ -153,22 +133,20 @@ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): s
|
|
|
153
133
|
|
|
154
134
|
Pixoo-specific:
|
|
155
135
|
|
|
156
|
-
-
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
- Push pacing: device commands serialized with a configurable minimum inter-push interval (default 1000ms) to prevent device freezes
|
|
160
|
-
- Animation capped at 40 frames (device instability beyond this); contact-sheet PNG preview for animations (GIF preview is inconsistent across MCP clients)
|
|
136
|
+
- All composition happens on the host in an RGBA canvas pipeline (`@cyanheads/pixoo-toolkit`); the device receives finished RGB frames
|
|
137
|
+
- Pushes switch the device to the custom channel and run one at a time, spaced by `PIXOO_PUSH_MIN_INTERVAL_MS` (default 1000) so rapid pushes don't freeze the device
|
|
138
|
+
- Animations cap at 40 frames, past which the device becomes unstable
|
|
161
139
|
|
|
162
140
|
Agent-friendly output:
|
|
163
141
|
|
|
164
|
-
- Preview
|
|
165
|
-
- Layout transparency
|
|
166
|
-
- Device truth
|
|
167
|
-
-
|
|
142
|
+
- Preview on every render: `pixoo_display_text`, `pixoo_compose_scene`, and `pixoo_push_image` return the frame as an 8× upscaled PNG image block, pushed or not, so `push: false` checks a design with no device attached. Animations preview as a grid of every frame, since GIF display varies across MCP clients; the GIF itself is saved to `PIXOO_OUTPUT_DIR` when set
|
|
143
|
+
- Layout transparency: `layout[]` reports every renderer decision (font fallback, truncation, scrolling, clipping) so agents can refine a design
|
|
144
|
+
- Device truth: `pushed` reflects the device ACK, and the `deviceState` read back after a push comes with a notice naming the fix when the render won't be visible (screen off, brightness ≤ 10, off the custom channel)
|
|
145
|
+
- Renders survive failed pushes: the typed error (`device_unreachable`, `device_http_error`, `device_rejected`, `no_device_configured`) carries `outputFiles` pointing at the saved preview (the `PIXOO_OUTPUT_DIR` copy, or a temp file when that is unset)
|
|
168
146
|
|
|
169
147
|
## Getting started
|
|
170
148
|
|
|
171
|
-
Add the following to your MCP client configuration file
|
|
149
|
+
Add the following to your MCP client configuration file, with `PIXOO_IP` set to your Pixoo's LAN address. `pixoo_discover_devices` finds it if you don't know it.
|
|
172
150
|
|
|
173
151
|
```json
|
|
174
152
|
{
|
|
@@ -235,7 +213,7 @@ MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 PIXOO_IP=192.168.1.50 bun run start:h
|
|
|
235
213
|
### Prerequisites
|
|
236
214
|
|
|
237
215
|
- [Bun v1.4.0](https://bun.sh/) or higher (or Node.js v24+).
|
|
238
|
-
- A Divoom Pixoo
|
|
216
|
+
- A Divoom Pixoo on the local network (Pixoo-64, Pixoo-32, or Pixoo-16).
|
|
239
217
|
|
|
240
218
|
### Installation
|
|
241
219
|
|
|
@@ -266,22 +244,20 @@ cp .env.example .env
|
|
|
266
244
|
|
|
267
245
|
## Configuration
|
|
268
246
|
|
|
269
|
-
All configuration is validated at startup via Zod schemas in `src/config/server-config.ts`. Key environment variables:
|
|
270
|
-
|
|
271
247
|
| Variable | Description | Default |
|
|
272
|
-
|
|
273
|
-
| `PIXOO_IP` | Device IP
|
|
248
|
+
|:---|:---|:---|
|
|
249
|
+
| `PIXOO_IP` | Device IP on the local network. **Required** for pushes, overlays, and device control; discovery, design briefs, and `push: false` renders work without it. | — |
|
|
274
250
|
| `PIXOO_SIZE` | Display size in pixels: `16`, `32`, or `64`. | `64` |
|
|
275
|
-
| `PIXOO_OUTPUT_DIR` | Directory
|
|
276
|
-
| `PIXOO_PUSH_MIN_INTERVAL_MS` | Minimum
|
|
251
|
+
| `PIXOO_OUTPUT_DIR` | Directory where render tools save preview PNG and GIF files. Unset, previews are returned only in the response. | — |
|
|
252
|
+
| `PIXOO_PUSH_MIN_INTERVAL_MS` | Minimum gap between device pushes, in ms. | `1000` |
|
|
277
253
|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
278
254
|
| `MCP_HTTP_PORT` | HTTP server port. | `3010` |
|
|
279
|
-
| `MCP_SESSION_MODE` | HTTP session
|
|
255
|
+
| `MCP_SESSION_MODE` | HTTP session mode: `stateless`, `stateful`, or `auto`. A value set here overrides the server's declared `stateless`. | `stateless` |
|
|
280
256
|
| `MCP_AUTH_MODE` | Authentication: `none`, `jwt`, or `oauth`. | `none` |
|
|
281
257
|
| `MCP_LOG_LEVEL` | Log level (`debug`, `info`, `warning`, `error`, etc.). | `info` |
|
|
282
258
|
| `LOGS_DIR` | Directory for log files (Node.js only). | `<project-root>/logs` |
|
|
283
|
-
| `
|
|
284
|
-
| `OTEL_ENABLED` | Enable OpenTelemetry
|
|
259
|
+
| `LOG_TOOL_FAILURE_PAYLOADS` | Log each failed tool call's arguments and result, redacted by key name and capped at `LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES` (default `16384`). A secret inside a free-form value is not redacted. | `false` |
|
|
260
|
+
| `OTEL_ENABLED` | Enable [OpenTelemetry](https://github.com/cyanheads/mcp-ts-core/tree/main/docs/telemetry). | `false` |
|
|
285
261
|
|
|
286
262
|
See [`.env.example`](./.env.example) for the full list of optional overrides.
|
|
287
263
|
|
|
@@ -316,18 +292,18 @@ docker build -t pixoo-mcp-server .
|
|
|
316
292
|
docker run --rm -e PIXOO_IP=192.168.1.50 -p 3010:3010 pixoo-mcp-server
|
|
317
293
|
```
|
|
318
294
|
|
|
319
|
-
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `/var/log/pixoo-mcp-server`. OpenTelemetry peer dependencies are installed by default
|
|
295
|
+
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.
|
|
320
296
|
|
|
321
297
|
## Project structure
|
|
322
298
|
|
|
323
299
|
| Directory | Purpose |
|
|
324
|
-
|
|
325
|
-
| `src/index.ts` | `createApp()` entry point
|
|
300
|
+
|:---|:---|
|
|
301
|
+
| `src/index.ts` | `createApp()` entry point: registers tools and resources and initializes the Pixoo service. |
|
|
326
302
|
| `src/config/` | Server-specific environment variable parsing and validation with Zod. |
|
|
327
|
-
| `src/mcp-server/tools/` | Tool definitions (`*.tool.ts`). |
|
|
303
|
+
| `src/mcp-server/tools/` | Tool definitions (`*.tool.ts`) and the shared post-render push path. |
|
|
328
304
|
| `src/mcp-server/resources/` | Resource definitions (`*.resource.ts`). |
|
|
329
|
-
| `src/services/pixoo/` | `PixooService
|
|
330
|
-
| `src/renderer/` | Pure rendering pipeline: element renderers, styled-text engine, themes, icons, effect compiler, preview encoding
|
|
305
|
+
| `src/services/pixoo/` | `PixooService`: wraps `@cyanheads/pixoo-toolkit` with push pacing, result mapping, and device state reads. |
|
|
306
|
+
| `src/renderer/` | Pure rendering pipeline with no device dependency: element renderers, styled-text engine, themes, icons, effect compiler, preview encoding, remote image fetch. |
|
|
331
307
|
| `tests/` | Unit and integration tests mirroring `src/`. |
|
|
332
308
|
|
|
333
309
|
## Development guide
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "pixoo_display_text adds scroll/float/pulse effects, align, and an honored font; animated previews return a full frame grid; failed pushes keep their render; design_brief's suggestion shape and overlay_text's x/y/width bounds change (breaking); scene image sizing and per-source caching are fixed."
|
|
3
|
+
breaking: true
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 1.2.0 — 2026-09-23
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`pixoo_display_text` gains `effect: "scroll" | "float" | "pulse"`** — animates the text and pushes it as a multi-frame animation; `effect: "auto"` scrolls only when the text overflows ([#3](https://github.com/cyanheads/pixoo-mcp-server/issues/3)).
|
|
12
|
+
- **`align: "left" | "center" | "right"`** on `pixoo_display_text` lines up multi-line text within the block `position.x` places ([#3](https://github.com/cyanheads/pixoo-mcp-server/issues/3)).
|
|
13
|
+
- **An explicit `font` on `pixoo_display_text` is honored on single-line text** instead of always starting from the 5×7 font ([#20](https://github.com/cyanheads/pixoo-mcp-server/issues/20)).
|
|
14
|
+
- **`pixoo_display_text` and `pixoo_compose_scene` animations return a real contact-sheet grid** tiling every frame, instead of the single middle frame ([#6](https://github.com/cyanheads/pixoo-mcp-server/issues/6)).
|
|
15
|
+
- **A successful push the panel won't show now carries a notice** — screen off, brightness ≤ 10, or the device off the Custom channel — naming the `pixoo_control_device` call that fixes it ([#16](https://github.com/cyanheads/pixoo-mcp-server/issues/16)).
|
|
16
|
+
|
|
17
|
+
## Changed
|
|
18
|
+
|
|
19
|
+
- **`nextToolSuggestions` on `pixoo_design_brief` is now `{ toolName, reason, args }`**, replacing `{ tool, rationale, suggestedArgs? }`; `args` is required. Breaking ([#10](https://github.com/cyanheads/pixoo-mcp-server/issues/10)).
|
|
20
|
+
- **An explicit `output` on `pixoo_compose_scene` replaces the `PIXOO_OUTPUT_DIR` auto-save** for that call instead of writing both ([#9](https://github.com/cyanheads/pixoo-mcp-server/issues/9)).
|
|
21
|
+
- **A failed push now keeps its render** — the preview's path (the auto-save, or a fresh temp file) rides the error as `data.outputFiles` instead of being lost ([#17](https://github.com/cyanheads/pixoo-mcp-server/issues/17)).
|
|
22
|
+
- Remote image downloads on `pixoo_push_image` and `pixoo_compose_scene` now cancel mid-stream when the calling request is cancelled ([#18](https://github.com/cyanheads/pixoo-mcp-server/issues/18)).
|
|
23
|
+
|
|
24
|
+
## Fixed
|
|
25
|
+
|
|
26
|
+
- **`pixoo_overlay_text` rejects `x`/`y` at or beyond the configured `PIXOO_SIZE` and `width` above it** — the schema's `.max(64)` ceiling can't see the runtime size on 16/32px devices. Breaking: `x`/`y` equal to the display size, previously accepted off-canvas, is now rejected ([#8](https://github.com/cyanheads/pixoo-mcp-server/issues/8)).
|
|
27
|
+
- **`pixoo_compose_scene` `image` elements fit the configured `PIXOO_SIZE`** instead of always loading onto a 64px canvas ([#15](https://github.com/cyanheads/pixoo-mcp-server/issues/15)).
|
|
28
|
+
- **Two `image` elements sharing a source now render independently** instead of both taking whichever element's placement loaded last ([#21](https://github.com/cyanheads/pixoo-mcp-server/issues/21)).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "pixoo_compose_scene checks animate keyframes per property and caps image, icon, and sprite sizes; stroke icons, icon palettes, keyframed colors, and layout fits now render and report as documented. mcp-ts-core ^0.13.6 → ^0.13.9."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 1.2.1 — 2026-09-26
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- **`animate` keyframe values are checked per property** — `dx`, `dy`, and `opacity` take numbers or numeric strings, `visible` takes `true`/`false` only (numbers are now rejected), and a bad value fails `-32602` naming the keyframe ([#47](https://github.com/cyanheads/pixoo-mcp-server/issues/47)). An empty track fails the same way ([#45](https://github.com/cyanheads/pixoo-mcp-server/issues/45)).
|
|
12
|
+
- **Element sizes are capped** — `image` and `icon` `w`/`h` must be 1–256, and sprite `cols`, `rows`, and `scale` at most 64; out-of-range values fail `-32602` naming the field ([#33](https://github.com/cyanheads/pixoo-mcp-server/issues/33), [#37](https://github.com/cyanheads/pixoo-mcp-server/issues/37), [#38](https://github.com/cyanheads/pixoo-mcp-server/issues/38)).
|
|
13
|
+
- **Registry icons draw their stroke parts as 1-pixel lines** — `snow` and `wind` render, `sun`, `rain`, and the arrows keep their rays, drops, and shafts, and the status icons draw as a ring plus mark instead of a solid disk ([#39](https://github.com/cyanheads/pixoo-mcp-server/issues/39)).
|
|
14
|
+
- **`layout[].fits` is computed from the placed box on all four edges** for every element; `image` and `line` boxes include `dx`/`dy`, `circle` and `line` boxes their last pixel, a `bitmap` box spans its widest row, and a `pixels` box bounds its points ([#42](https://github.com/cyanheads/pixoo-mcp-server/issues/42)).
|
|
15
|
+
- **Effect `amplitude` sets the depth of the `pulse` and `twinkle` opacity dip** on a 0–1 scale; the defaults (0.5, 0.6) keep the 50–100 and 40–100 ranges ([#41](https://github.com/cyanheads/pixoo-mcp-server/issues/41)).
|
|
16
|
+
- **A keyframed `color` interpolates and drives every element with a `color` field** — in-between frames resolve as `#rrggbb` instead of failing `invalid_color`, and `text`, `icon`, `rect`, `circle`, `line`, and `sparkline` animate it, not only `pixels` ([#36](https://github.com/cyanheads/pixoo-mcp-server/issues/36)).
|
|
17
|
+
- **Framework argument handling (mcp-ts-core 0.13.7–0.13.9)** — an integer sent to a string field, or a JSON-stringified object, is repaired before validation; rejections name the field path; stack traces and request context no longer reach client error data.
|
|
18
|
+
- **Opt-in `LOG_TOOL_FAILURE_PAYLOADS` and `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`** log failed calls' arguments and results and export logs over OTLP; the Docker image installs the log-export peers.
|
|
19
|
+
- Repo hygiene: framework skills and scripts resynced with mcp-ts-core 0.13.9; the npm tarball excludes `dist/*.mcpb`; `.mcpbignore` excludes `docs/idea.md` and `logs/`.
|
|
20
|
+
|
|
21
|
+
## Fixed
|
|
22
|
+
|
|
23
|
+
- **`Object.prototype` names such as `constructor` or `__proto__` as an icon `name` fail as `unknown_icon`** instead of an internal `-32603` ([#32](https://github.com/cyanheads/pixoo-mcp-server/issues/32)). The same names as color values are not covered yet.
|
|
24
|
+
- **Icon `palette` paints a top-to-bottom ramp** from the palette's `from` to its `to` color and takes precedence over `color`; it was accepted and ignored ([#35](https://github.com/cyanheads/pixoo-mcp-server/issues/35)).
|
|
25
|
+
- **A `color` keyframe that isn't a color fails as `invalid_color` wherever it sits in the track**, including past the scene's last frame ([#40](https://github.com/cyanheads/pixoo-mcp-server/issues/40)).
|
|
26
|
+
- **Numeric-string keyframes on `dx`, `dy`, and `opacity` interpolate like the numbers they spell** (`"000"` → `"100"` ramps 0 → 100); only the `color` track lerps through RGB ([#43](https://github.com/cyanheads/pixoo-mcp-server/issues/43)).
|
|
27
|
+
- **A line-mode `sparkline` stays inside its `w × h` box** instead of inking one column and one row past it ([#44](https://github.com/cyanheads/pixoo-mcp-server/issues/44)).
|
|
28
|
+
- **The `music` icon's beam joins its two stems** ([#46](https://github.com/cyanheads/pixoo-mcp-server/issues/46)).
|
|
29
|
+
|
|
30
|
+
## Dependencies
|
|
31
|
+
|
|
32
|
+
- `@cyanheads/mcp-ts-core` ^0.13.6 → ^0.13.9 (`@modelcontextprotocol/server` 2.0.0 → 2.1.0, transitive)
|
|
33
|
+
- `@socketsecurity/bun-security-scanner` ^1.1.2 → ^1.1.3 (dev)
|
|
34
|
+
- `ignore` ^7.0.9 → ^7.0.10 (dev)
|
|
35
|
+
- Bun 1.4.0 → 1.4.2 (`packageManager` and Docker base images)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pixoo-design-guide.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/pixoo-design-guide.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"pixoo-design-guide.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/pixoo-design-guide.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAwGrD,eAAO,MAAM,wBAAwB,2GAyBnC,CAAC"}
|
|
@@ -99,6 +99,7 @@ At typical viewing distance for a 64×64 LED display:
|
|
|
99
99
|
## Known Device Behaviors
|
|
100
100
|
|
|
101
101
|
- **Channel must be Custom** to display pushed content. The server auto-switches when pushing.
|
|
102
|
+
- **A push the panel won't show** — screen off, brightness 10 or lower, or still off Custom after a failed switch — succeeds with a notice naming the pixoo_control_device call that fixes it.
|
|
102
103
|
- **getConfig() omits SelectIndex** on current Pixoo-64 firmware — use getChannel() for reliable channel reads
|
|
103
104
|
- **Text overlays (pixoo_overlay_text)** persist across channel switches until explicitly cleared
|
|
104
105
|
- **Discovery requires internet** — Divoom cloud endpoint even for local device control
|