@cyanheads/mcp-ts-core 0.10.16 → 0.11.0

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 (151) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/README.md +2 -2
  4. package/biome.json +1 -1
  5. package/changelog/0.10.x/0.10.17.md +41 -0
  6. package/changelog/0.11.x/0.11.0.md +69 -0
  7. package/dist/cli/init.js.map +1 -1
  8. package/dist/config/index.d.ts +111 -108
  9. package/dist/config/index.d.ts.map +1 -1
  10. package/dist/config/index.js +14 -0
  11. package/dist/config/index.js.map +1 -1
  12. package/dist/config/parseEnvConfig.js.map +1 -1
  13. package/dist/core/app.js.map +1 -1
  14. package/dist/core/gcPressure.d.ts.map +1 -1
  15. package/dist/core/serverManifest.d.ts +1 -1
  16. package/dist/core/serverManifest.d.ts.map +1 -1
  17. package/dist/core/worker.d.ts.map +1 -1
  18. package/dist/core/worker.js.map +1 -1
  19. package/dist/linter/rules/format-parity-rules.js.map +1 -1
  20. package/dist/linter/rules/portability-rules.js.map +1 -1
  21. package/dist/logs/combined.log +8 -8
  22. package/dist/logs/error.log +4 -4
  23. package/dist/mcp-server/prompts/prompt-registration.d.ts.map +1 -1
  24. package/dist/mcp-server/prompts/prompt-registration.js.map +1 -1
  25. package/dist/mcp-server/resources/resource-registration.d.ts.map +1 -1
  26. package/dist/mcp-server/resources/resource-registration.js.map +1 -1
  27. package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.d.ts +53 -0
  28. package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.d.ts.map +1 -0
  29. package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.js +65 -0
  30. package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.js.map +1 -0
  31. package/dist/mcp-server/tasks/core/sessionAwareTaskStore.d.ts +30 -2
  32. package/dist/mcp-server/tasks/core/sessionAwareTaskStore.d.ts.map +1 -1
  33. package/dist/mcp-server/tasks/core/sessionAwareTaskStore.js +65 -4
  34. package/dist/mcp-server/tasks/core/sessionAwareTaskStore.js.map +1 -1
  35. package/dist/mcp-server/tasks/core/storageBackedTaskStore.d.ts.map +1 -1
  36. package/dist/mcp-server/tasks/core/storageBackedTaskStore.js.map +1 -1
  37. package/dist/mcp-server/tasks/core/taskManager.d.ts.map +1 -1
  38. package/dist/mcp-server/tasks/core/taskManager.js +6 -2
  39. package/dist/mcp-server/tasks/core/taskManager.js.map +1 -1
  40. package/dist/mcp-server/tasks/core/taskTypes.d.ts +7 -0
  41. package/dist/mcp-server/tasks/core/taskTypes.d.ts.map +1 -1
  42. package/dist/mcp-server/tasks/core/taskTypes.js +7 -0
  43. package/dist/mcp-server/tasks/core/taskTypes.js.map +1 -1
  44. package/dist/mcp-server/tools/tool-registration.d.ts.map +1 -1
  45. package/dist/mcp-server/tools/tool-registration.js +1 -2
  46. package/dist/mcp-server/tools/tool-registration.js.map +1 -1
  47. package/dist/mcp-server/tools/utils/toolHandlerFactory.js.map +1 -1
  48. package/dist/mcp-server/transports/auth/strategies/jwtStrategy.d.ts.map +1 -1
  49. package/dist/mcp-server/transports/auth/strategies/jwtStrategy.js.map +1 -1
  50. package/dist/mcp-server/transports/auth/strategies/oauthStrategy.d.ts.map +1 -1
  51. package/dist/mcp-server/transports/auth/strategies/oauthStrategy.js.map +1 -1
  52. package/dist/mcp-server/transports/heartbeat.d.ts.map +1 -1
  53. package/dist/mcp-server/transports/http/httpErrorHandler.d.ts.map +1 -1
  54. package/dist/mcp-server/transports/http/landing-page/handler.d.ts.map +1 -1
  55. package/dist/mcp-server/transports/http/robotsTxt.d.ts.map +1 -1
  56. package/dist/mcp-server/transports/http/serverCard.d.ts.map +1 -1
  57. package/dist/mcp-server/transports/http/sessionStore.d.ts.map +1 -1
  58. package/dist/mcp-server/transports/http/sessionStore.js.map +1 -1
  59. package/dist/mcp-server/transports/manager.d.ts.map +1 -1
  60. package/dist/mcp-server/transports/manager.js.map +1 -1
  61. package/dist/services/canvas/core/CanvasInstance.d.ts.map +1 -1
  62. package/dist/services/canvas/core/CanvasInstance.js.map +1 -1
  63. package/dist/services/canvas/core/CanvasRegistry.d.ts.map +1 -1
  64. package/dist/services/canvas/core/CanvasRegistry.js.map +1 -1
  65. package/dist/services/canvas/core/DataCanvas.d.ts.map +1 -1
  66. package/dist/services/canvas/core/DataCanvas.js.map +1 -1
  67. package/dist/services/canvas/core/canvasFactory.d.ts.map +1 -1
  68. package/dist/services/canvas/core/canvasFactory.js +1 -0
  69. package/dist/services/canvas/core/canvasFactory.js.map +1 -1
  70. package/dist/services/canvas/core/sqlGate.d.ts +10 -10
  71. package/dist/services/canvas/core/sqlGate.d.ts.map +1 -1
  72. package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts +16 -0
  73. package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts.map +1 -1
  74. package/dist/services/canvas/providers/duckdb/DuckdbProvider.js +25 -7
  75. package/dist/services/canvas/providers/duckdb/DuckdbProvider.js.map +1 -1
  76. package/dist/services/canvas/providers/duckdb/exportWriter.d.ts +4 -2
  77. package/dist/services/canvas/providers/duckdb/exportWriter.d.ts.map +1 -1
  78. package/dist/services/canvas/providers/duckdb/exportWriter.js +4 -2
  79. package/dist/services/canvas/providers/duckdb/exportWriter.js.map +1 -1
  80. package/dist/services/graph/core/GraphService.d.ts.map +1 -1
  81. package/dist/services/graph/core/GraphService.js.map +1 -1
  82. package/dist/services/llm/providers/openrouter.provider.d.ts.map +1 -1
  83. package/dist/services/llm/providers/openrouter.provider.js.map +1 -1
  84. package/dist/services/mirror/sqlite/handle.js.map +1 -1
  85. package/dist/services/speech/core/SpeechService.d.ts.map +1 -1
  86. package/dist/services/speech/core/SpeechService.js.map +1 -1
  87. package/dist/services/speech/providers/elevenlabs.provider.d.ts.map +1 -1
  88. package/dist/services/speech/providers/whisper.provider.d.ts.map +1 -1
  89. package/dist/storage/core/StorageService.d.ts.map +1 -1
  90. package/dist/storage/core/StorageService.js.map +1 -1
  91. package/dist/storage/core/storageFactory.js.map +1 -1
  92. package/dist/storage/providers/cloudflare/d1Provider.d.ts.map +1 -1
  93. package/dist/storage/providers/cloudflare/d1Provider.js.map +1 -1
  94. package/dist/storage/providers/cloudflare/kvProvider.d.ts.map +1 -1
  95. package/dist/storage/providers/cloudflare/r2Provider.d.ts.map +1 -1
  96. package/dist/storage/providers/fileSystem/fileSystemProvider.d.ts.map +1 -1
  97. package/dist/storage/providers/inMemory/inMemoryProvider.d.ts.map +1 -1
  98. package/dist/storage/providers/supabase/supabaseProvider.d.ts.map +1 -1
  99. package/dist/storage/providers/supabase/supabaseProvider.js.map +1 -1
  100. package/dist/testing/fuzz.js.map +1 -1
  101. package/dist/testing/index.js.map +1 -1
  102. package/dist/testing/vitest.d.ts +1 -1
  103. package/dist/types-global/errors.d.ts.map +1 -1
  104. package/dist/utils/formatting/diffFormatter.d.ts.map +1 -1
  105. package/dist/utils/formatting/html.d.ts.map +1 -1
  106. package/dist/utils/formatting/html.js.map +1 -1
  107. package/dist/utils/formatting/markdownBuilder.d.ts.map +1 -1
  108. package/dist/utils/formatting/tableFormatter.d.ts.map +1 -1
  109. package/dist/utils/formatting/tableFormatter.js.map +1 -1
  110. package/dist/utils/formatting/treeFormatter.d.ts.map +1 -1
  111. package/dist/utils/internal/error-handler/errorHandler.d.ts.map +1 -1
  112. package/dist/utils/internal/logger.d.ts +19 -3
  113. package/dist/utils/internal/logger.d.ts.map +1 -1
  114. package/dist/utils/internal/logger.js +51 -21
  115. package/dist/utils/internal/logger.js.map +1 -1
  116. package/dist/utils/internal/requestContext.js.map +1 -1
  117. package/dist/utils/internal/telemetryMessages.d.ts +4 -4
  118. package/dist/utils/internal/telemetryMessages.d.ts.map +1 -1
  119. package/dist/utils/network/fetchWithTimeout.d.ts.map +1 -1
  120. package/dist/utils/network/fetchWithTimeout.js +33 -16
  121. package/dist/utils/network/fetchWithTimeout.js.map +1 -1
  122. package/dist/utils/network/httpError.js.map +1 -1
  123. package/dist/utils/network/retry.js.map +1 -1
  124. package/dist/utils/pagination/pagination.d.ts.map +1 -1
  125. package/dist/utils/parsing/csvParser.d.ts.map +1 -1
  126. package/dist/utils/parsing/dateParser.d.ts.map +1 -1
  127. package/dist/utils/parsing/frontmatterParser.d.ts.map +1 -1
  128. package/dist/utils/parsing/htmlExtractor.d.ts.map +1 -1
  129. package/dist/utils/parsing/jsonParser.d.ts.map +1 -1
  130. package/dist/utils/parsing/jsonParser.js.map +1 -1
  131. package/dist/utils/parsing/pdfParser.d.ts.map +1 -1
  132. package/dist/utils/parsing/pdfParser.js.map +1 -1
  133. package/dist/utils/parsing/xmlParser.d.ts.map +1 -1
  134. package/dist/utils/parsing/yamlParser.d.ts.map +1 -1
  135. package/dist/utils/scheduling/scheduler.d.ts.map +1 -1
  136. package/dist/utils/security/idGenerator.d.ts.map +1 -1
  137. package/dist/utils/security/idGenerator.js.map +1 -1
  138. package/dist/utils/security/rateLimiter.d.ts.map +1 -1
  139. package/dist/utils/security/rateLimiter.js.map +1 -1
  140. package/dist/utils/security/sanitization.d.ts.map +1 -1
  141. package/dist/utils/security/sanitization.js.map +1 -1
  142. package/package.json +43 -34
  143. package/scripts/check-dependency-specifiers.ts +13 -7
  144. package/scripts/clean-mcpb.ts +48 -15
  145. package/scripts/lint-packaging.ts +36 -13
  146. package/skills/api-canvas/SKILL.md +4 -3
  147. package/skills/api-config/SKILL.md +2 -1
  148. package/skills/field-test/SKILL.md +71 -28
  149. package/templates/AGENTS.md +1 -1
  150. package/templates/CLAUDE.md +1 -1
  151. package/templates/package.json +5 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyanheads/mcp-ts-core",
3
- "version": "0.10.16",
3
+ "version": "0.11.0",
4
4
  "mcpName": "io.github.cyanheads/mcp-ts-core",
5
5
  "description": "Agent-native TypeScript framework for building MCP servers. Declarative definitions with auth, multi-backend storage, OpenTelemetry, and first-class support for Bun/Node/Cloudflare Workers.",
6
6
  "files": [
@@ -193,18 +193,18 @@
193
193
  "publish-mcp": "mcp-publisher login github -token \"$(security find-generic-password -a \"$USER\" -s mcp-publisher-github-pat -w)\" && mcp-publisher publish"
194
194
  },
195
195
  "devDependencies": {
196
- "@biomejs/biome": "2.5.4",
196
+ "@biomejs/biome": "2.5.5",
197
197
  "@cloudflare/vitest-pool-workers": "^0.18.6",
198
198
  "@cloudflare/workers-types": "5.20260706.1",
199
- "@duckdb/node-api": "^1.5.4-r.1",
199
+ "@duckdb/node-api": "^1.5.5-r.1",
200
200
  "@hono/otel": "^1.1.2",
201
- "@opentelemetry/exporter-metrics-otlp-http": "^0.220.0",
202
- "@opentelemetry/exporter-trace-otlp-http": "^0.220.0",
203
- "@opentelemetry/instrumentation-http": "^0.220.0",
201
+ "@opentelemetry/exporter-metrics-otlp-http": "^0.221.0",
202
+ "@opentelemetry/exporter-trace-otlp-http": "^0.221.0",
203
+ "@opentelemetry/instrumentation-http": "^0.221.0",
204
204
  "@opentelemetry/instrumentation-pino": "^0.66.0",
205
205
  "@opentelemetry/resources": "^2.10.0",
206
206
  "@opentelemetry/sdk-metrics": "^2.10.0",
207
- "@opentelemetry/sdk-node": "^0.220.0",
207
+ "@opentelemetry/sdk-node": "^0.221.0",
208
208
  "@opentelemetry/sdk-trace-node": "^2.10.0",
209
209
  "@opentelemetry/semantic-conventions": "^1.43.0",
210
210
  "@socketsecurity/bun-security-scanner": "^1.1.2",
@@ -216,14 +216,14 @@
216
216
  "@types/validator": "^13.15.10",
217
217
  "@vitest/coverage-istanbul": "4.1.10",
218
218
  "@vitest/ui": "4.1.10",
219
- "better-sqlite3": "^12.11.1",
219
+ "better-sqlite3": "^13.0.1",
220
220
  "bun-types": "^1.3.14",
221
221
  "chrono-node": "^2.10.1",
222
222
  "clipboardy": "^5.3.1",
223
223
  "defuddle": "^0.19.2",
224
224
  "depcheck": "^1.4.7",
225
225
  "diff": "^9.0.0",
226
- "execa": "^9.6.1",
226
+ "execa": "^10.0.0",
227
227
  "fast-check": "^4.9.0",
228
228
  "fast-xml-parser": "^5.10.1",
229
229
  "ignore": "^7.0.6",
@@ -239,7 +239,8 @@
239
239
  "sanitize-html": "^2.17.6",
240
240
  "tsc-alias": "^1.9.1",
241
241
  "typedoc": "^0.28.20",
242
- "typescript": "^6.0.3",
242
+ "typescript": "^7.0.2",
243
+ "typescript-v6": "npm:typescript@^6.0.3",
243
244
  "unpdf": "^1.6.2",
244
245
  "validator": "^13.15.35",
245
246
  "vite": "8.1.5",
@@ -307,34 +308,34 @@
307
308
  "zod": "^4.4.3"
308
309
  },
309
310
  "peerDependencies": {
310
- "@duckdb/node-api": "^1.5.0",
311
- "@hono/otel": "^1.1.1",
312
- "@opentelemetry/instrumentation-http": "^0.215.0",
313
- "@opentelemetry/exporter-metrics-otlp-http": "^0.215.0",
314
- "@opentelemetry/exporter-trace-otlp-http": "^0.215.0",
315
- "@opentelemetry/instrumentation-pino": "^0.61.0",
316
- "@opentelemetry/resources": "^2.7.0",
317
- "@opentelemetry/sdk-metrics": "^2.7.0",
318
- "@opentelemetry/sdk-node": "^0.215.0",
319
- "@opentelemetry/sdk-trace-node": "^2.7.0",
320
- "@opentelemetry/semantic-conventions": "^1.40.0",
321
- "@supabase/supabase-js": "^2.103.3",
322
- "better-sqlite3": "^12.0.0",
323
- "chrono-node": "^2.9.0",
324
- "defuddle": "^0.18.1",
311
+ "@duckdb/node-api": "^1.5.5-r.1",
312
+ "@hono/otel": "^1.1.2",
313
+ "@opentelemetry/instrumentation-http": "^0.221.0",
314
+ "@opentelemetry/exporter-metrics-otlp-http": "^0.221.0",
315
+ "@opentelemetry/exporter-trace-otlp-http": "^0.221.0",
316
+ "@opentelemetry/instrumentation-pino": "^0.66.0",
317
+ "@opentelemetry/resources": "^2.10.0",
318
+ "@opentelemetry/sdk-metrics": "^2.10.0",
319
+ "@opentelemetry/sdk-node": "^0.221.0",
320
+ "@opentelemetry/sdk-trace-node": "^2.10.0",
321
+ "@opentelemetry/semantic-conventions": "^1.43.0",
322
+ "@supabase/supabase-js": "^2.110.8",
323
+ "better-sqlite3": "^13.0.1",
324
+ "chrono-node": "^2.10.1",
325
+ "defuddle": "^0.19.2",
325
326
  "diff": "^9.0.0",
326
- "fast-check": "^4.0.0",
327
+ "fast-check": "^4.9.0",
327
328
  "vitest": ">=4.0.0",
328
- "fast-xml-parser": "^5.8.0",
329
- "js-yaml": "^5.2.0",
330
- "linkedom": "^0.18.12",
331
- "node-cron": "^4.2.1",
332
- "openai": "^6.34.0",
333
- "papaparse": "^5.5.3",
329
+ "fast-xml-parser": "^5.10.1",
330
+ "js-yaml": "^5.2.2",
331
+ "linkedom": "^0.18.13",
332
+ "node-cron": "^4.6.0",
333
+ "openai": "^6.48.0",
334
+ "papaparse": "^5.5.4",
334
335
  "partial-json": "^0.1.7",
335
336
  "pdf-lib": "^1.17.1",
336
- "sanitize-html": "^2.17.4",
337
- "unpdf": "^1.6.0",
337
+ "sanitize-html": "^2.17.6",
338
+ "unpdf": "^1.6.2",
338
339
  "validator": "^13.15.35",
339
340
  "zod": "^4.4.3"
340
341
  },
@@ -426,5 +427,13 @@
426
427
  "vitest": {
427
428
  "optional": true
428
429
  }
430
+ },
431
+ "overrides": {
432
+ "brace-expansion": "^2.1.2",
433
+ "postcss": "^8.5.22",
434
+ "protobufjs": "^7.6.5",
435
+ "sharp": "^0.35.3",
436
+ "fast-uri": "^3.1.4",
437
+ "@hono/node-server": "^2.0.11"
429
438
  }
430
439
  }
@@ -12,11 +12,16 @@
12
12
  * Section-specific rules — `peer`/`optional` may legitimately float to "any
13
13
  * host version", so `*` and dist-tags are allowed there; `latest` never is:
14
14
  *
15
- * | specifier | dependencies / devDependencies | peer / optional |
16
- * |---------------------------|:------------------------------:|:---------------:|
17
- * | latest | fail | fail |
18
- * | * | fail | allow |
19
- * | next / beta / canary / rc | fail | allow |
15
+ * | specifier | dependencies / devDependencies / overrides | peer / optional |
16
+ * |---------------------------|:------------------------------------------:|:---------------:|
17
+ * | latest | fail | fail |
18
+ * | * | fail | allow |
19
+ * | next / beta / canary / rc | fail | allow |
20
+ *
21
+ * `overrides` is held to the strict rule for a sharper reason than the rest: an
22
+ * override exists to force a transitive off a known-vulnerable version, so a
23
+ * floating specifier there re-resolves the very pin the entry was added to
24
+ * hold — the advisory silently returns while the block still looks present.
20
25
  *
21
26
  * Only the `workspaces` section of `bun.lock` is inspected — the `packages`
22
27
  * section records third-party packages' own nested declarations, which can
@@ -41,6 +46,7 @@ const DEP_SECTIONS = [
41
46
  'devDependencies',
42
47
  'peerDependencies',
43
48
  'optionalDependencies',
49
+ 'overrides',
44
50
  ] as const;
45
51
  type DepSection = (typeof DEP_SECTIONS)[number];
46
52
 
@@ -67,7 +73,7 @@ function isFloating(specifier: string, section: DepSection): boolean {
67
73
  return spec === '*' || FLOATING_DIST_TAGS.has(spec);
68
74
  }
69
75
 
70
- /** Scan the four dependency sections of one manifest object. */
76
+ /** Scan every dependency-declaring section of one manifest object. */
71
77
  function scanManifest(manifest: SectionedManifest, label: string): Offender[] {
72
78
  const offenders: Offender[] = [];
73
79
  for (const section of DEP_SECTIONS) {
@@ -138,7 +144,7 @@ function parseJsonc<T>(text: string): T {
138
144
 
139
145
  const offenders: Offender[] = [];
140
146
 
141
- // ── package.json (all four dependency sections) ──
147
+ // ── package.json (every dependency-declaring section) ──
142
148
  const pkgPath = resolve(ROOT, 'package.json');
143
149
  if (existsSync(pkgPath)) {
144
150
  try {
@@ -6,10 +6,14 @@
6
6
  *
7
7
  * 1. `mcpb clean <bundle>` — official dev-dependency prune + manifest
8
8
  * validation (a measured real-world bundle dropped 61 MB → 12.9 MB).
9
- * 2. Exact-name strip of agent-doc entries nested under `node_modules/` —
10
- * dependency-shipped `skills/`, `.claude/`, `.agents/` trees and stray
11
- * `SKILL.md` files. Root-anchored `.mcpbignore` patterns cannot reach
12
- * these by design (issues #146/#207); this is issue #230.
9
+ * 2. Exact-name strip of two entry classes nested under `node_modules/`,
10
+ * which root-anchored `.mcpbignore` patterns cannot reach by design
11
+ * (issues #146/#207):
12
+ * a. Dependency-shipped agent docs — `skills/`, `.claude/`, `.agents/`
13
+ * trees and stray `SKILL.md` files (issue #230).
14
+ * b. Platform-specific native bindings, which would otherwise lock the
15
+ * bundle to the build host's platform and push it past the 25 MB cap
16
+ * registries enforce (issue #274).
13
17
  * 3. Re-list and assert zero matching entries remain.
14
18
  *
15
19
  * Entry names are passed to `zip -d` with `-nw` (no-wildcard) so they match
@@ -34,11 +38,33 @@ import { fileURLToPath } from 'node:url';
34
38
  export const AGENT_DOC_ENTRY =
35
39
  /^node_modules\/.*(?:\/skills\/|\/\.claude\/|\/\.agents\/|\/SKILL\.md$)/;
36
40
 
41
+ /**
42
+ * Platform-specific native binding packages, which must not ship in a bundle.
43
+ * KEEP IN SYNC with `NATIVE_BINDING_ENTRY` in `scripts/lint-packaging.ts`
44
+ * (post-bundle content check) — a unit test asserts the two are identical.
45
+ *
46
+ * `mcpb pack` archives the whole project directory, so a native dependency
47
+ * contributes the build host's platform slice and nothing else — for
48
+ * `@duckdb/node-api` that is a ~108 MB `libduckdb` shared library. The bundle
49
+ * then runs only on the platform it was packed on, contradicting the
50
+ * cross-platform "Install in Claude Desktop" badge, and blows past the 25 MB
51
+ * cap registries enforce. Stripping them keeps the bundle portable and small;
52
+ * DuckDB is an optional peer loaded through `lazyImport`, so a server whose
53
+ * canvas is disabled (`CANVAS_PROVIDER_TYPE=none`, the default) is unaffected
54
+ * and one that enables it gets the helper's actionable install hint.
55
+ */
56
+ export const NATIVE_BINDING_ENTRY = /^node_modules\/@duckdb\/node-bindings-[^/]+\//;
57
+
37
58
  /** Filter a bundle entry listing down to the agent-doc entries to strip. */
38
59
  export function filterAgentDocEntries(entries: string[]): string[] {
39
60
  return entries.filter((entry) => AGENT_DOC_ENTRY.test(entry));
40
61
  }
41
62
 
63
+ /** Filter a bundle entry listing down to the native-binding entries to strip. */
64
+ export function filterNativeBindingEntries(entries: string[]): string[] {
65
+ return entries.filter((entry) => NATIVE_BINDING_ENTRY.test(entry));
66
+ }
67
+
42
68
  /** Listing a 12k-entry bundle exceeds execFileSync's 1 MB default buffer. */
43
69
  const MAX_LIST_BUFFER = 64 * 1024 * 1024;
44
70
 
@@ -81,35 +107,42 @@ function main(): void {
81
107
  process.exit(1);
82
108
  }
83
109
 
84
- // 2. Exact-name strip of dependency-shipped agent docs.
85
- let doomed: string[] = [];
110
+ // 2. Exact-name strip of dependency-shipped agent docs and platform natives.
111
+ let agentDocs: string[] = [];
112
+ let natives: string[] = [];
86
113
  try {
87
- doomed = filterAgentDocEntries(listEntries(bundle));
114
+ const entries = listEntries(bundle);
115
+ agentDocs = filterAgentDocEntries(entries);
116
+ natives = filterNativeBindingEntries(entries);
117
+ const doomed = [...agentDocs, ...natives];
88
118
  for (let i = 0; i < doomed.length; i += DELETE_BATCH) {
89
119
  run('zip', ['-q', '-d', '-nw', bundle, ...doomed.slice(i, i + DELETE_BATCH)]);
90
120
  }
91
121
  } catch (err) {
92
122
  if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
93
- console.error(
94
- '✗ Info-ZIP `zip`/`unzip` not found on PATH — required for the agent-doc strip.',
95
- );
123
+ console.error('✗ Info-ZIP `zip`/`unzip` not found on PATH — required for the strip step.');
96
124
  } else {
97
- console.error(`✗ Agent-doc strip failed: ${err instanceof Error ? err.message : err}`);
125
+ console.error(`✗ Bundle strip failed: ${err instanceof Error ? err.message : err}`);
98
126
  }
99
127
  process.exit(1);
100
128
  }
101
129
 
102
- // 3. Verify: zero matching entries remain.
103
- const remaining = filterAgentDocEntries(listEntries(bundle));
130
+ // 3. Verify: zero matching entries remain in either class.
131
+ const remainingEntries = listEntries(bundle);
132
+ const remaining = [
133
+ ...filterAgentDocEntries(remainingEntries),
134
+ ...filterNativeBindingEntries(remainingEntries),
135
+ ];
104
136
  if (remaining.length > 0) {
105
- console.error(`✗ ${remaining.length} agent-doc entries still present after strip, e.g.:`);
137
+ console.error(`✗ ${remaining.length} entries still present after strip, e.g.:`);
106
138
  for (const entry of remaining.slice(0, 5)) console.error(` ${entry}`);
107
139
  process.exit(1);
108
140
  }
109
141
 
110
142
  const sizeAfter = statSync(bundle).size;
111
143
  console.log(
112
- `Bundle cleaned: ${mb(sizeBefore)} → ${mb(sizeAfter)} (${doomed.length} agent-doc entries stripped).`,
144
+ `Bundle cleaned: ${mb(sizeBefore)} → ${mb(sizeAfter)} ` +
145
+ `(${agentDocs.length} agent-doc, ${natives.length} native-binding entries stripped).`,
113
146
  );
114
147
  }
115
148
 
@@ -111,6 +111,13 @@ export const CRITICAL_RUNTIME_PATHS = [
111
111
  export const AGENT_DOC_ENTRY =
112
112
  /^node_modules\/.*(?:\/skills\/|\/\.claude\/|\/\.agents\/|\/SKILL\.md$)/;
113
113
 
114
+ /**
115
+ * Platform-specific native binding packages that must not ship in a bundle.
116
+ * KEEP IN SYNC with `NATIVE_BINDING_ENTRY` in `scripts/clean-mcpb.ts` (the
117
+ * strip step this check verifies) — a unit test asserts the two are identical.
118
+ */
119
+ export const NATIVE_BINDING_ENTRY = /^node_modules\/@duckdb\/node-bindings-[^/]+\//;
120
+
114
121
  /** The canonical in-code identity pair — both must equal the unscoped package name. */
115
122
  const IDENTITY_PAIR = ['name', 'title'] as const;
116
123
 
@@ -225,21 +232,37 @@ export async function checkBundleContent(raw: string): Promise<string[]> {
225
232
 
226
233
  /**
227
234
  * Check 8: a built bundle must contain zero `node_modules/**` agent-doc
228
- * entries. `scripts/clean-mcpb.ts` (wired into the `bundle` script) strips
229
- * them after `mcpb pack`.
235
+ * entries and zero platform-specific native bindings. `scripts/clean-mcpb.ts`
236
+ * (wired into the `bundle` script) strips both after `mcpb pack`.
230
237
  */
231
238
  export function checkBundleEntries(entries: string[], bundleLabel: string): string[] {
232
- const offending = entries.filter((entry) => AGENT_DOC_ENTRY.test(entry));
233
- if (offending.length === 0) return [];
234
- const sample = offending
235
- .slice(0, 5)
236
- .map((entry) => `\n ${entry}`)
237
- .join('');
238
- return [
239
- `${bundleLabel} contains ${offending.length} node_modules agent-doc entries ` +
240
- `(dependency-shipped skills/, .claude/, .agents/, SKILL.md) — re-run the \`bundle\` ` +
241
- `script (scripts/clean-mcpb.ts strips them):${sample}`,
242
- ];
239
+ const sampleOf = (offending: string[]) =>
240
+ offending
241
+ .slice(0, 5)
242
+ .map((entry) => `\n ${entry}`)
243
+ .join('');
244
+
245
+ const errors: string[] = [];
246
+
247
+ const agentDocs = entries.filter((entry) => AGENT_DOC_ENTRY.test(entry));
248
+ if (agentDocs.length > 0) {
249
+ errors.push(
250
+ `${bundleLabel} contains ${agentDocs.length} node_modules agent-doc entries ` +
251
+ `(dependency-shipped skills/, .claude/, .agents/, SKILL.md) — re-run the \`bundle\` ` +
252
+ `script (scripts/clean-mcpb.ts strips them):${sampleOf(agentDocs)}`,
253
+ );
254
+ }
255
+
256
+ const natives = entries.filter((entry) => NATIVE_BINDING_ENTRY.test(entry));
257
+ if (natives.length > 0) {
258
+ errors.push(
259
+ `${bundleLabel} contains ${natives.length} platform-specific native binding entries — ` +
260
+ `the bundle would run only on the platform it was packed on. Re-run the \`bundle\` ` +
261
+ `script (scripts/clean-mcpb.ts strips them):${sampleOf(natives)}`,
262
+ );
263
+ }
264
+
265
+ return errors;
243
266
  }
244
267
 
245
268
  /**
@@ -4,7 +4,7 @@ description: >
4
4
  DataCanvas primitive reference — a Tier 3 SQL/analytical workspace for tabular MCP servers, backed by DuckDB. Use when registering tables from upstream APIs, running ad-hoc SQL across them, and exporting results. Covers the acquire → register → query → export flow, per-table TTL, the token-sharing pattern for multi-agent collaboration, env config, and Cloudflare Workers fail-closed behavior.
5
5
  metadata:
6
6
  author: cyanheads
7
- version: "1.9"
7
+ version: "2.0"
8
8
  audience: external
9
9
  type: reference
10
10
  ---
@@ -205,7 +205,7 @@ const result = await instance.query("SELECT total FROM sales_by_region WHERE reg
205
205
 
206
206
  ### `instance.importFrom(sourceCanvasId, sourceTableName, options?)`
207
207
 
208
- Copy a table from another canvas the caller controls into this one. The lifecycle wrapper validates tenancy on both ids before the provider sees either. Round-trips through a sandbox-rooted Parquet temp file so `TIMESTAMP`/`DATE`/`BLOB` columns survive losslessly.
208
+ Copy a table from another canvas the caller controls into this one. The lifecycle wrapper validates tenancy on both ids before the provider sees either. Round-trips through a Parquet file under the scratch root (`CANVAS_TEMP_PATH`) so `TIMESTAMP`/`DATE`/`BLOB` columns survive losslessly.
209
209
 
210
210
  ```ts
211
211
  const imported = await target.importFrom(source.canvasId, 'orders', { asName: 'orders_copy' });
@@ -222,7 +222,7 @@ Export a canvas table. Path-based exports are sandboxed to `CANVAS_EXPORT_PATH`
222
222
  // Path target — written inside the sandbox.
223
223
  await instance.export('g_with_obs', { format: 'parquet', path: 'observations.parquet' });
224
224
 
225
- // Stream target — copied to a temp file in the sandbox, piped to the stream, unlinked.
225
+ // Stream target — copied to a file under the scratch root, piped to the stream, unlinked.
226
226
  await instance.export('g_with_obs', { format: 'csv', stream: writableStream });
227
227
  ```
228
228
 
@@ -274,6 +274,7 @@ If your tool surfaces row data via `structuredContent`, the JSON-safe shape flow
274
274
  | `CANVAS_PROVIDER_TYPE` | `canvas.providerType` | `none` (also: `duckdb`) |
275
275
  | `CANVAS_DEFAULT_MEMORY_LIMIT_MB` | `canvas.defaultMemoryLimitMb` | `1024` |
276
276
  | `CANVAS_EXPORT_PATH` | `canvas.exportRootPath` | `./.canvas-exports` |
277
+ | `CANVAS_TEMP_PATH` | `canvas.tempRootPath` | `<os.tmpdir()>/mcp-canvas` |
277
278
  | `CANVAS_MAX_CANVASES_PER_TENANT` | `canvas.maxCanvasesPerTenant` | `100` |
278
279
  | `CANVAS_TTL_MS` | `canvas.ttlMs` | `86_400_000` (24 h) |
279
280
  | `CANVAS_ABSOLUTE_CAP_MS` | `canvas.absoluteCapMs` | `604_800_000` (7 d) |
@@ -4,7 +4,7 @@ description: >
4
4
  Reference for core and server configuration in `@cyanheads/mcp-ts-core`. Covers env var tables with defaults, priority order, server-specific Zod schema pattern, and Workers lazy-parsing requirement.
5
5
  metadata:
6
6
  author: cyanheads
7
- version: "1.8"
7
+ version: "1.9"
8
8
  audience: external
9
9
  type: reference
10
10
  ---
@@ -125,6 +125,7 @@ Activated when `OAUTH_PROXY_AUTHORIZATION_URL` or `OAUTH_PROXY_TOKEN_URL` is set
125
125
  | `CANVAS_PROVIDER_TYPE` | `canvas.providerType` | `none` | `none` \| `duckdb`. Set to `duckdb` to enable `core.canvas`. Fails closed on Cloudflare Workers (DuckDB has no V8-isolate build). |
126
126
  | `CANVAS_DEFAULT_MEMORY_LIMIT_MB` | `canvas.defaultMemoryLimitMb` | `1024` | Per-canvas DuckDB `memory_limit` PRAGMA value, in MB. |
127
127
  | `CANVAS_EXPORT_PATH` | `canvas.exportRootPath` | `./.canvas-exports` | Sandbox root for path-targeted exports. Absolute paths and `..` traversal are rejected. |
128
+ | `CANVAS_TEMP_PATH` | `canvas.tempRootPath` | `<os.tmpdir()>/mcp-canvas` | Scratch root: DuckDB's `temp_directory` for queries that spill past `memory_limit`, plus the transient files behind stream exports and the spillover round-trip. Never resolves to the process cwd — DuckDB's own cwd-relative `.tmp` default fails on a non-root or read-only container rootfs. |
128
129
  | `CANVAS_MAX_CANVASES_PER_TENANT` | `canvas.maxCanvasesPerTenant` | `100` | Active canvas cap per tenant; throws `RateLimited` when exceeded. |
129
130
  | `CANVAS_TTL_MS` | `canvas.ttlMs` | `86400000` | Sliding TTL (24 h). Every operation extends the expiry. |
130
131
  | `CANVAS_ABSOLUTE_CAP_MS` | `canvas.absoluteCapMs` | `604800000` | Absolute cap from creation (7 d). Sliding window clamps to this. |