@frontmcp/skills 1.8.6 → 1.8.7
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/SKILL.md +24 -24
- package/catalog/create-tool/examples/22-tool-with-ui-html-template.md +0 -1
- package/catalog/create-tool/examples/23-tool-with-ui-filesource-tsx.md +1 -3
- package/catalog/create-tool/examples/24-tool-with-ui-csp-and-bridge.md +4 -6
- package/catalog/create-tool/references/decorator-options.md +1 -1
- package/catalog/create-tool/references/ui-widgets.md +68 -41
- package/catalog/frontmcp-config/examples/configure-throttle/distributed-redis-throttle.md +3 -3
- package/catalog/frontmcp-config/references/configure-deployment-targets.md +19 -1
- package/catalog/frontmcp-config/references/configure-http.md +6 -4
- package/catalog/frontmcp-config/references/configure-security-headers.md +18 -13
- package/catalog/frontmcp-config/references/configure-throttle-guard-config.md +4 -4
- package/catalog/frontmcp-config/references/configure-throttle.md +1 -1
- package/catalog/frontmcp-deployment/SKILL.md +19 -19
- package/catalog/frontmcp-deployment/examples/build-for-browser/react-provider-setup.md +5 -3
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-with-kv.md +2 -0
- package/catalog/frontmcp-deployment/references/build-for-browser.md +8 -0
- package/catalog/frontmcp-deployment/references/build-for-mcpb.md +9 -8
- package/catalog/frontmcp-deployment/references/build-for-sdk.md +9 -9
- package/catalog/frontmcp-deployment/references/deploy-to-cloudflare.md +3 -1
- package/catalog/frontmcp-deployment/references/deploy-to-lambda.md +9 -8
- package/catalog/frontmcp-deployment/references/deploy-to-vercel.md +15 -7
- package/catalog/frontmcp-development/references/create-agent.md +8 -7
- package/catalog/frontmcp-development/references/create-plugin.md +17 -0
- package/catalog/frontmcp-development/references/official-plugins.md +12 -5
- package/catalog/frontmcp-guides/references/example-task-manager.md +2 -2
- package/catalog/frontmcp-guides/references/example-weather-api.md +2 -2
- package/catalog/frontmcp-production-readiness/examples/distributed-ha/ha-kubernetes-3-replicas.md +1 -0
- package/catalog/frontmcp-production-readiness/examples/production-node-sdk/package-json-config.md +2 -2
- package/catalog/frontmcp-production-readiness/references/common-checklist.md +1 -1
- package/catalog/frontmcp-production-readiness/references/distributed-ha.md +17 -7
- package/catalog/frontmcp-production-readiness/references/health-readiness-endpoints.md +3 -1
- package/catalog/frontmcp-setup/examples/project-structure-nx/nx-generator-scaffolding.md +1 -1
- package/catalog/frontmcp-setup/references/nx-workflow.md +25 -17
- package/catalog/frontmcp-setup/references/setup-redis.md +1 -1
- package/catalog/frontmcp-setup/references/setup-sqlite.md +9 -6
- package/catalog/frontmcp-testing/SKILL.md +24 -23
- package/catalog/frontmcp-testing/references/setup-testing.md +26 -2
- package/catalog/frontmcp-testing/references/test-auth.md +8 -0
- package/catalog/skills-manifest.json +4 -4
- package/package.json +1 -1
|
@@ -127,12 +127,13 @@ export default class Server {}
|
|
|
127
127
|
|
|
128
128
|
Configuration reference:
|
|
129
129
|
|
|
130
|
-
| Option | Type | Default | Description
|
|
131
|
-
| ---------------------- | -------------------- | ----------- |
|
|
132
|
-
| `path` | `string` | (optional) | Absolute or `~`-prefixed path to the `.sqlite` file. Auto-resolved when omitted — see the default-path policy below.
|
|
133
|
-
| `walMode` | `boolean` | `true` | Enable WAL mode for better read concurrency
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
130
|
+
| Option | Type | Default | Description |
|
|
131
|
+
| ---------------------- | -------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
132
|
+
| `path` | `string` | (optional) | Absolute or `~`-prefixed path to the `.sqlite` file. Auto-resolved when omitted — see the default-path policy below. |
|
|
133
|
+
| `walMode` | `boolean` | `true` | Enable WAL mode for better read concurrency |
|
|
134
|
+
| `busyTimeoutMs` | `number` | `5000` | How long a connection waits on a lock held by another process before `SQLITE_BUSY`. Set before WAL and table creation, so two processes starting on one file wait for each other |
|
|
135
|
+
| `encryption` | `{ secret: string }` | `undefined` | AES-256-GCM encryption for values at rest |
|
|
136
|
+
| `ttlCleanupIntervalMs` | `number` | `60000` | Interval for purging expired keys (milliseconds) |
|
|
136
137
|
|
|
137
138
|
### With at-rest encryption
|
|
138
139
|
|
|
@@ -155,6 +156,8 @@ If the database stores sensitive session data (tokens, credentials), enable encr
|
|
|
155
156
|
export default class Server {}
|
|
156
157
|
```
|
|
157
158
|
|
|
159
|
+
Reading a value written under a different secret throws `SqliteDecryptionError` (code `SQLITE_DECRYPTION_FAILED`) whose message names the secret as the likely cause; restore the original secret or delete the database file.
|
|
160
|
+
|
|
158
161
|
The encryption uses HKDF-SHA256 for key derivation and AES-256-GCM for value encryption. The secret should be at least 32 characters. Store it in environment variables, never in source code.
|
|
159
162
|
|
|
160
163
|
### For a unix-socket daemon
|
|
@@ -95,18 +95,18 @@ This is a router skill. Follow this order to pick a testing approach, then move
|
|
|
95
95
|
|
|
96
96
|
## Cross-Cutting Testing Patterns
|
|
97
97
|
|
|
98
|
-
| Pattern | Rule
|
|
99
|
-
| ------------------ |
|
|
100
|
-
| File naming | Always `.spec.ts` (not `.test.ts`); E2E uses `.e2e.spec.ts`
|
|
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
|
|
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 |
|
|
104
|
-
| Coverage threshold | 95%+ across statements, branches, functions, lines
|
|
105
|
-
| Test descriptions | Plain English, no prefixes like "PT-001"; describe behavior not implementation
|
|
106
|
-
| Mocking | Mock providers via DI token replacement, never mock the framework
|
|
107
|
-
| httpMock scope | `httpMock` intercepts HTTP in the **test process** only, NOT in the MCP server subprocess. Do not use httpMock to intercept server-to-API calls — those happen in the child process. Use httpMock for verifying client-to-server request shapes or mocking external APIs called from the test itself
|
|
108
|
-
| Error testing | Assert `instanceof` specific error class AND MCP error code
|
|
109
|
-
| Async | Always `await` async operations; use `expect(...).rejects.toThrow()` for async errors
|
|
98
|
+
| Pattern | Rule |
|
|
99
|
+
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
100
|
+
| File naming | Always `.spec.ts` (not `.test.ts`); E2E uses `.e2e.spec.ts` |
|
|
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 |
|
|
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`, `@noble/hashes` and `@noble/ciphers` (CodeCall) under npm, yarn AND pnpm's `node_modules/.pnpm/` store — add your own via `test.esmPackages` in `frontmcp.config.ts`; does not force `NODE_OPTIONS=--experimental-vm-modules` (it would bypass the ESM transforms; scaffolded projects use Jest 30); 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 |
|
|
104
|
+
| Coverage threshold | 95%+ across statements, branches, functions, lines |
|
|
105
|
+
| Test descriptions | Plain English, no prefixes like "PT-001"; describe behavior not implementation |
|
|
106
|
+
| Mocking | Mock providers via DI token replacement, never mock the framework |
|
|
107
|
+
| httpMock scope | `httpMock` intercepts HTTP in the **test process** only, NOT in the MCP server subprocess. Do not use httpMock to intercept server-to-API calls — those happen in the child process. Use httpMock for verifying client-to-server request shapes or mocking external APIs called from the test itself |
|
|
108
|
+
| Error testing | Assert `instanceof` specific error class AND MCP error code |
|
|
109
|
+
| Async | Always `await` async operations; use `expect(...).rejects.toThrow()` for async errors |
|
|
110
110
|
|
|
111
111
|
## Common Patterns
|
|
112
112
|
|
|
@@ -146,17 +146,18 @@ This is a router skill. Follow this order to pick a testing approach, then move
|
|
|
146
146
|
|
|
147
147
|
## Troubleshooting
|
|
148
148
|
|
|
149
|
-
| Problem
|
|
150
|
-
|
|
|
151
|
-
| Jest not finding test files
|
|
152
|
-
| `SyntaxError: Unexpected token 'export'`
|
|
153
|
-
| Coverage below 95%
|
|
154
|
-
| E2E test timeout
|
|
155
|
-
| DI resolution fails in tests
|
|
156
|
-
| Istanbul shows 0% on async methods
|
|
157
|
-
| Specs see no `.env` values
|
|
158
|
-
| `Invalid first argument, true` at collection time
|
|
159
|
-
|
|
|
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
|
+
| `test.use()` in one `describe` leaks into another, or two files fight over a port | Older `@frontmcp/testing` kept one global config and per-process ports | Upgrade — `test.use()` is scoped per `describe` and ports are locked across Jest workers; use `port: 0` |
|
|
160
|
+
| 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 |
|
|
160
161
|
|
|
161
162
|
## Examples
|
|
162
163
|
|
|
@@ -396,6 +396,27 @@ You usually do not need to set this: when the client's first request 404s and th
|
|
|
396
396
|
|
|
397
397
|
`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).
|
|
398
398
|
|
|
399
|
+
### Scoping config, parameterised tests, ports and restarts
|
|
400
|
+
|
|
401
|
+
- `test.use()` is scoped to the `describe` block it is called in. Nested blocks merge over outer ones (`env` key by key); each distinct configuration gets its own server, stopped by the block that configured it. At file level it applies to the whole file.
|
|
402
|
+
- `port: 0` (or omitting `port`) picks any free port. Ports are reserved with a cross-process lock, so parallel Jest workers do not collide.
|
|
403
|
+
- `auth: { mode, type }` reaches the server process as `FRONTMCP_TEST_AUTH_MODE` / `FRONTMCP_TEST_AUTH_TYPE`; `mode: 'public'` also keeps the `mcp` client anonymous.
|
|
404
|
+
- `test.each` / `test.describe.each` pass the row values to the callback (fixtures first for `test.each`):
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
test.each([
|
|
408
|
+
['read', 1],
|
|
409
|
+
['write', 2],
|
|
410
|
+
])('scope %s', async ({ mcp }, scope, level) => {
|
|
411
|
+
expect(mcp.isConnected()).toBe(true);
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
- `server.info.pid` is the pid of the process that listens on the port. `server.restart()` reconnects `mcp` and every client made with `server.createClient()`.
|
|
416
|
+
- `mcp.logs` holds the log notifications the client received; `server.getLogs()` holds the server process output. They are different sources.
|
|
417
|
+
- `mcp.intercept.failMethod(method, message)` makes matching calls reject with `message`; the returned function removes it.
|
|
418
|
+
- `httpMock` patches `fetch` in the test process only (see above) and `interceptor.restore()` puts the original `fetch` back.
|
|
419
|
+
|
|
399
420
|
### Gating a block on credentials
|
|
400
421
|
|
|
401
422
|
`test.skip(condition, reason)` is the Playwright signature and skips every test registered after it in the enclosing block:
|
|
@@ -494,7 +515,10 @@ matches at the first `node_modules/`, and the run fails with
|
|
|
494
515
|
`SyntaxError: Unexpected token 'export'`.
|
|
495
516
|
|
|
496
517
|
In standalone projects driven by `frontmcp test`, prefer `test.esmPackages` in
|
|
497
|
-
`frontmcp.config.ts` — the injected config already carries the pattern above
|
|
518
|
+
`frontmcp.config.ts` — the injected config already carries the pattern above,
|
|
519
|
+
and already transpiles `jose`, `@noble/hashes` and `@noble/ciphers` (CodeCall).
|
|
520
|
+
`frontmcp test` does not set `NODE_OPTIONS=--experimental-vm-modules` (it would make Jest
|
|
521
|
+
load ESM natively and bypass these transforms); use Jest 30 (what `frontmcp create` scaffolds):
|
|
498
522
|
|
|
499
523
|
```typescript
|
|
500
524
|
// frontmcp.config.ts
|
|
@@ -607,7 +631,7 @@ node scripts/fix-unused-imports.mjs feature/my-branch
|
|
|
607
631
|
| `toContainTool` matcher not found | Using `expect` from Jest instead of `@frontmcp/testing` | Import `expect` from `@frontmcp/testing` to get MCP-specific matchers |
|
|
608
632
|
| `McpTestClient.create()` connection refused | Test server not running or wrong `baseUrl` | Ensure `TestServer.start()` completes before creating client; verify port matches |
|
|
609
633
|
| Istanbul shows 0% coverage for async methods | TypeScript compilation source-map mismatch | Known issue with `ts-jest` and certain async patterns; check `tsconfig.spec.json` source-map settings |
|
|
610
|
-
| Auth E2E test returns 401 unexpectedly | Token not set or expired | Call `mcp.
|
|
634
|
+
| Auth E2E test returns 401 unexpectedly | Token not set or expired | Call `await mcp.authenticate(token)` before the tool call; use `auth.createToken()` with valid claims |
|
|
611
635
|
|
|
612
636
|
## Examples
|
|
613
637
|
|
|
@@ -94,6 +94,14 @@ describe('Authenticated Server', () => {
|
|
|
94
94
|
});
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
+
## Token semantics
|
|
98
|
+
|
|
99
|
+
- Default issuer `https://test.frontmcp.local`, default audience `frontmcp-test` (override with `new TestTokenFactory({ issuer, audience })`).
|
|
100
|
+
- `expiresIn` is counted from now and rounded up to whole seconds, so `expiresIn: 1` is valid for at least one second. `createAnonymousToken(expiresIn?)` takes a lifetime too.
|
|
101
|
+
- `await mcp.authenticate(token)` opens a new session for the token and **rejects** if the server refuses it (expired, bad signature); the client then keeps its previous identity. On an unconnected client it only stores the token. 401/403 are never retried.
|
|
102
|
+
- Tools read token scopes through `this.auth` (e.g. `this.auth.scopes`).
|
|
103
|
+
- Access tokens from `MockOAuthServer` carry the granted `scope` claim and `exp = accessTokenTtlSeconds`, also after a refresh.
|
|
104
|
+
|
|
97
105
|
## Mock OAuth / OIDC server
|
|
98
106
|
|
|
99
107
|
`MockOAuthServer` serves JWKS, OAuth metadata, authorization, token, and userinfo endpoints. Construct it with a `TestTokenFactory`, call `.start()` to bind a port, and configure your MCP server to point at the returned `info.issuer` / `info.jwksUrl`.
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
"name": "ui-widgets",
|
|
77
|
-
"description": "@Tool({ ui }) \u2014 template formats, trusted markup (html / escapeStringResults), servingMode, host-detect resourceMode, CSP,
|
|
77
|
+
"description": "@Tool({ ui }) \u2014 template formats, trusted markup (html / escapeStringResults), servingMode, host-detect resourceMode, CSP, ignored options, MCP Apps spec."
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
"name": "annotations",
|
|
@@ -362,10 +362,10 @@
|
|
|
362
362
|
"name": "24-tool-with-ui-csp-and-bridge",
|
|
363
363
|
"level": "advanced",
|
|
364
364
|
"description": "Interactive tool widget that fetches from an allow-listed CSP origin and invokes another tool via `window.FrontMcpBridge.callTool` \u2014 the full pattern for live-data widgets that need cross-tool composition.",
|
|
365
|
-
"tags": ["ui", "csp", "
|
|
365
|
+
"tags": ["ui", "csp", "callTool", "FrontMcpBridge", "interactive-widget"],
|
|
366
366
|
"features": [
|
|
367
367
|
"Restricting the widget's outbound `fetch` via `ui.csp.connectDomains` (emitted on the resource per #455)",
|
|
368
|
-
"
|
|
368
|
+
"Calling other tools from the widget with `window.FrontMcpBridge.callTool(name, args)` instead of host-specific APIs",
|
|
369
369
|
"Building the markup with `ctx.helpers.html` and embedding initial data into the inline `<script>` via `trustedHtml(jsonEmbed(...))` (`jsonEmbed` escapes `<`, `>` and `&`)",
|
|
370
370
|
"Surfacing in-flight status via `invocationStatus.invoking` / `invoked` so the host UI shows feedback"
|
|
371
371
|
]
|
|
@@ -944,7 +944,7 @@
|
|
|
944
944
|
"Using `keyPrefix` to namespace guard keys in a shared Redis instance",
|
|
945
945
|
"Combining `partitionBy: 'ip'` for global limits with `partitionBy: 'session'` per tool",
|
|
946
946
|
"In-memory counters are per-process and would allow N times the intended rate with N instances",
|
|
947
|
-
"Startup fails closed with `GuardStorageUnavailableError` when Redis is down, unless `fallback: 'memory'`"
|
|
947
|
+
"Startup fails closed, and a limited call is refused, with `GuardStorageUnavailableError` when Redis is down, unless `fallback: 'memory'`"
|
|
948
948
|
]
|
|
949
949
|
},
|
|
950
950
|
{
|