@cyanheads/pixoo-mcp-server 1.0.0 → 1.1.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.
Files changed (56) hide show
  1. package/AGENTS.md +51 -25
  2. package/CLAUDE.md +51 -25
  3. package/Dockerfile +21 -7
  4. package/LICENSE +1 -1
  5. package/README.md +3 -2
  6. package/changelog/1.1.x/1.1.0.md +37 -0
  7. package/changelog/1.1.x/1.1.1.md +11 -0
  8. package/changelog/template.md +60 -19
  9. package/dist/index.js +11 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/mcp-server/resources/definitions/pixoo-design-guide.resource.d.ts.map +1 -1
  12. package/dist/mcp-server/resources/definitions/pixoo-design-guide.resource.js +2 -0
  13. package/dist/mcp-server/resources/definitions/pixoo-design-guide.resource.js.map +1 -1
  14. package/dist/mcp-server/resources/definitions/pixoo-device-status.resource.d.ts +9 -1
  15. package/dist/mcp-server/resources/definitions/pixoo-device-status.resource.d.ts.map +1 -1
  16. package/dist/mcp-server/resources/definitions/pixoo-device-status.resource.js +25 -0
  17. package/dist/mcp-server/resources/definitions/pixoo-device-status.resource.js.map +1 -1
  18. package/dist/mcp-server/resources/definitions/pixoo-icons.resource.d.ts +9 -1
  19. package/dist/mcp-server/resources/definitions/pixoo-icons.resource.d.ts.map +1 -1
  20. package/dist/mcp-server/resources/definitions/pixoo-icons.resource.js +17 -0
  21. package/dist/mcp-server/resources/definitions/pixoo-icons.resource.js.map +1 -1
  22. package/dist/mcp-server/resources/definitions/pixoo-themes.resource.d.ts +23 -1
  23. package/dist/mcp-server/resources/definitions/pixoo-themes.resource.d.ts.map +1 -1
  24. package/dist/mcp-server/resources/definitions/pixoo-themes.resource.js +57 -0
  25. package/dist/mcp-server/resources/definitions/pixoo-themes.resource.js.map +1 -1
  26. package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.d.ts +77 -76
  27. package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.d.ts.map +1 -1
  28. package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.js +29 -27
  29. package/dist/mcp-server/tools/definitions/pixoo-compose-scene.tool.js.map +1 -1
  30. package/dist/mcp-server/tools/definitions/pixoo-control-device.tool.d.ts +2 -2
  31. package/dist/mcp-server/tools/definitions/pixoo-design-brief.tool.d.ts +3 -3
  32. package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.d.ts +17 -21
  33. package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.d.ts.map +1 -1
  34. package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.js +5 -14
  35. package/dist/mcp-server/tools/definitions/pixoo-display-text.tool.js.map +1 -1
  36. package/dist/mcp-server/tools/definitions/pixoo-overlay-text.tool.d.ts +2 -2
  37. package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.d.ts +2 -6
  38. package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.d.ts.map +1 -1
  39. package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.js +13 -42
  40. package/dist/mcp-server/tools/definitions/pixoo-push-image.tool.js.map +1 -1
  41. package/dist/renderer/keyframes.js.map +1 -1
  42. package/dist/renderer/remote-image.d.ts +21 -0
  43. package/dist/renderer/remote-image.d.ts.map +1 -0
  44. package/dist/renderer/remote-image.js +64 -0
  45. package/dist/renderer/remote-image.js.map +1 -0
  46. package/dist/renderer/scene-renderer.d.ts +9 -3
  47. package/dist/renderer/scene-renderer.d.ts.map +1 -1
  48. package/dist/renderer/scene-renderer.js +16 -33
  49. package/dist/renderer/scene-renderer.js.map +1 -1
  50. package/dist/renderer/text-engine.js.map +1 -1
  51. package/dist/services/pixoo/pixoo-service.d.ts.map +1 -1
  52. package/dist/services/pixoo/pixoo-service.js +2 -2
  53. package/dist/services/pixoo/pixoo-service.js.map +1 -1
  54. package/package.json +14 -12
  55. package/server.json +3 -3
  56. package/dist/pixoo-mcp-server.mcpb +0 -0
package/AGENTS.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Developer Protocol
2
2
 
3
3
  **Server:** pixoo-mcp-server
4
- **Version:** 1.0.0
5
- **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.10.6`
4
+ **Version:** 1.1.1
5
+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.12.3`
6
6
  **Engines:** Bun ≥1.3.0, Node ≥24.0.0
7
- **MCP SDK:** `@modelcontextprotocol/sdk` ^1.29.0
7
+ **MCP SDK:** `@modelcontextprotocol/server` ^2.0.0 (protocol revision 2026-07-28 alongside the 2025 era)
8
8
  **Zod:** ^4.4.3
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.
@@ -32,8 +32,9 @@ When the user asks what's next or needs direction, suggest options based on the
32
32
  2. **Add tools/resources/prompts** — scaffold new definitions using the `add-tool`, `add-resource`, `add-prompt` skills
33
33
  3. **Field-test definitions** — exercise tools/resources/prompts with real inputs using the `field-test` skill
34
34
  4. **Run `devcheck`** — lint, format, typecheck, and security audit
35
- 5. **Run the `polish-docs-meta` skill** — finalize README, CHANGELOG, metadata, and agent protocol for shipping
36
- 6. **Run the `maintenance` skill** — investigate changelogs, adopt upstream changes, and sync skills after `bun update --latest`
35
+ 5. **Run the `security-pass` skill** — audit handlers for MCP-specific security gaps: output injection, scope blast radius, input sinks, tenant isolation
36
+ 6. **Run the `polish-docs-meta` skill** — finalize README, CHANGELOG, metadata, and agent protocol for shipping
37
+ 7. **Run the `maintenance` skill** — investigate changelogs, adopt upstream changes, and sync skills after `bun update --latest`
37
38
 
38
39
  Tailor suggestions to what's actually missing or stale — don't recite the full list every time.
39
40
 
@@ -44,10 +45,11 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
44
45
  - **Logic throws, framework catches.** Tool/resource handlers are pure — throw on failure, no `try/catch`. Plain `Error` is fine; the framework catches, classifies, and formats. Use error factories (`notFound()`, `serviceUnavailable()`, etc.) when the error code matters.
45
46
  - **Use `ctx.log`** for request-scoped logging. No `console` calls.
46
47
  - **Use `ctx.state`** for tenant-scoped storage. Never access persistence directly.
47
- - **Check `ctx.elicit`** for presence before calling.
48
+ - **Need input the caller didn't supply?** `return ctx.requestInput(...)` and read `ctx.inputs` when the handler is re-entered. Never `await` for user input mid-handler. (`ctx.elicit` was removed in the SDK v2 migration.)
48
49
  - **Secrets in env vars only** — never hardcoded.
49
50
  - **Every `PixooResult` checked.** No fire-and-forget device calls. `pushed: true` means `error_code: 0` from the device.
50
- - **Close the loop on issues.** When implementing work tracked by a GitHub issue, comment on the issue with what landed and close it.
51
+ - **Adding an env var requires both files** — `server.json` (`environmentVariables[]`) and `manifest.json` (`mcp_config.env` + `user_config`). `bun run lint:packaging` verifies the names match.
52
+ - **Close the loop on issues.** When implementing work tracked by a GitHub issue, comment on the issue with what landed and close it. Do both — a comment without a close leaves stale issues open; a close without a comment leaves no record of what shipped.
51
53
 
52
54
  ---
53
55
 
@@ -73,22 +75,25 @@ export const pixooDisplayText = tool('pixoo_display_text', {
73
75
  push: z.boolean().default(true).describe('Push to device after render.'),
74
76
  }),
75
77
  output: z.object({
76
- preview: z.string().describe('Base64-encoded PNG preview of the rendered frame.'),
77
78
  pushed: z.boolean().describe('True if the device acknowledged the push.'),
78
79
  }),
79
80
  async handler(input, ctx) {
80
81
  const service = getPixooService();
81
- const result = await renderAndPush(input, service);
82
- ctx.log.info('Text rendered', { pushed: result.pushed });
83
- return result;
82
+ const { preview, pushed } = await renderAndPush(input, service);
83
+ // Rendered bytes go through ctx.content — prepended to content[] and never
84
+ // written to structuredContent, so the base64 is carried once, not twice.
85
+ ctx.content.image(preview, 'image/png');
86
+ ctx.log.info('Text rendered', { pushed });
87
+ return { pushed };
84
88
  },
85
- format: (result) => [
86
- { type: 'image', data: result.preview, mimeType: 'image/png' },
87
- { type: 'text', text: `Pushed: ${result.pushed}` },
88
- ],
89
+ format: (result) => [{ type: 'text', text: `Pushed: ${result.pushed}` }],
89
90
  });
90
91
  ```
91
92
 
93
+ **Rendered previews never enter `output`.** Every render tool emits its PNG with
94
+ `ctx.content.image(...)`. Declaring it as an `output` field too would ship the base64
95
+ twice — once in `structuredContent`, once in the `content[]` block.
96
+
92
97
  ### Resource
93
98
 
94
99
  ```ts
@@ -141,9 +146,14 @@ Handlers receive a unified `ctx` object. Key properties used by this server:
141
146
 
142
147
  | Property | Description |
143
148
  |:---------|:------------|
144
- | `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. |
145
- | `ctx.signal` | `AbortSignal` for cancellation. |
149
+ | `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. Dual-sink: Pino **and** `notifications/message` to the client, so treat it as client-visible. |
150
+ | `ctx.enrich` | Success-path agent context — `.notice()` / `.total()` / `.echo()` / `.truncated()`. Lands only when the definition declares an `enrichment` block. |
151
+ | `ctx.fail` | Typed throw against the definition's `errors[]` reason union — auto-populates `data.reason`. |
152
+ | `ctx.state` | Tenant-scoped KV — `.get`, `.set(key, value, { ttl? })`, `.delete`, `.getMany`, `.list`. Keys are validated; colons are not legal separators. |
153
+ | `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. |
154
+ | `ctx.signal` | `AbortSignal` for cancellation. Pass it to any long-running I/O. |
146
155
  | `ctx.requestId` | Unique request ID. |
156
+ | `ctx.tenantId` | Tenant ID from JWT; `'default'` for stdio or HTTP with auth off. |
147
157
 
148
158
  ---
149
159
 
@@ -251,15 +261,26 @@ Available skills:
251
261
  | `tool-defs-analysis` | Read-only audit of MCP definition language across the surface |
252
262
  | `security-pass` | Audit server for MCP-flavored security gaps |
253
263
  | `code-simplifier` | Post-session cleanup against `git diff` |
254
- | `devcheck` | Lint, format, typecheck, audit |
255
264
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
256
265
  | `git-wrapup` | Land working-tree changes as a versioned commit + annotated tag |
257
266
  | `release-and-publish` | Push + npm + MCP Registry + GH Release + Docker |
258
267
  | `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
268
+ | `orchestrations` | Chain task skills into a gated multi-phase pipeline when sub-agents are available |
269
+ | `techniques` | Catalog of response/data-shaping techniques — overflow handling, payload shaping |
259
270
  | `report-issue-local` | File a bug or feature request against this server's own repo via `gh` CLI |
271
+ | `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
272
+ | `api-auth` | Auth modes, scopes, JWT/OAuth |
273
+ | `api-canvas` | DataCanvas: register tabular data, run SQL, export — Tier 3 opt-in |
274
+ | `api-config` | AppConfig, parseEnvConfig, env vars |
275
+ | `api-context` | Context interface, RequestContext, logger, state, multi-round-trip input |
260
276
  | `api-errors` | McpError, JsonRpcErrorCode, error patterns |
261
- | `api-context` | Context interface, logger, state, progress |
262
- | `api-testing` | createMockContext, test patterns |
277
+ | `api-linter` | Definition linter rule catalog — invoked by `bun run lint:mcp` and `devcheck` |
278
+ | `api-mirror` | MirrorService: self-refreshing local SQLite/FTS5 mirror of a bulk dataset — Tier 3 opt-in |
279
+ | `api-services` | LLM, Speech, Graph services |
280
+ | `api-telemetry` | OTel catalog: spans, metrics, completion logs, env config, cardinality rules |
281
+ | `api-testing` | createMockContext, createFetchMock, runToolContract, test patterns |
282
+ | `api-utils` | Formatting, parsing, security, pagination, scheduling, telemetry helpers |
283
+ | `api-workers` | Cloudflare Workers runtime |
263
284
 
264
285
  ---
265
286
 
@@ -273,11 +294,14 @@ Available skills:
273
294
  | `bun run rebuild` | Clean + build |
274
295
  | `bun run clean` | Remove build artifacts |
275
296
  | `bun run devcheck` | Lint + format + typecheck + security + changelog sync |
276
- | `bun run audit:refresh` | Delete `bun.lock`, reinstall, and re-run `bun audit` |
297
+ | `bun run audit:refresh` | Delete `bun.lock`, reinstall, and re-run `bun audit`. Re-resolves the `^`-ranged framework pin — verify the lock afterwards |
298
+ | `bun run lint:mcp` | Run the MCP definition linter standalone (rule catalog: `api-linter` skill) |
299
+ | `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity |
300
+ | `bun run list-skills` | Print the skill registry |
277
301
  | `bun run tree` | Generate directory structure doc |
278
302
  | `bun run format` | Auto-fix formatting (safe fixes only) |
279
303
  | `bun run format:unsafe` | Also apply Biome's unsafe autofixes — review the diff |
280
- | `bunx vitest run` | Run tests |
304
+ | `bun run test` | Run tests (Vitest — use `bun run test`, not `bun test`) |
281
305
  | `bun run start:stdio` | Production mode (stdio) |
282
306
  | `bun run start:http` | Production mode (HTTP) |
283
307
  | `bun run changelog:build` | Regenerate `CHANGELOG.md` from `changelog/*.md` |
@@ -288,11 +312,13 @@ Available skills:
288
312
 
289
313
  ## Checklist
290
314
 
291
- - [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types
315
+ - [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types (no `z.custom()`, `z.date()`, `z.transform()`, `z.bigint()`, `z.symbol()`, `z.void()`, `z.map()`, `z.set()`, `z.function()`, `z.nan()`)
316
+ - [ ] Tool inputs are strict at the root — an undeclared argument key is rejected by name. Add `.passthrough()` / `.catchall()` only where an open object is genuinely required
292
317
  - [ ] JSDoc `@fileoverview` + `@module` on every file
293
318
  - [ ] `ctx.log` for logging, `ctx.state` for storage
294
319
  - [ ] Handlers throw on failure — error factories or plain `Error`, no try/catch
295
- - [ ] `format()` renders all data the LLM needs — image content blocks for renders, text for structured data
320
+ - [ ] `format()` renders every `output` field as text — different clients read different surfaces (`structuredContent` vs `content[]`); `lint:mcp` enforces parity. Rendered image bytes go through `ctx.content.image(...)`, never an `output` field
296
321
  - [ ] Every device call goes through `PixooService`; every `PixooResult` checked
297
322
  - [ ] Renderer functions have no device dependency — testable without hardware
298
- - [ ] `npm run devcheck` passes
323
+ - [ ] Env var added? Declared in BOTH `server.json` and `manifest.json` (`lint:packaging` enforces parity)
324
+ - [ ] `bun run devcheck` and `bun run test` pass
package/CLAUDE.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Developer Protocol
2
2
 
3
3
  **Server:** pixoo-mcp-server
4
- **Version:** 1.0.0
5
- **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.10.6`
4
+ **Version:** 1.1.1
5
+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.12.3`
6
6
  **Engines:** Bun ≥1.3.0, Node ≥24.0.0
7
- **MCP SDK:** `@modelcontextprotocol/sdk` ^1.29.0
7
+ **MCP SDK:** `@modelcontextprotocol/server` ^2.0.0 (protocol revision 2026-07-28 alongside the 2025 era)
8
8
  **Zod:** ^4.4.3
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.
@@ -32,8 +32,9 @@ When the user asks what's next or needs direction, suggest options based on the
32
32
  2. **Add tools/resources/prompts** — scaffold new definitions using the `add-tool`, `add-resource`, `add-prompt` skills
33
33
  3. **Field-test definitions** — exercise tools/resources/prompts with real inputs using the `field-test` skill
34
34
  4. **Run `devcheck`** — lint, format, typecheck, and security audit
35
- 5. **Run the `polish-docs-meta` skill** — finalize README, CHANGELOG, metadata, and agent protocol for shipping
36
- 6. **Run the `maintenance` skill** — investigate changelogs, adopt upstream changes, and sync skills after `bun update --latest`
35
+ 5. **Run the `security-pass` skill** — audit handlers for MCP-specific security gaps: output injection, scope blast radius, input sinks, tenant isolation
36
+ 6. **Run the `polish-docs-meta` skill** — finalize README, CHANGELOG, metadata, and agent protocol for shipping
37
+ 7. **Run the `maintenance` skill** — investigate changelogs, adopt upstream changes, and sync skills after `bun update --latest`
37
38
 
38
39
  Tailor suggestions to what's actually missing or stale — don't recite the full list every time.
39
40
 
@@ -44,10 +45,11 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
44
45
  - **Logic throws, framework catches.** Tool/resource handlers are pure — throw on failure, no `try/catch`. Plain `Error` is fine; the framework catches, classifies, and formats. Use error factories (`notFound()`, `serviceUnavailable()`, etc.) when the error code matters.
45
46
  - **Use `ctx.log`** for request-scoped logging. No `console` calls.
46
47
  - **Use `ctx.state`** for tenant-scoped storage. Never access persistence directly.
47
- - **Check `ctx.elicit`** for presence before calling.
48
+ - **Need input the caller didn't supply?** `return ctx.requestInput(...)` and read `ctx.inputs` when the handler is re-entered. Never `await` for user input mid-handler. (`ctx.elicit` was removed in the SDK v2 migration.)
48
49
  - **Secrets in env vars only** — never hardcoded.
49
50
  - **Every `PixooResult` checked.** No fire-and-forget device calls. `pushed: true` means `error_code: 0` from the device.
50
- - **Close the loop on issues.** When implementing work tracked by a GitHub issue, comment on the issue with what landed and close it.
51
+ - **Adding an env var requires both files** — `server.json` (`environmentVariables[]`) and `manifest.json` (`mcp_config.env` + `user_config`). `bun run lint:packaging` verifies the names match.
52
+ - **Close the loop on issues.** When implementing work tracked by a GitHub issue, comment on the issue with what landed and close it. Do both — a comment without a close leaves stale issues open; a close without a comment leaves no record of what shipped.
51
53
 
52
54
  ---
53
55
 
@@ -73,22 +75,25 @@ export const pixooDisplayText = tool('pixoo_display_text', {
73
75
  push: z.boolean().default(true).describe('Push to device after render.'),
74
76
  }),
75
77
  output: z.object({
76
- preview: z.string().describe('Base64-encoded PNG preview of the rendered frame.'),
77
78
  pushed: z.boolean().describe('True if the device acknowledged the push.'),
78
79
  }),
79
80
  async handler(input, ctx) {
80
81
  const service = getPixooService();
81
- const result = await renderAndPush(input, service);
82
- ctx.log.info('Text rendered', { pushed: result.pushed });
83
- return result;
82
+ const { preview, pushed } = await renderAndPush(input, service);
83
+ // Rendered bytes go through ctx.content — prepended to content[] and never
84
+ // written to structuredContent, so the base64 is carried once, not twice.
85
+ ctx.content.image(preview, 'image/png');
86
+ ctx.log.info('Text rendered', { pushed });
87
+ return { pushed };
84
88
  },
85
- format: (result) => [
86
- { type: 'image', data: result.preview, mimeType: 'image/png' },
87
- { type: 'text', text: `Pushed: ${result.pushed}` },
88
- ],
89
+ format: (result) => [{ type: 'text', text: `Pushed: ${result.pushed}` }],
89
90
  });
90
91
  ```
91
92
 
93
+ **Rendered previews never enter `output`.** Every render tool emits its PNG with
94
+ `ctx.content.image(...)`. Declaring it as an `output` field too would ship the base64
95
+ twice — once in `structuredContent`, once in the `content[]` block.
96
+
92
97
  ### Resource
93
98
 
94
99
  ```ts
@@ -141,9 +146,14 @@ Handlers receive a unified `ctx` object. Key properties used by this server:
141
146
 
142
147
  | Property | Description |
143
148
  |:---------|:------------|
144
- | `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. |
145
- | `ctx.signal` | `AbortSignal` for cancellation. |
149
+ | `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. Dual-sink: Pino **and** `notifications/message` to the client, so treat it as client-visible. |
150
+ | `ctx.enrich` | Success-path agent context — `.notice()` / `.total()` / `.echo()` / `.truncated()`. Lands only when the definition declares an `enrichment` block. |
151
+ | `ctx.fail` | Typed throw against the definition's `errors[]` reason union — auto-populates `data.reason`. |
152
+ | `ctx.state` | Tenant-scoped KV — `.get`, `.set(key, value, { ttl? })`, `.delete`, `.getMany`, `.list`. Keys are validated; colons are not legal separators. |
153
+ | `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. |
154
+ | `ctx.signal` | `AbortSignal` for cancellation. Pass it to any long-running I/O. |
146
155
  | `ctx.requestId` | Unique request ID. |
156
+ | `ctx.tenantId` | Tenant ID from JWT; `'default'` for stdio or HTTP with auth off. |
147
157
 
148
158
  ---
149
159
 
@@ -251,15 +261,26 @@ Available skills:
251
261
  | `tool-defs-analysis` | Read-only audit of MCP definition language across the surface |
252
262
  | `security-pass` | Audit server for MCP-flavored security gaps |
253
263
  | `code-simplifier` | Post-session cleanup against `git diff` |
254
- | `devcheck` | Lint, format, typecheck, audit |
255
264
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
256
265
  | `git-wrapup` | Land working-tree changes as a versioned commit + annotated tag |
257
266
  | `release-and-publish` | Push + npm + MCP Registry + GH Release + Docker |
258
267
  | `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
268
+ | `orchestrations` | Chain task skills into a gated multi-phase pipeline when sub-agents are available |
269
+ | `techniques` | Catalog of response/data-shaping techniques — overflow handling, payload shaping |
259
270
  | `report-issue-local` | File a bug or feature request against this server's own repo via `gh` CLI |
271
+ | `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
272
+ | `api-auth` | Auth modes, scopes, JWT/OAuth |
273
+ | `api-canvas` | DataCanvas: register tabular data, run SQL, export — Tier 3 opt-in |
274
+ | `api-config` | AppConfig, parseEnvConfig, env vars |
275
+ | `api-context` | Context interface, RequestContext, logger, state, multi-round-trip input |
260
276
  | `api-errors` | McpError, JsonRpcErrorCode, error patterns |
261
- | `api-context` | Context interface, logger, state, progress |
262
- | `api-testing` | createMockContext, test patterns |
277
+ | `api-linter` | Definition linter rule catalog — invoked by `bun run lint:mcp` and `devcheck` |
278
+ | `api-mirror` | MirrorService: self-refreshing local SQLite/FTS5 mirror of a bulk dataset — Tier 3 opt-in |
279
+ | `api-services` | LLM, Speech, Graph services |
280
+ | `api-telemetry` | OTel catalog: spans, metrics, completion logs, env config, cardinality rules |
281
+ | `api-testing` | createMockContext, createFetchMock, runToolContract, test patterns |
282
+ | `api-utils` | Formatting, parsing, security, pagination, scheduling, telemetry helpers |
283
+ | `api-workers` | Cloudflare Workers runtime |
263
284
 
264
285
  ---
265
286
 
@@ -273,11 +294,14 @@ Available skills:
273
294
  | `bun run rebuild` | Clean + build |
274
295
  | `bun run clean` | Remove build artifacts |
275
296
  | `bun run devcheck` | Lint + format + typecheck + security + changelog sync |
276
- | `bun run audit:refresh` | Delete `bun.lock`, reinstall, and re-run `bun audit` |
297
+ | `bun run audit:refresh` | Delete `bun.lock`, reinstall, and re-run `bun audit`. Re-resolves the `^`-ranged framework pin — verify the lock afterwards |
298
+ | `bun run lint:mcp` | Run the MCP definition linter standalone (rule catalog: `api-linter` skill) |
299
+ | `bun run lint:packaging` | Packaging surface checks — `server.json`/`manifest.json` env-var parity |
300
+ | `bun run list-skills` | Print the skill registry |
277
301
  | `bun run tree` | Generate directory structure doc |
278
302
  | `bun run format` | Auto-fix formatting (safe fixes only) |
279
303
  | `bun run format:unsafe` | Also apply Biome's unsafe autofixes — review the diff |
280
- | `bunx vitest run` | Run tests |
304
+ | `bun run test` | Run tests (Vitest — use `bun run test`, not `bun test`) |
281
305
  | `bun run start:stdio` | Production mode (stdio) |
282
306
  | `bun run start:http` | Production mode (HTTP) |
283
307
  | `bun run changelog:build` | Regenerate `CHANGELOG.md` from `changelog/*.md` |
@@ -288,11 +312,13 @@ Available skills:
288
312
 
289
313
  ## Checklist
290
314
 
291
- - [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types
315
+ - [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types (no `z.custom()`, `z.date()`, `z.transform()`, `z.bigint()`, `z.symbol()`, `z.void()`, `z.map()`, `z.set()`, `z.function()`, `z.nan()`)
316
+ - [ ] Tool inputs are strict at the root — an undeclared argument key is rejected by name. Add `.passthrough()` / `.catchall()` only where an open object is genuinely required
292
317
  - [ ] JSDoc `@fileoverview` + `@module` on every file
293
318
  - [ ] `ctx.log` for logging, `ctx.state` for storage
294
319
  - [ ] Handlers throw on failure — error factories or plain `Error`, no try/catch
295
- - [ ] `format()` renders all data the LLM needs — image content blocks for renders, text for structured data
320
+ - [ ] `format()` renders every `output` field as text — different clients read different surfaces (`structuredContent` vs `content[]`); `lint:mcp` enforces parity. Rendered image bytes go through `ctx.content.image(...)`, never an `output` field
296
321
  - [ ] Every device call goes through `PixooService`; every `PixooResult` checked
297
322
  - [ ] Renderer functions have no device dependency — testable without hardware
298
- - [ ] `npm run devcheck` passes
323
+ - [ ] Env var added? Declared in BOTH `server.json` and `manifest.json` (`lint:packaging` enforces parity)
324
+ - [ ] `bun run devcheck` and `bun run test` pass
package/Dockerfile CHANGED
@@ -3,16 +3,23 @@
3
3
  #
4
4
  # This stage installs all dependencies (including dev), builds the TypeScript
5
5
  # source code into JavaScript, and prepares the production assets.
6
+ #
7
+ # Pinned to $BUILDPLATFORM so a multi-arch build runs `tsc` once, natively. Only
8
+ # `dist/` crosses into the production stage and that output is JavaScript, so it
9
+ # is architecture-independent — emulating this stage buys nothing, and Bun 1.4
10
+ # aborts with MemoryExhaustion under QEMU x86_64 when it is emulated.
6
11
  # ==============================================================================
7
- FROM oven/bun:1.3 AS build
12
+ FROM --platform=$BUILDPLATFORM oven/bun:1.4.0 AS build
8
13
 
9
14
  WORKDIR /usr/src/app
10
15
 
11
16
  # Copy dependency manifests for optimized layer caching
12
17
  COPY package.json bun.lock ./
13
18
 
14
- # Install all dependencies (including dev dependencies for building)
15
- RUN bun install --frozen-lockfile
19
+ # Install all dependencies (including dev dependencies for building).
20
+ # The BuildKit cache mount persists Bun's global package cache across builds.
21
+ RUN --mount=type=cache,target=/root/.bun/install/cache \
22
+ bun install --frozen-lockfile --ignore-scripts
16
23
 
17
24
  # Copy the rest of the source code
18
25
  COPY . .
@@ -28,7 +35,7 @@ RUN bun run build
28
35
  # application. It uses a slim base image and only includes production
29
36
  # dependencies and build artifacts.
30
37
  # ==============================================================================
31
- FROM oven/bun:1.3-slim AS production
38
+ FROM oven/bun:1.4.0-slim AS production
32
39
 
33
40
  WORKDIR /usr/src/app
34
41
 
@@ -49,14 +56,21 @@ COPY package.json bun.lock ./
49
56
 
50
57
  # Install only production dependencies, ignoring any lifecycle scripts (like 'prepare')
51
58
  # that are not needed in the final production image.
52
- RUN bun install --production --frozen-lockfile --ignore-scripts
59
+ # `--omit=peer` drops the framework's optional peer tiers (test runner, service
60
+ # SDKs, parsers) that Bun would otherwise auto-install. Anything this server
61
+ # actually imports belongs in its own `dependencies`, so nothing needed at
62
+ # runtime is lost. The OTEL step below carries the same flag — without it, that
63
+ # install re-resolves the graph and pulls every optional peer back in.
64
+ RUN --mount=type=cache,target=/root/.bun/install/cache \
65
+ bun install --production --omit=peer --frozen-lockfile --ignore-scripts
53
66
 
54
67
  # Conditionally install OpenTelemetry optional peer dependencies (Tier 3).
55
68
  # These are not bundled by default to keep the base image lean. Enable at build time
56
69
  # with: docker build --build-arg OTEL_ENABLED=true
57
70
  ARG OTEL_ENABLED=true
58
- RUN if [ "$OTEL_ENABLED" = "true" ]; then \
59
- bun add @hono/otel \
71
+ RUN --mount=type=cache,target=/root/.bun/install/cache \
72
+ if [ "$OTEL_ENABLED" = "true" ]; then \
73
+ bun add --omit=dev --omit=peer --ignore-scripts @hono/otel \
60
74
  @opentelemetry/instrumentation-http \
61
75
  @opentelemetry/exporter-metrics-otlp-http \
62
76
  @opentelemetry/exporter-trace-otlp-http \
package/LICENSE CHANGED
@@ -186,7 +186,7 @@ Apache License
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright 2025 Casey Hand @cyanheads
189
+ Copyright 2026 Casey Hand @cyanheads
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  <div align="center">
9
9
 
10
- [![Version](https://img.shields.io/badge/Version-1.0.0-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/pixoo-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.29.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/pixoo-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/pixoo-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^6.0.3-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.3.2-blueviolet.svg?style=flat-square)](https://bun.sh/)
10
+ [![Version](https://img.shields.io/badge/Version-1.1.1-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/pixoo-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.0.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/pixoo-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/pixoo-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.4.0-blueviolet.svg?style=flat-square)](https://bun.sh/)
11
11
 
12
12
  </div>
13
13
 
@@ -115,7 +115,7 @@ Built on [`@cyanheads/mcp-ts-core`](https://www.npmjs.com/package/@cyanheads/mcp
115
115
  - Pluggable auth: `none`, `jwt`, `oauth`
116
116
  - Swappable storage backends: `in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`
117
117
  - Structured logging with optional OpenTelemetry tracing
118
- - STDIO and Streamable HTTP transports
118
+ - STDIO and Streamable HTTP transports, serving MCP protocol revision 2026-07-28 alongside the 2025 revisions
119
119
 
120
120
  Pixoo-specific:
121
121
 
@@ -246,6 +246,7 @@ All configuration is validated at startup via Zod schemas in `src/config/server-
246
246
  | `PIXOO_PUSH_MIN_INTERVAL_MS` | Minimum interval between device pushes in milliseconds. Prevents device freeze from rapid-fire commands. | `1000` |
247
247
  | `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
248
248
  | `MCP_HTTP_PORT` | HTTP server port. | `3010` |
249
+ | `MCP_SESSION_MODE` | HTTP session handling: `stateful`, `stateless`, or `auto`. Shipped as `stateless` in `.env.example` and the Dockerfile — no tool requests input mid-call. | `auto` (resolves to `stateful`) |
249
250
  | `MCP_AUTH_MODE` | Authentication: `none`, `jwt`, or `oauth`. | `none` |
250
251
  | `MCP_LOG_LEVEL` | Log level (`debug`, `info`, `warning`, `error`, etc.). | `info` |
251
252
  | `LOGS_DIR` | Directory for log files (Node.js only). | `<project-root>/logs` |
@@ -0,0 +1,37 @@
1
+ ---
2
+ summary: "SDK v2 adoption: rendered previews move from `output` to `content[]` (`previewData`/`previewMimeType` removed from 3 tools); fixes a dead path-traversal guard in `pixoo_compose_scene`'s output path (#5)."
3
+ breaking: true
4
+ security: true
5
+ ---
6
+
7
+ # 1.1.0 — 2026-08-22
8
+
9
+ ## Added
10
+
11
+ - **`cacheHints`** — `src/index.ts` declares 1h `tools/list`/`resources/list`/`resources/templates/list` hints; `pixoo://reference/design-guide`, `pixoo://reference/icons`, and `pixoo://reference/themes` each declare a 24h `cacheHint` (compile-time-constant content). `pixoo://device/status` declares none — live device state.
12
+ - **`output` schemas** on `pixoo://device/status`, `pixoo://reference/icons`, and `pixoo://reference/themes` resources.
13
+ - **`invalid_output_path`** error reason on `pixoo_compose_scene` — thrown when `output` is relative or contains traversal segments.
14
+ - **`MCP_SESSION_MODE`** documented in `.env.example` and the README env table; shipped as `stateless` (matching the Dockerfile) since no tool or resource here requests input mid-call.
15
+
16
+ ## Changed
17
+
18
+ - **`pixoo_display_text`, `pixoo_compose_scene`, `pixoo_push_image`** — rendered/pushed images now go through `ctx.content.image(...)` into `content[]` instead of a `previewData`/`previewMimeType` pair on `output`. A client reading `structuredContent.previewData` from these three tools must switch to the image content block; the block was already present, so no client loses the image itself.
19
+ - **Remote image fetch** extracted to `src/renderer/remote-image.ts` (`fetchRemoteImageToTempPng`, `isRemoteSource`), shared by `pixoo_push_image` and the scene renderer's image elements. Uses the framework's `fetchWithTimeout` (15s budget) instead of a bare `fetch`.
20
+
21
+ ## Fixed
22
+
23
+ - **`pixoo_compose_scene`'s output-path guard** validated `path.resolve(input.output)` — always absolute and already-normalized, so the guard could never reject anything. A relative path like `../../foo.png` resolved against the process cwd and was written. The raw `input.output` is now checked before resolving (#5).
24
+
25
+ ## Dependencies
26
+
27
+ - `@cyanheads/mcp-ts-core` `^0.10.6` → `^0.12.3`
28
+ - `@cyanheads/pixoo-toolkit` `^0.6.1` → `^0.8.2`
29
+ - `sharp` `^0.35.1` → `^0.35.3`
30
+ - `@biomejs/biome` `2.4.16` → `2.5.9` (dev)
31
+ - `@types/node` `25.9.3` → `26.2.0` (dev)
32
+ - `ignore` `^7.0.5` → `^7.0.6` (dev)
33
+ - `tsc-alias` `^1.8.17` → `^1.9.2` (dev)
34
+ - `typescript` `^6.0.3` → `^7.0.2` (dev)
35
+ - `vitest` `^4.1.8` → `^4.1.11` (dev)
36
+ - `@socketsecurity/bun-security-scanner` `^1.1.2` — new (dev), wired as the `bun install` security scanner in `bunfig.toml`
37
+ - Bun `1.3.2` → `1.4.0` (`packageManager`, Dockerfile base images)
@@ -0,0 +1,11 @@
1
+ ---
2
+ summary: "Docker build stage pinned to $BUILDPLATFORM — 1.1.0 published no GHCR image; this restores the multi-arch (linux/amd64 + linux/arm64) publish."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 1.1.1 — 2026-08-22
8
+
9
+ ## Fixed
10
+
11
+ - **Multi-arch Docker publish** — the build stage now runs `FROM --platform=$BUILDPLATFORM oven/bun:1.4.0 AS build`. Bun 1.4.0 aborts with a JavaScriptCore `MemoryExhaustion` assertion under QEMU x86_64 emulation, so the `linux/amd64` leg of the 1.1.0 `docker buildx` multi-arch build failed and no image published for either architecture — npm, the MCP Registry, and the GitHub Release all shipped fine, only GHCR was missing ([cyanheads/mcp-ts-core#370](https://github.com/cyanheads/mcp-ts-core/issues/370)). Only `dist/` (JavaScript, architecture-independent) crosses into the production stage, so the build stage never needed emulating.
@@ -4,10 +4,11 @@
4
4
  # to author a new release. Set that file's H1 to `# <version> — YYYY-MM-DD`
5
5
  # with a concrete date.
6
6
 
7
- # Required. One-line GitHub Release-style headline. 350 character cap.
8
- # Default short and scannable. Don't pad, don't stitch unrelated changes with
9
- # semicolons — pick the headline. Quotes required: unquoted YAML treats `: `
10
- # inside the value as a key separator and fails GitHub's strict parser.
7
+ # Required. One-line GitHub Release-style headline. 350 character cap — a
8
+ # ceiling, not a target. Default short and scannable. Don't pad, don't stitch
9
+ # unrelated changes with commas/semicolons into an inventory — pick the
10
+ # headline, like a tag's theme line. Quotes required: unquoted YAML treats
11
+ # `: ` inside the value as a key separator and fails GitHub's strict parser.
11
12
  summary: ""
12
13
 
13
14
  # Set `true` when consumers must change code to upgrade: API removals,
@@ -15,16 +16,19 @@ summary: ""
15
16
  # usage. Flagged as `Breaking` in the rollup.
16
17
  breaking: false
17
18
 
18
- # Set `true` if this release contains any security fix. Pairs with the
19
- # `## Security` section below. Flagged as `Security` in the rollup so
20
- # users can triage upgrade urgency at a glance.
19
+ # Set `true` ONLY for a security fix in THIS project's own source code — a
20
+ # vulnerability or hardening in code you ship. A dependency or transitive CVE
21
+ # bump is routine maintenance, NOT a security release: record it under
22
+ # `## Dependencies` (with the advisory ID) and leave this `false`. When true,
23
+ # pairs with the `## Security` section below and flags `Security` in the rollup.
21
24
  security: false
22
25
 
23
26
  # Optional free-form notes for maintenance agents processing this release.
24
27
  # Not rendered in CHANGELOG — consumed by agents running `maintenance` on
25
- # downstream servers. Use for adoption instructions that don't fit the
26
- # human-facing sections: new files to create, fields to populate, one-time
27
- # migration steps. Omit the field entirely when there's nothing to say.
28
+ # downstream servers. ADOPTION STEPS ONLY — new files to create, fields to
29
+ # populate, one-time migration steps. Never a second rendering of the body:
30
+ # if a body bullet already says it, name the bullet's symbol instead of
31
+ # re-explaining. Omit the field entirely when there's nothing to say.
28
32
  # agent-notes: |
29
33
  # <instructions for downstream maintenance agents>
30
34
  ---
@@ -39,17 +43,54 @@ security: false
39
43
  each bullet with the symbol or concept name in **bold** so they can skip
40
44
  what's irrelevant and zoom in on what's not.
41
45
 
42
- Tone: terse, fact-dense, not verbose. Default to one sentence per bullet —
43
- name the symbol, state what changed, stop. Use a second sentence only when
44
- it carries weight. If a bullet feels long, it is.
45
-
46
- Cut: mechanism walkthroughs (those belong in JSDoc, CLAUDE.md/AGENTS.md, or the
47
- relevant skill), ceremonial framings ("This release introduces…",
48
- backwards-compat paragraphs), file-by-file test enumerations, internal
49
- implementation notes. Prefer code/symbol names over English re-explanations.
46
+ Tone: terse, fact-dense, not verbose. Bullet shape: **symbol** + what
47
+ changed + at most one consumer-facing caveat. One sentence by default, two
48
+ when the second carries weight — a bullet past ~40 words or three sentences
49
+ is wrong. The depth lives one hop away: the linked issue carries the why,
50
+ the commit diff carries the how. The changelog names what changed and what
51
+ a consumer does about it; a reader who wants mechanism opens the link.
52
+
53
+ Model length on THIS guide, never on the previous entry — entries modeled
54
+ on entries compound.
55
+
56
+ Cut (each has shipped as a wall of text; these are the cruft):
57
+ - History/justification narration — how the bug worked, why the old
58
+ behavior was wrong. One short clause at most; the issue carries the story.
59
+ - Design-rationale defense — "chosen over Y because…", "guarding the
60
+ getter is not enough…". That is the author arguing with a reviewer;
61
+ reviewers read the PR, not the changelog.
62
+ - Defensive unchanged-clauses — "X is unchanged", "byte-identical to
63
+ <prev>". Keep one only where its absence would cause a real misread,
64
+ as a short parenthetical.
65
+ - Edge-case inventories — marker lists, not-flagged lists, escape tables.
66
+ Tests and the issue carry those.
67
+ - Mechanism walkthroughs (JSDoc, CLAUDE.md/AGENTS.md, or the relevant
68
+ skill own those), ceremonial framings ("This release introduces…"),
69
+ backwards-compat paragraphs, file-by-file test enumerations. Prefer
70
+ code/symbol names over English re-explanations.
71
+
72
+ Verified ≠ included: the every-claim-verified-from-the-diff rule bounds
73
+ the TRUTH of what you write, never the AMOUNT.
74
+
75
+ Example — same fact, right size:
76
+
77
+ TOO LONG: **`fetchWithTimeout`'s `timeoutMs` bounds the whole exchange**
78
+ (#341). `fetch` resolves once headers arrive and the deadline was
79
+ cleared as the helper returned, so a peer that answered promptly and
80
+ then stalled the stream held the request open indefinitely. A 2xx
81
+ carrying a body now comes back as a passthrough wrapper that disarms
82
+ the deadline when the body closes, errors, or is cancelled; …
83
+ [+90 more words of mechanism and edge cases]
84
+
85
+ RIGHT: **`fetchWithTimeout`'s `timeoutMs` now bounds the whole
86
+ exchange, not just the headers** (#341). A stalled body aborts with
87
+ the same `Timeout` error; the returned `Response` is a wrapper, so
88
+ identity assertions (`toBe(response)`) no longer hold.
50
89
 
51
90
  Narrative intro: skip by default. Add one short sentence only when the
52
- release theme genuinely needs framing the bullets can't carry.
91
+ release theme genuinely needs framing the bullets can't carry. When many
92
+ bullets share one upgrade consequence, state it ONCE — intro line or
93
+ agent-notes — never per bullet.
53
94
 
54
95
  Sections: Keep a Changelog order — Added, Changed, Deprecated, Removed,
55
96
  Fixed, Security. Include only sections with entries; delete the rest
package/dist/index.js CHANGED
@@ -37,6 +37,17 @@ await createApp({
37
37
  pixooDesignGuideResource,
38
38
  ],
39
39
  prompts: [],
40
+ /**
41
+ * The tool and resource surface is fixed at build time — nothing registers or
42
+ * retires a definition at runtime — so the list results are safe for shared
43
+ * caches to hold. Per-resource `resources/read` lifetimes are declared on the
44
+ * definitions themselves; the live device-status resource declares none.
45
+ */
46
+ cacheHints: {
47
+ 'tools/list': { ttlMs: 3_600_000, cacheScope: 'public' },
48
+ 'resources/list': { ttlMs: 3_600_000, cacheScope: 'public' },
49
+ 'resources/templates/list': { ttlMs: 3_600_000, cacheScope: 'public' },
50
+ },
40
51
  setup(core) {
41
52
  initPixooService(core.config, core.storage);
42
53
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY;AACZ,OAAO,EAAE,wBAAwB,EAAE,MAAM,mEAAmE,CAAC;AAC7G,OAAO,EAAE,yBAAyB,EAAE,MAAM,oEAAoE,CAAC;AAC/G,OAAO,EAAE,kBAAkB,EAAE,MAAM,4DAA4D,CAAC;AAChG,OAAO,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AAClG,QAAQ;AACR,OAAO,EAAE,iBAAiB,EAAE,MAAM,4DAA4D,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,+DAA+D,CAAC;AACrG,OAAO,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,MAAM,yDAAyD,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAErE,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,kBAAkB;IACxB,KAAK,EAAE,kBAAkB;IACzB,KAAK,EAAE;QACL,gBAAgB;QAChB,iBAAiB;QACjB,cAAc;QACd,gBAAgB;QAChB,kBAAkB;QAClB,oBAAoB;QACpB,gBAAgB;KACjB;IACD,SAAS,EAAE;QACT,yBAAyB;QACzB,mBAAmB;QACnB,kBAAkB;QAClB,wBAAwB;KACzB;IACD,OAAO,EAAE,EAAE;IACX,KAAK,CAAC,IAAI;QACR,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;IACD,YAAY,EACV,sGAAsG;QACtG,uHAAuH;QACvH,mGAAmG;CACtG,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY;AACZ,OAAO,EAAE,wBAAwB,EAAE,MAAM,mEAAmE,CAAC;AAC7G,OAAO,EAAE,yBAAyB,EAAE,MAAM,oEAAoE,CAAC;AAC/G,OAAO,EAAE,kBAAkB,EAAE,MAAM,4DAA4D,CAAC;AAChG,OAAO,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AAClG,QAAQ;AACR,OAAO,EAAE,iBAAiB,EAAE,MAAM,4DAA4D,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,+DAA+D,CAAC;AACrG,OAAO,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,MAAM,yDAAyD,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAErE,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,kBAAkB;IACxB,KAAK,EAAE,kBAAkB;IACzB,KAAK,EAAE;QACL,gBAAgB;QAChB,iBAAiB;QACjB,cAAc;QACd,gBAAgB;QAChB,kBAAkB;QAClB,oBAAoB;QACpB,gBAAgB;KACjB;IACD,SAAS,EAAE;QACT,yBAAyB;QACzB,mBAAmB;QACnB,kBAAkB;QAClB,wBAAwB;KACzB;IACD,OAAO,EAAE,EAAE;IACX;;;;;OAKG;IACH,UAAU,EAAE;QACV,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE;QACxD,gBAAgB,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE;QAC5D,0BAA0B,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE;KACvE;IACD,KAAK,CAAC,IAAI;QACR,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;IACD,YAAY,EACV,sGAAsG;QACtG,uHAAuH;QACvH,mGAAmG;CACtG,CAAC,CAAC"}
@@ -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;AAuGrD,eAAO,MAAM,wBAAwB,2GAuBnC,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;AAuGrD,eAAO,MAAM,wBAAwB,2GAyBnC,CAAC"}
@@ -109,6 +109,8 @@ export const pixooDesignGuideResource = resource('pixoo://reference/design-guide
109
109
  description: 'Long-form 64px craft guide: legibility floors, palette discipline, layout zones, animation budget, pixel art rules, and known device behaviors. Read this before composing scenes or troubleshooting display quality.',
110
110
  mimeType: 'text/markdown',
111
111
  params: z.object({}),
112
+ // Compile-time constant — safe for a shared cache to hold for a day.
113
+ cacheHint: { ttlMs: 86_400_000, cacheScope: 'public' },
112
114
  handler(_params, _ctx) {
113
115
  return DESIGN_GUIDE;
114
116
  },