@cyanheads/mcp-ts-core 0.10.4 → 0.10.6
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/AGENTS.md +6 -2
- package/CLAUDE.md +6 -2
- package/README.md +1 -1
- package/changelog/0.10.x/0.10.4.md +1 -1
- package/changelog/0.10.x/0.10.5.md +60 -0
- package/changelog/0.10.x/0.10.6.md +37 -0
- package/dist/core/app.d.ts.map +1 -1
- package/dist/core/app.js +5 -8
- package/dist/core/app.js.map +1 -1
- package/dist/core/worker.d.ts.map +1 -1
- package/dist/core/worker.js +0 -2
- package/dist/core/worker.js.map +1 -1
- package/dist/linter/rules/enrichment-rules.js +1 -1
- package/dist/linter/rules/enrichment-rules.js.map +1 -1
- package/dist/logs/combined.log +8 -0
- package/dist/logs/error.log +4 -0
- package/dist/logs/interactions.log +0 -0
- package/dist/services/canvas/core/CanvasRegistry.d.ts +6 -0
- package/dist/services/canvas/core/CanvasRegistry.d.ts.map +1 -1
- package/dist/services/canvas/core/CanvasRegistry.js +11 -0
- package/dist/services/canvas/core/CanvasRegistry.js.map +1 -1
- package/dist/services/mirror/sqlite/sqliteMirrorStore.d.ts.map +1 -1
- package/dist/services/mirror/sqlite/sqliteMirrorStore.js +6 -1
- package/dist/services/mirror/sqlite/sqliteMirrorStore.js.map +1 -1
- package/dist/services/mirror/types.d.ts +4 -2
- package/dist/services/mirror/types.d.ts.map +1 -1
- package/dist/services/speech/providers/elevenlabs.provider.d.ts +2 -2
- package/dist/services/speech/providers/elevenlabs.provider.js +3 -3
- package/dist/services/speech/providers/elevenlabs.provider.js.map +1 -1
- package/dist/services/speech/providers/whisper.provider.d.ts +1 -1
- package/dist/services/speech/providers/whisper.provider.js +3 -3
- package/dist/services/speech/providers/whisper.provider.js.map +1 -1
- package/dist/services/speech/types.d.ts +4 -4
- package/dist/services/speech/types.d.ts.map +1 -1
- package/dist/storage/providers/cloudflare/r2Provider.d.ts.map +1 -1
- package/dist/storage/providers/cloudflare/r2Provider.js +9 -2
- package/dist/storage/providers/cloudflare/r2Provider.js.map +1 -1
- package/dist/testing/vitest.d.ts +76 -0
- package/dist/testing/vitest.d.ts.map +1 -0
- package/dist/testing/vitest.js +70 -0
- package/dist/testing/vitest.js.map +1 -0
- package/dist/utils/internal/encoding.d.ts.map +1 -1
- package/dist/utils/internal/encoding.js +6 -17
- package/dist/utils/internal/encoding.js.map +1 -1
- package/dist/utils/internal/performance.d.ts +17 -27
- package/dist/utils/internal/performance.d.ts.map +1 -1
- package/dist/utils/internal/performance.js +23 -45
- package/dist/utils/internal/performance.js.map +1 -1
- package/dist/utils/network/fetchWithTimeout.d.ts.map +1 -1
- package/dist/utils/network/fetchWithTimeout.js +6 -13
- package/dist/utils/network/fetchWithTimeout.js.map +1 -1
- package/dist/utils/network/retry.js +11 -9
- package/dist/utils/network/retry.js.map +1 -1
- package/dist/utils/security/rateLimiter.d.ts +5 -0
- package/dist/utils/security/rateLimiter.d.ts.map +1 -1
- package/dist/utils/security/rateLimiter.js +7 -0
- package/dist/utils/security/rateLimiter.js.map +1 -1
- package/package.json +22 -11
- package/scripts/clean-mcpb.ts +118 -0
- package/scripts/lint-packaging.ts +312 -66
- package/skills/api-testing/SKILL.md +47 -1
- package/skills/api-workers/SKILL.md +97 -1
- package/skills/orchestrations/SKILL.md +1 -1
- package/skills/orchestrations/workflows/fix-wrapup-release.md +9 -5
- package/skills/polish-docs-meta/SKILL.md +4 -2
- package/templates/AGENTS.md +2 -2
- package/templates/CLAUDE.md +2 -2
- package/templates/manifest.json +0 -1
- package/templates/package.json +1 -1
- package/templates/src/index.ts +2 -0
- package/templates/tests/tools/echo.tool.test.ts +21 -0
|
@@ -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.5"
|
|
8
8
|
audience: external
|
|
9
9
|
type: reference
|
|
10
10
|
---
|
|
@@ -198,3 +198,99 @@ export function getServerConfig() {
|
|
|
198
198
|
> `DuckDB canvas requires Node.js or Bun. Set CANVAS_PROVIDER_TYPE=none or omit it for Cloudflare Workers deployment.`
|
|
199
199
|
|
|
200
200
|
Leave the env unset (or set to `none`) for Worker deployments. Tools that conditionally use canvas should check the module-level accessor (`if (!getCanvas()) { ... }`) and surface a clear "feature unavailable on this deployment" message. See `api-canvas` for the full DataCanvas reference and setup wiring pattern.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Testing Workers with miniflare
|
|
205
|
+
|
|
206
|
+
`bun run test:worker` runs the worker suite under `vitest.worker.ts` (using `@cloudflare/vitest-pool-workers` + miniflare). Each test **file** gets its own fresh V8 isolate — module scope (including `createWorkerHandler`'s `appPromise` singleton) is reset between files.
|
|
207
|
+
|
|
208
|
+
### vitest.worker.ts miniflare bindings
|
|
209
|
+
|
|
210
|
+
Declare all storage bindings used in the suite:
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
cloudflareTest({
|
|
214
|
+
main: './tests/fixtures/worker-runtime.fixture.ts',
|
|
215
|
+
miniflare: {
|
|
216
|
+
bindings: { STORAGE_PROVIDER_TYPE: 'cloudflare-kv', ... },
|
|
217
|
+
kvNamespaces: ['KV_NAMESPACE', 'CUSTOM_KV'],
|
|
218
|
+
r2Buckets: ['R2_BUCKET'],
|
|
219
|
+
d1Databases: ['DB'],
|
|
220
|
+
},
|
|
221
|
+
})
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Binding names must match the hardcoded names in `storageFactory.ts` (`KV_NAMESPACE`, `R2_BUCKET`, `DB`).
|
|
225
|
+
|
|
226
|
+
### Per-provider test isolation
|
|
227
|
+
|
|
228
|
+
`bindings.STORAGE_PROVIDER_TYPE` is a global default. Per-provider test files override it by passing a modified env to `worker.fetch()`:
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
import { env } from 'cloudflare:workers';
|
|
232
|
+
|
|
233
|
+
// Fresh isolate per file — appPromise starts null.
|
|
234
|
+
// First fetch initialises the singleton with the overridden provider type.
|
|
235
|
+
const r2Env = { ...env, STORAGE_PROVIDER_TYPE: 'cloudflare-r2' };
|
|
236
|
+
await worker.fetch(request, r2Env, ctx);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Use `reset()` from `cloudflare:test` in `afterEach` to clear binding state between tests. For D1, re-apply migrations immediately after each `reset()` (reset wipes the schema):
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import { applyD1Migrations, reset } from 'cloudflare:test';
|
|
243
|
+
|
|
244
|
+
afterEach(async () => {
|
|
245
|
+
await reset();
|
|
246
|
+
await applyD1Migrations(env.DB, [{ name: '0001_schema', queries: [CREATE_TABLE_SQL] }]);
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### D1 schema setup
|
|
251
|
+
|
|
252
|
+
The `cloudflare-d1` provider requires the `kv_store` table before any operations. Apply it in `beforeAll` via `applyD1Migrations`:
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
const KV_STORE_MIGRATION = `
|
|
256
|
+
CREATE TABLE IF NOT EXISTS kv_store (
|
|
257
|
+
tenant_id TEXT NOT NULL,
|
|
258
|
+
key TEXT NOT NULL,
|
|
259
|
+
value TEXT NOT NULL,
|
|
260
|
+
expires_at INTEGER,
|
|
261
|
+
PRIMARY KEY (tenant_id, key)
|
|
262
|
+
)`;
|
|
263
|
+
|
|
264
|
+
beforeAll(async () => {
|
|
265
|
+
await applyD1Migrations(env.DB, [
|
|
266
|
+
{ name: '0001_create_kv_store', queries: [KV_STORE_MIGRATION] },
|
|
267
|
+
]);
|
|
268
|
+
sessionId = await openSession(d1Env);
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### R2 list limit
|
|
273
|
+
|
|
274
|
+
The R2 provider fetches `limit + 1` objects to detect further pages. Miniflare caps R2 `MaxKeys` at 1000, so the default `limit=1000` → request 1001 → error. Pass `limit: 100` (or any value ≤ 999) to `ctx.state.list()` in test fixtures to stay under the cap:
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
const result = await ctx.state.list(prefix, { limit: 100 });
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Storage probe pattern
|
|
281
|
+
|
|
282
|
+
Expose storage operations as MCP tools in the fixture to test them through the real HTTP surface:
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
const storageSetTool = tool('storage_set', {
|
|
286
|
+
input: z.object({ key: z.string().describe('...'), value: z.string().describe('...') }),
|
|
287
|
+
output: z.object({ ok: z.boolean().describe('Always true on success') }),
|
|
288
|
+
async handler(input, ctx) {
|
|
289
|
+
await ctx.state.set(input.key, input.value);
|
|
290
|
+
return { ok: true };
|
|
291
|
+
},
|
|
292
|
+
format: (r) => [{ type: 'text', text: `ok=${r.ok}` }],
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Call via `tools/call` over MCP JSON-RPC and assert on `structuredContent`. See `tests/worker/storage-r2.worker.test.ts` and `tests/worker/storage-d1.worker.test.ts` for the full pattern.
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Pick and run a multi-phase workflow that chains foundational task skills (`git-wrapup`, `release-and-publish`, `maintenance`, `field-test`, `setup`, etc.) end-to-end. Routes user intent to a workflow file under `workflows/` — greenfield builds, maintenance + release, field-test + fix, or known-work + release. Single source for the universal rules (no commits without authorization, no destructive git, no marketing language), the orchestrator posture (own the goal, ground sub-agents in primary sources, verify against the goal), and the sub-agent strategy (orient block, parallel fanout, isolation, normalization) that apply across every workflow. Sub-agents are an optional capability — workflows run linearly when fanout isn't available.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.3"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -63,7 +63,7 @@ Each phase's Objective column is the goal state per target — the verifiable en
|
|
|
63
63
|
| 1b | Fix | Per target: targeted issues fixed in source, tests updated/added, `devcheck` + `rebuild` + `test` green, each fixed issue commented with fix details, working tree dirty for review | parallel fanout (one sub-agent per target — hard constraint) | **barrier** — orchestrator reviews diffs before verify (explicit gate in checklist) |
|
|
64
64
|
| 2 | Verify | Per target: full diff cold-reviewed; simplified if warranted; each fix re-exercised against the running server with actual tool output in the summary | parallel fanout | **barrier** — orchestrator reviews simplified diff and verified outputs; release authorization required |
|
|
65
65
|
| 3 | Wrap-up + release | Per target: fixes split into per-file commits with a release commit on top; annotated tag; published per repo visibility; tag annotation is structured markdown with issue backlinks | parallel fanout (Bash git only) | gate-free |
|
|
66
|
-
| 4 | Issue cleanup | Every
|
|
66
|
+
| 4 | Issue cleanup | Every shipped issue closed (reason: completed) carrying exactly one what-landed comment that cites the version | orchestrator (serial) | — |
|
|
67
67
|
|
|
68
68
|
Phase 1a is conditional — only runs when the input is a handoff document or otherwise unvalidated. When the input is already tracked GH issues, skip directly to Phase 1b. The release portion of Phase 3 is conditional on user authorization to ship.
|
|
69
69
|
|
|
@@ -137,14 +137,18 @@ The tag annotation and changelog cover ALL fixes — the commit split is about g
|
|
|
137
137
|
**Tag annotations** are for end users — internal dev cleanup (lockfile refreshes, linter fixes, build config) belongs in commit bodies, not the tag annotation.
|
|
138
138
|
|
|
139
139
|
### Phase 4: Issue cleanup
|
|
140
|
-
Close issues that shipped
|
|
140
|
+
Close issues that shipped — only those. Skipped issues stay open.
|
|
141
|
+
|
|
142
|
+
Each issue gets exactly ONE substantive comment recording what landed — concrete changes, file paths, and the version — written either by the fix sub-agent (Phase 1b) or by the orchestrator here. Then close without an additional comment:
|
|
141
143
|
|
|
142
144
|
```bash
|
|
143
|
-
for n in <
|
|
144
|
-
gh issue close "$n" -R "<owner>/<repo>" --reason completed
|
|
145
|
+
for n in <shipped-issue-numbers>; do
|
|
146
|
+
gh issue close "$n" -R "<owner>/<repo>" --reason completed
|
|
145
147
|
done
|
|
146
148
|
```
|
|
147
149
|
|
|
150
|
+
If no what-landed comment exists yet, the version belongs in that one comment ("Shipped in v\<version\>: …"). Never stack a bare "Fixed in v\<version\>" trailer on top of an existing summary — it duplicates the record, and "fixed" misdescribes enhancements (enhancements ship/land; only bugs are fixed).
|
|
151
|
+
|
|
148
152
|
## Workflow-specific gotchas
|
|
149
153
|
|
|
150
154
|
| # | Gotcha | Mitigation |
|
|
@@ -170,6 +174,6 @@ done
|
|
|
170
174
|
- [ ] Orchestrator gate after Phase 2: simplified diff reviewed, field-test claims verified
|
|
171
175
|
- [ ] Phase 3: version bumped, fix commits + release commit, annotated tag per target — scope matches private/public status
|
|
172
176
|
- [ ] Phase 3: published per scope (push, npm if public, MCP Registry if applicable, GH release, Docker if applicable)
|
|
173
|
-
- [ ] Phase 4:
|
|
177
|
+
- [ ] Phase 4: shipped issues closed, one what-landed comment each; skipped issues remain open
|
|
174
178
|
- [ ] Post-workflow verification: `git ls-remote --tags origin`, `npm view <pkg>@<version>` if public, GH release artifacts attached
|
|
175
179
|
- [ ] Tag/release quality review: tag subject omits version number, structured markdown, no marketing adjectives, issue backlinks present
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Finalize documentation and project metadata for a ship-ready MCP server. Use after implementation is complete, tests pass, and devcheck is clean. Safe to run at any stage — each step checks current state and only acts on what still needs work.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "2.
|
|
7
|
+
version: "2.7"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -76,6 +76,8 @@ Key fields: `name`, `description`, `repository`, `author`, `homepage`, `bugs`, `
|
|
|
76
76
|
|
|
77
77
|
**`name` must communicate the server's domain at a glance.** See `references/package-meta.md` for the naming convention — ambiguous abbreviations and acronym-only names fail the scannability test for humans and agents alike.
|
|
78
78
|
|
|
79
|
+
**`name` and `title` in `createApp()` / `createWorkerHandler()` must match the unscoped `package.json` `name`** — display identity is the machine name on every surface; `lint:packaging` (run by `devcheck`) enforces the match and warns when the pair is partial. `description` is never duplicated into the entrypoint — `package.json` is the canonical source (the framework derives the served description from it).
|
|
80
|
+
|
|
79
81
|
**`description` is the canonical source.** Every other surface (README header, `server.json`, Dockerfile OCI label, GitHub repo description) derives from it. Write it here first, then propagate.
|
|
80
82
|
|
|
81
83
|
### 6. `server.json`
|
|
@@ -193,7 +195,7 @@ If the project ships as an `.mcpb` bundle for Claude Desktop (check for `manifes
|
|
|
193
195
|
|
|
194
196
|
**`package.json` scripts:**
|
|
195
197
|
|
|
196
|
-
- `bundle` — builds the `.mcpb` (
|
|
198
|
+
- `bundle` — builds the `.mcpb` (`mcpb pack`, then `scripts/clean-mcpb.ts` prunes dev deps and strips dependency-shipped agent docs)
|
|
197
199
|
- `lint:packaging` — validates `manifest.json` ↔ `server.json` env var consistency (run by `devcheck`)
|
|
198
200
|
|
|
199
201
|
**Cross-file consistency:**
|
package/templates/AGENTS.md
CHANGED
|
@@ -335,13 +335,13 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
335
335
|
| `npm run start:http` | Production mode (HTTP) |
|
|
336
336
|
| `npm run changelog:build` | Regenerate `CHANGELOG.md` from `changelog/*.md` |
|
|
337
337
|
| `npm run changelog:check` | Verify `CHANGELOG.md` is in sync (used by devcheck) |
|
|
338
|
-
| `npm run bundle` | Build and
|
|
338
|
+
| `npm run bundle` | Build, pack, and clean a `.mcpb` for one-click Claude Desktop install |
|
|
339
339
|
|
|
340
340
|
---
|
|
341
341
|
|
|
342
342
|
## Bundling
|
|
343
343
|
|
|
344
|
-
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. MCPB is stdio-only — HTTP and Cloudflare Workers deployments are unaffected. Consumers who don't need it can delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly.
|
|
344
|
+
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips dependency-shipped agent docs (`node_modules/**` `skills/`, `.claude/`, `.agents/`, `SKILL.md`) that root-anchored `.mcpbignore` patterns cannot reach. MCPB is stdio-only — HTTP and Cloudflare Workers deployments are unaffected. Consumers who don't need it can delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly.
|
|
345
345
|
|
|
346
346
|
**Adding an env var requires both files:** `server.json` (registry discovery, `environmentVariables[]`) and `manifest.json` (bundle install UX, `mcp_config.env` + `user_config`). `lint:packaging` (run by `devcheck`) verifies the env var names match.
|
|
347
347
|
|
package/templates/CLAUDE.md
CHANGED
|
@@ -335,13 +335,13 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
335
335
|
| `npm run start:http` | Production mode (HTTP) |
|
|
336
336
|
| `npm run changelog:build` | Regenerate `CHANGELOG.md` from `changelog/*.md` |
|
|
337
337
|
| `npm run changelog:check` | Verify `CHANGELOG.md` is in sync (used by devcheck) |
|
|
338
|
-
| `npm run bundle` | Build and
|
|
338
|
+
| `npm run bundle` | Build, pack, and clean a `.mcpb` for one-click Claude Desktop install |
|
|
339
339
|
|
|
340
340
|
---
|
|
341
341
|
|
|
342
342
|
## Bundling
|
|
343
343
|
|
|
344
|
-
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. MCPB is stdio-only — HTTP and Cloudflare Workers deployments are unaffected. Consumers who don't need it can delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly.
|
|
344
|
+
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips dependency-shipped agent docs (`node_modules/**` `skills/`, `.claude/`, `.agents/`, `SKILL.md`) that root-anchored `.mcpbignore` patterns cannot reach. MCPB is stdio-only — HTTP and Cloudflare Workers deployments are unaffected. Consumers who don't need it can delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly.
|
|
345
345
|
|
|
346
346
|
**Adding an env var requires both files:** `server.json` (registry discovery, `environmentVariables[]`) and `manifest.json` (bundle install UX, `mcp_config.env` + `user_config`). `lint:packaging` (run by `devcheck`) verifies the env var names match.
|
|
347
347
|
|
package/templates/manifest.json
CHANGED
package/templates/package.json
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"format:unsafe": "biome check --write --unsafe .",
|
|
31
31
|
"lint:mcp": "bun run scripts/lint-mcp.ts",
|
|
32
32
|
"lint:packaging": "bun run scripts/lint-packaging.ts",
|
|
33
|
-
"bundle": "bun run build && npx -y @anthropic-ai/mcpb pack . dist/{{PACKAGE_NAME}}.mcpb",
|
|
33
|
+
"bundle": "bun run build && npx -y @anthropic-ai/mcpb pack . dist/{{PACKAGE_NAME}}.mcpb && bun run scripts/clean-mcpb.ts dist/{{PACKAGE_NAME}}.mcpb",
|
|
34
34
|
"changelog:build": "bun run scripts/build-changelog.ts",
|
|
35
35
|
"changelog:check": "bun run scripts/build-changelog.ts --check",
|
|
36
36
|
"release:github": "bun run scripts/release-github.ts",
|
package/templates/src/index.ts
CHANGED
|
@@ -12,6 +12,8 @@ import { echoAppUiResource } from './mcp-server/resources/definitions/echo-app-u
|
|
|
12
12
|
import { echoPrompt } from './mcp-server/prompts/definitions/echo.prompt.js';
|
|
13
13
|
|
|
14
14
|
await createApp({
|
|
15
|
+
name: '{{PACKAGE_NAME}}',
|
|
16
|
+
title: '{{PACKAGE_NAME}}',
|
|
15
17
|
tools: [echoTool, echoAppTool],
|
|
16
18
|
resources: [echoResource, echoAppUiResource],
|
|
17
19
|
prompts: [echoPrompt],
|
|
@@ -5,8 +5,29 @@
|
|
|
5
5
|
|
|
6
6
|
import { describe, expect, it } from 'vitest';
|
|
7
7
|
import { createMockContext } from '@cyanheads/mcp-ts-core/testing';
|
|
8
|
+
import { mcpTest } from '@cyanheads/mcp-ts-core/testing/vitest';
|
|
8
9
|
import { echoTool } from '@/mcp-server/tools/definitions/echo.tool.js';
|
|
9
10
|
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Fixture-based tests (mcpTest) — fresh ctx per test, no manual construction
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
mcpTest('echoTool: echoes the message back (fixture)', async ({ ctx }) => {
|
|
16
|
+
const input = echoTool.input.parse({ message: 'hello world' });
|
|
17
|
+
const result = await echoTool.handler(input, ctx);
|
|
18
|
+
expect(result).toEqual({ message: 'hello world' });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
mcpTest('echoTool: output conforms to declared schema (fixture)', async ({ ctx }) => {
|
|
22
|
+
const input = echoTool.input.parse({ message: 'hello world' });
|
|
23
|
+
const result = await echoTool.handler(input, ctx);
|
|
24
|
+
expect(result).toEqual(expect.schemaMatching(echoTool.output));
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Classic describe/it tests (createMockContext) — shown for comparison
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
10
31
|
describe('echoTool', () => {
|
|
11
32
|
it('echoes the message back', async () => {
|
|
12
33
|
const ctx = createMockContext();
|