@frontmcp/skills 1.1.2-beta.1 → 1.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/catalog/TEMPLATE.md +16 -11
- package/catalog/frontmcp-authorities/SKILL.md +116 -11
- package/catalog/frontmcp-authorities/references/authority-profiles.md +39 -36
- package/catalog/frontmcp-authorities/references/claims-mapping.md +7 -0
- package/catalog/frontmcp-authorities/references/custom-evaluators.md +63 -14
- package/catalog/frontmcp-channels/SKILL.md +36 -0
- package/catalog/frontmcp-channels/examples/channel-sources/file-watcher.md +8 -2
- package/catalog/frontmcp-channels/examples/channel-sources/replay-buffer.md +111 -30
- package/catalog/frontmcp-channels/examples/channel-two-way/whatsapp-bridge.md +45 -3
- package/catalog/frontmcp-channels/references/channel-sources.md +11 -3
- package/catalog/frontmcp-channels/references/channel-two-way.md +60 -89
- package/catalog/frontmcp-config/SKILL.md +111 -8
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-self-signed-tokens.md +4 -4
- package/catalog/frontmcp-config/examples/configure-auth-modes/remote-enterprise-oauth.md +7 -1
- package/catalog/frontmcp-config/examples/configure-deployment-targets/distributed-ha-config.md +1 -1
- package/catalog/frontmcp-config/examples/configure-deployment-targets/json-schema-ide-support.md +1 -1
- package/catalog/frontmcp-config/examples/configure-deployment-targets/multi-target-with-security.md +12 -9
- package/catalog/frontmcp-config/examples/configure-http/cors-restricted-origins.md +2 -2
- package/catalog/frontmcp-config/examples/configure-http/entry-path-reverse-proxy.md +1 -1
- package/catalog/frontmcp-config/examples/configure-security-headers/csp-report-only.md +1 -1
- package/catalog/frontmcp-config/examples/configure-security-headers/full-production-headers.md +1 -1
- package/catalog/frontmcp-config/examples/configure-skills-http/audit-log-basic.md +76 -0
- package/catalog/frontmcp-config/examples/configure-skills-http/audit-log-redis.md +116 -0
- package/catalog/frontmcp-config/examples/configure-skills-http/inject-instructions.md +59 -0
- package/catalog/frontmcp-config/references/configure-auth-modes.md +5 -5
- package/catalog/frontmcp-config/references/configure-deployment-targets.md +27 -24
- package/catalog/frontmcp-config/references/configure-http.md +14 -10
- package/catalog/frontmcp-config/references/configure-security-headers.md +2 -2
- package/catalog/frontmcp-config/references/configure-session.md +25 -25
- package/catalog/frontmcp-config/references/configure-skills-http.md +157 -0
- package/catalog/frontmcp-config/references/configure-throttle.md +1 -1
- package/catalog/frontmcp-config/references/configure-transport.md +2 -2
- package/catalog/frontmcp-deployment/SKILL.md +112 -9
- package/catalog/frontmcp-deployment/examples/build-for-browser/browser-build-with-custom-entry.md +23 -11
- package/catalog/frontmcp-deployment/examples/build-for-browser/browser-crypto-and-storage.md +44 -17
- package/catalog/frontmcp-deployment/examples/build-for-browser/react-provider-setup.md +53 -21
- package/catalog/frontmcp-deployment/examples/build-for-cli/cli-binary-build.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-cli/unix-socket-daemon.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-mcpb/mcpb-bundle-build.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-sdk/connect-openai.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-sdk/multi-platform-connect.md +1 -1
- package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/basic-worker-deploy.md +7 -8
- package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/worker-custom-domain.md +8 -6
- package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/worker-with-kv-storage.md +5 -4
- package/catalog/frontmcp-deployment/examples/deploy-to-lambda/cdk-deployment.md +8 -5
- package/catalog/frontmcp-deployment/examples/deploy-to-lambda/lambda-handler-with-cors.md +20 -18
- package/catalog/frontmcp-deployment/examples/deploy-to-lambda/sam-template-basic.md +8 -5
- package/catalog/frontmcp-deployment/examples/deploy-to-node/docker-compose-with-redis.md +3 -3
- package/catalog/frontmcp-deployment/examples/deploy-to-node/pm2-with-nginx.md +1 -1
- package/catalog/frontmcp-deployment/examples/deploy-to-node/resource-limits.md +2 -2
- package/catalog/frontmcp-deployment/examples/deploy-to-node-dockerfile/basic-multistage-dockerfile.md +2 -2
- package/catalog/frontmcp-deployment/examples/deploy-to-node-dockerfile/secure-nonroot-dockerfile.md +1 -1
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-mcp-endpoint-test.md +23 -21
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-with-kv.md +25 -22
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-with-skills-cache.md +23 -30
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel-config/minimal-vercel-config.md +52 -28
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel-config/vercel-config-with-security-headers.md +32 -55
- package/catalog/frontmcp-deployment/examples/mcp-client-integration/http-remote.md +9 -0
- package/catalog/frontmcp-deployment/references/build-for-browser.md +40 -17
- package/catalog/frontmcp-deployment/references/build-for-cli.md +8 -8
- package/catalog/frontmcp-deployment/references/deploy-to-cloudflare.md +43 -24
- package/catalog/frontmcp-deployment/references/deploy-to-lambda.md +36 -25
- package/catalog/frontmcp-deployment/references/deploy-to-node-dockerfile.md +56 -14
- package/catalog/frontmcp-deployment/references/deploy-to-node.md +9 -6
- package/catalog/frontmcp-deployment/references/deploy-to-vercel-config.md +57 -58
- package/catalog/frontmcp-deployment/references/deploy-to-vercel.md +49 -59
- package/catalog/frontmcp-deployment/references/mcp-client-integration.md +2 -0
- package/catalog/frontmcp-development/SKILL.md +186 -11
- package/catalog/frontmcp-development/examples/create-agent/custom-multi-pass-agent.md +1 -1
- package/catalog/frontmcp-development/examples/create-agent/nested-agents-with-swarm.md +30 -27
- package/catalog/frontmcp-development/examples/create-job/job-with-permissions.md +13 -8
- package/catalog/frontmcp-development/examples/create-provider/basic-database-provider.md +33 -23
- package/catalog/frontmcp-development/examples/create-provider/config-and-api-providers.md +19 -10
- package/catalog/frontmcp-development/examples/create-tool/tool-with-rate-limiting-and-progress.md +3 -3
- package/catalog/frontmcp-development/examples/create-workflow/webhook-triggered-workflow.md +6 -4
- package/catalog/frontmcp-development/examples/decorators-guide/agent-skill-job-workflow.md +1 -1
- package/catalog/frontmcp-development/examples/decorators-guide/basic-server-with-app-and-tools.md +13 -8
- package/catalog/frontmcp-development/examples/decorators-guide/multi-app-with-plugins-and-providers.md +50 -23
- package/catalog/frontmcp-development/references/create-agent.md +47 -30
- package/catalog/frontmcp-development/references/create-job.md +69 -54
- package/catalog/frontmcp-development/references/create-plugin-hooks.md +45 -28
- package/catalog/frontmcp-development/references/create-plugin.md +10 -8
- package/catalog/frontmcp-development/references/create-prompt.md +3 -3
- package/catalog/frontmcp-development/references/create-provider.md +91 -51
- package/catalog/frontmcp-development/references/create-resource.md +3 -3
- package/catalog/frontmcp-development/references/create-skill.md +2 -2
- package/catalog/frontmcp-development/references/create-tool.md +7 -7
- package/catalog/frontmcp-development/references/create-workflow.md +8 -10
- package/catalog/frontmcp-development/references/decorators-guide.md +92 -56
- package/catalog/frontmcp-development/references/official-plugins.md +4 -3
- package/catalog/frontmcp-development/references/openapi-adapter.md +1 -1
- package/catalog/frontmcp-extensibility/SKILL.md +70 -10
- package/catalog/frontmcp-extensibility/examples/skill-audit-log/custom-store.md +197 -0
- package/catalog/frontmcp-extensibility/examples/skill-audit-log/verify-chain.md +68 -0
- package/catalog/frontmcp-extensibility/examples/vectoriadb/product-catalog-search.md +3 -5
- package/catalog/frontmcp-extensibility/examples/vectoriadb/semantic-search-with-persistence.md +4 -11
- package/catalog/frontmcp-extensibility/examples/vectoriadb/tfidf-keyword-search.md +41 -30
- package/catalog/frontmcp-extensibility/references/skill-audit-log.md +233 -0
- package/catalog/frontmcp-extensibility/references/vectoriadb.md +73 -63
- package/catalog/frontmcp-guides/SKILL.md +84 -27
- package/catalog/frontmcp-guides/examples/example-knowledge-base/agent-and-plugin.md +72 -62
- package/catalog/frontmcp-guides/examples/example-knowledge-base/vector-search-and-resources.md +32 -43
- package/catalog/frontmcp-guides/examples/example-task-manager/auth-and-crud-tools.md +24 -17
- package/catalog/frontmcp-guides/examples/example-task-manager/authenticated-e2e-tests.md +23 -21
- package/catalog/frontmcp-guides/examples/example-task-manager/redis-provider-with-di.md +47 -39
- package/catalog/frontmcp-guides/examples/example-weather-api/server-and-app-setup.md +16 -6
- package/catalog/frontmcp-guides/examples/example-weather-api/unit-and-e2e-tests.md +9 -8
- package/catalog/frontmcp-guides/references/example-knowledge-base.md +192 -265
- package/catalog/frontmcp-guides/references/example-task-manager.md +60 -54
- package/catalog/frontmcp-guides/references/example-weather-api.md +22 -24
- package/catalog/frontmcp-observability/SKILL.md +66 -2
- package/catalog/frontmcp-observability/examples/telemetry-api/skill-counters.md +100 -0
- package/catalog/frontmcp-observability/examples/tracing-setup/production-tracing.md +7 -2
- package/catalog/frontmcp-observability/examples/vendor-integrations/coralogix-setup.md +6 -2
- package/catalog/frontmcp-observability/references/telemetry-api.md +72 -8
- package/catalog/frontmcp-observability/references/testing-observability.md +33 -49
- package/catalog/frontmcp-observability/references/tracing-setup.md +12 -5
- package/catalog/frontmcp-observability/references/vendor-integrations.md +46 -1
- package/catalog/frontmcp-production-readiness/SKILL.md +134 -3
- package/catalog/frontmcp-production-readiness/examples/common-checklist/caching-and-performance.md +57 -36
- package/catalog/frontmcp-production-readiness/examples/common-checklist/observability-setup.md +1 -1
- package/catalog/frontmcp-production-readiness/examples/common-checklist/security-hardening.md +102 -6
- package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/daemon-socket-config.md +2 -1
- package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/graceful-shutdown-cleanup.md +66 -58
- package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/security-and-permissions.md +5 -3
- package/catalog/frontmcp-production-readiness/examples/production-cloudflare/durable-objects-state.md +2 -1
- package/catalog/frontmcp-production-readiness/examples/production-cloudflare/wrangler-config.md +55 -76
- package/catalog/frontmcp-production-readiness/examples/production-lambda/cold-start-connection-reuse.md +43 -40
- package/catalog/frontmcp-production-readiness/examples/production-lambda/sam-template.md +63 -94
- package/catalog/frontmcp-production-readiness/examples/production-lambda/scaling-and-monitoring.md +28 -18
- package/catalog/frontmcp-production-readiness/examples/production-node-sdk/multi-instance-cleanup.md +29 -14
- package/catalog/frontmcp-production-readiness/examples/production-node-server/graceful-shutdown.md +58 -42
- package/catalog/frontmcp-production-readiness/examples/production-node-server/redis-session-scaling.md +5 -2
- package/catalog/frontmcp-production-readiness/examples/production-vercel/cold-start-optimization.md +41 -24
- package/catalog/frontmcp-production-readiness/examples/production-vercel/vercel-edge-config.md +56 -65
- package/catalog/frontmcp-production-readiness/references/common-checklist.md +17 -5
- package/catalog/frontmcp-production-readiness/references/production-cli-daemon.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-cloudflare.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-lambda.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-node-sdk.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-node-server.md +1 -1
- package/catalog/frontmcp-production-readiness/references/production-vercel.md +5 -5
- package/catalog/frontmcp-setup/SKILL.md +88 -0
- package/catalog/frontmcp-setup/examples/project-structure-nx/nx-workspace-with-apps.md +10 -4
- package/catalog/frontmcp-setup/examples/project-structure-standalone/dev-workflow-commands.md +21 -8
- package/catalog/frontmcp-setup/examples/readme-guide/node-server-readme.md +3 -3
- package/catalog/frontmcp-setup/references/multi-app-composition.md +4 -3
- package/catalog/frontmcp-setup/references/project-structure-nx.md +15 -6
- package/catalog/frontmcp-setup/references/project-structure-standalone.md +18 -15
- package/catalog/frontmcp-setup/references/readme-guide.md +1 -1
- package/catalog/frontmcp-setup/references/setup-project.md +19 -5
- package/catalog/frontmcp-setup/references/setup-redis.md +27 -39
- package/catalog/frontmcp-setup/references/setup-sqlite.md +25 -18
- package/catalog/frontmcp-testing/SKILL.md +102 -15
- package/catalog/frontmcp-testing/examples/setup-testing/unit-test-tool-resource-prompt.md +3 -3
- package/catalog/frontmcp-testing/examples/test-auth/oauth-flow-test.md +50 -39
- package/catalog/frontmcp-testing/examples/test-auth/role-based-access-test.md +52 -29
- package/catalog/frontmcp-testing/examples/test-auth/token-factory-test.md +37 -20
- package/catalog/frontmcp-testing/examples/test-direct-client/basic-create-test.md +25 -15
- package/catalog/frontmcp-testing/examples/test-direct-client/openai-claude-format-test.md +27 -21
- package/catalog/frontmcp-testing/examples/test-e2e-handler/basic-e2e-test.md +29 -20
- package/catalog/frontmcp-testing/examples/test-e2e-handler/manual-client-with-transport.md +5 -3
- package/catalog/frontmcp-testing/examples/test-e2e-handler/tool-call-and-error-e2e.md +35 -26
- package/catalog/frontmcp-testing/examples/test-tool-unit/basic-tool-test.md +8 -3
- package/catalog/frontmcp-testing/examples/test-tool-unit/schema-validation-test.md +4 -1
- package/catalog/frontmcp-testing/examples/test-tool-unit/tool-error-handling-test.md +6 -3
- package/catalog/frontmcp-testing/references/setup-testing.md +35 -39
- package/catalog/frontmcp-testing/references/test-auth.md +86 -43
- package/catalog/frontmcp-testing/references/test-browser-build.md +1 -1
- package/catalog/frontmcp-testing/references/test-direct-client.md +29 -19
- package/catalog/frontmcp-testing/references/test-e2e-handler.md +31 -19
- package/catalog/frontmcp-testing/references/test-tool-unit.md +6 -2
- package/catalog/skills-manifest.json +428 -339
- package/package.json +1 -1
- package/src/manifest.d.ts +13 -0
- package/src/manifest.js.map +1 -1
|
@@ -38,22 +38,38 @@ Entry point for testing FrontMCP applications. This skill helps you navigate tes
|
|
|
38
38
|
|
|
39
39
|
> **Decision:** Use this skill for testing strategy and routing. Use `setup-testing` for hands-on Jest configuration and test writing.
|
|
40
40
|
|
|
41
|
+
## Prerequisites
|
|
42
|
+
|
|
43
|
+
- A FrontMCP project with at least one component to test (see `frontmcp-development`).
|
|
44
|
+
- Jest installed and configured — if not, start with `setup-testing` before opening any other testing skill.
|
|
45
|
+
- The component itself implemented and exported; tests reach decorated classes through the SDK, not by importing internal builders.
|
|
46
|
+
|
|
47
|
+
## Steps
|
|
48
|
+
|
|
49
|
+
This is a router skill. Follow this order to pick a testing approach, then move to the target skill.
|
|
50
|
+
|
|
51
|
+
1. **Pick the test layer** — unit (fastest, mock DI), integration (real DI scope), or E2E (real MCP client + server). Use the Testing Strategy table below.
|
|
52
|
+
2. **Pick the component flavour** — tool / resource / prompt / agent / job — each has a distinct recipe.
|
|
53
|
+
3. **Pick the runtime concern** — auth, browser/CLI build, direct vs streamable transport — and add the matching skill to your reading list.
|
|
54
|
+
4. **Open the target skill** (e.g. `test-tool-unit`, `test-e2e-handler`, `test-auth`) and follow its Steps section.
|
|
55
|
+
5. **Enforce coverage** — confirm the project's 95%+ thresholds are wired into Jest before merging (see `setup-testing`).
|
|
56
|
+
|
|
41
57
|
## Scenario Routing Table
|
|
42
58
|
|
|
43
|
-
| Scenario | Skill / Section | Description
|
|
44
|
-
| --------------------------------------- | ------------------------------- |
|
|
45
|
-
| Set up Jest, coverage, and test harness | `setup-testing` | Full Jest config, test utilities, and coverage thresholds
|
|
46
|
-
| Write unit tests for a tool | `
|
|
47
|
-
| Write unit tests for a resource | `setup-testing` (Unit Testing) | Test URI resolution, template params, read results
|
|
48
|
-
| Write unit tests for a prompt | `setup-testing` (Unit Testing) | Test argument handling, message generation
|
|
49
|
-
| Write E2E protocol-level tests | `setup-testing` (E2E Testing) | Real MCP client/server, full protocol flow
|
|
50
|
-
| Test authenticated endpoints | `test-auth` | E2E with OAuth tokens, session validation, role-based access
|
|
51
|
-
| Test deployment builds | `setup-testing` + `deploy-to-*` | Smoke tests against built output
|
|
52
|
-
| Test browser builds | `test-browser-build` |
|
|
53
|
-
| Test CLI binary builds | `test-cli-binary` |
|
|
54
|
-
| Test with the direct API client | `test-direct-client` |
|
|
55
|
-
| Write E2E test handler patterns | `test-e2e-handler` | E2E
|
|
56
|
-
| Unit test individual tools | `test-tool-unit` | Unit testing individual
|
|
59
|
+
| Scenario | Skill / Section | Description |
|
|
60
|
+
| --------------------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
61
|
+
| Set up Jest, coverage, and test harness | `setup-testing` | Full Jest config, test utilities, and coverage thresholds |
|
|
62
|
+
| Write unit tests for a tool | `test-tool-unit` | Mock DI, validate input/output, test error paths |
|
|
63
|
+
| Write unit tests for a resource | `setup-testing` (Unit Testing) | Test URI resolution, template params, read results |
|
|
64
|
+
| Write unit tests for a prompt | `setup-testing` (Unit Testing) | Test argument handling, message generation |
|
|
65
|
+
| Write E2E protocol-level tests | `setup-testing` (E2E Testing) | Real MCP client/server, full protocol flow |
|
|
66
|
+
| Test authenticated endpoints | `test-auth` | E2E with OAuth tokens, session validation, role-based access |
|
|
67
|
+
| Test deployment builds | `setup-testing` + `deploy-to-*` | Smoke tests against built output |
|
|
68
|
+
| Test browser builds | `test-browser-build` | Smoke-test a `frontmcp build --target browser` bundle (import the bundle, optional Playwright suite) |
|
|
69
|
+
| Test CLI binary builds | `test-cli-binary` | Spawn-and-curl smoke tests for `frontmcp build --target cli` artifacts |
|
|
70
|
+
| Test with the direct API client | `test-direct-client` | In-memory testing via `create()`, `connectOpenAI()`, `connectClaude()` (no HTTP) |
|
|
71
|
+
| Write E2E test handler patterns | `test-e2e-handler` | Manual `McpTestClient` + `TestServer` E2E patterns (alternative to fixture API) |
|
|
72
|
+
| Unit test individual tools | `test-tool-unit` | Unit testing individual `ToolContext` subclasses with a mock context |
|
|
57
73
|
|
|
58
74
|
## Testing Strategy by Component Type
|
|
59
75
|
|
|
@@ -75,7 +91,7 @@ Entry point for testing FrontMCP applications. This skill helps you navigate tes
|
|
|
75
91
|
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
76
92
|
| File naming | Always `.spec.ts` (not `.test.ts`); E2E uses `.e2e.spec.ts` |
|
|
77
93
|
| 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` |
|
|
78
|
-
| Test runner |
|
|
94
|
+
| Test runner | Standalone projects: use `frontmcp test` (auto-generates Jest/SWC config). Nx monorepos: use `nx test <lib>` (resolves the project's `jest.config.ts`). Never invoke `jest --config ...` directly |
|
|
79
95
|
| Coverage threshold | 95%+ across statements, branches, functions, lines |
|
|
80
96
|
| Test descriptions | Plain English, no prefixes like "PT-001"; describe behavior not implementation |
|
|
81
97
|
| Mocking | Mock providers via DI token replacement, never mock the framework |
|
|
@@ -129,6 +145,77 @@ Entry point for testing FrontMCP applications. This skill helps you navigate tes
|
|
|
129
145
|
| DI resolution fails in tests | Provider not registered in test scope | Register mock providers before creating the test context |
|
|
130
146
|
| 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 |
|
|
131
147
|
|
|
148
|
+
## Examples
|
|
149
|
+
|
|
150
|
+
Each reference has matching examples under [`examples/<reference>/`](./examples/):
|
|
151
|
+
|
|
152
|
+
### `setup-testing`
|
|
153
|
+
|
|
154
|
+
| Example | Level | Description |
|
|
155
|
+
| ---------------------------------------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
156
|
+
| [`fixture-based-e2e-test`](./examples/setup-testing/fixture-based-e2e-test.md) | Advanced | Write E2E tests using the fixture API from `@frontmcp/testing` that manages server lifecycle automatically and uses MCP-specific custom matchers. |
|
|
157
|
+
| [`jest-config-with-coverage`](./examples/setup-testing/jest-config-with-coverage.md) | Basic | Set up a Jest configuration file that enforces 95%+ coverage across all metrics for a FrontMCP library. |
|
|
158
|
+
| [`unit-test-tool-resource-prompt`](./examples/setup-testing/unit-test-tool-resource-prompt.md) | Intermediate | Write unit tests for the three core MCP primitives, verifying that outputs match the expected MCP response shapes. |
|
|
159
|
+
|
|
160
|
+
### `test-auth`
|
|
161
|
+
|
|
162
|
+
| Example | Level | Description |
|
|
163
|
+
| -------------------------------------------------------------------------- | ------------ | --------------------------------------------------------------------------------------------------------- |
|
|
164
|
+
| [`oauth-flow-test`](./examples/test-auth/oauth-flow-test.md) | Advanced | Use `MockOAuthServer` to simulate an OAuth identity provider and test the authorization code flow. |
|
|
165
|
+
| [`role-based-access-test`](./examples/test-auth/role-based-access-test.md) | Intermediate | Verify that tools enforce role-based access by testing admin and user tokens against protected endpoints. |
|
|
166
|
+
| [`token-factory-test`](./examples/test-auth/token-factory-test.md) | Basic | Use `TestTokenFactory` to create tokens and verify authenticated and unauthenticated requests. |
|
|
167
|
+
|
|
168
|
+
### `test-browser-build`
|
|
169
|
+
|
|
170
|
+
| Example | Level | Description |
|
|
171
|
+
| ----------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------ |
|
|
172
|
+
| [`browser-bundle-validation`](./examples/test-browser-build/browser-bundle-validation.md) | Basic | Verify that the browser build produces a valid bundle without Node.js-only module references. |
|
|
173
|
+
| [`playwright-browser-test`](./examples/test-browser-build/playwright-browser-test.md) | Advanced | Use Playwright to test a browser-based MCP client that loads and calls tools from an MCP server. |
|
|
174
|
+
|
|
175
|
+
### `test-cli-binary`
|
|
176
|
+
|
|
177
|
+
| Example | Level | Description |
|
|
178
|
+
| ------------------------------------------------------------------------------ | ------------ | ------------------------------------------------------------------------------------------------------------------ |
|
|
179
|
+
| [`binary-startup-test`](./examples/test-cli-binary/binary-startup-test.md) | Basic | Verify that a compiled CLI binary starts correctly and responds to health checks. |
|
|
180
|
+
| [`js-bundle-import-test`](./examples/test-cli-binary/js-bundle-import-test.md) | Intermediate | Verify that the compiled JS bundle can be imported and exports the expected modules after a `frontmcp build` step. |
|
|
181
|
+
|
|
182
|
+
### `test-direct-client`
|
|
183
|
+
|
|
184
|
+
| Example | Level | Description |
|
|
185
|
+
| ----------------------------------------------------------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
186
|
+
| [`basic-create-test`](./examples/test-direct-client/basic-create-test.md) | Basic | Test tools in-memory without any HTTP overhead using the `create()` function from `@frontmcp/sdk`. |
|
|
187
|
+
| [`openai-claude-format-test`](./examples/test-direct-client/openai-claude-format-test.md) | Intermediate | Verify that tools are returned in the correct format for OpenAI and Claude clients using `connectOpenAI` and `connectClaude`. |
|
|
188
|
+
|
|
189
|
+
### `test-e2e-handler`
|
|
190
|
+
|
|
191
|
+
| Example | Level | Description |
|
|
192
|
+
| --------------------------------------------------------------------------------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------- |
|
|
193
|
+
| [`basic-e2e-test`](./examples/test-e2e-handler/basic-e2e-test.md) | Basic | Set up a basic E2E test that starts a server, connects a client, and verifies tools are listed. |
|
|
194
|
+
| [`manual-client-with-transport`](./examples/test-e2e-handler/manual-client-with-transport.md) | Advanced | Use `McpTestClient.create()` with explicit transport settings for fine-grained control over E2E tests. |
|
|
195
|
+
| [`tool-call-and-error-e2e`](./examples/test-e2e-handler/tool-call-and-error-e2e.md) | Intermediate | Test successful tool calls and verify that invalid inputs produce proper error responses over the full MCP protocol. |
|
|
196
|
+
|
|
197
|
+
### `test-tool-unit`
|
|
198
|
+
|
|
199
|
+
| Example | Level | Description |
|
|
200
|
+
| ----------------------------------------------------------------------------------- | ------------ | -------------------------------------------------------------------------------------------------------- |
|
|
201
|
+
| [`basic-tool-test`](./examples/test-tool-unit/basic-tool-test.md) | Basic | Test a simple tool's `execute()` method with mock context and verify the output. |
|
|
202
|
+
| [`schema-validation-test`](./examples/test-tool-unit/schema-validation-test.md) | Intermediate | Validate that a tool's Zod input schema rejects invalid data before `execute()` is called. |
|
|
203
|
+
| [`tool-error-handling-test`](./examples/test-tool-unit/tool-error-handling-test.md) | Advanced | Test that a tool throws the correct MCP error classes with proper error codes and JSON-RPC error shapes. |
|
|
204
|
+
|
|
205
|
+
## Accessing This Skill
|
|
206
|
+
|
|
207
|
+
Skills are distributed as plain SKILL.md files plus a sibling `references/`
|
|
208
|
+
and `examples/` tree, so consumers can pick whichever access mode fits:
|
|
209
|
+
|
|
210
|
+
| Mode | How it works |
|
|
211
|
+
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
212
|
+
| **Filesystem** | Read `libs/skills/catalog/frontmcp-testing/` directly from a clone of the catalog repo, or from a published `@frontmcp/skills` install. SKILL.md is the entry point. |
|
|
213
|
+
| **`frontmcp` CLI** | `frontmcp skills list`, `frontmcp skills read frontmcp-testing`, `frontmcp skills read frontmcp-testing:references/<file>.md`, `frontmcp skills install frontmcp-testing` — no server required. |
|
|
214
|
+
| **MCP `skill://`** | When a developer mounts this skill into their own FrontMCP server (`@FrontMcp({ skills: [...] })`), the SDK exposes it via SEP-2640 resources: `skill://frontmcp-testing/SKILL.md`, `skill://frontmcp-testing/references/{file}.md`, etc. The server’s `skill://index.json` returns the SEP-2640 discovery document for everything mounted on it. |
|
|
215
|
+
|
|
216
|
+
The catalog itself is **not** an MCP server. The `skill://` URIs only resolve
|
|
217
|
+
when a server has been configured to host this skill.
|
|
218
|
+
|
|
132
219
|
## Reference
|
|
133
220
|
|
|
134
221
|
- [Testing Documentation](https://docs.agentfront.dev/frontmcp/testing/overview)
|
|
@@ -6,7 +6,7 @@ description: 'Write unit tests for the three core MCP primitives, verifying that
|
|
|
6
6
|
tags: [testing, jest, unit-test, setup, unit, tool]
|
|
7
7
|
features:
|
|
8
8
|
- 'Testing tool `execute()` with a mock context object assigned via `Object.assign`'
|
|
9
|
-
- 'Verifying resource `
|
|
9
|
+
- 'Verifying resource `execute(uri, params)` output matches the MCP `ReadResourceResult` shape'
|
|
10
10
|
- 'Verifying prompt `execute()` output matches the MCP `GetPromptResult` shape'
|
|
11
11
|
- 'Using Jest matchers like `expect.stringContaining` and `expect.objectContaining` for flexible assertions'
|
|
12
12
|
---
|
|
@@ -66,7 +66,7 @@ import { MyResource } from '../my-resource';
|
|
|
66
66
|
describe('MyResource', () => {
|
|
67
67
|
it('should return resource contents matching ReadResourceResult', async () => {
|
|
68
68
|
const resource = new MyResource();
|
|
69
|
-
const result = await resource.
|
|
69
|
+
const result = await resource.execute('resource://item/123', { id: '123' });
|
|
70
70
|
|
|
71
71
|
expect(result).toEqual({
|
|
72
72
|
contents: [
|
|
@@ -105,7 +105,7 @@ describe('MyPrompt', () => {
|
|
|
105
105
|
## What This Demonstrates
|
|
106
106
|
|
|
107
107
|
- Testing tool `execute()` with a mock context object assigned via `Object.assign`
|
|
108
|
-
- Verifying resource `
|
|
108
|
+
- Verifying resource `execute(uri, params)` output matches the MCP `ReadResourceResult` shape
|
|
109
109
|
- Verifying prompt `execute()` output matches the MCP `GetPromptResult` shape
|
|
110
110
|
- Using Jest matchers like `expect.stringContaining` and `expect.objectContaining` for flexible assertions
|
|
111
111
|
|
|
@@ -2,76 +2,87 @@
|
|
|
2
2
|
name: oauth-flow-test
|
|
3
3
|
reference: test-auth
|
|
4
4
|
level: advanced
|
|
5
|
-
description:
|
|
6
|
-
tags:
|
|
5
|
+
description: Use `MockOAuthServer` to simulate an OAuth/OIDC identity provider. The server publishes a JWKS endpoint backed by your `TestTokenFactory`, so any token created by that factory is valid against the mock IDP.
|
|
6
|
+
tags:
|
|
7
|
+
- testing
|
|
8
|
+
- oauth
|
|
9
|
+
- auth
|
|
10
|
+
- flow
|
|
7
11
|
features:
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- 'Proper cleanup with `mockOAuth.close()` in `afterAll`'
|
|
12
|
+
- Constructing `MockOAuthServer` with a `TestTokenFactory` and starting it with `.start()`
|
|
13
|
+
- Reading server info from `mockOAuth.info.baseUrl` / `mockOAuth.info.jwksUrl` after start
|
|
14
|
+
- Issuing tokens via the same `TestTokenFactory` so the mock JWKS can verify them
|
|
15
|
+
- Cleaning up with `mockOAuth.stop()` in `afterAll`
|
|
13
16
|
---
|
|
14
17
|
|
|
15
|
-
# Testing
|
|
18
|
+
# Testing with the Mock OAuth Server
|
|
16
19
|
|
|
17
|
-
Use `MockOAuthServer` to simulate an OAuth identity provider
|
|
20
|
+
Use `MockOAuthServer` to simulate an OAuth/OIDC identity provider. The server publishes a JWKS endpoint backed by your `TestTokenFactory`, so any token created by that factory is valid against the mock IDP.
|
|
18
21
|
|
|
19
22
|
## Code
|
|
20
23
|
|
|
21
24
|
```typescript
|
|
22
25
|
// src/__tests__/oauth-flow.e2e.spec.ts
|
|
23
|
-
|
|
26
|
+
// Real API:
|
|
27
|
+
// libs/testing/src/auth/mock-oauth-server.ts:159 — `new MockOAuthServer(tokenFactory, options)` + `.start()` / `.stop()`
|
|
28
|
+
// libs/testing/src/auth/token-factory.ts:97 — `TestTokenFactory.createTestToken(opts)`
|
|
29
|
+
import { MockOAuthServer, TestTokenFactory } from '@frontmcp/testing';
|
|
24
30
|
|
|
25
|
-
describe('OAuth
|
|
31
|
+
describe('Mock OAuth Server', () => {
|
|
32
|
+
let tokenFactory: TestTokenFactory;
|
|
26
33
|
let mockOAuth: MockOAuthServer;
|
|
27
34
|
|
|
28
35
|
beforeAll(async () => {
|
|
29
|
-
|
|
36
|
+
tokenFactory = new TestTokenFactory({
|
|
30
37
|
issuer: 'https://test-idp.example.com',
|
|
31
|
-
|
|
38
|
+
audience: 'my-api',
|
|
32
39
|
});
|
|
40
|
+
|
|
41
|
+
mockOAuth = new MockOAuthServer(tokenFactory, {
|
|
42
|
+
autoApprove: true,
|
|
43
|
+
testUser: { sub: 'user-123', email: 'test@example.com' },
|
|
44
|
+
clientId: 'test-client',
|
|
45
|
+
validRedirectUris: ['http://localhost:3001/callback'],
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
await mockOAuth.start();
|
|
33
49
|
});
|
|
34
50
|
|
|
35
51
|
afterAll(async () => {
|
|
36
|
-
await mockOAuth.
|
|
52
|
+
await mockOAuth.stop();
|
|
37
53
|
});
|
|
38
54
|
|
|
39
|
-
it('
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
expect(authorizationUrl).toContain('code=');
|
|
55
|
+
it('exposes a JWKS endpoint with at least one key', async () => {
|
|
56
|
+
const res = await fetch(mockOAuth.info.jwksUrl);
|
|
57
|
+
const jwks = (await res.json()) as { keys: Array<{ kid: string }> };
|
|
58
|
+
|
|
59
|
+
expect(res.status).toBe(200);
|
|
60
|
+
expect(jwks.keys.length).toBeGreaterThan(0);
|
|
46
61
|
});
|
|
47
62
|
|
|
48
|
-
it('
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
scopes: ['openid'],
|
|
63
|
+
it('issues tokens via the same factory the mock server trusts', async () => {
|
|
64
|
+
const token = await tokenFactory.createTestToken({
|
|
65
|
+
sub: 'user-123',
|
|
66
|
+
scopes: ['openid', 'profile'],
|
|
53
67
|
});
|
|
54
68
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
scopes: ['openid', 'email'],
|
|
59
|
-
});
|
|
69
|
+
expect(typeof token).toBe('string');
|
|
70
|
+
expect(token.split('.')).toHaveLength(3);
|
|
71
|
+
});
|
|
60
72
|
|
|
61
|
-
|
|
62
|
-
expect(
|
|
63
|
-
expect(
|
|
73
|
+
it('reports server info after start', () => {
|
|
74
|
+
expect(mockOAuth.info.baseUrl).toMatch(/^http:\/\/localhost:\d+$/);
|
|
75
|
+
expect(mockOAuth.info.jwksUrl).toBe(`${mockOAuth.info.baseUrl}/.well-known/jwks.json`);
|
|
64
76
|
});
|
|
65
77
|
});
|
|
66
78
|
```
|
|
67
79
|
|
|
68
80
|
## What This Demonstrates
|
|
69
81
|
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
- Proper cleanup with `mockOAuth.close()` in `afterAll`
|
|
82
|
+
- Constructing `MockOAuthServer` with a `TestTokenFactory` and starting it with `.start()`
|
|
83
|
+
- Reading server info from `mockOAuth.info.baseUrl` / `mockOAuth.info.jwksUrl` after start
|
|
84
|
+
- Issuing tokens via the same `TestTokenFactory` so the mock JWKS can verify them
|
|
85
|
+
- Cleaning up with `mockOAuth.stop()` in `afterAll`
|
|
75
86
|
|
|
76
87
|
## Related
|
|
77
88
|
|
|
@@ -3,12 +3,12 @@ name: role-based-access-test
|
|
|
3
3
|
reference: test-auth
|
|
4
4
|
level: intermediate
|
|
5
5
|
description: 'Verify that tools enforce role-based access by testing admin and user tokens against protected endpoints.'
|
|
6
|
-
tags: [testing, auth, role
|
|
6
|
+
tags: [testing, auth, role-based-access]
|
|
7
7
|
features:
|
|
8
|
-
- '
|
|
8
|
+
- 'Putting roles inside `claims` (the `CreateTokenOptions` shape has no top-level `roles` field)'
|
|
9
9
|
- 'Testing that admin-only tools accept admin tokens and reject user tokens'
|
|
10
10
|
- 'Verifying that user-level tools remain accessible to users with the correct role'
|
|
11
|
-
- 'Each test creates and
|
|
11
|
+
- 'Each test creates and disconnects its own client for proper isolation'
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# Testing Role-Based Access Control
|
|
@@ -19,15 +19,22 @@ Verify that tools enforce role-based access by testing admin and user tokens aga
|
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
21
|
// src/__tests__/rbac.e2e.spec.ts
|
|
22
|
+
// Real API:
|
|
23
|
+
// libs/testing/src/server/test-server.ts:101 — `TestServer.start({ command, port })`
|
|
24
|
+
// libs/testing/src/auth/token-factory.ts:97 — `TestTokenFactory.createTestToken({ sub, scopes, claims })`
|
|
25
|
+
// libs/testing/src/client/mcp-test-client.builder.ts — `McpTestClient.create(...).withToken(...).buildAndConnect()`
|
|
26
|
+
// libs/testing/src/client/mcp-test-client.ts:306 — namespaced client API: `client.tools.call(name, args)`
|
|
22
27
|
import { McpTestClient, TestServer, TestTokenFactory } from '@frontmcp/testing';
|
|
23
|
-
import Server from '../src/main';
|
|
24
28
|
|
|
25
29
|
describe('Role-Based Access', () => {
|
|
26
30
|
let server: TestServer;
|
|
27
31
|
let tokenFactory: TestTokenFactory;
|
|
28
32
|
|
|
29
33
|
beforeAll(async () => {
|
|
30
|
-
server = await TestServer.
|
|
34
|
+
server = await TestServer.start({
|
|
35
|
+
command: 'npx tsx src/main.ts',
|
|
36
|
+
port: 3011,
|
|
37
|
+
});
|
|
31
38
|
tokenFactory = new TestTokenFactory({
|
|
32
39
|
issuer: 'https://test-idp.example.com',
|
|
33
40
|
audience: 'my-api',
|
|
@@ -35,53 +42,69 @@ describe('Role-Based Access', () => {
|
|
|
35
42
|
});
|
|
36
43
|
|
|
37
44
|
afterAll(async () => {
|
|
38
|
-
await server.
|
|
45
|
+
await server.stop();
|
|
39
46
|
});
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
async function clientWithToken(token: string): Promise<McpTestClient> {
|
|
49
|
+
return McpTestClient.create({ baseUrl: server.info.baseUrl })
|
|
50
|
+
.withTransport('streamable-http')
|
|
51
|
+
.withToken(token)
|
|
52
|
+
.buildAndConnect();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
it('allows admin access to an admin-only tool', async () => {
|
|
56
|
+
const adminToken = await tokenFactory.createTestToken({
|
|
43
57
|
sub: 'admin-1',
|
|
44
|
-
roles: ['admin'],
|
|
58
|
+
claims: { roles: ['admin'] },
|
|
45
59
|
});
|
|
46
60
|
|
|
47
|
-
const client = await
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
const client = await clientWithToken(adminToken);
|
|
62
|
+
try {
|
|
63
|
+
const result = await client.tools.call('admin_only_tool', {});
|
|
64
|
+
expect(result).toBeSuccessful();
|
|
65
|
+
} finally {
|
|
66
|
+
await client.disconnect();
|
|
67
|
+
}
|
|
51
68
|
});
|
|
52
69
|
|
|
53
|
-
it('
|
|
54
|
-
const userToken = await tokenFactory.
|
|
70
|
+
it('denies user access to an admin-only tool', async () => {
|
|
71
|
+
const userToken = await tokenFactory.createTestToken({
|
|
55
72
|
sub: 'user-1',
|
|
56
|
-
roles: ['user'],
|
|
73
|
+
claims: { roles: ['user'] },
|
|
57
74
|
});
|
|
58
75
|
|
|
59
|
-
const client = await
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
76
|
+
const client = await clientWithToken(userToken);
|
|
77
|
+
try {
|
|
78
|
+
const result = await client.tools.call('admin_only_tool', {});
|
|
79
|
+
expect(result).toBeError();
|
|
80
|
+
} finally {
|
|
81
|
+
await client.disconnect();
|
|
82
|
+
}
|
|
63
83
|
});
|
|
64
84
|
|
|
65
|
-
it('
|
|
66
|
-
const userToken = await tokenFactory.
|
|
85
|
+
it('allows user access to a user-level tool', async () => {
|
|
86
|
+
const userToken = await tokenFactory.createTestToken({
|
|
67
87
|
sub: 'user-2',
|
|
68
|
-
roles: ['user'],
|
|
88
|
+
claims: { roles: ['user'] },
|
|
69
89
|
});
|
|
70
90
|
|
|
71
|
-
const client = await
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
91
|
+
const client = await clientWithToken(userToken);
|
|
92
|
+
try {
|
|
93
|
+
const result = await client.tools.call('user_tool', { data: 'hello' });
|
|
94
|
+
expect(result).toBeSuccessful();
|
|
95
|
+
} finally {
|
|
96
|
+
await client.disconnect();
|
|
97
|
+
}
|
|
75
98
|
});
|
|
76
99
|
});
|
|
77
100
|
```
|
|
78
101
|
|
|
79
102
|
## What This Demonstrates
|
|
80
103
|
|
|
81
|
-
-
|
|
104
|
+
- Putting roles inside `claims` (the `CreateTokenOptions` shape has no top-level `roles` field)
|
|
82
105
|
- Testing that admin-only tools accept admin tokens and reject user tokens
|
|
83
106
|
- Verifying that user-level tools remain accessible to users with the correct role
|
|
84
|
-
- Each test creates and
|
|
107
|
+
- Each test creates and disconnects its own client for proper isolation
|
|
85
108
|
|
|
86
109
|
## Related
|
|
87
110
|
|
|
@@ -3,12 +3,12 @@ name: token-factory-test
|
|
|
3
3
|
reference: test-auth
|
|
4
4
|
level: basic
|
|
5
5
|
description: 'Use `TestTokenFactory` to create tokens and verify authenticated and unauthenticated requests.'
|
|
6
|
-
tags: [testing, auth, token
|
|
6
|
+
tags: [testing, auth, token-factory]
|
|
7
7
|
features:
|
|
8
8
|
- 'Creating a `TestTokenFactory` with issuer and audience configuration'
|
|
9
|
-
- 'Generating test tokens with specific subjects and scopes via `
|
|
10
|
-
- '
|
|
11
|
-
- '
|
|
9
|
+
- 'Generating test tokens with specific subjects and scopes via `createTestToken()`'
|
|
10
|
+
- 'Building authenticated clients with `McpTestClient.create(...).withToken(token)`'
|
|
11
|
+
- 'Using `.withPublicMode()` to suppress the anonymous token request and test unauthenticated rejection'
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# Testing Authentication with TestTokenFactory
|
|
@@ -19,15 +19,21 @@ Use `TestTokenFactory` to create tokens and verify authenticated and unauthentic
|
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
21
|
// src/__tests__/auth.e2e.spec.ts
|
|
22
|
+
// Real API:
|
|
23
|
+
// libs/testing/src/server/test-server.ts:101 — `TestServer.start({ command, port })`
|
|
24
|
+
// libs/testing/src/auth/token-factory.ts:97 — `TestTokenFactory.createTestToken({ sub, scopes, claims })`
|
|
25
|
+
// libs/testing/src/client/mcp-test-client.builder.ts — `withToken`, `withPublicMode`, `buildAndConnect`
|
|
22
26
|
import { McpTestClient, TestServer, TestTokenFactory } from '@frontmcp/testing';
|
|
23
|
-
import Server from '../src/main';
|
|
24
27
|
|
|
25
28
|
describe('Authenticated Server', () => {
|
|
26
29
|
let server: TestServer;
|
|
27
30
|
let tokenFactory: TestTokenFactory;
|
|
28
31
|
|
|
29
32
|
beforeAll(async () => {
|
|
30
|
-
server = await TestServer.
|
|
33
|
+
server = await TestServer.start({
|
|
34
|
+
command: 'npx tsx src/main.ts',
|
|
35
|
+
port: 3012,
|
|
36
|
+
});
|
|
31
37
|
tokenFactory = new TestTokenFactory({
|
|
32
38
|
issuer: 'https://test-idp.example.com',
|
|
33
39
|
audience: 'my-api',
|
|
@@ -35,26 +41,37 @@ describe('Authenticated Server', () => {
|
|
|
35
41
|
});
|
|
36
42
|
|
|
37
43
|
afterAll(async () => {
|
|
38
|
-
await server.
|
|
44
|
+
await server.stop();
|
|
39
45
|
});
|
|
40
46
|
|
|
41
|
-
it('
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
it('rejects unauthenticated requests', async () => {
|
|
48
|
+
// withPublicMode() = no Authorization header, no anonymous-token request.
|
|
49
|
+
const client = await McpTestClient.create({ baseUrl: server.info.baseUrl })
|
|
50
|
+
.withTransport('streamable-http')
|
|
51
|
+
.withPublicMode()
|
|
52
|
+
.buildAndConnect();
|
|
53
|
+
|
|
54
|
+
const result = await client.tools.call('protected_tool', {});
|
|
55
|
+
expect(result).toBeError();
|
|
56
|
+
|
|
57
|
+
await client.disconnect();
|
|
46
58
|
});
|
|
47
59
|
|
|
48
|
-
it('
|
|
49
|
-
const token = await tokenFactory.
|
|
60
|
+
it('accepts a valid token', async () => {
|
|
61
|
+
const token = await tokenFactory.createTestToken({
|
|
50
62
|
sub: 'user-123',
|
|
51
63
|
scopes: ['read', 'write'],
|
|
52
64
|
});
|
|
53
65
|
|
|
54
|
-
const client = await
|
|
55
|
-
|
|
66
|
+
const client = await McpTestClient.create({ baseUrl: server.info.baseUrl })
|
|
67
|
+
.withTransport('streamable-http')
|
|
68
|
+
.withToken(token)
|
|
69
|
+
.buildAndConnect();
|
|
70
|
+
|
|
71
|
+
const result = await client.tools.call('protected_tool', { data: 'test' });
|
|
56
72
|
expect(result).toBeSuccessful();
|
|
57
|
-
|
|
73
|
+
|
|
74
|
+
await client.disconnect();
|
|
58
75
|
});
|
|
59
76
|
});
|
|
60
77
|
```
|
|
@@ -62,9 +79,9 @@ describe('Authenticated Server', () => {
|
|
|
62
79
|
## What This Demonstrates
|
|
63
80
|
|
|
64
81
|
- Creating a `TestTokenFactory` with issuer and audience configuration
|
|
65
|
-
- Generating test tokens with specific subjects and scopes via `
|
|
66
|
-
-
|
|
67
|
-
-
|
|
82
|
+
- Generating test tokens with specific subjects and scopes via `createTestToken()`
|
|
83
|
+
- Building authenticated clients with `McpTestClient.create(...).withToken(token)`
|
|
84
|
+
- Using `.withPublicMode()` to suppress the anonymous token request and test unauthenticated rejection
|
|
68
85
|
|
|
69
86
|
## Related
|
|
70
87
|
|
|
@@ -3,11 +3,11 @@ name: basic-create-test
|
|
|
3
3
|
reference: test-direct-client
|
|
4
4
|
level: basic
|
|
5
5
|
description: 'Test tools in-memory without any HTTP overhead using the `create()` function from `@frontmcp/sdk`.'
|
|
6
|
-
tags: [testing, sdk,
|
|
6
|
+
tags: [testing, sdk, direct-client]
|
|
7
7
|
features:
|
|
8
|
-
- 'Using `create()` to spin up an in-memory
|
|
9
|
-
- 'Defining tools
|
|
10
|
-
- 'Calling tools directly via `server.callTool()` and checking
|
|
8
|
+
- 'Using `create()` to spin up an in-memory `DirectMcpServer` with no HTTP transport'
|
|
9
|
+
- 'Defining tools as classes with the `@Tool` decorator and Zod schemas'
|
|
10
|
+
- 'Calling tools directly via `server.callTool()` and checking the structured output'
|
|
11
11
|
- 'Proper cleanup with `server.dispose()` in each test'
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -19,17 +19,25 @@ Test tools in-memory without any HTTP overhead using the `create()` function fro
|
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
21
|
// src/__tests__/direct-client.spec.ts
|
|
22
|
-
|
|
22
|
+
// Real API:
|
|
23
|
+
// libs/sdk/src/direct/create.ts — `create(config)` returns a DirectMcpServer
|
|
24
|
+
// libs/sdk/src/index.ts — exports `Tool`, `ToolContext`, `z` (no `tool()` factory)
|
|
25
|
+
import { create, Tool, ToolContext, z } from '@frontmcp/sdk';
|
|
23
26
|
|
|
24
|
-
|
|
27
|
+
@Tool({
|
|
25
28
|
name: 'add',
|
|
26
29
|
description: 'Add numbers',
|
|
27
30
|
inputSchema: { a: z.number(), b: z.number() },
|
|
28
31
|
outputSchema: { sum: z.number() },
|
|
29
|
-
})
|
|
32
|
+
})
|
|
33
|
+
class AddTool extends ToolContext {
|
|
34
|
+
async execute(input: { a: number; b: number }) {
|
|
35
|
+
return { sum: input.a + input.b };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
30
38
|
|
|
31
39
|
describe('Direct Client Testing', () => {
|
|
32
|
-
it('
|
|
40
|
+
it('calls a tool via create()', async () => {
|
|
33
41
|
const server = await create({
|
|
34
42
|
info: { name: 'test', version: '1.0.0' },
|
|
35
43
|
tools: [AddTool],
|
|
@@ -37,12 +45,14 @@ describe('Direct Client Testing', () => {
|
|
|
37
45
|
});
|
|
38
46
|
|
|
39
47
|
const result = await server.callTool('add', { a: 2, b: 3 });
|
|
40
|
-
|
|
48
|
+
// The framework wraps the tool's `{ sum: 5 }` return into a CallToolResult
|
|
49
|
+
// with `structuredContent` set to the typed output.
|
|
50
|
+
expect(result.structuredContent).toEqual({ sum: 5 });
|
|
41
51
|
|
|
42
52
|
await server.dispose();
|
|
43
53
|
});
|
|
44
54
|
|
|
45
|
-
it('
|
|
55
|
+
it('handles multiple tool calls', async () => {
|
|
46
56
|
const server = await create({
|
|
47
57
|
info: { name: 'test', version: '1.0.0' },
|
|
48
58
|
tools: [AddTool],
|
|
@@ -50,10 +60,10 @@ describe('Direct Client Testing', () => {
|
|
|
50
60
|
});
|
|
51
61
|
|
|
52
62
|
const r1 = await server.callTool('add', { a: 10, b: 20 });
|
|
53
|
-
expect(r1.
|
|
63
|
+
expect(r1.structuredContent).toEqual({ sum: 30 });
|
|
54
64
|
|
|
55
65
|
const r2 = await server.callTool('add', { a: -5, b: 5 });
|
|
56
|
-
expect(r2.
|
|
66
|
+
expect(r2.structuredContent).toEqual({ sum: 0 });
|
|
57
67
|
|
|
58
68
|
await server.dispose();
|
|
59
69
|
});
|
|
@@ -62,9 +72,9 @@ describe('Direct Client Testing', () => {
|
|
|
62
72
|
|
|
63
73
|
## What This Demonstrates
|
|
64
74
|
|
|
65
|
-
- Using `create()` to spin up an in-memory
|
|
66
|
-
- Defining tools
|
|
67
|
-
- Calling tools directly via `server.callTool()` and checking
|
|
75
|
+
- Using `create()` to spin up an in-memory `DirectMcpServer` with no HTTP transport
|
|
76
|
+
- Defining tools as classes with the `@Tool` decorator and Zod schemas
|
|
77
|
+
- Calling tools directly via `server.callTool()` and checking the structured output
|
|
68
78
|
- Proper cleanup with `server.dispose()` in each test
|
|
69
79
|
|
|
70
80
|
## Related
|