@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.
- package/CLAUDE.md +5 -3
- package/README.md +14 -1
- package/changelog/0.8.x/0.8.14.md +33 -0
- package/changelog/0.8.x/0.8.15.md +22 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/logs/combined.log +4 -4
- package/dist/logs/error.log +4 -4
- package/dist/services/canvas/{providers/duckdb → core}/schemaSniffer.d.ts +14 -8
- package/dist/services/canvas/core/schemaSniffer.d.ts.map +1 -0
- package/dist/services/canvas/{providers/duckdb → core}/schemaSniffer.js +41 -33
- package/dist/services/canvas/core/schemaSniffer.js.map +1 -0
- package/dist/services/canvas/index.d.ts +2 -0
- package/dist/services/canvas/index.d.ts.map +1 -1
- package/dist/services/canvas/index.js +2 -0
- package/dist/services/canvas/index.js.map +1 -1
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts.map +1 -1
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.js +1 -1
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.js.map +1 -1
- package/dist/services/canvas/spillover.d.ts +121 -0
- package/dist/services/canvas/spillover.d.ts.map +1 -0
- package/dist/services/canvas/spillover.js +201 -0
- package/dist/services/canvas/spillover.js.map +1 -0
- package/dist/storage/core/IStorageProvider.d.ts +10 -3
- package/dist/storage/core/IStorageProvider.d.ts.map +1 -1
- package/package.json +9 -8
- package/skills/add-tool/SKILL.md +8 -2
- package/skills/api-canvas/SKILL.md +77 -1
- package/skills/api-errors/SKILL.md +3 -1
- package/skills/api-workers/SKILL.md +4 -4
- package/skills/design-mcp-server/SKILL.md +2 -1
- package/skills/tool-defs-analysis/SKILL.md +209 -0
- package/templates/AGENTS.md +3 -0
- package/templates/CLAUDE.md +3 -0
- package/dist/services/canvas/providers/duckdb/schemaSniffer.d.ts.map +0 -1
- 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.
|
|
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.
|
|
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.
|
|
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
|
|
129
|
+
`filesystem`, `supabase`, and unknown provider types are not on the whitelist:
|
|
130
130
|
|
|
131
|
-
- **`filesystem`** and
|
|
132
|
-
- **`supabase`** does **not** silently fall back. The framework
|
|
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.
|
|
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
|
package/templates/AGENTS.md
CHANGED
|
@@ -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 |
|
package/templates/CLAUDE.md
CHANGED
|
@@ -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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"}
|