@cyanheads/mcp-ts-core 0.8.13 → 0.8.15

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 (38) hide show
  1. package/CLAUDE.md +5 -3
  2. package/README.md +14 -1
  3. package/changelog/0.8.x/0.8.14.md +33 -0
  4. package/changelog/0.8.x/0.8.15.md +22 -0
  5. package/dist/core/index.d.ts +2 -2
  6. package/dist/core/index.d.ts.map +1 -1
  7. package/dist/core/index.js +1 -1
  8. package/dist/core/index.js.map +1 -1
  9. package/dist/logs/combined.log +4 -4
  10. package/dist/logs/error.log +4 -4
  11. package/dist/services/canvas/{providers/duckdb → core}/schemaSniffer.d.ts +14 -8
  12. package/dist/services/canvas/core/schemaSniffer.d.ts.map +1 -0
  13. package/dist/services/canvas/{providers/duckdb → core}/schemaSniffer.js +41 -33
  14. package/dist/services/canvas/core/schemaSniffer.js.map +1 -0
  15. package/dist/services/canvas/index.d.ts +2 -0
  16. package/dist/services/canvas/index.d.ts.map +1 -1
  17. package/dist/services/canvas/index.js +2 -0
  18. package/dist/services/canvas/index.js.map +1 -1
  19. package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts.map +1 -1
  20. package/dist/services/canvas/providers/duckdb/DuckdbProvider.js +1 -1
  21. package/dist/services/canvas/providers/duckdb/DuckdbProvider.js.map +1 -1
  22. package/dist/services/canvas/spillover.d.ts +121 -0
  23. package/dist/services/canvas/spillover.d.ts.map +1 -0
  24. package/dist/services/canvas/spillover.js +201 -0
  25. package/dist/services/canvas/spillover.js.map +1 -0
  26. package/dist/storage/core/IStorageProvider.d.ts +10 -3
  27. package/dist/storage/core/IStorageProvider.d.ts.map +1 -1
  28. package/package.json +9 -8
  29. package/skills/add-tool/SKILL.md +8 -2
  30. package/skills/api-canvas/SKILL.md +77 -1
  31. package/skills/api-errors/SKILL.md +3 -1
  32. package/skills/api-workers/SKILL.md +4 -4
  33. package/skills/design-mcp-server/SKILL.md +2 -1
  34. package/skills/tool-defs-analysis/SKILL.md +209 -0
  35. package/templates/AGENTS.md +3 -0
  36. package/templates/CLAUDE.md +3 -0
  37. package/dist/services/canvas/providers/duckdb/schemaSniffer.d.ts.map +0 -1
  38. package/dist/services/canvas/providers/duckdb/schemaSniffer.js.map +0 -1
@@ -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, 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.1"
7
+ version: "1.2"
8
8
  audience: external
9
9
  type: reference
10
10
  ---
@@ -265,6 +265,82 @@ export const fetchAndStage = tool('fetch_and_stage_germplasm', {
265
265
 
266
266
  ---
267
267
 
268
+ ## Pattern: spillover
269
+
270
+ A handler produces a tabular result that's too big to inline: a paginated REST call that returns 50k rows, a streamed CSV, a database cursor. Inlining everything blows the agent's context; inlining a fixed slice leaves it blind to the rest. **Spillover** is the third option — show a small preview, register the whole result on the canvas, hand back a token pointing at it. The agent reads the preview directly and reaches for SQL when it needs the rest.
271
+
272
+ ### `spillover(opts)`
273
+
274
+ ```ts
275
+ import { spillover } from '@cyanheads/mcp-ts-core/canvas';
276
+
277
+ const result = await spillover({
278
+ canvas: instance,
279
+ source: fetchAllPages(), // any AsyncIterable<Row> or Iterable<Row>
280
+ previewChars: 100_000, // ≈ 25k tokens of inline rows
281
+ caps: { maxRows: 50_000 }, // hard upper bound on registered rows
282
+ signal: ctx.signal,
283
+ });
284
+
285
+ if (result.spilled) {
286
+ // result.previewRows → inline these in the response
287
+ // result.handle.tableName → surface so the agent can SQL the full set
288
+ // result.truncated → true if caps.maxRows was hit before the source exhausted
289
+ } else {
290
+ // result.previewRows → entire source fit; no canvas table was created
291
+ }
292
+ ```
293
+
294
+ The discriminated union narrows on `result.spilled` — no runtime checks needed.
295
+
296
+ ### Sizing the preview
297
+
298
+ The budget is **characters of `JSON.stringify(row)`**, not rows. A row count is a leaky proxy: the same `50` rows is ~500 tokens for compact IDs and ~25k tokens for nested observations. A character budget gives one number that works across heterogeneous tools.
299
+
300
+ | Token budget you want | Rough `previewChars` |
301
+ |:---------------------|:---------------------|
302
+ | 10k tokens | 40_000 |
303
+ | 25k tokens | 100_000 |
304
+ | 50k tokens | 200_000 |
305
+
306
+ Heuristic: ~4 chars per token for typical JSON. Refine empirically per tool if the row shape is unusual.
307
+
308
+ ### Flow
309
+
310
+ 1. **Drain.** Pull rows, accumulating `JSON.stringify(row).length` per row, until the running total would exceed `previewChars` (the row that crosses the budget is the **overflow sentinel**) or the source exhausts.
311
+ 2. **Source fit.** Drain finished under budget — return `{ spilled: false, previewRows }`. No canvas call was made.
312
+ 3. **Source overflows.** The sentinel proves there are more rows than fit. Build a merged iterable of *(buffered preview rows + sentinel + remaining iterator)*, hand it to `canvas.registerTable`, return `{ spilled: true, previewRows, handle, truncated }`.
313
+
314
+ The merged iterable streams — the helper does not double-buffer the full source.
315
+
316
+ ### Schema handling
317
+
318
+ | Source | Schema | Behavior |
319
+ |:-------|:-------|:---------|
320
+ | Sync or async | Caller-supplied | Forwarded to `registerTable` as-is |
321
+ | Sync or async | Omitted | Helper infers via `inferSchemaFromRows` over preview buffer + sentinel |
322
+
323
+ When the preview budget is small (single-digit rows) and the sniff window matters, pass `schema` explicitly — the helper's window is only as large as the preview budget allows.
324
+
325
+ ### Cancellation and partial state
326
+
327
+ `signal.abort()` throws on the next iteration of the preview drain or the spill drain. If abort fires after `canvas.registerTable` has begun appending rows, the helper best-effort calls `canvas.drop(tableName)` before the throw propagates — the contract is "partial drain is not registered."
328
+
329
+ ### When *not* to use spillover
330
+
331
+ - **Tiny known result.** If the upstream call returns ≤ 100 rows, just inline them — no canvas needed.
332
+ - **Headless register** (caller wants the full set on canvas with zero preview rows). Call `canvas.registerTable` directly. `previewChars` is rejected at `0`; spillover always implies a visible preview.
333
+ - **Workers runtime.** Canvas requires DuckDB native; spillover is a canvas-coupled helper. For Workers parity, persist via `ctx.state` instead.
334
+
335
+ ### Out of scope
336
+
337
+ - **Provenance metadata** (source URI, original query). Caller stores externally — see #112 option 3.
338
+ - **Pagination-flavored builder.** A `paginate(fetchPage) → AsyncIterable<Row>` adapter is deferred until a second non-paginated consumer surfaces.
339
+ - **Token-accurate budget.** `previewTokens` (tokenizer-driven) is a future option; characters cover the common case.
340
+ - **`caps.maxBytes`.** Row caps cover the common case without re-doing serialization the canvas appender skips.
341
+
342
+ ---
343
+
268
344
  ## Trade-offs
269
345
 
270
346
  - **DuckDB only in v1.** Polars/SQLite/DataFusion don't fit the "agent writes ad-hoc SQL across N registered tables" shape.
@@ -4,7 +4,7 @@ description: >
4
4
  McpError constructor, JsonRpcErrorCode reference, and error handling patterns for `@cyanheads/mcp-ts-core`. Use when looking up error codes, understanding where errors should be thrown vs. caught, or using ErrorHandler.tryCatch in services.
5
5
  metadata:
6
6
  author: cyanheads
7
- version: "1.4"
7
+ version: "1.5"
8
8
  audience: external
9
9
  type: reference
10
10
  ---
@@ -120,6 +120,8 @@ throw ctx.fail('no_match', `No item ${id}`, {
120
120
 
121
121
  **Skip the contract** for one-off internal tools or quick prototypes — `ctx` is plain `Context` (no `fail`) and you throw via [factories](#error-factories-fallback) directly. Behavior is identical at the wire; the contract just adds compile-time safety.
122
122
 
123
+ > **Declare contracts inline on each tool, even when similar across tools.** The contract is part of the tool's documented public surface — reading one tool definition file should give the full picture (input, output, errors, handler, format). Don't extract a shared `errors[]` constant or contract module to deduplicate near-identical entries; per-tool repetition is the intended cost of locality, and dynamic `recovery` hints often need tool-specific runtime context anyway. If a code-cleanup pass suggests consolidating contracts, decline — the duplication is load-bearing for tool-def readability.
124
+
123
125
  > **Limits of the conformance lint.** The conformance and prefer-fail rules scan the handler's source text for `throw` statements. Errors thrown from called services (e.g. `await myService.fetch()` raising `RateLimited` internally) are invisible — the lint only sees what's lexically in the handler. Treat the contract as the *advertised* failure surface; bubbled-up codes still reach the client correctly via the auto-classifier, just without lint enforcement.
124
126
 
125
127
  ### Carrying contract `reason` from services
@@ -4,7 +4,7 @@ description: >
4
4
  Cloudflare Workers deployment using `createWorkerHandler` from `@cyanheads/mcp-ts-core/worker`. Covers the full handler signature, binding types, CloudflareBindings extensibility, runtime compatibility guards, and wrangler.toml requirements.
5
5
  metadata:
6
6
  author: cyanheads
7
- version: "1.2"
7
+ version: "1.3"
8
8
  audience: external
9
9
  type: reference
10
10
  ---
@@ -126,10 +126,10 @@ In Workers, only these storage providers are allowed:
126
126
  | `cloudflare-r2` | R2 bucket binding — object storage |
127
127
  | `cloudflare-d1` | D1 database binding — SQLite-compatible |
128
128
 
129
- `filesystem` and `supabase` are not on the whitelist and behave differently:
129
+ `filesystem`, `supabase`, and unknown provider types are not on the whitelist:
130
130
 
131
- - **`filesystem`** and other unknown types are **silently forced to `in-memory`** (a warning is logged) in a serverless environment.
132
- - **`supabase`** does **not** silently fall back. The framework attempts to connect and throws `ConfigurationError` if credentials (`SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`) are missing or the client cannot be constructed. Do not set `STORAGE_PROVIDER_TYPE=supabase` in a Worker.
131
+ - **`filesystem`** and unknown types throw `ConfigurationError` in serverless environments.
132
+ - **`supabase`** does **not** silently fall back. The framework may validate Supabase credentials first, but Worker startup still fails with `ConfigurationError` because Supabase storage is not a supported serverless provider. Do not set `STORAGE_PROVIDER_TYPE=supabase` in a Worker.
133
133
 
134
134
  Set `STORAGE_PROVIDER_TYPE` to one of the four whitelisted values to avoid unexpected behavior.
135
135
 
@@ -4,7 +4,7 @@ description: >
4
4
  Design the tool surface, resources, and service layer for a new MCP server. Use when starting a new server, planning a major feature expansion, or when the user describes a domain/API they want to expose via MCP. Produces a design doc at docs/design.md that drives implementation.
5
5
  metadata:
6
6
  author: cyanheads
7
- version: "2.9"
7
+ version: "2.10"
8
8
  audience: external
9
9
  type: workflow
10
10
  ---
@@ -271,6 +271,7 @@ output: z.object({
271
271
  ```
272
272
 
273
273
  - **Truncate large output with counts.** When a list exceeds a reasonable display size, show the top N and append "...and X more". Don't silently drop results.
274
+ - **Spill big tabular results to a queryable surface.** When a tool's row set can exceed any reasonable context budget — paginated APIs, streamed exports, big query results — pair an inline preview with a `DataCanvas` table holding the full set, returned as a token the agent can SQL. Compute distributions or refinement hints across the full result, not the preview, so aggregate signal stays honest. See `api-canvas` for the `spillover()` helper.
274
275
  - **`format()` is the markdown twin of `structuredContent` — make both content-complete.** Different MCP clients forward different surfaces to the model: some (e.g., Claude Code) read `structuredContent` from `output`, others (e.g., Claude Desktop) read `content[]` from `format()`. Both must carry the same data so every client sees the same picture — `format()` just dresses it up with markdown. A thin `format()` that returns only a count or title leaves `content[]`-only clients blind to data that `structuredContent` clients can see. Render all fields the LLM needs, with structured markdown (headers, bold labels, lists) for readability.
275
276
 
276
277
  #### Batch input design
@@ -0,0 +1,209 @@
1
+ ---
2
+ name: tool-defs-analysis
3
+ description: >
4
+ Read-only audit of MCP definition language across an existing surface — tools, resources, prompts. Walks every definition file and checks 10 categories the LLM reads to decide whether and how to call: voice & tense, internal leaks, audience leaks, defaults, recovery hints, output descriptions, cross-references, sparsity, examples, structure. Produces grouped findings with file:line citations and a numbered options list. Use during polish, after a refactor, or before a release. Complements `field-test` (behavior testing) and `security-pass` (security audit).
5
+ metadata:
6
+ author: cyanheads
7
+ version: "1.0"
8
+ audience: external
9
+ type: audit
10
+ ---
11
+
12
+ ## Context
13
+
14
+ Every string in a tool/resource/prompt definition is part of an LLM-facing API contract. The model reads the description, every parameter `.describe()`, the output schema, the recovery hints — and decides what to call and how. Definition language drifts: an internal mapping leaks into a parameter doc during a fix, a self-referential output description survives a refactor, a default that suited the developer at scaffold time stays after the typical call shape changes.
15
+
16
+ This skill is the **review-time pass** for that drift. Read each definition the way a mid-tier model with no project context would — can it pick the tool, fill the fields, and recover from errors using only the rendered schema?
17
+
18
+ | Skill | Lens |
19
+ |:---|:---|
20
+ | `design-mcp-server` | Authoring rules at write-time |
21
+ | `field-test` | Behavior testing + a narrow 3-category leak audit |
22
+ | `security-pass` | Injection, scopes, input sinks |
23
+ | `tool-defs-analysis` (this) | LLM-facing language across the existing surface |
24
+
25
+ `field-test` already audits descriptions for implementation leaks, meta-coaching, and consumer-aware phrasing during its catalog step — that's a fast shallow pass alongside live tool calls. This skill is the deeper review: 10 categories, every field, every recovery hint, every default value, with file:line citations.
26
+
27
+ **Read-only.** This skill produces a report; the maintainer applies fixes. While running it, do not run git, do not stage or commit, do not update the changelog, do not run `devcheck`, do not invoke wrapup or release workflows. Fixes flow through the normal authoring path (edit the definition, then re-run this skill if you want to verify).
28
+
29
+ ## When to Use
30
+
31
+ - After a polish session or refactor that touched definitions
32
+ - Before a release, alongside `polish-docs-meta` and `security-pass`
33
+ - When the user says "review my tool definitions", "audit descriptions", "are my tool descriptions any good"
34
+ - After scaffolding a new server but before it ships
35
+
36
+ Skip during initial authoring — `add-tool` and `design-mcp-server` cover that. Skip diff-only review — read each file in full so drift across the whole definition surfaces.
37
+
38
+ ## Inputs
39
+
40
+ Gather before starting. Ask if unclear:
41
+
42
+ 1. **Scope** — whole server, specific definitions, or a single directory?
43
+ 2. **Severity floor** — all findings (default), or skip nits?
44
+ 3. **Known concerns** — anything the user already wants emphasized?
45
+
46
+ ## Steps
47
+
48
+ ### 1. Build the inventory
49
+
50
+ ```bash
51
+ find src/mcp-server/tools/definitions -type f -name "*tool.ts" 2>/dev/null | sort
52
+ find src/mcp-server/resources/definitions -type f -name "*resource.ts" 2>/dev/null | sort
53
+ find src/mcp-server/prompts/definitions -type f -name "*.prompt.ts" 2>/dev/null | sort
54
+ ```
55
+
56
+ The `*tool.ts` / `*resource.ts` patterns also catch `*.app-tool.ts` / `*.app-resource.ts`. If the server's definitions live elsewhere (`examples/`, a packages workspace, …), audit those paths too.
57
+
58
+ Use `TaskCreate` — one task per file. Mark each complete after its findings are captured.
59
+
60
+ ### 2. Walk the 10 categories per file
61
+
62
+ Read each definition file in full. Apply every category — most files trip more than one. Capture each hit with `file:line`, the offending excerpt, and a one-line fix.
63
+
64
+ #### 1. Voice & tense
65
+
66
+ **Look in:** tool / resource / prompt `description`.
67
+
68
+ **Check:** imperative present-tense. "Search for trials" beats "Searches for trials" or "This tool will search trials".
69
+
70
+ **Smell:** "Allows you to…", "This tool…", "Provides functionality to…", "Searches for…", "Fetches…", "Will return…".
71
+
72
+ (Parameter `.describe()` text describes the *value*, not the tool — it doesn't need imperative voice.)
73
+
74
+ #### 2. Internal leaks
75
+
76
+ **Look in:** every `description` and `.describe()`.
77
+
78
+ **Check:** internal API routes, endpoint paths, API call counts, internal parameter mappings, sibling service names, version notes, TODOs.
79
+
80
+ **Smell:** "/api/v2/by-state", "Adds a second API call", "API requires `two_year_period`", "(deprecated; use bar_v2)", "TODO: support batch mode", "Used internally by FooService".
81
+
82
+ Prior art: #25.
83
+
84
+ #### 3. Audience leaks
85
+
86
+ **Look in:** every `description` and `.describe()`.
87
+
88
+ **Check:** reader-naming or meta-coaching directed at the LLM rather than describing the tool.
89
+
90
+ **Smell:** "suitable for LLM consumption", "Treat the returned ID as the canonical Y", "Agents should…", "Callers should…", "When you call this tool…", any reference to "LLM", "agent", "Claude", "the model".
91
+
92
+ Prior art: #74. Field-test catches this in its leak audit; this skill is the more thorough pass.
93
+
94
+ #### 4. Defaults
95
+
96
+ **Look in:** every `.default(...)` call in input schemas.
97
+
98
+ **Check:** the default matches the typical caller's case. A default that suited the developer at scaffold time often skews real calls — `limit: 1` makes default-args searches useless, `verbose: true` floods context, `dryRun: false` on a destructive op invites an irreversible accident.
99
+
100
+ **Smell:** dev-convenience values that survived the schema's first draft, dangerous defaults on destructive operations, defaults that contradict the description's framing of typical use.
101
+
102
+ #### 5. Recovery hints
103
+
104
+ **Look in:** `errors: [{ recovery: '…' }]` arrays, `data.recovery.hint` at throw sites in handler bodies.
105
+
106
+ **Check:** the hint directs the *agent* to its next action, not the developer to debugging. "Call `pubmed_search` with a narrower query" beats "Verify the configuration is correct" or "Internal error".
107
+
108
+ **Smell:** "Check the logs", "See documentation", "Contact admin", "Try again later" (with no condition), generic non-actionable text, hints that name internal classes, files, or env vars.
109
+
110
+ #### 6. Output descriptions
111
+
112
+ **Look in:** every field `.describe()` inside `output: z.object({ ... })`.
113
+
114
+ **Check:** the description tells the agent what the *value* is — not just the field name restated, not silent on dynamic shapes.
115
+
116
+ **Smell:**
117
+
118
+ - `name: z.string().describe('Name')` — tautology
119
+ - `description: z.string().describe('Description.')` — tautology
120
+ - `metadata: z.record(z.string(), z.unknown()).describe('Metadata')` — opaque dynamic shape with no hint about keys/values
121
+ - Optional fields with no note on when they're absent
122
+ - Enum fields with no `.describe()` on the variants
123
+
124
+ #### 7. Cross-references
125
+
126
+ **Look in:** tool descriptions, prompt content, recovery hints.
127
+
128
+ **Check:** when one tool/resource is mentioned, *when* to reach for it is explained — and the references cover the relevant siblings, not a partial sample.
129
+
130
+ **Smell:** "Use `foo_search` to find IDs" (no when); a prompt naming 3 of 7 landscape-relevant tools; a tool description listing one sibling but not the others that fit the same workflow.
131
+
132
+ #### 8. Sparsity
133
+
134
+ **Look in:** `output` schemas (especially fields wrapping external API data), `format()` rendering.
135
+
136
+ **Check:** optional upstream fields are acknowledged as such — not implied to always be present. `format()` doesn't print fabricated values for missing fields.
137
+
138
+ **Smell:**
139
+
140
+ - `pmid: z.string().describe('PubMed ID')` when only ~60% of records have one (should be `.optional()` and noted)
141
+ - `format()` printing `**PMID:** undefined`
142
+ - A required field in `output` for an upstream value the API doesn't always return
143
+
144
+ #### 9. Examples
145
+
146
+ **Look in:** parameter `.describe()` text containing "e.g.,", "(e.g. ...)", `.example(...)` calls.
147
+
148
+ **Check:** examples are domain-realistic — real-shaped IDs, real query strings, real values from the upstream domain. One example is usually enough.
149
+
150
+ **Smell:** `.describe('Item ID (e.g., "abc123")')` when real IDs have structure (`NCT12345678`); toy values ("foo", "bar"); padding multiple toy examples instead of one realistic one.
151
+
152
+ #### 10. Structure
153
+
154
+ **Look in:** tool / resource / prompt `description`.
155
+
156
+ **Check:** single cohesive paragraph. No bullet lists, no blank-line-separated sections, no markdown headers inside the description.
157
+
158
+ **Smell:** blank lines (`\n\n`) inside a description string, `- bullet` lines, `## Header` lines, "Operations:\n- foo: …" duplicating an enum's `.describe()` text.
159
+
160
+ Prior art: #33.
161
+
162
+ ### 3. Report
163
+
164
+ Three sections.
165
+
166
+ #### Summary (1 paragraph)
167
+
168
+ Definitions reviewed, categories with findings, total finding count. One sentence on the single most material finding.
169
+
170
+ #### Findings
171
+
172
+ Group by category. Within each category, list each finding:
173
+
174
+ ```
175
+ **<file>:<line> — <category> — (material|nit)**
176
+ Excerpt: `<the offending text>`
177
+ Issue: <one line: what's wrong>
178
+ Fix: <one line: what to change to>
179
+ ```
180
+
181
+ Two-level severity:
182
+
183
+ - **material** — affects agent decisions (will mis-select tool, mis-fill input, mis-handle output, swallow an irrecoverable error)
184
+ - **nit** — polish (style, voice consistency, minor phrasing)
185
+
186
+ Skip categories with no findings — don't list empty headers.
187
+
188
+ #### Options
189
+
190
+ Numbered, cherry-pickable. Map each item to a concrete change in a single file.
191
+
192
+ ```
193
+ 1. Tighten `metadata` description in `pubmed_fetch.tool.ts:42` — explain the dynamic shape (finding #3, material)
194
+ 2. Drop bullet list from `clinicaltrials_get_field_definitions.tool.ts:18` description — single paragraph (finding #5, material)
195
+ 3. Replace toy "abc123" example in `inventory_search.tool.ts:27` with real shape (finding #8, nit)
196
+ ```
197
+
198
+ End with:
199
+
200
+ > Pick by number (e.g. "do 1, 3, 5" or "expand on 2").
201
+
202
+ ## Checklist
203
+
204
+ - [ ] Scope confirmed (whole server / module / specific files)
205
+ - [ ] Inventory built — every `*.tool.ts`, `*.app-tool.ts`, `*.resource.ts`, `*.app-resource.ts`, `*.prompt.ts` listed
206
+ - [ ] Each file walked through all 10 categories (per-file, not 10 separate passes)
207
+ - [ ] **Read-only:** no git, no commits, no changelog edits, no `devcheck`, no wrapup invoked during the audit
208
+ - [ ] Findings carry file:line citation, excerpt, issue, fix
209
+ - [ ] Report: summary → grouped-by-category findings → numbered options
@@ -183,6 +183,8 @@ async handler(input, ctx) {
183
183
  }
184
184
  ```
185
185
 
186
+ **Declare contracts inline on each tool, even when similar across tools.** The contract is part of the tool's documented public surface — reading one tool definition file should give the full picture. Don't extract a shared `errors[]` constant or contract module to deduplicate; per-tool repetition is the intended cost of locality.
187
+
186
188
  **Fallback (no contract entry fits):** throw via factories or plain `Error`.
187
189
 
188
190
  ```ts
@@ -263,6 +265,7 @@ Available skills:
263
265
  | `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
264
266
  | `report-issue-local` | File a bug or feature request against this server's own repo via `gh` CLI |
265
267
  | `api-auth` | Auth modes, scopes, JWT/OAuth |
268
+ | `api-canvas` | DataCanvas: register tabular data, run SQL, export, plus the `spillover()` helper for big result sets — Tier 3 opt-in |
266
269
  | `api-config` | AppConfig, parseConfig, env vars |
267
270
  | `api-context` | Context interface, logger, state, progress |
268
271
  | `api-errors` | McpError, JsonRpcErrorCode, error patterns |
@@ -183,6 +183,8 @@ async handler(input, ctx) {
183
183
  }
184
184
  ```
185
185
 
186
+ **Declare contracts inline on each tool, even when similar across tools.** The contract is part of the tool's documented public surface — reading one tool definition file should give the full picture. Don't extract a shared `errors[]` constant or contract module to deduplicate; per-tool repetition is the intended cost of locality.
187
+
186
188
  **Fallback (no contract entry fits):** throw via factories or plain `Error`.
187
189
 
188
190
  ```ts
@@ -263,6 +265,7 @@ Available skills:
263
265
  | `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
264
266
  | `report-issue-local` | File a bug or feature request against this server's own repo via `gh` CLI |
265
267
  | `api-auth` | Auth modes, scopes, JWT/OAuth |
268
+ | `api-canvas` | DataCanvas: register tabular data, run SQL, export, plus the `spillover()` helper for big result sets — Tier 3 opt-in |
266
269
  | `api-config` | AppConfig, parseConfig, env vars |
267
270
  | `api-context` | Context interface, logger, state, progress |
268
271
  | `api-errors` | McpError, JsonRpcErrorCode, error patterns |
@@ -1 +0,0 @@
1
- {"version":3,"file":"schemaSniffer.d.ts","sourceRoot":"","sources":["../../../../../src/services/canvas/providers/duckdb/schemaSniffer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,gBAAgB,CAAC;AAE/D,sDAAsD;AACtD,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEnC;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,SAAS,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,iDAAiD;IACjD,WAAW,EAAE,GAAG,EAAE,CAAC;CACpB;AAkDD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,aAAa,EAAE,MAAM,GAAG,aAAa,CA6CzF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"schemaSniffer.js","sourceRoot":"","sources":["../../../../../src/services/canvas/providers/duckdb/schemaSniffer.ts"],"names":[],"mappings":"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"}