@cyanheads/mcp-ts-core 0.1.29 → 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 +19 -1
- package/README.md +18 -1
- package/biome.json +10 -0
- package/dist/testing/fuzz.d.ts +109 -0
- package/dist/testing/fuzz.d.ts.map +1 -0
- package/dist/testing/fuzz.js +558 -0
- package/dist/testing/fuzz.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/network/retry.d.ts +83 -0
- package/dist/utils/network/retry.d.ts.map +1 -0
- package/dist/utils/network/retry.js +152 -0
- package/dist/utils/network/retry.js.map +1 -0
- package/package.json +5 -1
- package/skills/add-service/SKILL.md +53 -0
- package/skills/api-utils/SKILL.md +1 -0
- package/skills/design-mcp-server/SKILL.md +11 -0
- package/skills/report-issue-framework/SKILL.md +231 -0
- package/skills/report-issue-local/SKILL.md +225 -0
- package/skills/setup/SKILL.md +1 -0
- package/templates/.github/ISSUE_TEMPLATE/bug_report.yml +106 -0
- package/templates/.github/ISSUE_TEMPLATE/config.yml +1 -0
- package/templates/.github/ISSUE_TEMPLATE/feature_request.yml +36 -0
- package/templates/CLAUDE.md +2 -0
package/CLAUDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
|
-
**Package:** `@cyanheads/mcp-ts-core` · **Version:** 0.
|
|
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
|
-
[](./CHANGELOG.md) [](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-11-25/changelog.mdx) [](https://modelcontextprotocol.io/) [](./LICENSE)
|
|
9
9
|
|
|
10
10
|
[](https://www.typescriptlang.org/) [](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
|
@@ -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"}
|