@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.
Files changed (176) hide show
  1. package/catalog/TEMPLATE.md +16 -11
  2. package/catalog/frontmcp-authorities/SKILL.md +116 -11
  3. package/catalog/frontmcp-authorities/references/authority-profiles.md +39 -36
  4. package/catalog/frontmcp-authorities/references/claims-mapping.md +7 -0
  5. package/catalog/frontmcp-authorities/references/custom-evaluators.md +63 -14
  6. package/catalog/frontmcp-channels/SKILL.md +36 -0
  7. package/catalog/frontmcp-channels/examples/channel-sources/file-watcher.md +8 -2
  8. package/catalog/frontmcp-channels/examples/channel-sources/replay-buffer.md +111 -30
  9. package/catalog/frontmcp-channels/examples/channel-two-way/whatsapp-bridge.md +45 -3
  10. package/catalog/frontmcp-channels/references/channel-sources.md +11 -3
  11. package/catalog/frontmcp-channels/references/channel-two-way.md +60 -89
  12. package/catalog/frontmcp-config/SKILL.md +111 -8
  13. package/catalog/frontmcp-config/examples/configure-auth-modes/local-self-signed-tokens.md +4 -4
  14. package/catalog/frontmcp-config/examples/configure-auth-modes/remote-enterprise-oauth.md +7 -1
  15. package/catalog/frontmcp-config/examples/configure-deployment-targets/distributed-ha-config.md +1 -1
  16. package/catalog/frontmcp-config/examples/configure-deployment-targets/json-schema-ide-support.md +1 -1
  17. package/catalog/frontmcp-config/examples/configure-deployment-targets/multi-target-with-security.md +12 -9
  18. package/catalog/frontmcp-config/examples/configure-http/cors-restricted-origins.md +2 -2
  19. package/catalog/frontmcp-config/examples/configure-http/entry-path-reverse-proxy.md +1 -1
  20. package/catalog/frontmcp-config/examples/configure-security-headers/csp-report-only.md +1 -1
  21. package/catalog/frontmcp-config/examples/configure-security-headers/full-production-headers.md +1 -1
  22. package/catalog/frontmcp-config/examples/configure-skills-http/audit-log-basic.md +76 -0
  23. package/catalog/frontmcp-config/examples/configure-skills-http/audit-log-redis.md +116 -0
  24. package/catalog/frontmcp-config/examples/configure-skills-http/inject-instructions.md +59 -0
  25. package/catalog/frontmcp-config/references/configure-auth-modes.md +5 -5
  26. package/catalog/frontmcp-config/references/configure-deployment-targets.md +27 -24
  27. package/catalog/frontmcp-config/references/configure-http.md +14 -10
  28. package/catalog/frontmcp-config/references/configure-security-headers.md +2 -2
  29. package/catalog/frontmcp-config/references/configure-session.md +25 -25
  30. package/catalog/frontmcp-config/references/configure-skills-http.md +157 -0
  31. package/catalog/frontmcp-config/references/configure-throttle.md +1 -1
  32. package/catalog/frontmcp-config/references/configure-transport.md +2 -2
  33. package/catalog/frontmcp-deployment/SKILL.md +112 -9
  34. package/catalog/frontmcp-deployment/examples/build-for-browser/browser-build-with-custom-entry.md +23 -11
  35. package/catalog/frontmcp-deployment/examples/build-for-browser/browser-crypto-and-storage.md +44 -17
  36. package/catalog/frontmcp-deployment/examples/build-for-browser/react-provider-setup.md +53 -21
  37. package/catalog/frontmcp-deployment/examples/build-for-cli/cli-binary-build.md +1 -1
  38. package/catalog/frontmcp-deployment/examples/build-for-cli/unix-socket-daemon.md +1 -1
  39. package/catalog/frontmcp-deployment/examples/build-for-mcpb/mcpb-bundle-build.md +1 -1
  40. package/catalog/frontmcp-deployment/examples/build-for-sdk/connect-openai.md +1 -1
  41. package/catalog/frontmcp-deployment/examples/build-for-sdk/multi-platform-connect.md +1 -1
  42. package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/basic-worker-deploy.md +7 -8
  43. package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/worker-custom-domain.md +8 -6
  44. package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/worker-with-kv-storage.md +5 -4
  45. package/catalog/frontmcp-deployment/examples/deploy-to-lambda/cdk-deployment.md +8 -5
  46. package/catalog/frontmcp-deployment/examples/deploy-to-lambda/lambda-handler-with-cors.md +20 -18
  47. package/catalog/frontmcp-deployment/examples/deploy-to-lambda/sam-template-basic.md +8 -5
  48. package/catalog/frontmcp-deployment/examples/deploy-to-node/docker-compose-with-redis.md +3 -3
  49. package/catalog/frontmcp-deployment/examples/deploy-to-node/pm2-with-nginx.md +1 -1
  50. package/catalog/frontmcp-deployment/examples/deploy-to-node/resource-limits.md +2 -2
  51. package/catalog/frontmcp-deployment/examples/deploy-to-node-dockerfile/basic-multistage-dockerfile.md +2 -2
  52. package/catalog/frontmcp-deployment/examples/deploy-to-node-dockerfile/secure-nonroot-dockerfile.md +1 -1
  53. package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-mcp-endpoint-test.md +23 -21
  54. package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-with-kv.md +25 -22
  55. package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-with-skills-cache.md +23 -30
  56. package/catalog/frontmcp-deployment/examples/deploy-to-vercel-config/minimal-vercel-config.md +52 -28
  57. package/catalog/frontmcp-deployment/examples/deploy-to-vercel-config/vercel-config-with-security-headers.md +32 -55
  58. package/catalog/frontmcp-deployment/examples/mcp-client-integration/http-remote.md +9 -0
  59. package/catalog/frontmcp-deployment/references/build-for-browser.md +40 -17
  60. package/catalog/frontmcp-deployment/references/build-for-cli.md +8 -8
  61. package/catalog/frontmcp-deployment/references/deploy-to-cloudflare.md +43 -24
  62. package/catalog/frontmcp-deployment/references/deploy-to-lambda.md +36 -25
  63. package/catalog/frontmcp-deployment/references/deploy-to-node-dockerfile.md +56 -14
  64. package/catalog/frontmcp-deployment/references/deploy-to-node.md +9 -6
  65. package/catalog/frontmcp-deployment/references/deploy-to-vercel-config.md +57 -58
  66. package/catalog/frontmcp-deployment/references/deploy-to-vercel.md +49 -59
  67. package/catalog/frontmcp-deployment/references/mcp-client-integration.md +2 -0
  68. package/catalog/frontmcp-development/SKILL.md +186 -11
  69. package/catalog/frontmcp-development/examples/create-agent/custom-multi-pass-agent.md +1 -1
  70. package/catalog/frontmcp-development/examples/create-agent/nested-agents-with-swarm.md +30 -27
  71. package/catalog/frontmcp-development/examples/create-job/job-with-permissions.md +13 -8
  72. package/catalog/frontmcp-development/examples/create-provider/basic-database-provider.md +33 -23
  73. package/catalog/frontmcp-development/examples/create-provider/config-and-api-providers.md +19 -10
  74. package/catalog/frontmcp-development/examples/create-tool/tool-with-rate-limiting-and-progress.md +3 -3
  75. package/catalog/frontmcp-development/examples/create-workflow/webhook-triggered-workflow.md +6 -4
  76. package/catalog/frontmcp-development/examples/decorators-guide/agent-skill-job-workflow.md +1 -1
  77. package/catalog/frontmcp-development/examples/decorators-guide/basic-server-with-app-and-tools.md +13 -8
  78. package/catalog/frontmcp-development/examples/decorators-guide/multi-app-with-plugins-and-providers.md +50 -23
  79. package/catalog/frontmcp-development/references/create-agent.md +47 -30
  80. package/catalog/frontmcp-development/references/create-job.md +69 -54
  81. package/catalog/frontmcp-development/references/create-plugin-hooks.md +45 -28
  82. package/catalog/frontmcp-development/references/create-plugin.md +10 -8
  83. package/catalog/frontmcp-development/references/create-prompt.md +3 -3
  84. package/catalog/frontmcp-development/references/create-provider.md +91 -51
  85. package/catalog/frontmcp-development/references/create-resource.md +3 -3
  86. package/catalog/frontmcp-development/references/create-skill.md +2 -2
  87. package/catalog/frontmcp-development/references/create-tool.md +7 -7
  88. package/catalog/frontmcp-development/references/create-workflow.md +8 -10
  89. package/catalog/frontmcp-development/references/decorators-guide.md +92 -56
  90. package/catalog/frontmcp-development/references/official-plugins.md +4 -3
  91. package/catalog/frontmcp-development/references/openapi-adapter.md +1 -1
  92. package/catalog/frontmcp-extensibility/SKILL.md +70 -10
  93. package/catalog/frontmcp-extensibility/examples/skill-audit-log/custom-store.md +197 -0
  94. package/catalog/frontmcp-extensibility/examples/skill-audit-log/verify-chain.md +68 -0
  95. package/catalog/frontmcp-extensibility/examples/vectoriadb/product-catalog-search.md +3 -5
  96. package/catalog/frontmcp-extensibility/examples/vectoriadb/semantic-search-with-persistence.md +4 -11
  97. package/catalog/frontmcp-extensibility/examples/vectoriadb/tfidf-keyword-search.md +41 -30
  98. package/catalog/frontmcp-extensibility/references/skill-audit-log.md +233 -0
  99. package/catalog/frontmcp-extensibility/references/vectoriadb.md +73 -63
  100. package/catalog/frontmcp-guides/SKILL.md +84 -27
  101. package/catalog/frontmcp-guides/examples/example-knowledge-base/agent-and-plugin.md +72 -62
  102. package/catalog/frontmcp-guides/examples/example-knowledge-base/vector-search-and-resources.md +32 -43
  103. package/catalog/frontmcp-guides/examples/example-task-manager/auth-and-crud-tools.md +24 -17
  104. package/catalog/frontmcp-guides/examples/example-task-manager/authenticated-e2e-tests.md +23 -21
  105. package/catalog/frontmcp-guides/examples/example-task-manager/redis-provider-with-di.md +47 -39
  106. package/catalog/frontmcp-guides/examples/example-weather-api/server-and-app-setup.md +16 -6
  107. package/catalog/frontmcp-guides/examples/example-weather-api/unit-and-e2e-tests.md +9 -8
  108. package/catalog/frontmcp-guides/references/example-knowledge-base.md +192 -265
  109. package/catalog/frontmcp-guides/references/example-task-manager.md +60 -54
  110. package/catalog/frontmcp-guides/references/example-weather-api.md +22 -24
  111. package/catalog/frontmcp-observability/SKILL.md +66 -2
  112. package/catalog/frontmcp-observability/examples/telemetry-api/skill-counters.md +100 -0
  113. package/catalog/frontmcp-observability/examples/tracing-setup/production-tracing.md +7 -2
  114. package/catalog/frontmcp-observability/examples/vendor-integrations/coralogix-setup.md +6 -2
  115. package/catalog/frontmcp-observability/references/telemetry-api.md +72 -8
  116. package/catalog/frontmcp-observability/references/testing-observability.md +33 -49
  117. package/catalog/frontmcp-observability/references/tracing-setup.md +12 -5
  118. package/catalog/frontmcp-observability/references/vendor-integrations.md +46 -1
  119. package/catalog/frontmcp-production-readiness/SKILL.md +134 -3
  120. package/catalog/frontmcp-production-readiness/examples/common-checklist/caching-and-performance.md +57 -36
  121. package/catalog/frontmcp-production-readiness/examples/common-checklist/observability-setup.md +1 -1
  122. package/catalog/frontmcp-production-readiness/examples/common-checklist/security-hardening.md +102 -6
  123. package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/daemon-socket-config.md +2 -1
  124. package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/graceful-shutdown-cleanup.md +66 -58
  125. package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/security-and-permissions.md +5 -3
  126. package/catalog/frontmcp-production-readiness/examples/production-cloudflare/durable-objects-state.md +2 -1
  127. package/catalog/frontmcp-production-readiness/examples/production-cloudflare/wrangler-config.md +55 -76
  128. package/catalog/frontmcp-production-readiness/examples/production-lambda/cold-start-connection-reuse.md +43 -40
  129. package/catalog/frontmcp-production-readiness/examples/production-lambda/sam-template.md +63 -94
  130. package/catalog/frontmcp-production-readiness/examples/production-lambda/scaling-and-monitoring.md +28 -18
  131. package/catalog/frontmcp-production-readiness/examples/production-node-sdk/multi-instance-cleanup.md +29 -14
  132. package/catalog/frontmcp-production-readiness/examples/production-node-server/graceful-shutdown.md +58 -42
  133. package/catalog/frontmcp-production-readiness/examples/production-node-server/redis-session-scaling.md +5 -2
  134. package/catalog/frontmcp-production-readiness/examples/production-vercel/cold-start-optimization.md +41 -24
  135. package/catalog/frontmcp-production-readiness/examples/production-vercel/vercel-edge-config.md +56 -65
  136. package/catalog/frontmcp-production-readiness/references/common-checklist.md +17 -5
  137. package/catalog/frontmcp-production-readiness/references/production-cli-daemon.md +5 -5
  138. package/catalog/frontmcp-production-readiness/references/production-cloudflare.md +5 -5
  139. package/catalog/frontmcp-production-readiness/references/production-lambda.md +5 -5
  140. package/catalog/frontmcp-production-readiness/references/production-node-sdk.md +5 -5
  141. package/catalog/frontmcp-production-readiness/references/production-node-server.md +1 -1
  142. package/catalog/frontmcp-production-readiness/references/production-vercel.md +5 -5
  143. package/catalog/frontmcp-setup/SKILL.md +88 -0
  144. package/catalog/frontmcp-setup/examples/project-structure-nx/nx-workspace-with-apps.md +10 -4
  145. package/catalog/frontmcp-setup/examples/project-structure-standalone/dev-workflow-commands.md +21 -8
  146. package/catalog/frontmcp-setup/examples/readme-guide/node-server-readme.md +3 -3
  147. package/catalog/frontmcp-setup/references/multi-app-composition.md +4 -3
  148. package/catalog/frontmcp-setup/references/project-structure-nx.md +15 -6
  149. package/catalog/frontmcp-setup/references/project-structure-standalone.md +18 -15
  150. package/catalog/frontmcp-setup/references/readme-guide.md +1 -1
  151. package/catalog/frontmcp-setup/references/setup-project.md +19 -5
  152. package/catalog/frontmcp-setup/references/setup-redis.md +27 -39
  153. package/catalog/frontmcp-setup/references/setup-sqlite.md +25 -18
  154. package/catalog/frontmcp-testing/SKILL.md +102 -15
  155. package/catalog/frontmcp-testing/examples/setup-testing/unit-test-tool-resource-prompt.md +3 -3
  156. package/catalog/frontmcp-testing/examples/test-auth/oauth-flow-test.md +50 -39
  157. package/catalog/frontmcp-testing/examples/test-auth/role-based-access-test.md +52 -29
  158. package/catalog/frontmcp-testing/examples/test-auth/token-factory-test.md +37 -20
  159. package/catalog/frontmcp-testing/examples/test-direct-client/basic-create-test.md +25 -15
  160. package/catalog/frontmcp-testing/examples/test-direct-client/openai-claude-format-test.md +27 -21
  161. package/catalog/frontmcp-testing/examples/test-e2e-handler/basic-e2e-test.md +29 -20
  162. package/catalog/frontmcp-testing/examples/test-e2e-handler/manual-client-with-transport.md +5 -3
  163. package/catalog/frontmcp-testing/examples/test-e2e-handler/tool-call-and-error-e2e.md +35 -26
  164. package/catalog/frontmcp-testing/examples/test-tool-unit/basic-tool-test.md +8 -3
  165. package/catalog/frontmcp-testing/examples/test-tool-unit/schema-validation-test.md +4 -1
  166. package/catalog/frontmcp-testing/examples/test-tool-unit/tool-error-handling-test.md +6 -3
  167. package/catalog/frontmcp-testing/references/setup-testing.md +35 -39
  168. package/catalog/frontmcp-testing/references/test-auth.md +86 -43
  169. package/catalog/frontmcp-testing/references/test-browser-build.md +1 -1
  170. package/catalog/frontmcp-testing/references/test-direct-client.md +29 -19
  171. package/catalog/frontmcp-testing/references/test-e2e-handler.md +31 -19
  172. package/catalog/frontmcp-testing/references/test-tool-unit.md +6 -2
  173. package/catalog/skills-manifest.json +428 -339
  174. package/package.json +1 -1
  175. package/src/manifest.d.ts +13 -0
  176. 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 | `setup-testing` (Unit Testing) | Mock DI, validate input/output, test error paths |
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` | Testing browser builds |
53
- | Test CLI binary builds | `test-cli-binary` | Testing CLI binary builds |
54
- | Test with the direct API client | `test-direct-client` | Testing with the direct API client |
55
- | Write E2E test handler patterns | `test-e2e-handler` | E2E test handler patterns |
56
- | Unit test individual tools | `test-tool-unit` | Unit testing individual tools |
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 | Use `frontmcp test` (not `jest --config ...`). It auto-generates the correct Jest/SWC config |
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 `read()` output matches the MCP `ReadResourceResult` shape'
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.read({ id: '123' });
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 `read()` output matches the MCP `ReadResourceResult` shape
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: 'Use `MockOAuthServer` to simulate an OAuth identity provider and test the authorization code flow.'
6
- tags: [testing, oauth, auth, flow]
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
- - 'Setting up `MockOAuthServer` with a mock issuer URL and port'
9
- - 'Starting an OAuth flow with `startFlow()` specifying client ID, redirect URI, and scopes'
10
- - 'Verifying the authorization URL contains an authorization code'
11
- - 'Testing concurrent OAuth flows with different client configurations'
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 OAuth Authorization Code Flow
18
+ # Testing with the Mock OAuth Server
16
19
 
17
- Use `MockOAuthServer` to simulate an OAuth identity provider and test the authorization code flow.
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
- import { MockOAuthServer } from '@frontmcp/testing';
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 Flow', () => {
31
+ describe('Mock OAuth Server', () => {
32
+ let tokenFactory: TestTokenFactory;
26
33
  let mockOAuth: MockOAuthServer;
27
34
 
28
35
  beforeAll(async () => {
29
- mockOAuth = await MockOAuthServer.create({
36
+ tokenFactory = new TestTokenFactory({
30
37
  issuer: 'https://test-idp.example.com',
31
- port: 9999,
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.close();
52
+ await mockOAuth.stop();
37
53
  });
38
54
 
39
- it('should complete OAuth authorization code flow', async () => {
40
- const { authorizationUrl } = await mockOAuth.startFlow({
41
- clientId: 'test-client',
42
- redirectUri: 'http://localhost:3001/callback',
43
- scopes: ['openid', 'profile'],
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('should support multiple concurrent flows', async () => {
49
- const flow1 = await mockOAuth.startFlow({
50
- clientId: 'client-a',
51
- redirectUri: 'http://localhost:3001/callback',
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
- const flow2 = await mockOAuth.startFlow({
56
- clientId: 'client-b',
57
- redirectUri: 'http://localhost:3002/callback',
58
- scopes: ['openid', 'email'],
59
- });
69
+ expect(typeof token).toBe('string');
70
+ expect(token.split('.')).toHaveLength(3);
71
+ });
60
72
 
61
- expect(flow1.authorizationUrl).toContain('code=');
62
- expect(flow2.authorizationUrl).toContain('code=');
63
- expect(flow1.authorizationUrl).not.toBe(flow2.authorizationUrl);
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
- - Setting up `MockOAuthServer` with a mock issuer URL and port
71
- - Starting an OAuth flow with `startFlow()` specifying client ID, redirect URI, and scopes
72
- - Verifying the authorization URL contains an authorization code
73
- - Testing concurrent OAuth flows with different client configurations
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, based, access]
6
+ tags: [testing, auth, role-based-access]
7
7
  features:
8
- - 'Creating tokens with different `roles` arrays to simulate admin and user access'
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 closes its own client for proper isolation'
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.create(Server);
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.dispose();
45
+ await server.stop();
39
46
  });
40
47
 
41
- it('should allow admin access to admin-only tool', async () => {
42
- const adminToken = await tokenFactory.createToken({
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 server.connect({ authToken: adminToken });
48
- const result = await client.callTool('admin_only_tool', {});
49
- expect(result).toBeSuccessful();
50
- await client.close();
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('should deny user access to admin-only tool', async () => {
54
- const userToken = await tokenFactory.createToken({
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 server.connect({ authToken: userToken });
60
- const result = await client.callTool('admin_only_tool', {});
61
- expect(result.isError).toBe(true);
62
- await client.close();
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('should allow user access to user-level tool', async () => {
66
- const userToken = await tokenFactory.createToken({
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 server.connect({ authToken: userToken });
72
- const result = await client.callTool('user_tool', { data: 'hello' });
73
- expect(result).toBeSuccessful();
74
- await client.close();
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
- - Creating tokens with different `roles` arrays to simulate admin and user access
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 closes its own client for proper isolation
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, factory]
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 `createToken()`'
10
- - 'Passing tokens to `server.connect({ authToken })` for authenticated client connections'
11
- - 'Verifying that unauthenticated requests are rejected with `isError`'
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.create(Server);
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.dispose();
44
+ await server.stop();
39
45
  });
40
46
 
41
- it('should reject unauthenticated requests', async () => {
42
- const client = await server.connect();
43
- const result = await client.callTool('protected_tool', {});
44
- expect(result.isError).toBe(true);
45
- await client.close();
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('should accept valid token', async () => {
49
- const token = await tokenFactory.createToken({
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 server.connect({ authToken: token });
55
- const result = await client.callTool('protected_tool', { data: 'test' });
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
- await client.close();
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 `createToken()`
66
- - Passing tokens to `server.connect({ authToken })` for authenticated client connections
67
- - Verifying that unauthenticated requests are rejected with `isError`
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, transport, direct-client, direct, client]
6
+ tags: [testing, sdk, direct-client]
7
7
  features:
8
- - 'Using `create()` to spin up an in-memory server with no HTTP transport'
9
- - 'Defining tools inline with the functional `tool()` API and Zod schemas'
10
- - 'Calling tools directly via `server.callTool()` and checking text content'
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
- import { create, tool, z } from '@frontmcp/sdk';
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
- const AddTool = tool({
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
- })((input) => ({ sum: input.a + input.b }));
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('should call tools via create()', async () => {
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
- expect(result.content[0].text).toContain('5');
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('should handle multiple tool calls', async () => {
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.content[0].text).toContain('30');
63
+ expect(r1.structuredContent).toEqual({ sum: 30 });
54
64
 
55
65
  const r2 = await server.callTool('add', { a: -5, b: 5 });
56
- expect(r2.content[0].text).toContain('0');
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 server with no HTTP transport
66
- - Defining tools inline with the functional `tool()` API and Zod schemas
67
- - Calling tools directly via `server.callTool()` and checking text content
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