@cyanheads/mcp-ts-core 0.13.2 → 0.13.4

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 (117) hide show
  1. package/AGENTS.md +12 -10
  2. package/CLAUDE.md +12 -10
  3. package/README.md +2 -2
  4. package/changelog/0.13.x/0.13.3.md +44 -0
  5. package/changelog/0.13.x/0.13.4.md +65 -0
  6. package/changelog/template.md +7 -7
  7. package/dist/config/appRoot.d.ts.map +1 -1
  8. package/dist/config/appRoot.js +48 -16
  9. package/dist/config/appRoot.js.map +1 -1
  10. package/dist/core/app.d.ts +20 -0
  11. package/dist/core/app.d.ts.map +1 -1
  12. package/dist/core/app.js +1 -0
  13. package/dist/core/app.js.map +1 -1
  14. package/dist/core/index.d.ts +1 -0
  15. package/dist/core/index.d.ts.map +1 -1
  16. package/dist/core/index.js.map +1 -1
  17. package/dist/linter/rules/schema-rules.d.ts +19 -0
  18. package/dist/linter/rules/schema-rules.d.ts.map +1 -1
  19. package/dist/linter/rules/schema-rules.js +36 -0
  20. package/dist/linter/rules/schema-rules.js.map +1 -1
  21. package/dist/linter/rules/tool-rules.d.ts +17 -0
  22. package/dist/linter/rules/tool-rules.d.ts.map +1 -1
  23. package/dist/linter/rules/tool-rules.js +97 -1
  24. package/dist/linter/rules/tool-rules.js.map +1 -1
  25. package/dist/mcp-server/handlerContext.d.ts +6 -0
  26. package/dist/mcp-server/handlerContext.d.ts.map +1 -1
  27. package/dist/mcp-server/handlerContext.js.map +1 -1
  28. package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts.map +1 -1
  29. package/dist/mcp-server/resources/utils/resourceHandlerFactory.js +17 -9
  30. package/dist/mcp-server/resources/utils/resourceHandlerFactory.js.map +1 -1
  31. package/dist/mcp-server/tools/utils/inputPrevalidation.d.ts +114 -0
  32. package/dist/mcp-server/tools/utils/inputPrevalidation.d.ts.map +1 -0
  33. package/dist/mcp-server/tools/utils/inputPrevalidation.js +428 -0
  34. package/dist/mcp-server/tools/utils/inputPrevalidation.js.map +1 -0
  35. package/dist/mcp-server/tools/utils/strictenRecord.d.ts +42 -0
  36. package/dist/mcp-server/tools/utils/strictenRecord.d.ts.map +1 -0
  37. package/dist/mcp-server/tools/utils/strictenRecord.js +48 -0
  38. package/dist/mcp-server/tools/utils/strictenRecord.js.map +1 -0
  39. package/dist/mcp-server/tools/utils/toolDefinition.d.ts +27 -0
  40. package/dist/mcp-server/tools/utils/toolDefinition.d.ts.map +1 -1
  41. package/dist/mcp-server/tools/utils/toolDefinition.js +35 -6
  42. package/dist/mcp-server/tools/utils/toolDefinition.js.map +1 -1
  43. package/dist/mcp-server/tools/utils/toolHandlerFactory.d.ts +28 -4
  44. package/dist/mcp-server/tools/utils/toolHandlerFactory.d.ts.map +1 -1
  45. package/dist/mcp-server/tools/utils/toolHandlerFactory.js +245 -23
  46. package/dist/mcp-server/tools/utils/toolHandlerFactory.js.map +1 -1
  47. package/dist/services/canvas/core/sqlGate.d.ts +14 -1
  48. package/dist/services/canvas/core/sqlGate.d.ts.map +1 -1
  49. package/dist/services/canvas/core/sqlGate.js +69 -7
  50. package/dist/services/canvas/core/sqlGate.js.map +1 -1
  51. package/dist/services/canvas/index.d.ts +1 -1
  52. package/dist/services/canvas/index.d.ts.map +1 -1
  53. package/dist/services/canvas/index.js +1 -1
  54. package/dist/services/canvas/index.js.map +1 -1
  55. package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts +20 -0
  56. package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts.map +1 -1
  57. package/dist/services/canvas/providers/duckdb/DuckdbProvider.js +75 -25
  58. package/dist/services/canvas/providers/duckdb/DuckdbProvider.js.map +1 -1
  59. package/dist/services/canvas/types.d.ts +6 -1
  60. package/dist/services/canvas/types.d.ts.map +1 -1
  61. package/dist/types-global/errors.d.ts.map +1 -1
  62. package/dist/types-global/errors.js +4 -3
  63. package/dist/types-global/errors.js.map +1 -1
  64. package/dist/utils/index.d.ts +3 -2
  65. package/dist/utils/index.d.ts.map +1 -1
  66. package/dist/utils/index.js +3 -2
  67. package/dist/utils/index.js.map +1 -1
  68. package/dist/utils/internal/error-handler/errorHandler.d.ts +33 -0
  69. package/dist/utils/internal/error-handler/errorHandler.d.ts.map +1 -1
  70. package/dist/utils/internal/error-handler/errorHandler.js +45 -3
  71. package/dist/utils/internal/error-handler/errorHandler.js.map +1 -1
  72. package/dist/utils/network/httpError.d.ts +13 -2
  73. package/dist/utils/network/httpError.d.ts.map +1 -1
  74. package/dist/utils/network/httpError.js +4 -2
  75. package/dist/utils/network/httpError.js.map +1 -1
  76. package/dist/utils/network/pacer.d.ts +117 -0
  77. package/dist/utils/network/pacer.d.ts.map +1 -0
  78. package/dist/utils/network/pacer.js +304 -0
  79. package/dist/utils/network/pacer.js.map +1 -0
  80. package/dist/utils/network/retry.d.ts +119 -3
  81. package/dist/utils/network/retry.d.ts.map +1 -1
  82. package/dist/utils/network/retry.js +176 -35
  83. package/dist/utils/network/retry.js.map +1 -1
  84. package/dist/utils/security/rateLimiter.d.ts +19 -1
  85. package/dist/utils/security/rateLimiter.d.ts.map +1 -1
  86. package/dist/utils/security/rateLimiter.js +49 -1
  87. package/dist/utils/security/rateLimiter.js.map +1 -1
  88. package/dist/utils/telemetry/attributes.d.ts +19 -0
  89. package/dist/utils/telemetry/attributes.d.ts.map +1 -1
  90. package/dist/utils/telemetry/attributes.js +30 -0
  91. package/dist/utils/telemetry/attributes.js.map +1 -1
  92. package/framework-skills/add-tool/SKILL.md +43 -2
  93. package/framework-skills/api-canvas/SKILL.md +8 -4
  94. package/framework-skills/api-config/SKILL.md +4 -4
  95. package/framework-skills/api-errors/SKILL.md +19 -10
  96. package/framework-skills/api-linter/SKILL.md +48 -3
  97. package/framework-skills/api-telemetry/SKILL.md +26 -2
  98. package/framework-skills/api-utils/SKILL.md +7 -3
  99. package/framework-skills/api-utils/references/security.md +2 -2
  100. package/framework-skills/design-mcp-server/SKILL.md +17 -2
  101. package/framework-skills/field-test/SKILL.md +3 -1
  102. package/framework-skills/git-wrapup/SKILL.md +90 -68
  103. package/framework-skills/orchestrations/SKILL.md +3 -3
  104. package/framework-skills/release-and-publish/SKILL.md +10 -10
  105. package/framework-skills/release-pr-review/SKILL.md +19 -26
  106. package/framework-skills/report-issue-framework/SKILL.md +6 -35
  107. package/framework-skills/report-issue-local/SKILL.md +6 -36
  108. package/framework-skills/tool-defs-analysis/SKILL.md +4 -4
  109. package/package.json +7 -7
  110. package/templates/.github/ISSUE_TEMPLATE/bug_report.yml +2 -2
  111. package/templates/.github/ISSUE_TEMPLATE/feature_request.yml +2 -2
  112. package/templates/.github/workflows/codeql.yml +39 -0
  113. package/templates/AGENTS.md +3 -1
  114. package/templates/CLAUDE.md +3 -1
  115. package/templates/changelog/template.md +7 -7
  116. package/templates/package.json +2 -2
  117. package/templates/src/index.ts +4 -3
package/AGENTS.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Developer Protocol
2
2
 
3
3
  **Package:** `@cyanheads/mcp-ts-core`
4
- **Version:** 0.13.2
4
+ **Version:** 0.13.4
5
5
  **Engines:** Bun ≥1.4.0, Node ≥24.0.0
6
6
  **MCP SDK:** `@modelcontextprotocol/server` ^2.0.0 (protocol revisions 2026-07-28 and 2025-*)
7
- **Zod:** ^4.6.2
7
+ **Zod:** ^4.6.5
8
8
  **GitHub:** [cyanheads/mcp-ts-core](https://github.com/cyanheads/mcp-ts-core)
9
9
  **npm:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)
10
10
  **Docker:** [ghcr.io/cyanheads/mcp-ts-core](https://ghcr.io/cyanheads/mcp-ts-core)
@@ -22,7 +22,7 @@ This package serves two consumer paths. When making changes, know which audience
22
22
  | **Direct package import** — existing project pulls in the package | `bun add @cyanheads/mcp-ts-core` → `import { createApp, tool, z } from '@cyanheads/mcp-ts-core'` | Public API surface (`src/`) — existing consumers feel changes immediately on upgrade |
23
23
  | **Init-scaffolded server** — fresh project bootstrapped from this repo's templates | `bunx @cyanheads/mcp-ts-core init [name]` copies `templates/` into the new directory | `templates/` — only affects newly scaffolded servers, not existing ones |
24
24
 
25
- Both paths share the same public API. Init copies starter `package.json`, configs (`tsconfig`, `biome.json`, `vitest.config.ts`, `devcheck.config.json`, `bunfig.toml`), `.env.example`, `Dockerfile`, `LICENSE`, `.gitattributes`, `CLAUDE.md`/`AGENTS.md`, `.github/` (issue forms, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`), example definitions and tests, framework `scripts/`, and external-audience `framework-skills/`. `_`-prefixed files (e.g. `_.gitignore`) drop the prefix on copy. Existing files are never overwritten; `init` without a name scaffolds in place (upgrade flow). After init, consult the `setup` skill.
25
+ Both paths share the same public API. Init copies starter `package.json`, configs (`tsconfig`, `biome.json`, `vitest.config.ts`, `devcheck.config.json`, `bunfig.toml`), `.env.example`, `Dockerfile`, `LICENSE`, `.gitattributes`, `CLAUDE.md`/`AGENTS.md`, `.github/` (issue forms, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `workflows/codeql.yml`), example definitions and tests, framework `scripts/`, and external-audience `framework-skills/`. `_`-prefixed files (e.g. `_.gitignore`) drop the prefix on copy. Existing files are never overwritten; `init` without a name scaffolds in place (upgrade flow). After init, consult the `setup` skill.
26
26
 
27
27
  ---
28
28
 
@@ -57,7 +57,7 @@ Both paths share the same public API. Init copies starter `package.json`, config
57
57
  | `/storage/types` | `IStorageProvider` | Provider interface |
58
58
  | `/canvas` | `DataCanvas`, `CanvasInstance`, `CanvasRegistry`, `IDataCanvasProvider`, `DuckdbProvider`, `spillover`, `inferSchemaFromRows`, `assertReadOnlyQuery`, `assertNoSystemCatalogs`, `quoteIdentifier`, ... | DataCanvas primitive (Tier 3, optional peer dep `@duckdb/node-api`); SQL/analytical workspace + source-agnostic spillover helper |
59
59
  | `/mirror` | `defineMirror`, `sqliteMirrorStore`, `buildSchemaSql`, `openSqliteHandle`, `Mirror`, `MirrorStore`, `MirrorDefinition`, `SyncContext`, `SyncPage`, ... | MirrorService primitive (Tier 3, optional peer dep `better-sqlite3` on Node; `bun:sqlite` built-in on Bun); persistent self-refreshing local mirror of a bulk upstream dataset (embedded SQLite + FTS5). Node/Bun only |
60
- | `/utils` | formatting, encoding, network, pagination, overflow (`outlineOnOverflow`, `OUTLINE_VARIANT`, `selectSections`, `formatOutline`), logging, runtime, telemetry, token counting, parsers†, sanitization†, scheduling† | All utilities (†optional peer deps) |
60
+ | `/utils` | formatting, encoding, network (`fetchWithTimeout`, `withRetry` + `deadlineMs`/`defaultIsTransient`, `createPacer`, `httpErrorFromResponse`), pagination, overflow (`outlineOnOverflow`, `OUTLINE_VARIANT`, `selectSections`, `formatOutline`), logging, runtime, telemetry, token counting, parsers†, sanitization†, scheduling† | All utilities (†optional peer deps) |
61
61
  | `/services` | `OpenRouterProvider`, `SpeechService`, `createSpeechProvider`, `ElevenLabsProvider`, `WhisperProvider`, `GraphService`, provider interfaces and types | LLM, Speech (TTS/STT), Graph services |
62
62
  | `/linter` | `validateDefinitions`, `LintReport`, `LintDiagnostic`, `LintInput`, `LintSeverity` | Definition validation |
63
63
  | `/testing` | `createMockContext`, `createMockSession`, `createFetchMock`, `runToolContract`, `createMockLogger`, `getEnrichment`, `getContentBlocks`, `createInMemoryStorage`, `expectInputRequired` | Test kit for handlers and upstream HTTP boundaries |
@@ -124,7 +124,7 @@ await createApp({
124
124
 
125
125
  **`teardown(core)`** — the `setup()` counterpart, awaited inside `shutdown()` after the transport stops accepting requests and before core services are disposed and the logger closes, so the hook can still log and still reach `core.storage`. Runs exactly once per shutdown, on the signal path, the stdin-EOF path, and a direct `ServerHandle.shutdown()` alike; an error it raises is logged and never blocks the exit, and on the signal and EOF paths a hook that never settles is cut by the shutdown ceiling (exit 1 on a signal, 0 on EOF). Register whatever the framework cannot see — a `fs.watch`, an open socket, a `setInterval` nobody `unref()`'d. Node/Bun only; `createWorkerHandler` does not accept it, because an isolate is evicted without notice.
126
126
 
127
- **Also available** — `landing` (`LandingConfig`, HTTP transport only: landing-page config, all fields optional), `context: { exposeStatelessSessionId }` (populate `ctx.sessionId` from the SDK's per-request token in stateless HTTP mode; default `false`), `eventBus` (the `ServerEventBus` backing `subscriptions/listen`; defaults to an in-process bus — supply one for a multi-isolate or multi-process runtime, Workers most of all), and `cacheHints` (2026-07-28 `ttlMs`/`cacheScope` per cacheable operation — see Adding a Resource for the per-resource override).
127
+ **Also available** — `landing` (`LandingConfig`, HTTP transport only: landing-page config, all fields optional), `context: { exposeStatelessSessionId }` (populate `ctx.sessionId` from the SDK's per-request token in stateless HTTP mode; default `false`), `input` (`InputHandlingOptions` — the tool-argument pre-validation switches `ignoreKeys` / `caseStyleAliases` / `coerce`; every stage on when unset, see Adding a Tool), `eventBus` (the `ServerEventBus` backing `subscriptions/listen`; defaults to an in-process bus — supply one for a multi-isolate or multi-process runtime, Workers most of all), and `cacheHints` (2026-07-28 `ttlMs`/`cacheScope` per cacheable operation — see Adding a Resource for the per-resource override).
128
128
 
129
129
  ### Cloudflare Workers — `createWorkerHandler(options)`
130
130
 
@@ -253,7 +253,9 @@ export const myTool = tool('my_tool', {
253
253
 
254
254
  **`enrichment`** (optional): The success-path counterpart to `errors[]` — a `ZodRawShape` of agent-facing context (empty-result notices, query/filter echo, pagination totals, truncation disclosure) that must reach both client surfaces. Populate via `ctx.enrich(...)` (or `ctx.enrich.notice()` / `.total()` / `.echo()` / `.truncated()`) in the handler or service layer. The framework merges it into `structuredContent`, advertises `output.extend(enrichment)` as `outputSchema`, and mirrors it into a `content[]` trailer — so it reaches `structuredContent`-only and `content[]`-only clients alike, with no `format()` entry. Keys must be disjoint from `output`; a required field never populated fails the effective-output parse. See `api-context`'s `ctx.enrich`.
255
255
 
256
- **Strict input:** `tool()` stores `input.strict()`, so an unrecognized argument key is rejected by name before the handler runs and `inputSchema` advertises `additionalProperties: false`. Root-level only — a nested `z.object()` still strips unless it is strict itself. An explicit `.passthrough()` / `.catchall()` is honored.
256
+ **Strict input:** `tool()` stores `input.strict()`, so an unrecognized argument key is rejected by name before the handler runs and `inputSchema` advertises `additionalProperties: false`. Root-level only — a nested `z.object()` still strips unless it is strict itself. An explicit `.passthrough()` / `.catchall()` is honored. Declare `.strict()` **before** `.describe()` / `.meta()` on the root: Zod keys both to the schema instance and `.strict()` clones without it, so a root describe declared after is discarded and never advertised — `lint:mcp` reports that as `schema-root-meta-discarded`.
257
+
258
+ **Pre-validation:** an ordered step inside `parseToolArguments` rescues calls strict input would otherwise reject — drop client-added root keys (`_meta`, `tool_call_description`, `toolCallId`, any undeclared `_`-prefixed key) → rewrite key aliases (declared `inputAliases`, plus any undeclared key whose case-folded form names exactly one declared key) → parse → on failure, repair a JSON-stringified array and re-parse once, keeping it only if the schema then accepts it. All on by default; nothing changes the advertised `inputSchema`, and a call that still fails throws the identical rejection. A declared key, an author-opened root, and a `headerParam` target are never touched. Server-level switches: `createApp({ input: { ignoreKeys, caseStyleAliases, coerce } })`. Counters: `mcp.input.ignored_key`, `mcp.input.aliased`, `mcp.input.coerced`. Lint: `input-alias-conflict`. See `add-tool` skill.
257
259
 
258
260
  **Header-mirrored input (2026-07-28):** `headerParam(z.string(), 'Region')` designates an input property with `x-mcp-header`, so its value also rides an `Mcp-Param-Region` request header and an intermediary can read it without parsing the body. Mirroring, not relocation — the handler still reads the argument from the body, and nothing else about the field changes. Only a primitive-typed (`string`/`integer`/`number`/`boolean`) property statically reachable through a chain of `properties` keys qualifies: an array element, a `z.record()` value, and every field of a discriminated-union input root are unreachable, and header names must be RFC 9110 tokens, case-insensitively unique per schema. `tool()` rejects a violation at definition time naming the field path — the SDK only warns, then conforming Streamable HTTP clients drop the tool. Lint rule: `header-param-designation`.
259
261
 
@@ -414,9 +416,9 @@ Available factories: `invalidParams`, `invalidRequest`, `notFound`, `forbidden`,
414
416
 
415
417
  For HTTP responses from upstream APIs, use `httpErrorFromResponse(response, { service, data })` from `/utils` — maps the full status table (401/403/408/422/429/5xx) and captures body + `Retry-After`.
416
418
 
417
- **Auto-classification.** Plain `Error`, `ZodError`, and any other thrown value are caught and classified automatically. Resolution order: `McpError` code (preserved as-is) → SDK `ConnectionClosed` (→ `RequestCancelled`) → JS constructor name (`TypeError` → `ValidationError`) → provider patterns (HTTP status codes, AWS errors, DB errors) → common message patterns → `AbortError` name (→ `Timeout`) → `InternalError` fallback.
419
+ **Auto-classification.** Plain `Error`, `ZodError`, and any other thrown value are caught and classified automatically. Resolution order: request signal already aborted (→ `RequestCancelled`, outranking the thrown value's own code, `McpError` included) → `McpError` code (preserved as-is) → SDK `ConnectionClosed` (→ `RequestCancelled`) → JS constructor name (`TypeError` → `ValidationError`) → provider patterns (HTTP status codes, AWS errors, DB errors) → common message patterns → `AbortError` name (→ `Timeout`) → `InternalError` fallback.
418
420
 
419
- **Error-path parity.** Tool errors: `content[]` carries markdown with `data.recovery.hint`; `structuredContent.error` carries `{ code, message, data? }`. No `_meta.error`. Resources re-throw via JSON-RPC error envelope.
421
+ **Error-path parity.** Tool errors: `content[]` carries markdown with `data.recovery.hint`; `structuredContent.error` carries `{ code, message, data? }`. No `_meta.error`. Resources re-throw via JSON-RPC error envelope. An argument rejection is one of them: `-32602` with `data.issues`, plus `data.reason: 'invalid_arguments'` and a hint synthesized from the issues and the root schema — never a tool-declared `reason`, since the handler never ran.
420
422
 
421
423
  **Lint rules** (all warnings, surfaced in `devcheck`): `prefer-mcp-error-in-handler`, `prefer-error-factory`, `preserve-cause-on-rethrow`, `no-stringify-upstream-error`, `error-contract-conformance`, `error-contract-prefer-fail`. See `api-linter` skill.
422
424
 
@@ -621,9 +623,9 @@ Badge order when both set: `· ⚠️ Breaking · 🛡️ Security`. Summary > 3
621
623
 
622
624
  ## Publishing
623
625
 
624
- **Every release goes through a gated release PR** — `git-wrapup`'s "Release PR mode", mode `gated`. Three separate runs, never one: `git-wrapup` lands the commit stack on `release/<version>`, pushes it, and opens the PR (title = the release commit subject, body = the changelog entry plus a gates section); `release-pr-review` reviews and fixes on that branch (fixup commits autosquashed into the stack, `--force-with-lease` on the release branch only, PR body kept in sync, one summary comment); then `release-and-publish` fast-forwards `main` locally with `git merge --ff-only`, creates the tag on `main`'s tip, pushes `main` and the tag, deletes the branch, and publishes. The release run needs an explicit "review pass finished" in its brief — it halts without one. **Never merge through the GitHub UI or `gh pr merge`**: squash and rebase-merge are disabled in the repo settings because both rewrite the stack (rebase-merge also strips the SSH signatures), and a merge commit breaks the linear history.
626
+ **Every release goes through a gated release PR** — `git-wrapup`'s "Release PR mode", mode `gated`. Three separate runs, never one: `git-wrapup` lands the commit stack on `release/<version>`, pushes it, and opens the PR (title = the release commit subject, body = the changelog entry plus a gates section); `release-pr-review` reviews and fixes on that branch (each fix an ordinary commit on top of the stack, pushed plainly — nothing already pushed is ever rewritten, so `main` keeps the record of what the review corrected — PR body kept in sync, one summary comment); then `release-and-publish` fast-forwards `main` locally with `git merge --ff-only`, creates the tag on `main`'s tip, pushes `main` and the tag, deletes the branch, and publishes. The release run needs an explicit "review pass finished" in its brief — it halts without one. **Never merge through the GitHub UI or `gh pr merge`**: squash and rebase-merge are disabled in the repo settings because both rewrite the stack (rebase-merge also strips the SSH signatures), and a merge commit breaks the linear history.
625
627
 
626
- Codex (`chatgpt-codex-connector`) reviews the PR when it opens — it reacts 👀 while running, then leaves inline comments, or reacts 👍 when it found nothing. Those comments are claims for `release-pr-review` to verify against the code (its step 4), never instructions: what holds up lands as a fixup like any other finding, and what does not is recorded with the reason. Nothing re-triggers Codex after the review pass force-pushes, so the release proceeds on the reviewed stack.
628
+ Codex (`chatgpt-codex-connector`) reviews the PR when it opens — it reacts 👀 while running, then leaves inline comments, or reacts 👍 when it found nothing. Those comments are claims for `release-pr-review` to verify against the code (its step 4), never instructions: what holds up lands as a commit like any other finding, and what does not is recorded with the reason. Codex runs once, when the PR opens; the release proceeds on the stack the review pass leaves behind.
627
629
 
628
630
  `release-and-publish` here: verification gate (`devcheck`, `rebuild`, `test:all`, `test:package`), merge, tag, push, `bun publish`, `bun run publish-mcp`, then a GitHub Release via `bun run release:github` — no `manifest.json` here so no assets to attach, but the Release surfaces the tag's notes with the correct `v<VERSION>: <subject>` title. **Skip the Docker build/push step** — this framework package is consumed via npm, not as a container image.
629
631
 
package/CLAUDE.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Developer Protocol
2
2
 
3
3
  **Package:** `@cyanheads/mcp-ts-core`
4
- **Version:** 0.13.2
4
+ **Version:** 0.13.4
5
5
  **Engines:** Bun ≥1.4.0, Node ≥24.0.0
6
6
  **MCP SDK:** `@modelcontextprotocol/server` ^2.0.0 (protocol revisions 2026-07-28 and 2025-*)
7
- **Zod:** ^4.6.2
7
+ **Zod:** ^4.6.5
8
8
  **GitHub:** [cyanheads/mcp-ts-core](https://github.com/cyanheads/mcp-ts-core)
9
9
  **npm:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)
10
10
  **Docker:** [ghcr.io/cyanheads/mcp-ts-core](https://ghcr.io/cyanheads/mcp-ts-core)
@@ -22,7 +22,7 @@ This package serves two consumer paths. When making changes, know which audience
22
22
  | **Direct package import** — existing project pulls in the package | `bun add @cyanheads/mcp-ts-core` → `import { createApp, tool, z } from '@cyanheads/mcp-ts-core'` | Public API surface (`src/`) — existing consumers feel changes immediately on upgrade |
23
23
  | **Init-scaffolded server** — fresh project bootstrapped from this repo's templates | `bunx @cyanheads/mcp-ts-core init [name]` copies `templates/` into the new directory | `templates/` — only affects newly scaffolded servers, not existing ones |
24
24
 
25
- Both paths share the same public API. Init copies starter `package.json`, configs (`tsconfig`, `biome.json`, `vitest.config.ts`, `devcheck.config.json`, `bunfig.toml`), `.env.example`, `Dockerfile`, `LICENSE`, `.gitattributes`, `CLAUDE.md`/`AGENTS.md`, `.github/` (issue forms, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`), example definitions and tests, framework `scripts/`, and external-audience `framework-skills/`. `_`-prefixed files (e.g. `_.gitignore`) drop the prefix on copy. Existing files are never overwritten; `init` without a name scaffolds in place (upgrade flow). After init, consult the `setup` skill.
25
+ Both paths share the same public API. Init copies starter `package.json`, configs (`tsconfig`, `biome.json`, `vitest.config.ts`, `devcheck.config.json`, `bunfig.toml`), `.env.example`, `Dockerfile`, `LICENSE`, `.gitattributes`, `CLAUDE.md`/`AGENTS.md`, `.github/` (issue forms, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `workflows/codeql.yml`), example definitions and tests, framework `scripts/`, and external-audience `framework-skills/`. `_`-prefixed files (e.g. `_.gitignore`) drop the prefix on copy. Existing files are never overwritten; `init` without a name scaffolds in place (upgrade flow). After init, consult the `setup` skill.
26
26
 
27
27
  ---
28
28
 
@@ -57,7 +57,7 @@ Both paths share the same public API. Init copies starter `package.json`, config
57
57
  | `/storage/types` | `IStorageProvider` | Provider interface |
58
58
  | `/canvas` | `DataCanvas`, `CanvasInstance`, `CanvasRegistry`, `IDataCanvasProvider`, `DuckdbProvider`, `spillover`, `inferSchemaFromRows`, `assertReadOnlyQuery`, `assertNoSystemCatalogs`, `quoteIdentifier`, ... | DataCanvas primitive (Tier 3, optional peer dep `@duckdb/node-api`); SQL/analytical workspace + source-agnostic spillover helper |
59
59
  | `/mirror` | `defineMirror`, `sqliteMirrorStore`, `buildSchemaSql`, `openSqliteHandle`, `Mirror`, `MirrorStore`, `MirrorDefinition`, `SyncContext`, `SyncPage`, ... | MirrorService primitive (Tier 3, optional peer dep `better-sqlite3` on Node; `bun:sqlite` built-in on Bun); persistent self-refreshing local mirror of a bulk upstream dataset (embedded SQLite + FTS5). Node/Bun only |
60
- | `/utils` | formatting, encoding, network, pagination, overflow (`outlineOnOverflow`, `OUTLINE_VARIANT`, `selectSections`, `formatOutline`), logging, runtime, telemetry, token counting, parsers†, sanitization†, scheduling† | All utilities (†optional peer deps) |
60
+ | `/utils` | formatting, encoding, network (`fetchWithTimeout`, `withRetry` + `deadlineMs`/`defaultIsTransient`, `createPacer`, `httpErrorFromResponse`), pagination, overflow (`outlineOnOverflow`, `OUTLINE_VARIANT`, `selectSections`, `formatOutline`), logging, runtime, telemetry, token counting, parsers†, sanitization†, scheduling† | All utilities (†optional peer deps) |
61
61
  | `/services` | `OpenRouterProvider`, `SpeechService`, `createSpeechProvider`, `ElevenLabsProvider`, `WhisperProvider`, `GraphService`, provider interfaces and types | LLM, Speech (TTS/STT), Graph services |
62
62
  | `/linter` | `validateDefinitions`, `LintReport`, `LintDiagnostic`, `LintInput`, `LintSeverity` | Definition validation |
63
63
  | `/testing` | `createMockContext`, `createMockSession`, `createFetchMock`, `runToolContract`, `createMockLogger`, `getEnrichment`, `getContentBlocks`, `createInMemoryStorage`, `expectInputRequired` | Test kit for handlers and upstream HTTP boundaries |
@@ -124,7 +124,7 @@ await createApp({
124
124
 
125
125
  **`teardown(core)`** — the `setup()` counterpart, awaited inside `shutdown()` after the transport stops accepting requests and before core services are disposed and the logger closes, so the hook can still log and still reach `core.storage`. Runs exactly once per shutdown, on the signal path, the stdin-EOF path, and a direct `ServerHandle.shutdown()` alike; an error it raises is logged and never blocks the exit, and on the signal and EOF paths a hook that never settles is cut by the shutdown ceiling (exit 1 on a signal, 0 on EOF). Register whatever the framework cannot see — a `fs.watch`, an open socket, a `setInterval` nobody `unref()`'d. Node/Bun only; `createWorkerHandler` does not accept it, because an isolate is evicted without notice.
126
126
 
127
- **Also available** — `landing` (`LandingConfig`, HTTP transport only: landing-page config, all fields optional), `context: { exposeStatelessSessionId }` (populate `ctx.sessionId` from the SDK's per-request token in stateless HTTP mode; default `false`), `eventBus` (the `ServerEventBus` backing `subscriptions/listen`; defaults to an in-process bus — supply one for a multi-isolate or multi-process runtime, Workers most of all), and `cacheHints` (2026-07-28 `ttlMs`/`cacheScope` per cacheable operation — see Adding a Resource for the per-resource override).
127
+ **Also available** — `landing` (`LandingConfig`, HTTP transport only: landing-page config, all fields optional), `context: { exposeStatelessSessionId }` (populate `ctx.sessionId` from the SDK's per-request token in stateless HTTP mode; default `false`), `input` (`InputHandlingOptions` — the tool-argument pre-validation switches `ignoreKeys` / `caseStyleAliases` / `coerce`; every stage on when unset, see Adding a Tool), `eventBus` (the `ServerEventBus` backing `subscriptions/listen`; defaults to an in-process bus — supply one for a multi-isolate or multi-process runtime, Workers most of all), and `cacheHints` (2026-07-28 `ttlMs`/`cacheScope` per cacheable operation — see Adding a Resource for the per-resource override).
128
128
 
129
129
  ### Cloudflare Workers — `createWorkerHandler(options)`
130
130
 
@@ -253,7 +253,9 @@ export const myTool = tool('my_tool', {
253
253
 
254
254
  **`enrichment`** (optional): The success-path counterpart to `errors[]` — a `ZodRawShape` of agent-facing context (empty-result notices, query/filter echo, pagination totals, truncation disclosure) that must reach both client surfaces. Populate via `ctx.enrich(...)` (or `ctx.enrich.notice()` / `.total()` / `.echo()` / `.truncated()`) in the handler or service layer. The framework merges it into `structuredContent`, advertises `output.extend(enrichment)` as `outputSchema`, and mirrors it into a `content[]` trailer — so it reaches `structuredContent`-only and `content[]`-only clients alike, with no `format()` entry. Keys must be disjoint from `output`; a required field never populated fails the effective-output parse. See `api-context`'s `ctx.enrich`.
255
255
 
256
- **Strict input:** `tool()` stores `input.strict()`, so an unrecognized argument key is rejected by name before the handler runs and `inputSchema` advertises `additionalProperties: false`. Root-level only — a nested `z.object()` still strips unless it is strict itself. An explicit `.passthrough()` / `.catchall()` is honored.
256
+ **Strict input:** `tool()` stores `input.strict()`, so an unrecognized argument key is rejected by name before the handler runs and `inputSchema` advertises `additionalProperties: false`. Root-level only — a nested `z.object()` still strips unless it is strict itself. An explicit `.passthrough()` / `.catchall()` is honored. Declare `.strict()` **before** `.describe()` / `.meta()` on the root: Zod keys both to the schema instance and `.strict()` clones without it, so a root describe declared after is discarded and never advertised — `lint:mcp` reports that as `schema-root-meta-discarded`.
257
+
258
+ **Pre-validation:** an ordered step inside `parseToolArguments` rescues calls strict input would otherwise reject — drop client-added root keys (`_meta`, `tool_call_description`, `toolCallId`, any undeclared `_`-prefixed key) → rewrite key aliases (declared `inputAliases`, plus any undeclared key whose case-folded form names exactly one declared key) → parse → on failure, repair a JSON-stringified array and re-parse once, keeping it only if the schema then accepts it. All on by default; nothing changes the advertised `inputSchema`, and a call that still fails throws the identical rejection. A declared key, an author-opened root, and a `headerParam` target are never touched. Server-level switches: `createApp({ input: { ignoreKeys, caseStyleAliases, coerce } })`. Counters: `mcp.input.ignored_key`, `mcp.input.aliased`, `mcp.input.coerced`. Lint: `input-alias-conflict`. See `add-tool` skill.
257
259
 
258
260
  **Header-mirrored input (2026-07-28):** `headerParam(z.string(), 'Region')` designates an input property with `x-mcp-header`, so its value also rides an `Mcp-Param-Region` request header and an intermediary can read it without parsing the body. Mirroring, not relocation — the handler still reads the argument from the body, and nothing else about the field changes. Only a primitive-typed (`string`/`integer`/`number`/`boolean`) property statically reachable through a chain of `properties` keys qualifies: an array element, a `z.record()` value, and every field of a discriminated-union input root are unreachable, and header names must be RFC 9110 tokens, case-insensitively unique per schema. `tool()` rejects a violation at definition time naming the field path — the SDK only warns, then conforming Streamable HTTP clients drop the tool. Lint rule: `header-param-designation`.
259
261
 
@@ -414,9 +416,9 @@ Available factories: `invalidParams`, `invalidRequest`, `notFound`, `forbidden`,
414
416
 
415
417
  For HTTP responses from upstream APIs, use `httpErrorFromResponse(response, { service, data })` from `/utils` — maps the full status table (401/403/408/422/429/5xx) and captures body + `Retry-After`.
416
418
 
417
- **Auto-classification.** Plain `Error`, `ZodError`, and any other thrown value are caught and classified automatically. Resolution order: `McpError` code (preserved as-is) → SDK `ConnectionClosed` (→ `RequestCancelled`) → JS constructor name (`TypeError` → `ValidationError`) → provider patterns (HTTP status codes, AWS errors, DB errors) → common message patterns → `AbortError` name (→ `Timeout`) → `InternalError` fallback.
419
+ **Auto-classification.** Plain `Error`, `ZodError`, and any other thrown value are caught and classified automatically. Resolution order: request signal already aborted (→ `RequestCancelled`, outranking the thrown value's own code, `McpError` included) → `McpError` code (preserved as-is) → SDK `ConnectionClosed` (→ `RequestCancelled`) → JS constructor name (`TypeError` → `ValidationError`) → provider patterns (HTTP status codes, AWS errors, DB errors) → common message patterns → `AbortError` name (→ `Timeout`) → `InternalError` fallback.
418
420
 
419
- **Error-path parity.** Tool errors: `content[]` carries markdown with `data.recovery.hint`; `structuredContent.error` carries `{ code, message, data? }`. No `_meta.error`. Resources re-throw via JSON-RPC error envelope.
421
+ **Error-path parity.** Tool errors: `content[]` carries markdown with `data.recovery.hint`; `structuredContent.error` carries `{ code, message, data? }`. No `_meta.error`. Resources re-throw via JSON-RPC error envelope. An argument rejection is one of them: `-32602` with `data.issues`, plus `data.reason: 'invalid_arguments'` and a hint synthesized from the issues and the root schema — never a tool-declared `reason`, since the handler never ran.
420
422
 
421
423
  **Lint rules** (all warnings, surfaced in `devcheck`): `prefer-mcp-error-in-handler`, `prefer-error-factory`, `preserve-cause-on-rethrow`, `no-stringify-upstream-error`, `error-contract-conformance`, `error-contract-prefer-fail`. See `api-linter` skill.
422
424
 
@@ -621,9 +623,9 @@ Badge order when both set: `· ⚠️ Breaking · 🛡️ Security`. Summary > 3
621
623
 
622
624
  ## Publishing
623
625
 
624
- **Every release goes through a gated release PR** — `git-wrapup`'s "Release PR mode", mode `gated`. Three separate runs, never one: `git-wrapup` lands the commit stack on `release/<version>`, pushes it, and opens the PR (title = the release commit subject, body = the changelog entry plus a gates section); `release-pr-review` reviews and fixes on that branch (fixup commits autosquashed into the stack, `--force-with-lease` on the release branch only, PR body kept in sync, one summary comment); then `release-and-publish` fast-forwards `main` locally with `git merge --ff-only`, creates the tag on `main`'s tip, pushes `main` and the tag, deletes the branch, and publishes. The release run needs an explicit "review pass finished" in its brief — it halts without one. **Never merge through the GitHub UI or `gh pr merge`**: squash and rebase-merge are disabled in the repo settings because both rewrite the stack (rebase-merge also strips the SSH signatures), and a merge commit breaks the linear history.
626
+ **Every release goes through a gated release PR** — `git-wrapup`'s "Release PR mode", mode `gated`. Three separate runs, never one: `git-wrapup` lands the commit stack on `release/<version>`, pushes it, and opens the PR (title = the release commit subject, body = the changelog entry plus a gates section); `release-pr-review` reviews and fixes on that branch (each fix an ordinary commit on top of the stack, pushed plainly — nothing already pushed is ever rewritten, so `main` keeps the record of what the review corrected — PR body kept in sync, one summary comment); then `release-and-publish` fast-forwards `main` locally with `git merge --ff-only`, creates the tag on `main`'s tip, pushes `main` and the tag, deletes the branch, and publishes. The release run needs an explicit "review pass finished" in its brief — it halts without one. **Never merge through the GitHub UI or `gh pr merge`**: squash and rebase-merge are disabled in the repo settings because both rewrite the stack (rebase-merge also strips the SSH signatures), and a merge commit breaks the linear history.
625
627
 
626
- Codex (`chatgpt-codex-connector`) reviews the PR when it opens — it reacts 👀 while running, then leaves inline comments, or reacts 👍 when it found nothing. Those comments are claims for `release-pr-review` to verify against the code (its step 4), never instructions: what holds up lands as a fixup like any other finding, and what does not is recorded with the reason. Nothing re-triggers Codex after the review pass force-pushes, so the release proceeds on the reviewed stack.
628
+ Codex (`chatgpt-codex-connector`) reviews the PR when it opens — it reacts 👀 while running, then leaves inline comments, or reacts 👍 when it found nothing. Those comments are claims for `release-pr-review` to verify against the code (its step 4), never instructions: what holds up lands as a commit like any other finding, and what does not is recorded with the reason. Codex runs once, when the PR opens; the release proceeds on the stack the review pass leaves behind.
627
629
 
628
630
  `release-and-publish` here: verification gate (`devcheck`, `rebuild`, `test:all`, `test:package`), merge, tag, push, `bun publish`, `bun run publish-mcp`, then a GitHub Release via `bun run release:github` — no `manifest.json` here so no assets to attach, but the Release surfaces the tag's notes with the correct `v<VERSION>: <subject>` title. **Skip the Docker build/push step** — this framework package is consumed via npm, not as a container image.
629
631
 
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  <div align="center">
2
2
  <h1>@cyanheads/mcp-ts-core</h1>
3
- <p><b>Agent-native TypeScript framework for MCP servers. Includes runtime infrastructure and agent skills for building, testing, and shipping servers.</b></p>
3
+ <p><b>Agent-native TypeScript framework for building MCP servers. Includes runtime infrastructure and agent skills for building, testing, and shipping servers.</b></p>
4
4
  <p>Give your agent the infrastructure, patterns, and skills to build and ship your server.</p>
5
5
  </div>
6
6
 
7
7
  <div align="center">
8
8
 
9
- [![Version](https://img.shields.io/badge/Version-0.13.2-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2026--07--28-8A2BE2.svg?style=flat-square)](https://modelcontextprotocol.io/specification/2026-07-28)
9
+ [![Version](https://img.shields.io/badge/Version-0.13.4-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2026--07--28-8A2BE2.svg?style=flat-square)](https://modelcontextprotocol.io/specification/2026-07-28)
10
10
 
11
11
  [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.0.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![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%2B-blueviolet.svg?style=flat-square)](https://bun.sh/)
12
12
 
@@ -0,0 +1,44 @@
1
+ ---
2
+ summary: "Argument rejections carry a reason and a schema-derived recovery hint, and render an omitted required field as missing rather than as a wrong choice. A handler unwound after its request was cancelled classifies RequestCancelled whatever it threw."
3
+ breaking: false
4
+ security: false
5
+ agent-notes: |
6
+ Two adoption steps for a consumer upgrading from 0.13.2.
7
+
8
+ 1. Every argument rejection's `content[0].text` now ends with a
9
+ `\n\nRecovery: <hint>` suffix, and its `data` carries
10
+ `reason: "invalid_arguments"`. `runToolContract` routes through the
11
+ production rejection path, so a test pinning that text byte-exact fails on
12
+ upgrade — assert that it *contains* the offending field instead.
13
+ `toolContractSuite` asserts only the `Error:` prefix and is unaffected.
14
+ 2. A cancelled call now logs at `info` with `metrics.errorCode: "-32011"`. A
15
+ dashboard or alert keyed on `UNKNOWN_ERROR` / `InternalError` to count
16
+ client disconnects no longer matches — key it on `-32011`.
17
+ ---
18
+
19
+ # 0.13.3 — 2026-09-17
20
+
21
+ ## Added
22
+
23
+ - **`data.reason: "invalid_arguments"` and a synthesized `data.recovery.hint` on every argument rejection** ([#445](https://github.com/cyanheads/mcp-ts-core/issues/445)). The hint is derived from the Zod issues, the arguments as sent, and the root schema: an unknown key names the root properties the tool does accept, a wrong type names the type to send instead, and missing fields collapse into one `Provide …` sentence. It rides `content[]` as `Recovery: …` like any handler-thrown hint. A `z.discriminatedUnion()` root omits the accepted-key list, since no single call accepts the union of every variant's keys.
24
+ - **`.github/workflows/codeql.yml`, at the repo root and in the scaffold** — the one workflow a server carries, copied by `init`. It runs only while the repo's CodeQL *default setup* is off.
25
+
26
+ ## Changed
27
+
28
+ - **A required field omitted from an enum or literal renders as missing** ([#378](https://github.com/cyanheads/mcp-ts-core/issues/378)) — `what: Missing required field. Expected one of "os"|"cpu"|"memory"`, where an omission and a wrong choice were previously byte-identical. A value outside the set keeps Zod's invalid-option sentence. Absence is resolved from the arguments in-process, so no value a caller sent is copied onto `data.issues`.
29
+ - **A union rejection renders its branch messages** ([#417](https://github.com/cyanheads/mcp-ts-core/issues/417)) joined by ` or `, instead of Zod's `Invalid input` placeholder. A branch whose only issue is a single-valued `invalid_value` — the `z.literal('')` blank-field sentinel — is skipped.
30
+ - **The scaffold's `instructions` comment shows the shape to write** — two to three cohesive sentences in one string literal, addressed to the calling agent, with operator configuration left to the README. `tool-defs-analysis` checks the same shape on `description` and `instructions`.
31
+ - Skill versions: `api-errors` 1.10 → 1.12, `git-wrapup` 1.17 → 1.18, `orchestrations` 1.9 → 1.10, `release-and-publish` 2.17 → 2.18, `release-pr-review` 1.1 → 1.3, `tool-defs-analysis` 1.5 → 1.6.
32
+
33
+ ## Fixed
34
+
35
+ - **A handler unwound after its request's abort signal fired classifies `RequestCancelled` (`-32011`)** ([#421](https://github.com/cyanheads/mcp-ts-core/issues/421)) whatever it threw — a `notifications/cancelled` `reason` string, the `AbortError` `DOMException` a reason-less cancellation leaves, a service's own `McpError`. It is resolved inside the measured region of both handler factories, so the completion log's `metrics.errorCode` and the execution span carry `-32011` too, and the record logs at `info` with neither a stack nor a cause chain. A throw raised while the signal is still live is untouched.
36
+ - **`git-wrapup` step 7 and `release-pr-review` step 5 commit by pathspec** ([#444](https://github.com/cyanheads/mcp-ts-core/issues/444)) — `git commit --only <paths>`, so anything staged before the run (a migration's `git mv`, a hook's output, a concurrent session) cannot ride into the first concern's commit. `release-pr-review` step 5 lands each review fix as an ordinary commit on top of the release branch and pushes plainly, so nothing already pushed is rewritten and `main` keeps the record of what the review corrected. `git-wrapup` step 1 also diffs against `HEAD` rather than the index, so a pre-staged group is reviewed rather than skipped.
37
+
38
+ ## Dependencies
39
+
40
+ - `zod` ^4.6.2 → ^4.6.5
41
+ - `@duckdb/node-api` ^1.5.5-r.4 → ^1.5.5-r.5 (dev)
42
+ - `fast-check` ^4.9.0 → ^4.10.0 (dev)
43
+ - `js-yaml` ^5.4.1 → ^5.4.2 (dev)
44
+ - `tsc-alias` ^1.9.4 → ^1.9.5 (dev; scaffold pin ^1.9.2 → ^1.9.5, alongside `ignore` ^7.0.7 → ^7.0.9)
@@ -0,0 +1,65 @@
1
+ ---
2
+ summary: "Tool arguments pass an ordered pre-validation step — client-added keys dropped, key aliases rewritten, a stringified array repaired after a failed parse — and httpErrorFromResponse no longer puts the upstream request URL on client-facing error.data by default."
3
+ breaking: true
4
+ security: true
5
+ agent-notes: |
6
+ Two adoption steps for a consumer upgrading from 0.13.3.
7
+
8
+ 1. The pre-validation step needs no adoption — every stage is on by default and
9
+ `inputSchema` is byte-identical either way. Two opt-ins exist. Declare
10
+ `inputAliases: { <alias>: <declared key> }` on a `tool()` whose callers
11
+ reach for another spelling of a parameter; `lint:mcp` fails the definition
12
+ when an alias cannot resolve to exactly one declared key. Pass
13
+ `createApp({ input: { ignoreKeys, caseStyleAliases, coerce } })` (also on
14
+ `createWorkerHandler`) to extend the ignore list or turn a stage off for
15
+ the whole server — there is no per-tool switch.
16
+ 2. The `git-wrapup` skill reordered its steps: the work stack is committed
17
+ first (step 3), then the version is bumped (step 4) and the release commit
18
+ lands on top (step 8). A project syncing this skill should re-read it
19
+ before its next wrap-up — a dependency refresh is now its own
20
+ `chore(deps): …` commit rather than hunks inside `chore(release): …`.
21
+ ---
22
+
23
+ # 0.13.4 — 2026-09-18
24
+
25
+ ## Added
26
+
27
+ - **Tool arguments pass an ordered pre-validation step inside `parseToolArguments`** — drop client-added root keys ([#453](https://github.com/cyanheads/mcp-ts-core/issues/453)) → rewrite key aliases ([#452](https://github.com/cyanheads/mcp-ts-core/issues/452)) → parse → on failure, repair a JSON-stringified array and re-parse once ([#234](https://github.com/cyanheads/mcp-ts-core/issues/234)). A declared key, an author-opened root, and a `headerParam` target are never touched, and a call that still fails throws the identical rejection.
28
+ - **`inputAliases` on `tool()`** — `{ <alias>: <declared key> }`, rewritten only when the target key is absent. Not advertised: `inputSchema` is byte-identical with or without it. Alongside it, an undeclared key whose case-folded form (`-`/`_` stripped, lowercased) names exactly one declared key is rewritten with nothing declared.
29
+ - **`createApp({ input })`** (`InputHandlingOptions`) — server-level `ignoreKeys` / `caseStyleAliases` / `coerce` switches for the three stages. Also accepted by `createWorkerHandler`.
30
+ - **`createPacer`** ([#454](https://github.com/cyanheads/mcp-ts-core/issues/454)) — a FIFO queue in front of one rate-limited upstream: sliding start-rate windows, `minStartGapMs`, `maxConcurrent`, `maxQueueDepth`, and a shared 429 cooldown gate. A shed is `RateLimited` with `data.reason: 'pacer_shed'`. `dispose()` / `[Symbol.dispose]()` wires through `createApp({ teardown })`.
31
+ - **`withRetry`'s `deadlineMs`** ([#455](https://github.com/cyanheads/mcp-ts-core/issues/455)) — one wall-clock budget across every attempt, backoff, and honored `Retry-After`. `fn` now receives a `RetryAttempt` (`{ signal, remainingMs }`); thread `signal` into the attempt's I/O or the deadline overshoots by one in-flight request. Expiry is `Timeout` with `data.reason: 'retry_deadline_exceeded'`.
32
+ - **`defaultIsTransient`** ([#450](https://github.com/cyanheads/mcp-ts-core/issues/450)) — exported so a custom `isTransient`, which replaces the default outright, composes off it instead of mirroring the transient code set.
33
+ - **`DUCKDB_ERROR_REASONS` / `DuckdbErrorReason`** from `/canvas`, so a canvas-consuming tool can map an engine failure onto an `errors[]` entry without duplicating the strings. `createObservableGauge` is now re-exported from `/utils`.
34
+ - **Lint rules `input-alias-conflict` (error) and `schema-root-meta-discarded` (warning)**, and metrics `mcp.input.ignored_key`, `mcp.input.aliased`, `mcp.input.coerced`, `mcp.pacer.queue_depth`, `mcp.pacer.wait`, `mcp.pacer.sheds`, `mcp.pacer.cooldowns`. Every attribute is author- or framework-defined; a caller's own key text never labels a series.
35
+
36
+ ## Changed
37
+
38
+ - **`httpErrorFromResponse` omits the upstream URL from `error.data` by default** — see **Security**. **Migration:** pass `includeUrl: true` to put the full `response.url` back on `data.url`.
39
+ - **A DuckDB execution-time data error is a caller-side `ValidationError`** ([#451](https://github.com/cyanheads/mcp-ts-core/issues/451)) with `data.reason: 'sql_execution_error'`, matched on DuckDB's own `Conversion` / `Invalid Input` / `Out of Range` class prefix. Engine faults — `IO Error`, `INTERNAL Error`, `Out of Memory Error`, anything unmatched — stay `DatabaseError`.
40
+ - **Every canvas gate and engine rejection carries `data.recovery.hint`** ([#299](https://github.com/cyanheads/mcp-ts-core/issues/299)), phrased as a capability the caller can reach rather than a framework method it cannot call. `assertNoSystemCatalogs` also drops the unobservable `denySystemCatalogs` flag from its message.
41
+ - **`TableInfo.approxSizeBytes` is `@deprecated` and never populated** ([#324](https://github.com/cyanheads/mcp-ts-core/issues/324)) — `duckdb_tables().estimated_size` is an estimated row count, not a byte footprint, and DuckDB exposes no per-table byte column. The member stays on the type so existing readers compile.
42
+ - **`RateLimiter.configure` enforces a lowered `maxTrackedKeys` before it returns** ([#407](https://github.com/cyanheads/mcp-ts-core/issues/407)) — one trim pass, expired windows before live entries, live entries in least-recently-used order. Survivors keep their counts and reset times.
43
+ - **`design-mcp-server` and `field-test` codify input-edge value normalization** ([#369](https://github.com/cyanheads/mcp-ts-core/issues/369)) — normalize a variant whose mapping is unambiguous, one-to-one, and meaning-preserving; error on the rest. The field-test battery probes an identifier, code, or enum-ish input with its obvious variants. Argument *key* names remain the framework's job.
44
+ - **Both `report-issue` skills and the issue forms carry a length budget** — ~150 words for a bug, ~250 for a feature, code and logs excluded. The optional `Scope` / `Flow` / `Design / Tradeoffs` / `Dependencies` scaffolding is gone from the CLI examples, at the repo root and in the scaffold.
45
+ - Skill versions: `add-tool` 2.26 → 2.27, `api-canvas` 2.1 → 2.2, `api-config` 1.18 → 1.19, `api-errors` 1.12 → 1.13, `api-linter` 1.14 → 1.15, `api-telemetry` 1.9 → 1.11, `api-utils` 2.9 → 2.10, `design-mcp-server` 2.26 → 2.27, `field-test` 2.14 → 2.15, `git-wrapup` 1.18 → 1.19, `release-and-publish` 2.18 → 2.19, `release-pr-review` 1.3 → 1.4, `report-issue-framework` 1.11 → 1.12, `report-issue-local` 1.9 → 1.10.
46
+
47
+ ## Fixed
48
+
49
+ - **`McpError` sets its prototype from `new.target`** ([#456](https://github.com/cyanheads/mcp-ts-core/issues/456)) — pinning `McpError.prototype` stripped a subclass of its own methods and broke `instanceof` against it. `Error.captureStackTrace` follows the same constructor.
50
+ - **A union-of-objects rejection prefixes each branch issue with its own field path** ([#447](https://github.com/cyanheads/mcp-ts-core/issues/447)), so two alternatives differing only in which field they require stay distinguishable rather than collapsing. Issues within a branch join on `; `, branches on ` or `. `data.issues` still ships the raw nested Zod issues.
51
+ - **`resolveAppRoot` picks the workspace package, not the runner's manifest, in a hoisted monorepo** ([#399](https://github.com/cyanheads/mcp-ts-core/issues/399)). An owning ancestor of the working directory claims identity only when it declares a workspace (a `workspaces` field, or a `pnpm-workspace.yaml` beside it), which keeps a cache prefix or a plain project root out. The owner is now the outermost `node_modules` boundary, so a transitive runner and a pnpm isolated layout resolve alike.
52
+ - **`tool()` records the root `.describe()` / `.meta()` that strictening discards, and `lint:mcp` reports it** as `schema-root-meta-discarded` ([#358](https://github.com/cyanheads/mcp-ts-core/issues/358), [#394](https://github.com/cyanheads/mcp-ts-core/issues/394)). This is the detection half only — re-applying the entry to the strictened schema would move advertised `inputSchema` bytes and remains held. Declaring `.strict()` before `.describe()` / `.meta()` keeps the entry today.
53
+ - **The `test:package` Worker lane typechecks with `skipLibCheck: false`** ([#411](https://github.com/cyanheads/mcp-ts-core/issues/411)) — the Worker consumer installs into its own root carrying no `@types/node`, so `dist/core/worker.d.ts` is checked against Cloudflare's globals instead of skipped. The lane asserts both that the file entered the program and that no `@types/node` declaration did.
54
+ - **`git-wrapup` commits the work stack before bumping the version** ([#448](https://github.com/cyanheads/mcp-ts-core/issues/448)), so a dependency refresh sharing `package.json` with the version lands as its own `chore(deps): …` commit and the release commit brings those files the version hunk alone.
55
+ - **The tag subject is written fresh at release time** ([#419](https://github.com/cyanheads/mcp-ts-core/issues/419)) rather than lifted from the changelog `summary:`, which budgets 350 characters for a different surface. The release-PR body's `## Changes` bullets and changelog link still become the tag body verbatim.
56
+ - **`api-config` attributes blank-env tolerance to the normalization layer, not `z.stringbool()`** ([#408](https://github.com/cyanheads/mcp-ts-core/issues/408)), which rejects `''` with `Invalid option`. A direct `Schema.parse(...)` runs no normalization; `normalizeEnv` is exported from `/config` for that path.
57
+
58
+ ## Security
59
+
60
+ - **The upstream request URL is no longer client-facing by default** ([#307](https://github.com/cyanheads/mcp-ts-core/issues/307)). `error.data` is forwarded to the client as `structuredContent.error.data`, and a request URL routinely carries user input, internal identifiers, or an API key in its query string. No `url` key is added unless `includeUrl: true` is passed; the message still names the host.
61
+ - **Tool-argument copying cannot be re-prototyped by a caller's own `__proto__` key.** The pre-validation step copies through spread and `Object.fromEntries`, which *define* properties rather than assigning them, so a `__proto__` key `JSON.parse` created as an own data property stays a key instead of replacing the copy's prototype.
62
+
63
+ ## Dependencies
64
+
65
+ - `hono` ^4.13.7 → ^4.13.8
@@ -6,8 +6,8 @@
6
6
 
7
7
  # Required. One-line GitHub Release-style headline. 350 character cap — a
8
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
9
+ # unrelated changes with commas/semicolons into an inventory — pick the one
10
+ # headline the release is about. Quotes required: unquoted YAML treats
11
11
  # `: ` inside the value as a key separator and fails GitHub's strict parser.
12
12
  summary: ""
13
13
 
@@ -119,11 +119,11 @@ security: false
119
119
  TAG ANNOTATIONS — the annotated tag body renders as the GitHub Release body
120
120
  via `gh release create --notes-from-tag`. It is a condensed digest of this
121
121
  entry, never a copy, and its format is owned by the `release-and-publish`
122
- skill (step 4, "Create the annotated tag"): the entry's `summary:` as the
123
- theme line without the version, flat headline bullets — no Keep-a-Changelog
124
- section headers, no gates line — at most one deps line, issue backlinks,
125
- and the changelog link last. In release-PR mode the `git-wrapup` skill
126
- authors that digest as the PR body's `## Changes` and the tag copies it.
122
+ skill (step 4, "Create the annotated tag"): a short subject line without the
123
+ version, flat headline bullets — no Keep-a-Changelog section headers, no
124
+ gates line — at most one deps line, issue backlinks, and the changelog link
125
+ last. In release-PR mode the `git-wrapup` skill authors those bullets as the
126
+ PR body's `## Changes` and the tag copies them.
127
127
  -->
128
128
 
129
129
  ## Added
@@ -1 +1 @@
1
- {"version":3,"file":"appRoot.d.ts","sourceRoot":"","sources":["../../src/config/appRoot.ts"],"names":[],"mappings":"AAaA,qEAAqE;AACrE,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEF,8EAA8E;AAC9E,MAAM,WAAW,OAAO;IACtB,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,QAAQ,EAAE,eAAe,CAAC;CAC3B;AA2GD;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,OAAO,GAAG,SAAS,CAMpD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC"}
1
+ {"version":3,"file":"appRoot.d.ts","sourceRoot":"","sources":["../../src/config/appRoot.ts"],"names":[],"mappings":"AAaA,qEAAqE;AACrE,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEF,8EAA8E;AAC9E,MAAM,WAAW,OAAO;IACtB,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,QAAQ,EAAE,eAAe,CAAC;CAC3B;AA4ID;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,OAAO,GAAG,SAAS,CAMpD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC"}
@@ -6,18 +6,23 @@
6
6
  * directory the launching client happened to be in.
7
7
  * @module src/config/appRoot
8
8
  */
9
- import { readFileSync, realpathSync, statSync } from 'node:fs';
9
+ import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';
10
10
  import { dirname, resolve, sep } from 'node:path';
11
11
  import { runtimeCaps } from '../utils/internal/runtime.js';
12
- /** Reads the identity fields of `<dir>/package.json`, or `undefined` if absent/unreadable. */
13
- function readManifest(dir) {
14
- let parsed;
12
+ /** Parses `<dir>/package.json`, or `undefined` if absent/unreadable/unparseable. */
13
+ function readPackageJson(dir) {
15
14
  try {
16
- parsed = JSON.parse(readFileSync(resolve(dir, 'package.json'), 'utf-8'));
15
+ return JSON.parse(readFileSync(resolve(dir, 'package.json'), 'utf-8'));
17
16
  }
18
17
  catch {
19
18
  return undefined;
20
19
  }
20
+ }
21
+ /** Reads the identity fields of `<dir>/package.json`, or `undefined` if absent/unreadable. */
22
+ function readManifest(dir) {
23
+ const parsed = readPackageJson(dir);
24
+ if (parsed === undefined)
25
+ return undefined;
21
26
  const manifest = {};
22
27
  if (typeof parsed.name === 'string')
23
28
  manifest.name = parsed.name;
@@ -44,16 +49,39 @@ function findManifestUpward(startDir) {
44
49
  }
45
50
  }
46
51
  /**
47
- * Returns the directory that owns the `node_modules` tree containing `dir`,
48
- * or `undefined` when `dir` is not inside one.
52
+ * Returns the directory that owns the outermost `node_modules` tree containing
53
+ * `dir`, or `undefined` when `dir` is not inside one.
54
+ *
55
+ * The *first* segment is the one that matters: a transitive dependency
56
+ * (`…/node_modules/a/node_modules/b`) and every pnpm isolated layout
57
+ * (`…/node_modules/.pnpm/<pkg>@<v>/node_modules/<pkg>`) nest, and the innermost
58
+ * owner is itself inside `node_modules` — never the installing project.
49
59
  */
50
60
  function nodeModulesOwner(dir) {
51
61
  const segments = dir.split(sep);
52
- const index = segments.lastIndexOf('node_modules');
62
+ const index = segments.indexOf('node_modules');
53
63
  if (index <= 0)
54
64
  return undefined;
55
65
  return segments.slice(0, index).join(sep) || sep;
56
66
  }
67
+ /**
68
+ * True when `dir` declares a package workspace — a `workspaces` field in its
69
+ * manifest (npm, Bun, Yarn) or a `pnpm-workspace.yaml` beside it.
70
+ *
71
+ * This is the discriminator that separates "the process runs from a package of
72
+ * this workspace" from "the process happens to run somewhere under this
73
+ * directory": a cache prefix and a plain project root are both ancestors of a
74
+ * working directory inside them, exactly as a workspace root is.
75
+ */
76
+ function declaresWorkspace(dir) {
77
+ if (existsSync(resolve(dir, 'pnpm-workspace.yaml')))
78
+ return true;
79
+ return readPackageJson(dir)?.workspaces !== undefined;
80
+ }
81
+ /** True when `ancestor` strictly contains `dir`. */
82
+ function contains(ancestor, dir) {
83
+ return dir.startsWith(ancestor.endsWith(sep) ? ancestor : `${ancestor}${sep}`);
84
+ }
57
85
  /** Absolute, symlink-resolved path, or `undefined` when it cannot be read. */
58
86
  function realPath(path) {
59
87
  try {
@@ -91,10 +119,14 @@ function entryDirectory() {
91
119
  * This is the installed server's own package on every stdio launch path —
92
120
  * `npx`, `.mcpb` bundles, a client config naming `dist/index.js` — none of
93
121
  * which run from the package root.
94
- * 2. When that manifest belongs to a tool installed under the application's own
95
- * `node_modules` and the process runs from the directory owning it — a test
96
- * runner spawning the process is the common case the owning directory's
97
- * manifest wins. A dependency's manifest is never the application's identity.
122
+ * 2. When that manifest belongs to a tool installed under a `node_modules` tree
123
+ * and the process runs from the owning directoryor from a package of a
124
+ * workspace that directory declares, which is where a hoisted runner puts a
125
+ * monorepo the nearest manifest at or above the working directory wins. A
126
+ * test runner spawning the process is the common case, and a dependency's
127
+ * manifest is never the application's identity. The workspace declaration is
128
+ * what keeps a cache prefix or a plain project root, both equally ancestors of
129
+ * the working directory, from claiming an installed package's identity.
98
130
  * 3. The nearest `package.json` at or above `process.cwd()`, when there is no
99
131
  * entry module to anchor on (`node -e`, an embedded host).
100
132
  */
@@ -107,10 +139,10 @@ function computeAppRoot() {
107
139
  if (!fromEntry)
108
140
  return cwd ? findManifestUpward(cwd) : undefined;
109
141
  const owner = nodeModulesOwner(fromEntry.dir);
110
- if (owner && owner === cwd) {
111
- const manifest = readManifest(owner);
112
- if (manifest)
113
- return { dir: owner, manifest };
142
+ if (cwd && owner && (owner === cwd || (contains(owner, cwd) && declaresWorkspace(owner)))) {
143
+ const fromCwd = findManifestUpward(cwd);
144
+ if (fromCwd)
145
+ return fromCwd;
114
146
  }
115
147
  return fromEntry;
116
148
  }
@@ -1 +1 @@
1
- {"version":3,"file":"appRoot.js","sourceRoot":"","sources":["../../src/config/appRoot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"appRoot.js","sourceRoot":"","sources":["../../src/config/appRoot.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,7 @@ import { type CacheHints } from '../mcp-server/cacheHints.js';
12
12
  import type { AnyPromptDefinition } from '../mcp-server/prompts/utils/promptDefinition.js';
13
13
  import type { AnyResourceDefinition } from '../mcp-server/resources/utils/resourceDefinition.js';
14
14
  import type { AnyToolDef } from '../mcp-server/tools/tool-registration.js';
15
+ import type { InputHandlingOptions } from '../mcp-server/tools/utils/inputPrevalidation.js';
15
16
  import { type FrameworkServerFactory, type SessionMode } from '../mcp-server/types.js';
16
17
  import type { DataCanvas } from '../services/canvas/core/DataCanvas.js';
17
18
  import type { ILlmProvider } from '../services/llm/core/ILlmProvider.js';
@@ -114,6 +115,25 @@ export interface CreateAppOptions<TSupabaseClient extends object = SupabaseClien
114
115
  * ```
115
116
  */
116
117
  icons?: Implementation['icons'];
118
+ /**
119
+ * Switches for the pre-validation step every `tools/call` argument object
120
+ * passes through: dropping client-added root keys, rewriting key aliases, and
121
+ * repairing a stringified array after a failed parse.
122
+ *
123
+ * Every stage is on with no configuration. An entry here either extends a
124
+ * stage or turns it off for the whole server; nothing about the advertised
125
+ * `inputSchema` changes either way.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * input: {
130
+ * ignoreKeys: ['some_client_field'], // adds to the built-in list; `false` disables the stage
131
+ * caseStyleAliases: false, // declared `inputAliases` only
132
+ * coerce: false, // never retry a failed parse
133
+ * }
134
+ * ```
135
+ */
136
+ input?: InputHandlingOptions;
117
137
  /**
118
138
  * Server-level orientation text included on every `initialize` response.
119
139
  * Spec-compliant clients SHOULD forward this to the model as session-level
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/core/app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/core/app.ts"],"names":[],"mappings":"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"}
package/dist/core/app.js CHANGED
@@ -207,6 +207,7 @@ export async function composeServices(options = {}) {
207
207
  logger,
208
208
  storage: storageService,
209
209
  exposeStatelessSessionId,
210
+ ...(options.input && { input: options.input }),
210
211
  });
211
212
  const resourceRegistry = new ResourceRegistry(resources, {
212
213
  logger,