@cyanheads/pixoo-mcp-server 1.2.0 → 1.2.2
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 +10 -7
- package/CLAUDE.md +10 -7
- package/Dockerfile +30 -10
- package/README.md +65 -86
- package/changelog/1.2.x/1.2.1.md +35 -0
- package/changelog/1.2.x/1.2.2.md +40 -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 +4 -1
- 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 +173 -13
- 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 +129 -28
- 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.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-design-brief.tool.js +15 -7
- 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 +2 -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 +27 -12
- package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.d.ts +30 -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 +105 -26
- package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.js.map +1 -1
- package/dist/mcp-server/tools/finish-schema.d.ts +28 -0
- package/dist/mcp-server/tools/finish-schema.d.ts.map +1 -0
- package/dist/mcp-server/tools/finish-schema.js +42 -0
- package/dist/mcp-server/tools/finish-schema.js.map +1 -0
- package/dist/renderer/finish.d.ts +34 -0
- package/dist/renderer/finish.d.ts.map +1 -0
- package/dist/renderer/finish.js +62 -0
- package/dist/renderer/finish.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 +40 -4
- package/dist/renderer/keyframes.d.ts.map +1 -1
- package/dist/renderer/keyframes.js +100 -53
- package/dist/renderer/keyframes.js.map +1 -1
- package/dist/renderer/remote-image.d.ts +13 -7
- package/dist/renderer/remote-image.d.ts.map +1 -1
- package/dist/renderer/remote-image.js +17 -21
- package/dist/renderer/remote-image.js.map +1 -1
- package/dist/renderer/scene-renderer.d.ts +45 -6
- package/dist/renderer/scene-renderer.d.ts.map +1 -1
- package/dist/renderer/scene-renderer.js +328 -159
- package/dist/renderer/scene-renderer.js.map +1 -1
- package/dist/renderer/text-engine.d.ts +24 -5
- package/dist/renderer/text-engine.d.ts.map +1 -1
- package/dist/renderer/text-engine.js +51 -28
- package/dist/renderer/text-engine.js.map +1 -1
- package/package.json +7 -6
- 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.2.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 1.2.2
|
|
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. |
|
|
@@ -187,6 +187,7 @@ Pixoo-specific error reasons declared on tools:
|
|
|
187
187
|
| `device_rejected` | `ServiceUnavailable` | Firmware returned non-zero `error_code` | — |
|
|
188
188
|
| `no_device_configured` | `InvalidParams` | Device tool called without `PIXOO_IP` | — |
|
|
189
189
|
| `asset_not_found` | `NotFound` | Image/sprite path or URL unreadable | — |
|
|
190
|
+
| `invalid_image` | `InvalidParams` | Image source or sprite path read but not decodable | — |
|
|
190
191
|
| `invalid_color` | `InvalidParams` | `resolveColor` throw — invalid color name or format | — |
|
|
191
192
|
| `unknown_icon` | `InvalidParams` | Icon name not in registry | — |
|
|
192
193
|
| `discovery_failed` | `ServiceUnavailable` | Divoom cloud unreachable | `true` |
|
|
@@ -234,11 +235,13 @@ src/
|
|
|
234
235
|
text-engine.ts # Gradient ramp + shadow + outline text engine, overflow handling
|
|
235
236
|
scene-renderer.ts # Element vocabulary, layout resolver, frame rendering
|
|
236
237
|
keyframes.ts # Keyframe interpolation + animation preset compiler
|
|
238
|
+
finish.ts # Palette finish (quantize + dither) for one frame, or frames sharing one palette
|
|
237
239
|
preview.ts # PNG/contact-sheet/GIF encoding
|
|
238
|
-
remote-image.ts # https image fetch
|
|
240
|
+
remote-image.ts # https image fetch into memory for the toolkit loader; stops on ctx.signal
|
|
239
241
|
mcp-server/
|
|
240
242
|
tools/
|
|
241
243
|
device-push.ts # Shared post-render push: preview kept on failure, visibility notice
|
|
244
|
+
finish-schema.ts # Shared `finish` input schema (colors | palette, plus dither)
|
|
242
245
|
tools/definitions/
|
|
243
246
|
pixoo-display-text.tool.ts
|
|
244
247
|
pixoo-compose-scene.tool.ts
|
|
@@ -332,7 +335,7 @@ Available skills:
|
|
|
332
335
|
| `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` |
|
|
333
336
|
| `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` |
|
|
334
337
|
| `bun run lint:mcp` | Run the MCP definition linter standalone (rule catalog: `api-linter` skill) |
|
|
335
|
-
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity, MCPB `user_config` wiring, plugin manifests, README version
|
|
338
|
+
| `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) |
|
|
336
339
|
| `bun run list-skills` | Print the skill registry |
|
|
337
340
|
| `bun run tree` | Generate directory structure doc |
|
|
338
341
|
| `bun run format` | Auto-fix formatting (safe fixes only) |
|
|
@@ -352,7 +355,7 @@ Available skills:
|
|
|
352
355
|
|
|
353
356
|
`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.
|
|
354
357
|
|
|
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, and
|
|
358
|
+
`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).
|
|
356
359
|
|
|
357
360
|
---
|
|
358
361
|
|
package/CLAUDE.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** pixoo-mcp-server
|
|
4
|
-
**Version:** 1.2.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 1.2.2
|
|
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. |
|
|
@@ -187,6 +187,7 @@ Pixoo-specific error reasons declared on tools:
|
|
|
187
187
|
| `device_rejected` | `ServiceUnavailable` | Firmware returned non-zero `error_code` | — |
|
|
188
188
|
| `no_device_configured` | `InvalidParams` | Device tool called without `PIXOO_IP` | — |
|
|
189
189
|
| `asset_not_found` | `NotFound` | Image/sprite path or URL unreadable | — |
|
|
190
|
+
| `invalid_image` | `InvalidParams` | Image source or sprite path read but not decodable | — |
|
|
190
191
|
| `invalid_color` | `InvalidParams` | `resolveColor` throw — invalid color name or format | — |
|
|
191
192
|
| `unknown_icon` | `InvalidParams` | Icon name not in registry | — |
|
|
192
193
|
| `discovery_failed` | `ServiceUnavailable` | Divoom cloud unreachable | `true` |
|
|
@@ -234,11 +235,13 @@ src/
|
|
|
234
235
|
text-engine.ts # Gradient ramp + shadow + outline text engine, overflow handling
|
|
235
236
|
scene-renderer.ts # Element vocabulary, layout resolver, frame rendering
|
|
236
237
|
keyframes.ts # Keyframe interpolation + animation preset compiler
|
|
238
|
+
finish.ts # Palette finish (quantize + dither) for one frame, or frames sharing one palette
|
|
237
239
|
preview.ts # PNG/contact-sheet/GIF encoding
|
|
238
|
-
remote-image.ts # https image fetch
|
|
240
|
+
remote-image.ts # https image fetch into memory for the toolkit loader; stops on ctx.signal
|
|
239
241
|
mcp-server/
|
|
240
242
|
tools/
|
|
241
243
|
device-push.ts # Shared post-render push: preview kept on failure, visibility notice
|
|
244
|
+
finish-schema.ts # Shared `finish` input schema (colors | palette, plus dither)
|
|
242
245
|
tools/definitions/
|
|
243
246
|
pixoo-display-text.tool.ts
|
|
244
247
|
pixoo-compose-scene.tool.ts
|
|
@@ -332,7 +335,7 @@ Available skills:
|
|
|
332
335
|
| `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` |
|
|
333
336
|
| `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` |
|
|
334
337
|
| `bun run lint:mcp` | Run the MCP definition linter standalone (rule catalog: `api-linter` skill) |
|
|
335
|
-
| `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity, MCPB `user_config` wiring, plugin manifests, README version
|
|
338
|
+
| `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) |
|
|
336
339
|
| `bun run list-skills` | Print the skill registry |
|
|
337
340
|
| `bun run tree` | Generate directory structure doc |
|
|
338
341
|
| `bun run format` | Auto-fix formatting (safe fixes only) |
|
|
@@ -352,7 +355,7 @@ Available skills:
|
|
|
352
355
|
|
|
353
356
|
`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.
|
|
354
357
|
|
|
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, and
|
|
358
|
+
`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).
|
|
356
359
|
|
|
357
360
|
---
|
|
358
361
|
|
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,130 +23,113 @@
|
|
|
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, an animated GIF or WebP as an animation |
|
|
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
|
-
-
|
|
59
|
-
- `effect` animates the text: `scroll` runs it across the display once (up to 40 frames), `auto` scrolls only text too wide to fit, `float` and `pulse` loop over 20 frames; animations push as one device animation and report `frames`
|
|
60
|
-
- Optional `brightness` (0–100) applied before push — a failure is a warning via an enrichment notice, not a tool error
|
|
61
|
-
- Returns the rendered frame (or a grid of every animation frame) as an image content block; `outputFiles` (PNG, or GIF when animated) 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
|
+
- `font`: `standard` (5×7) and `compact` (3×5) draw printable ASCII plus `° ← ↑ → ↓ ▲ ▼ ♥ · …`; `numerals` is an 11×18 digit face for clocks and readouts that draws 0–9, space, and `: . - + / % ° ?`, and text holding any other character fails validation, naming those characters
|
|
57
|
+
- `layout[]` reports every fit decision as an `action` (`none`, `shrunk-to-compact`, or `scrolling`), the `font` used, and whether each line's box `fits` on the panel; a scrolling line's box starts at x 0, where its static frame draws it. Single-line text falls back from the standard to the compact font unless `font` is set — never to `numerals` — and text still too wide only scrolls under `effect: "auto"` or `"scroll"`
|
|
58
|
+
- `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
|
|
62
59
|
|
|
63
60
|
---
|
|
64
61
|
|
|
65
62
|
### `pixoo_compose_scene` <sub>tool</sub>
|
|
66
63
|
|
|
67
|
-
- Up to 50
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
- `
|
|
71
|
-
- `opacity` (0–100) blends any element, images included, over the layers beneath it
|
|
72
|
-
- Static scenes return a PNG preview; animations return a contact-sheet PNG tiling every frame, plus a GIF saved to `PIXOO_OUTPUT_DIR` when configured (GIF preview is inconsistent across MCP clients)
|
|
73
|
-
- Typed failures for `asset_not_found`, `invalid_color`, and `unknown_icon`, alongside the shared device-error reasons
|
|
64
|
+
- Up to 50 `elements` drawn back-to-front: `text` (in the same three fonts as `pixoo_display_text`), `icon`, `rect`, `circle`, `line`, `progress`, `sparkline`, `bitmap`, `pixels`, `image` (absolute path or https URL, with the same `finish` as `pixoo_push_image`), `sprite` (absolute path). The `background` is a solid color, a `v` / `h` / `r` gradient, or a `theme`
|
|
65
|
+
- Every element takes `opacity` (each pixel lands at its own alpha × `opacity`, so soft edges fade evenly) and `blend`: `normal`, `add` (glows and light beams), `screen`, or `multiply`. `line` and outline `circle` take `strokeWidth` and `antialias`, and a `rect` border takes `strokeWidth`, growing inward; either field on a shape that draws no stroke fails validation, naming it
|
|
66
|
+
- Returns `layout[]`: each element's placed box — for a wide or anti-aliased stroke, every pixel it draws — 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_image` (an image or sprite that was read but does not decode), `invalid_color`, `unknown_icon`, `invalid_output_path`
|
|
67
|
+
- 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
|
|
74
68
|
|
|
75
69
|
---
|
|
76
70
|
|
|
77
71
|
### `pixoo_push_image` <sub>tool</sub>
|
|
78
72
|
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
73
|
+
- `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`
|
|
74
|
+
- A source that decodes as an animated GIF or WebP, whatever its file name, pushes as an animation of up to 40 frames, sampled evenly from a longer source. It plays at the source's total duration over the pushed frame count (150 ms when the source records no delays), or at `speed` (10–2000 ms per frame); `frames`, `sourceFrames`, and `speed` report what was pushed
|
|
75
|
+
- `finish` reduces the image to a palette before the push: exactly one of `colors` (2–256, built from the image) or `palette` (1–256 hex or named colors), plus `dither` (`none`, `bayer4`, `floyd-steinberg`). Transparent pixels stay unlit, and an animation's `colors` palette is shared by every frame
|
|
76
|
+
- An unreadable path or URL fails as `asset_not_found`, a source that is read but does not decode (a text file, an HTML page, a truncated download) fails as `invalid_image`, and an unresolvable `finish` palette entry fails as `invalid_color`; the preview is the exact frame the device receives, or a grid of every frame for an animation
|
|
83
77
|
|
|
84
78
|
---
|
|
85
79
|
|
|
86
80
|
### `pixoo_overlay_text` <sub>tool</sub>
|
|
87
81
|
|
|
88
|
-
- `mode: "set"`
|
|
89
|
-
-
|
|
90
|
-
- Configurable `x`/`y` (0 to display size − 1, checked against `PIXOO_SIZE`), 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
|
|
91
|
-
- Device-rendered, not previewable — for styled, previewable text use `pixoo_display_text`
|
|
82
|
+
- `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`
|
|
83
|
+
- Returns `acknowledged`, `mode`, and `id`. The device renders the overlay, so there is no preview, and it persists across channel switches until cleared
|
|
92
84
|
|
|
93
85
|
---
|
|
94
86
|
|
|
95
87
|
### `pixoo_control_device` <sub>tool</sub>
|
|
96
88
|
|
|
97
|
-
-
|
|
98
|
-
- `
|
|
99
|
-
- Always returns current `reachable`, `channel`, `brightness`, `screenOn`, and `clockId` (the latter three absent when the device is unreachable)
|
|
89
|
+
- 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
|
|
90
|
+
- 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
|
|
100
91
|
|
|
101
92
|
---
|
|
102
93
|
|
|
103
94
|
### `pixoo_discover_devices` <sub>tool</sub>
|
|
104
95
|
|
|
105
|
-
- Queries Divoom's cloud
|
|
106
|
-
- Returns each device's name
|
|
107
|
-
- When `PIXOO_IP` is already configured, flags whether it matches a discovered device (`configuredIpFound`) and notes a mismatch
|
|
108
|
-
- `timeoutMs` configurable 1000–30000ms (default 5000ms)
|
|
96
|
+
- Queries Divoom's cloud endpoint (`app.divoom-gz.com`), so it needs internet access; `timeoutMs` 1000–30000 (default 5000)
|
|
97
|
+
- Returns each device's `name`, `id`, and `ip`; with `PIXOO_IP` set, `configuredIpFound` says whether it matched. An unreachable endpoint fails as `discovery_failed`
|
|
109
98
|
|
|
110
99
|
---
|
|
111
100
|
|
|
112
101
|
### `pixoo_design_brief` <sub>tool</sub>
|
|
113
102
|
|
|
114
|
-
-
|
|
115
|
-
- Returns markdown
|
|
116
|
-
- `nextToolSuggestions` entries are `{ toolName, reason, args }`, with `args` pre-filled with ready-to-use arguments (`{}` when the tool needs none) tailored to the topic and current device state (e.g. suggests `pixoo_discover_devices` when the device is unreachable)
|
|
117
|
-
- Also returns `availableThemes` and `iconCategories` for direct use in other tools
|
|
103
|
+
- `topic`: `text`, `scene`, `dashboard`, `animation`, `pixel-art`, or `troubleshooting`; works without a reachable device
|
|
104
|
+
- 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`
|
|
118
105
|
|
|
119
106
|
---
|
|
120
107
|
|
|
121
108
|
### `pixoo://device/status` <sub>resource</sub>
|
|
122
109
|
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
- Equivalent to calling `pixoo_control_device` with no params
|
|
110
|
+
- Uncached live read: `reachable`, `channel`, `brightness`, `screenOn`, `clockId`, `displaySize`, `configuredIp`
|
|
111
|
+
- Returns `reachable: false` rather than an error when the device can't be reached or `PIXOO_IP` is unset
|
|
126
112
|
|
|
127
113
|
---
|
|
128
114
|
|
|
129
115
|
### `pixoo://reference/themes` <sub>resource</sub>
|
|
130
116
|
|
|
131
|
-
- Every
|
|
132
|
-
-
|
|
133
|
-
- Compile-time constants — cached for 24h
|
|
117
|
+
- Every theme (background, `textPalette`, `accent`, `shadow`) and palette (`from` / `to` stops), plus `themeNames` and `paletteNames` for the `theme` and `palette` parameters
|
|
118
|
+
- Static registry, cached for 24h
|
|
134
119
|
|
|
135
120
|
---
|
|
136
121
|
|
|
137
122
|
### `pixoo://reference/icons` <sub>resource</sub>
|
|
138
123
|
|
|
139
|
-
-
|
|
140
|
-
-
|
|
141
|
-
- Compile-time constants — cached for 24h
|
|
124
|
+
- 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
|
|
125
|
+
- Static registry, cached for 24h
|
|
142
126
|
|
|
143
127
|
---
|
|
144
128
|
|
|
145
129
|
### `pixoo://reference/design-guide` <sub>resource</sub>
|
|
146
130
|
|
|
147
|
-
-
|
|
148
|
-
- `
|
|
149
|
-
- Same content `pixoo_design_brief` surfaces per topic — this resource is the complete reference in one document
|
|
131
|
+
- `text/markdown`: legibility floors, palette discipline, layout zones, animation budget, effect presets, pixel art rules, push pacing, and known device behaviors
|
|
132
|
+
- The whole guide in one document, where `pixoo_design_brief` returns guidance per topic; cached for 24h
|
|
150
133
|
|
|
151
134
|
## Features
|
|
152
135
|
|
|
@@ -154,22 +137,20 @@ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): s
|
|
|
154
137
|
|
|
155
138
|
Pixoo-specific:
|
|
156
139
|
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
- Push pacing: device commands serialized with a configurable minimum inter-push interval (default 1000ms) to prevent device freezes
|
|
161
|
-
- Animation capped at 40 frames (device instability beyond this); contact-sheet PNG preview for animations (GIF preview is inconsistent across MCP clients)
|
|
140
|
+
- All composition happens on the host in an RGBA canvas pipeline (`@cyanheads/pixoo-toolkit`); the device receives finished RGB frames
|
|
141
|
+
- 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
|
|
142
|
+
- Animations cap at 40 frames, past which the device becomes unstable; `pixoo_push_image` samples a longer GIF or WebP down to 40
|
|
162
143
|
|
|
163
144
|
Agent-friendly output:
|
|
164
145
|
|
|
165
|
-
- Preview
|
|
166
|
-
- Layout transparency
|
|
167
|
-
- Device truth
|
|
168
|
-
-
|
|
146
|
+
- 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
|
|
147
|
+
- Layout transparency: `layout[]` reports every renderer decision (font fallback, truncation, scrolling, clipping) so agents can refine a design
|
|
148
|
+
- 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)
|
|
149
|
+
- 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)
|
|
169
150
|
|
|
170
151
|
## Getting started
|
|
171
152
|
|
|
172
|
-
Add the following to your MCP client configuration file
|
|
153
|
+
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.
|
|
173
154
|
|
|
174
155
|
```json
|
|
175
156
|
{
|
|
@@ -236,7 +217,7 @@ MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 PIXOO_IP=192.168.1.50 bun run start:h
|
|
|
236
217
|
### Prerequisites
|
|
237
218
|
|
|
238
219
|
- [Bun v1.4.0](https://bun.sh/) or higher (or Node.js v24+).
|
|
239
|
-
- A Divoom Pixoo
|
|
220
|
+
- A Divoom Pixoo on the local network (Pixoo-64, Pixoo-32, or Pixoo-16).
|
|
240
221
|
|
|
241
222
|
### Installation
|
|
242
223
|
|
|
@@ -267,22 +248,20 @@ cp .env.example .env
|
|
|
267
248
|
|
|
268
249
|
## Configuration
|
|
269
250
|
|
|
270
|
-
All configuration is validated at startup via Zod schemas in `src/config/server-config.ts`. Key environment variables:
|
|
271
|
-
|
|
272
251
|
| Variable | Description | Default |
|
|
273
|
-
|
|
274
|
-
| `PIXOO_IP` | Device IP
|
|
252
|
+
|:---|:---|:---|
|
|
253
|
+
| `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. | — |
|
|
275
254
|
| `PIXOO_SIZE` | Display size in pixels: `16`, `32`, or `64`. | `64` |
|
|
276
|
-
| `PIXOO_OUTPUT_DIR` | Directory
|
|
277
|
-
| `PIXOO_PUSH_MIN_INTERVAL_MS` | Minimum
|
|
255
|
+
| `PIXOO_OUTPUT_DIR` | Directory where render tools save preview PNG and GIF files. Unset, previews are returned only in the response. | — |
|
|
256
|
+
| `PIXOO_PUSH_MIN_INTERVAL_MS` | Minimum gap between device pushes, in ms. | `1000` |
|
|
278
257
|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
279
258
|
| `MCP_HTTP_PORT` | HTTP server port. | `3010` |
|
|
280
|
-
| `MCP_SESSION_MODE` | HTTP session
|
|
259
|
+
| `MCP_SESSION_MODE` | HTTP session mode: `stateless`, `stateful`, or `auto`. A value set here overrides the server's declared `stateless`. | `stateless` |
|
|
281
260
|
| `MCP_AUTH_MODE` | Authentication: `none`, `jwt`, or `oauth`. | `none` |
|
|
282
261
|
| `MCP_LOG_LEVEL` | Log level (`debug`, `info`, `warning`, `error`, etc.). | `info` |
|
|
283
262
|
| `LOGS_DIR` | Directory for log files (Node.js only). | `<project-root>/logs` |
|
|
284
|
-
| `
|
|
285
|
-
| `OTEL_ENABLED` | Enable OpenTelemetry
|
|
263
|
+
| `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` |
|
|
264
|
+
| `OTEL_ENABLED` | Enable [OpenTelemetry](https://github.com/cyanheads/mcp-ts-core/tree/main/docs/telemetry). | `false` |
|
|
286
265
|
|
|
287
266
|
See [`.env.example`](./.env.example) for the full list of optional overrides.
|
|
288
267
|
|
|
@@ -317,18 +296,18 @@ docker build -t pixoo-mcp-server .
|
|
|
317
296
|
docker run --rm -e PIXOO_IP=192.168.1.50 -p 3010:3010 pixoo-mcp-server
|
|
318
297
|
```
|
|
319
298
|
|
|
320
|
-
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `/var/log/pixoo-mcp-server`. OpenTelemetry peer dependencies are installed by default
|
|
299
|
+
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.
|
|
321
300
|
|
|
322
301
|
## Project structure
|
|
323
302
|
|
|
324
303
|
| Directory | Purpose |
|
|
325
|
-
|
|
326
|
-
| `src/index.ts` | `createApp()` entry point
|
|
304
|
+
|:---|:---|
|
|
305
|
+
| `src/index.ts` | `createApp()` entry point: registers tools and resources and initializes the Pixoo service. |
|
|
327
306
|
| `src/config/` | Server-specific environment variable parsing and validation with Zod. |
|
|
328
|
-
| `src/mcp-server/tools/` | Tool definitions (`*.tool.ts`). |
|
|
307
|
+
| `src/mcp-server/tools/` | Tool definitions (`*.tool.ts`), the shared post-render push path, and the shared `finish` input schema. |
|
|
329
308
|
| `src/mcp-server/resources/` | Resource definitions (`*.resource.ts`). |
|
|
330
|
-
| `src/services/pixoo/` | `PixooService
|
|
331
|
-
| `src/renderer/` | Pure rendering pipeline: element renderers, styled-text engine, themes, icons, effect compiler, preview encoding
|
|
309
|
+
| `src/services/pixoo/` | `PixooService`: wraps `@cyanheads/pixoo-toolkit` with push pacing, result mapping, and device state reads. |
|
|
310
|
+
| `src/renderer/` | Pure rendering pipeline with no device dependency: element renderers, styled-text engine, themes, icons, effect compiler, palette finishing, preview encoding, remote image fetch. |
|
|
332
311
|
| `tests/` | Unit and integration tests mirroring `src/`. |
|
|
333
312
|
|
|
334
313
|
## Development guide
|
|
@@ -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)
|