@cyanheads/mcp-ts-core 0.1.28 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Agent Protocol
2
2
 
3
- **Package:** `@cyanheads/mcp-ts-core` · **Version:** 0.1.28
3
+ **Package:** `@cyanheads/mcp-ts-core` · **Version:** 0.2.0
4
4
  **npm:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) · **Docker:** [ghcr.io/cyanheads/mcp-ts-core](https://ghcr.io/cyanheads/mcp-ts-core)
5
5
 
6
6
  > **Developer note:** Never assume. Read related files and docs before making changes. Read full file content for context. Never edit a file before reading it.
@@ -38,6 +38,7 @@
38
38
  | `/services` | `OpenRouterProvider`, `SpeechService`, `createSpeechProvider`, `ElevenLabsProvider`, `WhisperProvider`, `GraphService`, provider interfaces and types | LLM, Speech (TTS/STT), Graph services |
39
39
  | `/linter` | `validateDefinitions`, `LintReport`, `LintDiagnostic`, `LintInput`, `LintSeverity` | Definition validation |
40
40
  | `/testing` | `createMockContext` | Test helpers |
41
+ | `/testing/fuzz` | `fuzzTool`, `fuzzResource`, `fuzzPrompt`, `zodToArbitrary`, `adversarialArbitrary`, `ADVERSARIAL_STRINGS` | Fuzz testing |
41
42
 
42
43
  All subpaths prefixed with `@cyanheads/mcp-ts-core`. **†Tier 3 modules** require optional peer dependencies — see `package.json` `peerDependencies`. Tier 3 methods that lazy-load deps are **async**.
43
44
 
@@ -383,6 +384,21 @@ describe('myTool', () => {
383
384
 
384
385
  **`createMockContext` options:** `createMockContext()` (minimal), `{ tenantId: 'test-tenant' }` (enables state), `{ sample: vi.fn() }`, `{ elicit: vi.fn() }`, `{ progress: true }` (task progress).
385
386
 
387
+ **Fuzz testing:** `fuzzTool`/`fuzzResource`/`fuzzPrompt` from `/testing/fuzz` generate valid and adversarial inputs from Zod schemas via `fast-check`, then assert handler invariants (no crashes, no prototype pollution, no stack trace leaks). Returns a `FuzzReport` for custom assertions.
388
+
389
+ ```ts
390
+ import { fuzzTool } from '@cyanheads/mcp-ts-core/testing/fuzz';
391
+
392
+ it('survives fuzz testing', async () => {
393
+ const report = await fuzzTool(myTool, { numRuns: 100 });
394
+ expect(report.crashes).toHaveLength(0);
395
+ expect(report.leaks).toHaveLength(0);
396
+ expect(report.prototypePollution).toBe(false);
397
+ });
398
+ ```
399
+
400
+ Options: `numRuns` (valid inputs, default 50), `numAdversarial` (adversarial inputs, default 30), `seed` (reproducibility), `timeout` (per-call ms, default 5000), `ctx` (`MockContextOptions` for stateful handlers). Also exports `zodToArbitrary(schema)` for custom property-based tests and `ADVERSARIAL_STRINGS` for targeted injection testing.
401
+
386
402
  **Vitest config:** Extend core config, add `@/` alias: `resolve: { alias: { '@/': new URL('./src/', import.meta.url).pathname } }`. Construct deps in `beforeEach`. Re-init services per suite.
387
403
 
388
404
  ---
@@ -413,6 +429,8 @@ Detailed method signatures, options, and examples live in skill files. Read the
413
429
  | `setup` | `skills/setup/SKILL.md` | Initialize a new consumer server from the template |
414
430
  | `devcheck` | `skills/devcheck/SKILL.md` | Run lint, format, typecheck, security checks |
415
431
  | `polish-docs-meta` | `skills/polish-docs-meta/SKILL.md` | Finalize docs, README, metadata, and agent protocol for shipping |
432
+ | `report-issue-framework` | `skills/report-issue-framework/SKILL.md` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
433
+ | `report-issue-local` | `skills/report-issue-local/SKILL.md` | File a bug or feature request against this server's own repo via `gh` CLI |
416
434
  | `release` | `skills/release/SKILL.md` | Version bump, changelog, publish workflow |
417
435
  | `maintenance` | `skills/maintenance/SKILL.md` | Dependency updates, housekeeping tasks |
418
436
  | `migrate-mcp-ts-template` | `skills/migrate-mcp-ts-template/SKILL.md` | Migrate legacy template fork to package dependency |
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  <div align="center">
7
7
 
8
- [![Version](https://img.shields.io/badge/Version-0.1.28-blue.svg?style=flat-square)](./CHANGELOG.md) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2025--11--25-8A2BE2.svg?style=flat-square)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-11-25/changelog.mdx) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.27.1-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE)
8
+ [![Version](https://img.shields.io/badge/Version-0.2.0-blue.svg?style=flat-square)](./CHANGELOG.md) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2025--11--25-8A2BE2.svg?style=flat-square)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-11-25/changelog.mdx) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.27.1-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE)
9
9
 
10
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-^6.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.3.2-blueviolet.svg?style=flat-square)](https://bun.sh/)
11
11
 
@@ -191,6 +191,7 @@ import { markdown, fetchWithTimeout } from '@cyanheads/mcp-ts-core/utils';
191
191
  import { OpenRouterProvider, GraphService } from '@cyanheads/mcp-ts-core/services';
192
192
  import { validateDefinitions } from '@cyanheads/mcp-ts-core/linter';
193
193
  import { createMockContext } from '@cyanheads/mcp-ts-core/testing';
194
+ import { fuzzTool, fuzzResource, fuzzPrompt } from '@cyanheads/mcp-ts-core/testing/fuzz';
194
195
  ```
195
196
 
196
197
  See [CLAUDE.md](CLAUDE.md) for the complete exports reference.
@@ -222,6 +223,21 @@ const result = await myTool.handler(input, ctx);
222
223
 
223
224
  `createMockContext()` provides stubbed `log`, `state`, and `signal`. Pass `{ tenantId }` for state operations, `{ sample }` for LLM mocking, `{ elicit }` for elicitation mocking, `{ progress: true }` for task tools.
224
225
 
226
+ ### Fuzz testing
227
+
228
+ Schema-aware fuzz testing via `fast-check`. Generates valid inputs from Zod schemas and adversarial payloads (prototype pollution, injection strings, type confusion) to verify handler invariants.
229
+
230
+ ```ts
231
+ import { fuzzTool } from '@cyanheads/mcp-ts-core/testing/fuzz';
232
+
233
+ const report = await fuzzTool(myTool, { numRuns: 100 });
234
+ expect(report.crashes).toHaveLength(0);
235
+ expect(report.leaks).toHaveLength(0);
236
+ expect(report.prototypePollution).toBe(false);
237
+ ```
238
+
239
+ Also exports `fuzzResource`, `fuzzPrompt`, `zodToArbitrary`, and `ADVERSARIAL_STRINGS` for custom property-based tests.
240
+
225
241
  ## Documentation
226
242
 
227
243
  - **[CLAUDE.md](CLAUDE.md)** — Complete API reference: exports catalog, patterns, Context interface, error codes, auth, config, testing. Ships in the npm package.
@@ -232,6 +248,7 @@ const result = await myTool.handler(input, ctx);
232
248
  ```bash
233
249
  bun run build # tsc && tsc-alias
234
250
  bun run devcheck # lint, format, typecheck, security
251
+ bun run lint:mcp # validate MCP definitions against spec
235
252
  bun run test # vitest
236
253
  bun run dev:stdio # dev mode (stdio)
237
254
  bun run dev:http # dev mode (HTTP)
package/biome.json CHANGED
@@ -81,6 +81,16 @@
81
81
  }
82
82
  }
83
83
  },
84
+ {
85
+ "includes": ["src/testing/**"],
86
+ "linter": {
87
+ "rules": {
88
+ "suspicious": {
89
+ "noExplicitAny": "off"
90
+ }
91
+ }
92
+ }
93
+ },
84
94
  {
85
95
  "includes": ["scripts/**"],
86
96
  "linter": {
@@ -123,28 +123,16 @@ function lintToolAnnotations(annotations, toolName) {
123
123
  });
124
124
  }
125
125
  }
126
- // Semantic coherence: destructiveHint and idempotentHint are meaningless when readOnlyHint is true
127
- if (annotations.readOnlyHint === true) {
128
- if ('destructiveHint' in annotations) {
129
- diagnostics.push({
130
- rule: 'annotation-coherence',
131
- severity: 'warning',
132
- message: `Tool '${toolName}' sets destructiveHint while readOnlyHint is true. ` +
133
- 'destructiveHint is meaningless for read-only tools.',
134
- definitionType: 'tool',
135
- definitionName: toolName,
136
- });
137
- }
138
- if ('idempotentHint' in annotations) {
139
- diagnostics.push({
140
- rule: 'annotation-coherence',
141
- severity: 'warning',
142
- message: `Tool '${toolName}' sets idempotentHint while readOnlyHint is true. ` +
143
- 'Read-only tools are inherently idempotent — this hint is redundant.',
144
- definitionType: 'tool',
145
- definitionName: toolName,
146
- });
147
- }
126
+ // Semantic coherence: destructiveHint is meaningless when readOnlyHint is true
127
+ if (annotations.readOnlyHint === true && 'destructiveHint' in annotations) {
128
+ diagnostics.push({
129
+ rule: 'annotation-coherence',
130
+ severity: 'warning',
131
+ message: `Tool '${toolName}' sets destructiveHint while readOnlyHint is true. ` +
132
+ 'destructiveHint is meaningless for read-only tools.',
133
+ definitionType: 'tool',
134
+ definitionName: toolName,
135
+ });
148
136
  }
149
137
  return diagnostics;
150
138
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tool-rules.js","sourceRoot":"","sources":["../../../src/linter/rules/tool-rules.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tool-rules.js","sourceRoot":"","sources":["../../../src/linter/rules/tool-rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @fileoverview Schema-aware fuzz testing utilities for MCP definitions.
3
+ * Generates valid, near-miss, and adversarial inputs from Zod schemas,
4
+ * then asserts handler invariants (no crashes, well-formed errors, etc.).
5
+ *
6
+ * Uses `fast-check` for property-based generation. Consumers use
7
+ * `fuzzTool()`, `fuzzResource()`, and `fuzzPrompt()` in their Vitest suites.
8
+ *
9
+ * @module src/testing/fuzz
10
+ */
11
+ import fc from 'fast-check';
12
+ import type { ZodObject, ZodRawShape } from 'zod';
13
+ import type { AnyPromptDefinition } from '../mcp-server/prompts/utils/promptDefinition.js';
14
+ import type { AnyResourceDefinition } from '../mcp-server/resources/utils/resourceDefinition.js';
15
+ import type { AnyToolDefinition } from '../mcp-server/tools/utils/toolDefinition.js';
16
+ import { type MockContextOptions } from './index.js';
17
+ /** Options for fuzz test runners. */
18
+ export interface FuzzOptions {
19
+ /** Mock context options passed to `createMockContext()`. */
20
+ ctx?: MockContextOptions;
21
+ /** Number of adversarial-input runs. @default 30 */
22
+ numAdversarial?: number;
23
+ /** Number of valid-input runs. @default 50 */
24
+ numRuns?: number;
25
+ /** fast-check seed for reproducibility. */
26
+ seed?: number;
27
+ /** Timeout per individual handler call in ms. @default 5000 */
28
+ timeout?: number;
29
+ }
30
+ /**
31
+ * Converts a Zod schema to a fast-check `Arbitrary` that produces valid values.
32
+ * Supports the JSON-Schema-serializable subset used by MCP tool/resource schemas.
33
+ */
34
+ export declare function zodToArbitrary(schema: unknown): fc.Arbitrary<unknown>;
35
+ /** Strings designed to trigger injection, encoding, or parsing vulnerabilities. */
36
+ export declare const ADVERSARIAL_STRINGS: readonly string[];
37
+ /** Generates adversarial values for object fields based on expected type. */
38
+ export declare function adversarialArbitrary(): fc.Arbitrary<unknown>;
39
+ /**
40
+ * Generates an adversarial variant of a Zod object schema's input.
41
+ * Produces objects that match the key structure but have wrong-type values.
42
+ */
43
+ export declare function adversarialObjectArbitrary(schema: ZodObject<ZodRawShape>): fc.Arbitrary<Record<string, unknown>>;
44
+ /** Result of a fuzz run, useful for custom assertions. */
45
+ export interface FuzzReport {
46
+ /** Inputs that caused the handler to crash (unhandled throw past framework). */
47
+ crashes: Array<{
48
+ input: unknown;
49
+ error: unknown;
50
+ }>;
51
+ /** Responses that leaked stack traces or internal paths. */
52
+ leaks: Array<{
53
+ input: unknown;
54
+ errorText: string;
55
+ }>;
56
+ /** Prototype pollution detected on global objects. */
57
+ prototypePollution: boolean;
58
+ /** Total inputs tested. */
59
+ totalRuns: number;
60
+ }
61
+ /**
62
+ * Fuzz-tests a tool definition's handler with valid and adversarial inputs.
63
+ * Designed to be called inside a `describe()` / `it()` block.
64
+ *
65
+ * Checks:
66
+ * 1. Valid inputs -> handler runs without crash, output matches schema
67
+ * 2. Adversarial inputs -> Zod rejects or handler errors gracefully
68
+ * 3. No prototype pollution on Object.prototype
69
+ * 4. No stack trace / path leaks in error messages
70
+ * 5. Aborted signals -> handler doesn't hang
71
+ *
72
+ * @returns FuzzReport for additional custom assertions.
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * import { fuzzTool } from '@cyanheads/mcp-ts-core/testing/fuzz';
77
+ *
78
+ * describe('myTool fuzz', () => {
79
+ * it('survives fuzz testing', async () => {
80
+ * const report = await fuzzTool(myTool, { numRuns: 100 });
81
+ * expect(report.crashes).toHaveLength(0);
82
+ * expect(report.leaks).toHaveLength(0);
83
+ * expect(report.prototypePollution).toBe(false);
84
+ * });
85
+ * });
86
+ * ```
87
+ */
88
+ export declare function fuzzTool(def: AnyToolDefinition, options?: FuzzOptions): Promise<FuzzReport>;
89
+ /**
90
+ * Fuzz-tests a resource definition's handler with valid and adversarial params.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * const report = await fuzzResource(myResource, { numRuns: 50 });
95
+ * expect(report.crashes).toHaveLength(0);
96
+ * ```
97
+ */
98
+ export declare function fuzzResource(def: AnyResourceDefinition, options?: FuzzOptions): Promise<FuzzReport>;
99
+ /**
100
+ * Fuzz-tests a prompt definition's `generate()` with valid and adversarial args.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const report = await fuzzPrompt(myPrompt, { numRuns: 50 });
105
+ * expect(report.crashes).toHaveLength(0);
106
+ * ```
107
+ */
108
+ export declare function fuzzPrompt(def: AnyPromptDefinition, options?: FuzzOptions): Promise<FuzzReport>;
109
+ //# sourceMappingURL=fuzz.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzz.d.ts","sourceRoot":"","sources":["../../src/testing/fuzz.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAalD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gDAAgD,CAAC;AAC1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oDAAoD,CAAC;AAChG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,EAAqB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAMxE,qCAAqC;AACrC,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,GAAG,CAAC,EAAE,kBAAkB,CAAC;IACzB,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAwBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAErE;AAmHD,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAwDvC,CAAC;AAEX,6EAA6E;AAC7E,wBAAgB,oBAAoB,IAAI,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CA4B5D;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,CAAC,WAAW,CAAC,GAC7B,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CASvC;AA2DD,0DAA0D;AAC1D,MAAM,WAAW,UAAU;IACzB,gFAAgF;IAChF,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACnD,4DAA4D;IAC5D,KAAK,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,sDAAsD;IACtD,kBAAkB,EAAE,OAAO,CAAC;IAC5B,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,iBAAiB,EACtB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CA8FrB;AAMD;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,qBAAqB,EAC1B,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CA4ErB;AAMD;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,mBAAmB,EACxB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAmErB"}