@frontmcp/skills 1.7.2 → 1.8.1
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/catalog/create-tool/examples/08-tool-with-provider-injection.md +2 -2
- package/catalog/create-tool/examples/22-tool-with-ui-html-template.md +7 -7
- package/catalog/create-tool/examples/24-tool-with-ui-csp-and-bridge.md +3 -3
- package/catalog/create-tool/references/decorator-options.md +1 -0
- package/catalog/create-tool/references/elicitation.md +9 -0
- package/catalog/create-tool/references/error-handling.md +10 -6
- package/catalog/create-tool/references/execution-context.md +7 -3
- package/catalog/create-tool/references/input-schema.md +2 -0
- package/catalog/create-tool/references/output-schema.md +6 -1
- package/catalog/create-tool/references/throttling.md +7 -8
- package/catalog/create-tool/references/ui-widgets.md +14 -1
- package/catalog/frontmcp-authorities/SKILL.md +1 -0
- package/catalog/frontmcp-authorities/references/custom-evaluators.md +13 -2
- package/catalog/frontmcp-authorities/references/rbac-abac-rebac.md +2 -0
- package/catalog/frontmcp-config/examples/configure-skills-http/inject-instructions.md +4 -4
- package/catalog/frontmcp-config/examples/configure-throttle/server-level-rate-limit.md +1 -2
- package/catalog/frontmcp-config/examples/configure-throttle-guard-config/full-guard-config.md +2 -3
- package/catalog/frontmcp-config/references/configure-auth-modes.md +36 -13
- package/catalog/frontmcp-config/references/configure-auth.md +1 -0
- package/catalog/frontmcp-config/references/configure-http.md +10 -2
- package/catalog/frontmcp-config/references/configure-skills-http.md +2 -2
- package/catalog/frontmcp-config/references/configure-throttle-guard-config.md +5 -5
- package/catalog/frontmcp-config/references/configure-throttle.md +97 -20
- package/catalog/frontmcp-deployment/SKILL.md +10 -6
- package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/worker-custom-domain.md +4 -7
- package/catalog/frontmcp-deployment/references/deploy-to-cloudflare-skills-only.md +4 -0
- package/catalog/frontmcp-deployment/references/deploy-to-cloudflare.md +82 -39
- package/catalog/frontmcp-development/examples/create-plugin-hooks/caching-with-around.md +7 -6
- package/catalog/frontmcp-development/examples/official-plugins/production-multi-plugin-setup.md +2 -2
- package/catalog/frontmcp-development/references/create-job.md +2 -2
- package/catalog/frontmcp-development/references/create-plugin-hooks.md +21 -17
- package/catalog/frontmcp-development/references/create-prompt.md +18 -16
- package/catalog/frontmcp-development/references/create-provider.md +3 -3
- package/catalog/frontmcp-development/references/create-resource.md +10 -8
- package/catalog/frontmcp-development/references/create-skill.md +7 -0
- package/catalog/frontmcp-development/references/decorators-guide.md +9 -8
- package/catalog/frontmcp-development/references/official-plugins.md +167 -6
- package/catalog/frontmcp-development/references/openapi-adapter.md +16 -0
- package/catalog/frontmcp-observability/references/metrics-endpoint.md +1 -1
- package/catalog/frontmcp-observability/references/structured-logging.md +35 -0
- package/catalog/frontmcp-setup/SKILL.md +8 -7
- package/catalog/frontmcp-testing/SKILL.md +12 -8
- package/catalog/frontmcp-testing/examples/test-e2e-handler/tool-call-and-error-e2e.md +3 -1
- package/catalog/frontmcp-testing/references/setup-testing.md +42 -9
- package/catalog/frontmcp-testing/references/test-e2e-handler.md +35 -0
- package/catalog/skills-manifest.json +4 -3
- package/package.json +1 -1
|
@@ -99,6 +99,41 @@ logging: {
|
|
|
99
99
|
|
|
100
100
|
Redaction is recursive (handles nested objects) and case-insensitive.
|
|
101
101
|
|
|
102
|
+
## CodeCall Audit Events
|
|
103
|
+
|
|
104
|
+
If `CodeCallPlugin` is installed, it emits a structured audit event at every meaningful point in a
|
|
105
|
+
script execution. The plugin registers the bridge itself, so the events reach your normal log
|
|
106
|
+
output at `info` under the `codecall:audit` prefix with no wiring.
|
|
107
|
+
|
|
108
|
+
Event families, all carrying `executionId` for correlation:
|
|
109
|
+
|
|
110
|
+
- `codecall:execution:start` / `:success` / `:failure` / `:timeout`
|
|
111
|
+
- `codecall:tool:call:start` / `:success` / `:failure`
|
|
112
|
+
- `codecall:security:self-reference` / `:access-denied` / `:ast-blocked`
|
|
113
|
+
- `codecall:search:performed` / `codecall:describe:performed` / `codecall:invoke:performed`
|
|
114
|
+
|
|
115
|
+
No event carries script source, tool arguments, tool results, or query text — a script is reduced
|
|
116
|
+
to `scriptHash` + `scriptLength`, a query to `queryLength`. Do not add those fields when building
|
|
117
|
+
on this; the omission is what makes the events safe to emit at `info`.
|
|
118
|
+
|
|
119
|
+
To route events elsewhere, subscribe rather than parsing logs:
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { AUDIT_EVENT_TYPES, AuditLoggerService, type AuditEvent } from '@frontmcp/plugin-codecall';
|
|
123
|
+
|
|
124
|
+
const audit = scope.providers.get(AuditLoggerService);
|
|
125
|
+
const unsubscribe = audit.subscribe((event: AuditEvent) => myShipper.send(event));
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Fan-out is synchronous and on the execution hot path — hand off to a queue, never do network I/O
|
|
129
|
+
inside the listener. Note the file transport writes only the message, so structured fields are
|
|
130
|
+
dropped there; use the structured transport or subscribe directly.
|
|
131
|
+
|
|
132
|
+
**Over stdio:** stdout carries the MCP JSON-RPC frames, so nothing else may be written there.
|
|
133
|
+
`runStdio()` redirects the stdout-bound `console` methods to stderr, and the NDJSON `stdout` sink
|
|
134
|
+
defaults to stderr when `FRONTMCP_STDIO` is set. Never configure a sink with an explicit
|
|
135
|
+
`stream: process.stdout` on a stdio server — an explicit stream overrides the guard.
|
|
136
|
+
|
|
102
137
|
## Examples
|
|
103
138
|
|
|
104
139
|
| Example | Level | Description |
|
|
@@ -118,13 +118,14 @@ Entry point for project setup and scaffolding. This skill helps you find the rig
|
|
|
118
118
|
|
|
119
119
|
## Troubleshooting
|
|
120
120
|
|
|
121
|
-
| Problem
|
|
122
|
-
|
|
|
123
|
-
| `frontmcp create` fails
|
|
124
|
-
| Server fails to start
|
|
125
|
-
| Redis connection refused
|
|
126
|
-
| Nx generator not found
|
|
127
|
-
| Skills not loading
|
|
121
|
+
| Problem | Cause | Solution |
|
|
122
|
+
| ------------------------------------------------------------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
123
|
+
| `frontmcp create` fails | Missing Node.js 24+ or npm/yarn | Install Node.js 24+ and ensure npm/yarn is available |
|
|
124
|
+
| Server fails to start | `main.ts` missing default export | Add `export default MyServerClass` to `main.ts` |
|
|
125
|
+
| Redis connection refused | Redis not running or wrong URL | Start Redis (`docker compose up redis`) or fix `REDIS_URL` env var |
|
|
126
|
+
| Nx generator not found | `@frontmcp/nx` not installed | Run `npm install -D @frontmcp/nx` |
|
|
127
|
+
| Skills not loading | Skills placed in wrong directory | Catalog skills go in top-level `skills/`, app skills in `src/skills/` |
|
|
128
|
+
| Build or start fails under Yarn 4 with peer-dependency or `TS2688` errors | Yarn defaults to Plug'n'Play, which enforces peer dependencies strictly | `frontmcp create --pm yarn` scaffolds `.yarnrc.yml` with `nodeLinker: node-modules`; add that file and reinstall for projects scaffolded by an older CLI |
|
|
128
129
|
|
|
129
130
|
## Examples
|
|
130
131
|
|
|
@@ -99,6 +99,7 @@ This is a router skill. Follow this order to pick a testing approach, then move
|
|
|
99
99
|
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
100
100
|
| File naming | Always `.spec.ts` (not `.test.ts`); E2E uses `.e2e.spec.ts` |
|
|
101
101
|
| File organization | Split E2E tests by app/feature: `e2e/calc.e2e.spec.ts`, `e2e/ecommerce.e2e.spec.ts`. Never put all tests in a single `server.e2e.spec.ts` |
|
|
102
|
+
| Environment | `frontmcp test` loads `.env` / `.env.local` into the Jest child, same precedence as `dev` (real environment wins over the files, config `env.shared` + `env.test` underneath). `--no-env` skips it |
|
|
102
103
|
| Test runner | Standalone projects: use `frontmcp test` (auto-generates Jest/SWC config; discovers `src/**/*.spec.ts(x)`, `__tests__/**/*.spec.ts(x)`, and `e2e/**/*.e2e.spec.ts(x)`; transforms both `.ts` and `.tsx` with the automatic JSX runtime; transpiles ESM-only deps such as `jose` under npm, yarn AND pnpm's `node_modules/.pnpm/` store — add your own via `test.esmPackages` in `frontmcp.config.ts`; delegates to a user-provided `jest.config.{ts,js,mjs,cjs,json}` if present, which drops the injected ESM transforms). Nx monorepos: use `nx test <lib>` (resolves the project's `jest.config.ts`). Never invoke `jest --config ...` directly |
|
|
103
104
|
| Coverage threshold | 95%+ across statements, branches, functions, lines |
|
|
104
105
|
| Test descriptions | Plain English, no prefixes like "PT-001"; describe behavior not implementation |
|
|
@@ -145,14 +146,17 @@ This is a router skill. Follow this order to pick a testing approach, then move
|
|
|
145
146
|
|
|
146
147
|
## Troubleshooting
|
|
147
148
|
|
|
148
|
-
| Problem
|
|
149
|
-
|
|
|
150
|
-
| Jest not finding test files
|
|
151
|
-
| `SyntaxError: Unexpected token 'export'`
|
|
152
|
-
| Coverage below 95%
|
|
153
|
-
| E2E test timeout
|
|
154
|
-
| DI resolution fails in tests
|
|
155
|
-
| Istanbul shows 0% on async methods
|
|
149
|
+
| Problem | Cause | Solution |
|
|
150
|
+
| --------------------------------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
151
|
+
| Jest not finding test files | Wrong file extension (`.test.ts` instead of `.spec.ts`) | Rename to `.spec.ts`; check `testMatch` in jest.config |
|
|
152
|
+
| `SyntaxError: Unexpected token 'export'` | An ESM-only dependency is being ignored instead of transpiled | Add it to `test.esmPackages` in `frontmcp.config.ts`. With a hand-written `jest.config.ts`, use the pnpm-safe `transformIgnorePatterns` in [`setup-testing`](./references/setup-testing.md#jest-configuration) AND make sure `transform` matches `.js` (`^.+\.[tj]sx?$` + `allowJs`) — un-ignoring a file does nothing if no transform matches it |
|
|
153
|
+
| Coverage below 95% | Untested error paths or conditional branches | Run `frontmcp test --coverage` and inspect uncovered lines in the report |
|
|
154
|
+
| E2E test timeout | Server startup too slow or port conflict | Increase Jest timeout; use random port allocation |
|
|
155
|
+
| DI resolution fails in tests | Provider not registered in test scope | Register mock providers before creating the test context |
|
|
156
|
+
| Istanbul shows 0% on async methods | TypeScript source-map mismatch with Istanbul | Known issue with some TS compilation settings; verify coverage with actual test output |
|
|
157
|
+
| Specs see no `.env` values | An older CLI did not load `.env` for `frontmcp test`, only for `dev` | Upgrade the CLI — `frontmcp test` now loads `.env` / `.env.local` with the same precedence as `dev` (real environment wins, so CI secrets still override). Pass `--no-env` for a hermetic run |
|
|
158
|
+
| `Invalid first argument, true` at collection time | `test.skip(condition, reason)` reached Jest's `skip(name, fn)` | Upgrade the CLI — the Playwright signature is supported: `test.skip(!hasCredentials, 'credentials not set')` skips every test registered after it in the enclosing block |
|
|
159
|
+
| Every spec fails with `HTTP 404` after setting `http.entryPath` | The test client always connected to the server root | Upgrade the CLI — the client now follows the `entryPaths` a 404 reports, and `test.use({ entryPath: '/mcp' })` sets it explicitly |
|
|
156
160
|
|
|
157
161
|
## Examples
|
|
158
162
|
|
|
@@ -8,6 +8,7 @@ features:
|
|
|
8
8
|
- 'Calling tools via `client.tools.call(name, args)` and asserting success with `toBeSuccessful()`'
|
|
9
9
|
- 'Asserting text content with the `toHaveTextContent()` matcher'
|
|
10
10
|
- 'Asserting error results with `toBeError()` for invalid input and unknown tools'
|
|
11
|
+
- 'Matching the tool error code: invalid input is an `isError` result with `_meta.code: "INVALID_INPUT"`, so `toBeError(''INVALID_INPUT'')` matches it (a numeric code matches JSON-RPC errors only)'
|
|
11
12
|
- 'Testing edge cases like zero values'
|
|
12
13
|
---
|
|
13
14
|
|
|
@@ -53,7 +54,7 @@ describe('Tool Call E2E', () => {
|
|
|
53
54
|
|
|
54
55
|
it('returns an error for invalid input', async () => {
|
|
55
56
|
const result = await client.tools.call('add_numbers', { a: 'bad' });
|
|
56
|
-
expect(result).toBeError();
|
|
57
|
+
expect(result).toBeError('INVALID_INPUT');
|
|
57
58
|
});
|
|
58
59
|
|
|
59
60
|
it('returns an error for a nonexistent tool', async () => {
|
|
@@ -74,6 +75,7 @@ describe('Tool Call E2E', () => {
|
|
|
74
75
|
- Calling tools via `client.tools.call(name, args)` and asserting success with `toBeSuccessful()`
|
|
75
76
|
- Asserting text content with the `toHaveTextContent()` matcher
|
|
76
77
|
- Asserting error results with `toBeError()` for invalid input and unknown tools
|
|
78
|
+
- Matching the tool error code: invalid input is an `isError` result with `_meta.code: "INVALID_INPUT"`, so `toBeError('INVALID_INPUT')` matches it (a numeric code matches JSON-RPC errors only)
|
|
77
79
|
- Testing edge cases like zero values
|
|
78
80
|
|
|
79
81
|
## Related
|
|
@@ -380,6 +380,39 @@ test('unauthenticated call is rejected', async ({ mcp }) => {
|
|
|
380
380
|
});
|
|
381
381
|
```
|
|
382
382
|
|
|
383
|
+
### Servers that serve MCP somewhere other than `/`
|
|
384
|
+
|
|
385
|
+
A server configured with `http: { entryPath: '/mcp' }` serves MCP at `/mcp`, and the test client follows it:
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
test.use({
|
|
389
|
+
server: './src/main.ts',
|
|
390
|
+
entryPath: '/mcp',
|
|
391
|
+
});
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
You usually do not need to set this: when the client's first request 404s and the server reports where it does serve MCP (`{"error":"Not Found","entryPaths":["/mcp"]}`), the client reconnects there on its own, and a failure names the reported paths instead of a bare `HTTP 404`. `entryPath` applies to the MCP endpoint only — OAuth and discovery endpoints stay at the server root.
|
|
395
|
+
|
|
396
|
+
`baseUrl` may also be supplied alongside `server` to override the booted server's own URL (for a proxy, or a different host than it binds).
|
|
397
|
+
|
|
398
|
+
### Gating a block on credentials
|
|
399
|
+
|
|
400
|
+
`test.skip(condition, reason)` is the Playwright signature and skips every test registered after it in the enclosing block:
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
const hasCredentials = Boolean(process.env.TWILIO_ACCOUNT_SID);
|
|
404
|
+
|
|
405
|
+
test.describe('against the live API', () => {
|
|
406
|
+
test.skip(!hasCredentials, 'credentials not set');
|
|
407
|
+
|
|
408
|
+
test('looks up a carrier', async ({ mcp }) => {
|
|
409
|
+
// ...
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
A nested `test.describe` inherits an outer skip. The `(name, fn)` form still skips a single named test. `frontmcp test` loads `.env` / `.env.local`, so a credential in `.env` reaches the condition above.
|
|
415
|
+
|
|
383
416
|
## Custom MCP Matchers
|
|
384
417
|
|
|
385
418
|
`@frontmcp/testing` provides Jest matchers tailored for MCP responses. Import `expect` from `@frontmcp/testing` instead of from Jest:
|
|
@@ -388,15 +421,15 @@ test('unauthenticated call is rejected', async ({ mcp }) => {
|
|
|
388
421
|
import { expect } from '@frontmcp/testing';
|
|
389
422
|
```
|
|
390
423
|
|
|
391
|
-
| Matcher | Asserts
|
|
392
|
-
| ------------------------- |
|
|
393
|
-
| `toContainTool(name)` | Tools list includes a tool with the given name
|
|
394
|
-
| `toContainResource(uri)` | Resources list includes a resource with the given URI
|
|
395
|
-
| `toContainPrompt(name)` | Prompts list includes a prompt with the given name
|
|
396
|
-
| `toBeSuccessful()` | Tool call result is not an error
|
|
397
|
-
| `toBeError()`
|
|
398
|
-
| `toHaveTextContent(text)` | Result contains text content matching the string
|
|
399
|
-
| `toHaveMimeType(mime)` | Resource content has the expected MIME type
|
|
424
|
+
| Matcher | Asserts |
|
|
425
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
426
|
+
| `toContainTool(name)` | Tools list includes a tool with the given name |
|
|
427
|
+
| `toContainResource(uri)` | Resources list includes a resource with the given URI |
|
|
428
|
+
| `toContainPrompt(name)` | Prompts list includes a prompt with the given name |
|
|
429
|
+
| `toBeSuccessful()` | Tool call result is not an error |
|
|
430
|
+
| `toBeError(code?)` | Result is an error; a string code matches `_meta.code` (`'INVALID_INPUT'`), a number matches a JSON-RPC error code |
|
|
431
|
+
| `toHaveTextContent(text)` | Result contains text content matching the string |
|
|
432
|
+
| `toHaveMimeType(mime)` | Resource content has the expected MIME type |
|
|
400
433
|
|
|
401
434
|
## Running Tests with Nx
|
|
402
435
|
|
|
@@ -67,6 +67,41 @@ describe('Server E2E', () => {
|
|
|
67
67
|
});
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
## Error Codes
|
|
71
|
+
|
|
72
|
+
Errors raised while a tool runs, including invalid input, come back as a tool result with `isError: true` and a string `_meta.code`, not as a JSON-RPC error. Match them with the string form, and keep the numeric form for JSON-RPC errors:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
expect(await client.tools.call('add_numbers', { a: 5 })).toBeError('INVALID_INPUT');
|
|
76
|
+
expect(await client.tools.call('nonexistent_tool', {})).toBeError('TOOL_NOT_FOUND');
|
|
77
|
+
expect(await client.prompts.get('nonexistent_prompt')).toBeError(-32602);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
A tool without an `outputSchema` that returns a plain number sends `{ value: 8 }`, so assert `expect(result.json()).toEqual({ value: 8 })`.
|
|
81
|
+
|
|
82
|
+
## Notifications and Progress
|
|
83
|
+
|
|
84
|
+
After `initialize`, `McpTestClient` opens the session's notification stream (a `GET` on the MCP endpoint) and records what the server sends there and on each request's own response:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
it('records progress and log messages', async () => {
|
|
88
|
+
const progress = client.notifications.collectProgress(); // tools.call now sends a _meta.progressToken
|
|
89
|
+
const notifications = client.notifications.collect();
|
|
90
|
+
await client.raw.request({ jsonrpc: '2.0', id: 1, method: 'logging/setLevel', params: { level: 'info' } });
|
|
91
|
+
|
|
92
|
+
await client.tools.call('import_files', {});
|
|
93
|
+
|
|
94
|
+
await progress.waitForComplete(5000);
|
|
95
|
+
expect(progress.all.length).toBeGreaterThan(0);
|
|
96
|
+
await notifications.waitFor('notifications/message', 5000);
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
- Pass `{ progressToken }` as the third argument of `tools.call()` to choose the token yourself.
|
|
101
|
+
- The server sends `notifications/message` (from `this.notify()`) only after `logging/setLevel`.
|
|
102
|
+
- Session-stream notifications can arrive after the call's result, so wait with `waitFor()` / `waitForComplete()` before asserting.
|
|
103
|
+
- `McpTestClient` speaks `2025-06-18` by default. `2026-07-28` has no `initialize` handshake, so `withProtocolVersion('2026-07-28')` makes `build()` throw.
|
|
104
|
+
|
|
70
105
|
## Examples
|
|
71
106
|
|
|
72
107
|
| Example | Level | Description |
|
|
@@ -365,7 +365,7 @@
|
|
|
365
365
|
"features": [
|
|
366
366
|
"Restricting the widget's outbound `fetch` via `ui.csp.connectDomains` (emitted on the resource per #455)",
|
|
367
367
|
"Opting the widget into cross-tool calls with `widgetAccessible: true` and using `window.FrontMcpBridge.callTool(name, args)` instead of host-specific APIs",
|
|
368
|
-
"Embedding initial data into the widget's inline `<script>` safely via `ctx.helpers.jsonEmbed(...)` (escapes
|
|
368
|
+
"Embedding initial data into the widget's inline `<script>` safely via `ctx.helpers.jsonEmbed(...)` (escapes `<`, `>` and `&`)",
|
|
369
369
|
"Surfacing in-flight status via `invocationStatus.invoking` / `invoked` so the host UI shows feedback"
|
|
370
370
|
]
|
|
371
371
|
},
|
|
@@ -1069,7 +1069,7 @@
|
|
|
1069
1069
|
"Top-level `instructions` on `@FrontMcp` exposes a global system prompt to MCP clients",
|
|
1070
1070
|
"`skillsConfig.injectInstructions: 'append'` adds the skill catalog summary after the user prompt",
|
|
1071
1071
|
"Dynamic skills are picked up because the composer runs on every initialize request",
|
|
1072
|
-
"Catalog summary is bounded at 16 KB with a truncation footer pointing at skill://
|
|
1072
|
+
"Catalog summary is bounded at 16 KB with a truncation footer pointing at skill://index.json"
|
|
1073
1073
|
]
|
|
1074
1074
|
},
|
|
1075
1075
|
{
|
|
@@ -1276,7 +1276,7 @@
|
|
|
1276
1276
|
"tags": ["deployment", "json-rpc", "cloudflare", "worker", "custom", "domain"],
|
|
1277
1277
|
"features": [
|
|
1278
1278
|
"Using `frontmcp create --target cloudflare` to scaffold a project with `wrangler.toml` and deploy scripts",
|
|
1279
|
-
"Adding a custom domain with `wrangler
|
|
1279
|
+
"Adding a custom domain with `wrangler deploy --domain` for production-ready URLs",
|
|
1280
1280
|
"End-to-end verification of both the health check and MCP JSON-RPC endpoint"
|
|
1281
1281
|
]
|
|
1282
1282
|
},
|
|
@@ -3449,6 +3449,7 @@
|
|
|
3449
3449
|
"Calling tools via `client.tools.call(name, args)` and asserting success with `toBeSuccessful()`",
|
|
3450
3450
|
"Asserting text content with the `toHaveTextContent()` matcher",
|
|
3451
3451
|
"Asserting error results with `toBeError()` for invalid input and unknown tools",
|
|
3452
|
+
"Matching the tool error code: invalid input is an `isError` result with `_meta.code: \"INVALID_INPUT\"`, so `toBeError('INVALID_INPUT')` matches it (a numeric code matches JSON-RPC errors only)",
|
|
3452
3453
|
"Testing edge cases like zero values"
|
|
3453
3454
|
]
|
|
3454
3455
|
}
|