@frontmcp/skills 1.1.2 → 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
@@ -2,14 +2,20 @@
2
2
  name: vector-search-and-resources
3
3
  reference: example-knowledge-base
4
4
  level: intermediate
5
- description: 'Shows a semantic search tool with embedding generation and a resource template for retrieving documents by ID using URI parameters.'
6
- tags: [guides, openai, semantic-search, knowledge-base, knowledge, base]
5
+ description: Shows a semantic search tool with embedding generation and a resource template for retrieving documents by ID using URI parameters.
6
+ tags:
7
+ - guides
8
+ - vectoriadb
9
+ - semantic-search
10
+ - knowledge-base
11
+ - knowledge
12
+ - base
7
13
  features:
8
- - 'Semantic search tool that generates query embeddings via `this.fetch()` to OpenAI'
9
- - 'Using `this.mark()` for execution phase tracing'
14
+ - Semantic search tool that delegates embedding generation to VectoriaDB via `store.search(query, topK)`
15
+ - Using `this.mark()` for execution phase tracing
10
16
  - "Resource template with `uriTemplate: 'kb://documents/{documentId}'` for parameterized URIs"
11
17
  - 'Typed params via `ResourceContext<{ documentId: string }>` for type-safe URI parameters'
12
- - 'Returning `ReadResourceResult` with proper MCP protocol structure'
18
+ - Returning `ReadResourceResult` with proper MCP protocol structure
13
19
  ---
14
20
 
15
21
  # Knowledge Base: Semantic Search Tool and Resource Template
@@ -22,7 +28,7 @@ Shows a semantic search tool with embedding generation and a resource template f
22
28
  // src/search/tools/search-docs.tool.ts
23
29
  import { Tool, ToolContext, z } from '@frontmcp/sdk';
24
30
 
25
- import { VECTOR_STORE } from '../../ingestion/providers/vector-store.provider';
31
+ import { VectorStoreProvider } from '../../ingestion/providers/vector-store.provider';
26
32
 
27
33
  @Tool({
28
34
  name: 'search_docs',
@@ -45,46 +51,29 @@ import { VECTOR_STORE } from '../../ingestion/providers/vector-store.provider';
45
51
  })
46
52
  export class SearchDocsTool extends ToolContext {
47
53
  async execute(input: { query: string; topK: number }) {
48
- const store = this.get(VECTOR_STORE);
49
-
50
- // Mark execution phases for observability
51
- this.mark('embedding-query');
52
- const queryEmbedding = await this.generateQueryEmbedding(input.query);
54
+ const store = this.get(VectorStoreProvider);
53
55
 
56
+ // VectoriaDB handles embedding generation internally — pass the raw query.
54
57
  this.mark('searching');
55
- const chunks = await store.search(queryEmbedding, input.topK);
58
+ const matches = await store.search(input.query, input.topK);
56
59
 
57
- const results = chunks.map((chunk) => ({
58
- documentId: chunk.documentId,
59
- content: chunk.content,
60
- score: chunk.metadata.score ? parseFloat(chunk.metadata.score) : 0,
61
- title: chunk.metadata.title ?? 'Untitled',
60
+ const results = matches.map((m) => ({
61
+ documentId: m.metadata.documentId,
62
+ content: m.metadata.content,
63
+ score: m.score,
64
+ title: m.metadata.title ?? 'Untitled',
62
65
  }));
63
66
 
64
67
  return { results, total: results.length };
65
68
  }
66
-
67
- private async generateQueryEmbedding(query: string): Promise<number[]> {
68
- const response = await this.fetch('https://api.openai.com/v1/embeddings', {
69
- method: 'POST',
70
- headers: {
71
- 'Content-Type': 'application/json',
72
- Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
73
- },
74
- body: JSON.stringify({ input: query, model: 'text-embedding-3-small' }),
75
- });
76
- const data = await response.json();
77
- return data.data[0].embedding;
78
- }
79
69
  }
80
70
  ```
81
71
 
82
72
  ```typescript
83
73
  // src/search/resources/doc.resource.ts
84
- import type { ReadResourceResult } from '@frontmcp/protocol';
85
- import { ResourceContext, ResourceTemplate } from '@frontmcp/sdk';
74
+ import { ReadResourceResult, ResourceContext, ResourceNotFoundError, ResourceTemplate } from '@frontmcp/sdk';
86
75
 
87
- import { VECTOR_STORE } from '../../ingestion/providers/vector-store.provider';
76
+ import { VectorStoreProvider } from '../../ingestion/providers/vector-store.provider';
88
77
 
89
78
  @ResourceTemplate({
90
79
  name: 'document',
@@ -94,20 +83,20 @@ import { VECTOR_STORE } from '../../ingestion/providers/vector-store.provider';
94
83
  })
95
84
  export class DocResource extends ResourceContext<{ documentId: string }> {
96
85
  async execute(uri: string, params: { documentId: string }): Promise<ReadResourceResult> {
97
- const store = this.get(VECTOR_STORE);
98
- const chunks = await store.getByDocumentId(params.documentId);
86
+ const store = this.get(VectorStoreProvider);
87
+ const matches = await store.getByDocumentId(params.documentId);
99
88
 
100
- if (chunks.length === 0) {
101
- this.fail(new Error(`Document not found: ${params.documentId}`));
89
+ if (matches.length === 0) {
90
+ // Use a typed MCP error so the protocol response carries the correct JSON-RPC code.
91
+ throw new ResourceNotFoundError(uri);
102
92
  }
103
93
 
104
94
  const document = {
105
95
  documentId: params.documentId,
106
- title: chunks[0].metadata.title ?? 'Untitled',
107
- chunks: chunks.map((c) => ({
108
- chunkIndex: c.metadata.chunkIndex,
109
- content: c.content,
110
- })),
96
+ title: matches[0].metadata.title ?? 'Untitled',
97
+ chunks: matches
98
+ .map((m) => ({ chunkIndex: m.metadata.chunkIndex, content: m.metadata.content }))
99
+ .sort((a, b) => a.chunkIndex - b.chunkIndex),
111
100
  };
112
101
 
113
102
  return {
@@ -125,7 +114,7 @@ export class DocResource extends ResourceContext<{ documentId: string }> {
125
114
 
126
115
  ## What This Demonstrates
127
116
 
128
- - Semantic search tool that generates query embeddings via `this.fetch()` to OpenAI
117
+ - Semantic search tool that delegates embedding generation to VectoriaDB via `store.search(query, topK)`
129
118
  - Using `this.mark()` for execution phase tracing
130
119
  - Resource template with `uriTemplate: 'kb://documents/{documentId}'` for parameterized URIs
131
120
  - Typed params via `ResourceContext<{ documentId: string }>` for type-safe URI parameters
@@ -2,19 +2,25 @@
2
2
  name: auth-and-crud-tools
3
3
  reference: example-task-manager
4
4
  level: basic
5
- description: 'Shows how to create CRUD tools with authentication, using `this.context.session` for user isolation and `this.get()` for dependency injection.'
6
- tags: [guides, auth, session, task-manager, task, manager]
5
+ description: Shows how to create CRUD tools with authentication, using `this.auth?.user.sub` (the FrontMcpAuthContext exposed on every execution context) for user isolation and `this.get()` for dependency injection.
6
+ tags:
7
+ - guides
8
+ - auth
9
+ - session
10
+ - task-manager
11
+ - task
12
+ - manager
7
13
  features:
8
- - 'Using `this.context.session?.userId` for per-user data isolation'
9
- - 'Using `this.get(TASK_STORE)` for dependency injection of providers'
10
- - 'Enforcing authentication with `this.fail()` when no session exists'
11
- - 'Optional input fields with `.optional()` for filtering'
14
+ - Using `this.auth?.user.sub` (FrontMcpAuthContext) for per-user data isolation
15
+ - Using `this.get(TaskStoreProvider)` for dependency injection of providers (class-as-token)
16
+ - Enforcing authentication with `this.fail()` when no authenticated user is present in `this.auth`
17
+ - Optional input fields with `.optional()` for filtering
12
18
  - '`outputSchema` with nested `z.array(z.object(...))` for structured responses'
13
19
  ---
14
20
 
15
21
  # Task Manager: Authenticated CRUD Tools
16
22
 
17
- Shows how to create CRUD tools with authentication, using `this.context.session` for user isolation and `this.get()` for dependency injection.
23
+ Shows how to create CRUD tools with authentication, using `this.auth?.user.sub` (the FrontMcpAuthContext exposed on every execution context) for user isolation and `this.get()` for dependency injection.
18
24
 
19
25
  ## Code
20
26
 
@@ -22,7 +28,7 @@ Shows how to create CRUD tools with authentication, using `this.context.session`
22
28
  // src/tools/create-task.tool.ts
23
29
  import { Tool, ToolContext, z } from '@frontmcp/sdk';
24
30
 
25
- import { TASK_STORE } from '../providers/task-store.provider';
31
+ import { TaskStoreProvider } from '../providers/task-store.provider';
26
32
 
27
33
  @Tool({
28
34
  name: 'create_task',
@@ -42,10 +48,11 @@ import { TASK_STORE } from '../providers/task-store.provider';
42
48
  export class CreateTaskTool extends ToolContext {
43
49
  async execute(input: { title: string; priority: 'low' | 'medium' | 'high' }) {
44
50
  // Inject the task store via DI
45
- const store = this.get(TASK_STORE);
51
+ // Inject the task store via DI (the class itself is the token)
52
+ const store = this.get(TaskStoreProvider);
46
53
 
47
- // Get the authenticated user's ID from the session
48
- const userId = this.context.session?.userId;
54
+ // Get the authenticated user's id from FrontMcpAuthContext (`this.auth.user.sub`)
55
+ const userId = this.auth?.user.sub;
49
56
  if (!userId) {
50
57
  this.fail(new Error('Authentication required'));
51
58
  }
@@ -72,7 +79,7 @@ export class CreateTaskTool extends ToolContext {
72
79
  // src/tools/list-tasks.tool.ts
73
80
  import { Tool, ToolContext, z } from '@frontmcp/sdk';
74
81
 
75
- import { TASK_STORE } from '../providers/task-store.provider';
82
+ import { TaskStoreProvider } from '../providers/task-store.provider';
76
83
 
77
84
  @Tool({
78
85
  name: 'list_tasks',
@@ -95,8 +102,8 @@ import { TASK_STORE } from '../providers/task-store.provider';
95
102
  })
96
103
  export class ListTasksTool extends ToolContext {
97
104
  async execute(input: { status?: 'pending' | 'in_progress' | 'done' }) {
98
- const store = this.get(TASK_STORE);
99
- const userId = this.context.session?.userId;
105
+ const store = this.get(TaskStoreProvider);
106
+ const userId = this.auth?.user.sub;
100
107
 
101
108
  if (!userId) {
102
109
  this.fail(new Error('Authentication required'));
@@ -124,9 +131,9 @@ export class ListTasksTool extends ToolContext {
124
131
 
125
132
  ## What This Demonstrates
126
133
 
127
- - Using `this.context.session?.userId` for per-user data isolation
128
- - Using `this.get(TASK_STORE)` for dependency injection of providers
129
- - Enforcing authentication with `this.fail()` when no session exists
134
+ - Using `this.auth?.user.sub` (FrontMcpAuthContext) for per-user data isolation
135
+ - Using `this.get(TaskStoreProvider)` for dependency injection of providers (class-as-token)
136
+ - Enforcing authentication with `this.fail()` when no authenticated user is present in `this.auth`
130
137
  - Optional input fields with `.optional()` for filtering
131
138
  - `outputSchema` with nested `z.array(z.object(...))` for structured responses
132
139
 
@@ -7,9 +7,9 @@ tags: [guides, auth, session, e2e, unit-test, task-manager]
7
7
  features:
8
8
  - 'Using `TestTokenFactory` to create JWT tokens for authenticated E2E tests'
9
9
  - 'Chaining `.withToken(token).buildAndConnect()` for authenticated clients'
10
- - 'Unit testing with mocked DI tokens via `this.get()` mock'
11
- - 'Mocking session context (`context: { session: { userId } }`) for auth-dependent tools'
12
- - 'Testing the unauthenticated error path (no session)'
10
+ - 'Unit testing tools by mocking `this.get(TaskStoreProvider)` and the `auth` getter'
11
+ - 'Mocking `this.auth = { user: { sub } }` (FrontMcpAuthContext) for auth-dependent tools'
12
+ - 'Testing the unauthenticated error path (no `auth` / anonymous user)'
13
13
  ---
14
14
 
15
15
  # Task Manager: Authenticated E2E Tests
@@ -43,7 +43,7 @@ describe('Task Manager E2E', () => {
43
43
  });
44
44
 
45
45
  it('should list all CRUD tools', async () => {
46
- const { tools } = await client.listTools();
46
+ const tools = await client.tools.list();
47
47
  const names = tools.map((t) => t.name);
48
48
 
49
49
  expect(names).toContain('create_task');
@@ -53,16 +53,16 @@ describe('Task Manager E2E', () => {
53
53
  });
54
54
 
55
55
  it('should create and list a task', async () => {
56
- const createResult = await client.callTool('create_task', {
56
+ const createResult = await client.tools.call('create_task', {
57
57
  title: 'E2E test task',
58
58
  priority: 'high',
59
59
  });
60
- expect(createResult).toBeSuccessful();
60
+ expect(createResult.isError).toBeFalsy();
61
61
 
62
- const listResult = await client.callTool('list_tasks', {});
63
- expect(listResult).toBeSuccessful();
62
+ const listResult = await client.tools.call('list_tasks', {});
63
+ expect(listResult.isError).toBeFalsy();
64
64
 
65
- const parsed = JSON.parse(listResult.content[0].text);
65
+ const parsed = listResult.json<{ tasks: Array<{ title: string }> }>();
66
66
  expect(parsed.tasks.length).toBeGreaterThan(0);
67
67
  expect(parsed.tasks.some((t: { title: string }) => t.title === 'E2E test task')).toBe(true);
68
68
  });
@@ -70,15 +70,16 @@ describe('Task Manager E2E', () => {
70
70
  ```
71
71
 
72
72
  ```typescript
73
- // test/create-task.tool.spec.ts — Unit test with mocked session
73
+ // test/create-task.tool.spec.ts — Unit test with mocked auth context
74
74
  import { ToolContext } from '@frontmcp/sdk';
75
+
76
+ import { TaskStoreProvider } from '../src/providers/task-store.provider';
75
77
  import { CreateTaskTool } from '../src/tools/create-task.tool';
76
- import { TASK_STORE, type TaskStore } from '../src/providers/task-store.provider';
77
78
  import type { Task } from '../src/types/task';
78
79
 
79
80
  describe('CreateTaskTool', () => {
80
81
  let tool: CreateTaskTool;
81
- let mockStore: jest.Mocked<TaskStore>;
82
+ let mockStore: jest.Mocked<TaskStoreProvider>;
82
83
 
83
84
  beforeEach(() => {
84
85
  tool = new CreateTaskTool();
@@ -87,13 +88,13 @@ describe('CreateTaskTool', () => {
87
88
  list: jest.fn(),
88
89
  update: jest.fn(),
89
90
  delete: jest.fn(),
90
- };
91
+ } as unknown as jest.Mocked<TaskStoreProvider>;
91
92
  });
92
93
 
93
94
  function applyContext(userId: string | undefined): void {
94
95
  const ctx = {
95
- get: jest.fn((token: symbol) => {
96
- if (token === TASK_STORE) return mockStore;
96
+ get: jest.fn((token: unknown) => {
97
+ if (token === TaskStoreProvider) return mockStore;
97
98
  throw new Error(`Unknown token: ${String(token)}`);
98
99
  }),
99
100
  tryGet: jest.fn(),
@@ -101,9 +102,10 @@ describe('CreateTaskTool', () => {
101
102
  throw err;
102
103
  }),
103
104
  mark: jest.fn(),
104
- notify: jest.fn(),
105
- respondProgress: jest.fn(),
106
- context: { session: userId ? { userId } : undefined },
105
+ notify: jest.fn().mockResolvedValue(true),
106
+ progress: jest.fn().mockResolvedValue(true),
107
+ // Stub the FrontMcpAuthContext exposed via the `auth` getter on the real SDK.
108
+ auth: userId ? { user: { sub: userId }, isAnonymous: false } : undefined,
107
109
  } as unknown as ToolContext;
108
110
  Object.assign(tool, ctx);
109
111
  }
@@ -139,9 +141,9 @@ describe('CreateTaskTool', () => {
139
141
 
140
142
  - Using `TestTokenFactory` to create JWT tokens for authenticated E2E tests
141
143
  - Chaining `.withToken(token).buildAndConnect()` for authenticated clients
142
- - Unit testing with mocked DI tokens via `this.get()` mock
143
- - Mocking session context (`context: { session: { userId } }`) for auth-dependent tools
144
- - Testing the unauthenticated error path (no session)
144
+ - Unit testing tools by mocking `this.get(TaskStoreProvider)` and the `auth` getter
145
+ - Mocking `this.auth = { user: { sub } }` (FrontMcpAuthContext) for auth-dependent tools
146
+ - Testing the unauthenticated error path (no `auth` / anonymous user)
145
147
 
146
148
  ## Related
147
149
 
@@ -2,20 +2,25 @@
2
2
  name: redis-provider-with-di
3
3
  reference: example-task-manager
4
4
  level: intermediate
5
- description: 'Shows how to create a Redis-backed provider with a DI token, lifecycle hooks (`onInit`/`onDestroy`), and how tools inject it.'
6
- tags: [guides, redis, node, task-manager, task, manager]
5
+ description: Shows how to create a Redis-backed provider using the class-as-token DI pattern (`@Provider({ name, scope })`) plus an `AsyncProvider` factory that runs the async Redis setup before any tool is invoked.
6
+ tags:
7
+ - guides
8
+ - redis
9
+ - node
10
+ - task-manager
11
+ - task
12
+ - manager
7
13
  features:
8
- - "Defining an interface and DI token (`Symbol('TaskStore')`) for the provider"
9
- - 'Using `@Provider({ token: TASK_STORE })` to register the provider for DI'
10
- - 'Lifecycle hooks: `onInit()` for connection setup, `onDestroy()` for cleanup'
11
- - 'Lazy-loading `ioredis` via dynamic `import()` in `onInit()`'
12
- - 'Using `@frontmcp/utils` for `randomUUID()` instead of `node:crypto`'
13
- - 'Per-user data isolation using Redis hash keys (`tasks:${userId}`)'
14
+ - 'Class-as-token DI: `@Provider({ name, scope })` and inject via `this.get(TaskStoreProvider)`'
15
+ - Building the singleton with `AsyncProvider({ provide, name, scope, useFactory })` for async setup
16
+ - 'Cleanup: explicit `disconnect()` method (called from the host before `server.dispose()`) `@Provider` has no `onDestroy` hook'
17
+ - Using `@frontmcp/utils` for `randomUUID()` instead of `node:crypto`
18
+ - Per-user data isolation using Redis hash keys (`tasks:${userId}`)
14
19
  ---
15
20
 
16
21
  # Task Manager: Redis Provider with Dependency Injection
17
22
 
18
- Shows how to create a Redis-backed provider with a DI token, lifecycle hooks (`onInit`/`onDestroy`), and how tools inject it.
23
+ Shows how to create a Redis-backed provider using the class-as-token DI pattern (`@Provider({ name, scope })`) plus an `AsyncProvider` factory that runs the async Redis setup before any tool is invoked.
19
24
 
20
25
  ## Code
21
26
 
@@ -33,32 +38,18 @@ export interface Task {
33
38
 
34
39
  ```typescript
35
40
  // src/providers/task-store.provider.ts
36
- import { Provider } from '@frontmcp/sdk';
37
- import type { Token } from '@frontmcp/di';
38
- import type { Task } from '../types/task';
39
-
40
- export interface TaskStore {
41
- create(task: Omit<Task, 'id' | 'createdAt'>): Promise<Task>;
42
- list(userId: string): Promise<Task[]>;
43
- update(id: string, userId: string, data: Partial<Pick<Task, 'title' | 'priority' | 'status'>>): Promise<Task>;
44
- delete(id: string, userId: string): Promise<void>;
45
- }
41
+ import Redis, { Redis as RedisClient } from 'ioredis';
46
42
 
47
- // DI token tools use this.get(TASK_STORE) to access the provider
48
- export const TASK_STORE: Token<TaskStore> = Symbol('TaskStore');
43
+ import { AsyncProvider, Provider, ProviderScope } from '@frontmcp/sdk';
44
+ import { randomUUID } from '@frontmcp/utils';
49
45
 
50
- @Provider({ token: TASK_STORE })
51
- export class RedisTaskStoreProvider implements TaskStore {
52
- private redis!: import('ioredis').default;
46
+ import type { Task } from '../types/task';
53
47
 
54
- // Lifecycle: initialize Redis connection
55
- async onInit(): Promise<void> {
56
- const Redis = (await import('ioredis')).default;
57
- this.redis = new Redis(process.env.REDIS_URL ?? 'redis://localhost:6379');
58
- }
48
+ @Provider({ name: 'task-store', scope: ProviderScope.GLOBAL })
49
+ export class TaskStoreProvider {
50
+ constructor(private readonly redis: RedisClient) {}
59
51
 
60
52
  async create(input: Omit<Task, 'id' | 'createdAt'>): Promise<Task> {
61
- const { randomUUID } = await import('@frontmcp/utils');
62
53
  const task: Task = {
63
54
  ...input,
64
55
  id: randomUUID(),
@@ -90,26 +81,44 @@ export class RedisTaskStoreProvider implements TaskStore {
90
81
  }
91
82
  }
92
83
 
93
- // Lifecycle: close Redis connection on shutdown
94
- async onDestroy(): Promise<void> {
84
+ // `@Provider` has no `onDestroy` hook — expose explicit cleanup that the
85
+ // host calls before `server.dispose()` (e.g., from the SIGTERM/process
86
+ // shutdown side-effect handler).
87
+ async disconnect(): Promise<void> {
95
88
  await this.redis.quit();
96
89
  }
97
90
  }
91
+
92
+ // AsyncProvider factory: builds the TaskStoreProvider singleton with a connected Redis client.
93
+ // Tools still inject the class itself: `this.get(TaskStoreProvider)`.
94
+ export const createTaskStoreProvider = AsyncProvider({
95
+ provide: TaskStoreProvider,
96
+ name: 'task-store-factory',
97
+ scope: ProviderScope.GLOBAL,
98
+ inject: () => [] as const,
99
+ useFactory: async () => {
100
+ const redis = new Redis(process.env.REDIS_URL ?? 'redis://localhost:6379');
101
+ return new TaskStoreProvider(redis);
102
+ },
103
+ });
98
104
  ```
99
105
 
100
106
  ```typescript
101
107
  // src/tasks.app.ts
102
108
  import { App } from '@frontmcp/sdk';
103
- import { RedisTaskStoreProvider } from './providers/task-store.provider';
109
+
110
+ import { createTaskStoreProvider } from './providers/task-store.provider';
104
111
  import { CreateTaskTool } from './tools/create-task.tool';
112
+ import { DeleteTaskTool } from './tools/delete-task.tool';
105
113
  import { ListTasksTool } from './tools/list-tasks.tool';
106
114
  import { UpdateTaskTool } from './tools/update-task.tool';
107
- import { DeleteTaskTool } from './tools/delete-task.tool';
108
115
 
109
116
  @App({
110
117
  name: 'Tasks',
111
118
  description: 'Task management with CRUD operations',
112
- providers: [RedisTaskStoreProvider],
119
+ // The AsyncProvider factory binds the `TaskStoreProvider` class as the DI token.
120
+ // Tools inject the same class via `this.get(TaskStoreProvider)`.
121
+ providers: [createTaskStoreProvider],
113
122
  tools: [CreateTaskTool, ListTasksTool, UpdateTaskTool, DeleteTaskTool],
114
123
  })
115
124
  export class TasksApp {}
@@ -117,10 +126,9 @@ export class TasksApp {}
117
126
 
118
127
  ## What This Demonstrates
119
128
 
120
- - Defining an interface and DI token (`Symbol('TaskStore')`) for the provider
121
- - Using `@Provider({ token: TASK_STORE })` to register the provider for DI
122
- - Lifecycle hooks: `onInit()` for connection setup, `onDestroy()` for cleanup
123
- - Lazy-loading `ioredis` via dynamic `import()` in `onInit()`
129
+ - Class-as-token DI: `@Provider({ name, scope })` and inject via `this.get(TaskStoreProvider)`
130
+ - Building the singleton with `AsyncProvider({ provide, name, scope, useFactory })` for async setup
131
+ - Cleanup: explicit `disconnect()` method (called from the host before `server.dispose()`) `@Provider` has no `onDestroy` hook
124
132
  - Using `@frontmcp/utils` for `randomUUID()` instead of `node:crypto`
125
133
  - Per-user data isolation using Redis hash keys (`tasks:${userId}`)
126
134
 
@@ -7,7 +7,7 @@ tags: [guides, weather, api, app, setup]
7
7
  features:
8
8
  - 'Server entry point with `@FrontMcp` decorator and `info` configuration'
9
9
  - 'App registration with `@App` grouping tools and resources together'
10
- - 'Static resource that returns JSON data via `read()`'
10
+ - 'Static resource that returns JSON data via `execute(uri)` and `ReadResourceResult`'
11
11
  - 'Clean separation between server, app, tools, and resources'
12
12
  ---
13
13
 
@@ -20,6 +20,7 @@ Shows the server entry point, app registration, and static resource for a beginn
20
20
  ```typescript
21
21
  // src/main.ts
22
22
  import { FrontMcp } from '@frontmcp/sdk';
23
+
23
24
  import { WeatherApp } from './weather.app';
24
25
 
25
26
  @FrontMcp({
@@ -32,8 +33,9 @@ export default class WeatherServer {}
32
33
  ```typescript
33
34
  // src/weather.app.ts
34
35
  import { App } from '@frontmcp/sdk';
35
- import { GetWeatherTool } from './tools/get-weather.tool';
36
+
36
37
  import { CitiesResource } from './resources/cities.resource';
38
+ import { GetWeatherTool } from './tools/get-weather.tool';
37
39
 
38
40
  @App({
39
41
  name: 'Weather',
@@ -46,7 +48,7 @@ export class WeatherApp {}
46
48
 
47
49
  ```typescript
48
50
  // src/resources/cities.resource.ts
49
- import { Resource, ResourceContext } from '@frontmcp/sdk';
51
+ import { ReadResourceResult, Resource, ResourceContext } from '@frontmcp/sdk';
50
52
 
51
53
  const SUPPORTED_CITIES = ['London', 'Tokyo', 'New York', 'Paris', 'Sydney', 'Berlin', 'Toronto', 'Mumbai'];
52
54
 
@@ -57,8 +59,16 @@ const SUPPORTED_CITIES = ['London', 'Tokyo', 'New York', 'Paris', 'Sydney', 'Ber
57
59
  mimeType: 'application/json',
58
60
  })
59
61
  export class CitiesResource extends ResourceContext {
60
- async read() {
61
- return JSON.stringify(SUPPORTED_CITIES);
62
+ async execute(uri: string): Promise<ReadResourceResult> {
63
+ return {
64
+ contents: [
65
+ {
66
+ uri,
67
+ mimeType: 'application/json',
68
+ text: JSON.stringify(SUPPORTED_CITIES),
69
+ },
70
+ ],
71
+ };
62
72
  }
63
73
  }
64
74
  ```
@@ -67,7 +77,7 @@ export class CitiesResource extends ResourceContext {
67
77
 
68
78
  - Server entry point with `@FrontMcp` decorator and `info` configuration
69
79
  - App registration with `@App` grouping tools and resources together
70
- - Static resource that returns JSON data via `read()`
80
+ - Static resource that returns JSON data via `execute(uri)` and `ReadResourceResult`
71
81
  - Clean separation between server, app, tools, and resources
72
82
 
73
83
  ## Related
@@ -8,7 +8,7 @@ features:
8
8
  - 'Unit testing tools by mocking `this.fetch()`, `this.fail()`, and other context methods'
9
9
  - 'Using `Object.assign(tool, ctx)` to inject mock context into the tool instance'
10
10
  - 'E2E testing with `TestServer.start()` and `McpTestClient.create()`'
11
- - 'Using `toContainTool()` custom matcher for asserting tool presence'
11
+ - 'Asserting tool presence via `expect(tools.map((t) => t.name)).toContain(...)` and parsing resource JSON via `result.json<T>()`'
12
12
  - 'Proper cleanup with `client.disconnect()` and `server.stop()` in `afterAll`'
13
13
  ---
14
14
 
@@ -21,6 +21,7 @@ Shows how to write unit tests for tools by mocking context methods, and E2E test
21
21
  ```typescript
22
22
  // test/get-weather.tool.spec.ts
23
23
  import { ToolContext } from '@frontmcp/sdk';
24
+
24
25
  import { GetWeatherTool } from '../src/tools/get-weather.tool';
25
26
 
26
27
  describe('GetWeatherTool', () => {
@@ -49,7 +50,7 @@ describe('GetWeatherTool', () => {
49
50
  get: jest.fn(),
50
51
  tryGet: jest.fn(),
51
52
  notify: jest.fn(),
52
- respondProgress: jest.fn(),
53
+ progress: jest.fn(),
53
54
  } as unknown as ToolContext;
54
55
  Object.assign(tool, ctx);
55
56
 
@@ -81,7 +82,7 @@ describe('GetWeatherTool', () => {
81
82
  get: jest.fn(),
82
83
  tryGet: jest.fn(),
83
84
  notify: jest.fn(),
84
- respondProgress: jest.fn(),
85
+ progress: jest.fn(),
85
86
  } as unknown as ToolContext;
86
87
  Object.assign(tool, ctx);
87
88
 
@@ -112,15 +113,15 @@ describe('Weather Server E2E', () => {
112
113
  });
113
114
 
114
115
  it('should list tools including get_weather', async () => {
115
- const { tools } = await client.listTools();
116
+ const tools = await client.tools.list();
116
117
 
117
118
  expect(tools.length).toBeGreaterThan(0);
118
- expect(tools).toContainTool('get_weather');
119
+ expect(tools.map((t) => t.name)).toContain('get_weather');
119
120
  });
120
121
 
121
122
  it('should read the cities resource', async () => {
122
- const result = await client.readResource('weather://cities');
123
- const cities = JSON.parse(result.contents[0].text);
123
+ const result = await client.resources.read('weather://cities');
124
+ const cities = result.json<string[]>();
124
125
 
125
126
  expect(Array.isArray(cities)).toBe(true);
126
127
  expect(cities).toContain('London');
@@ -134,7 +135,7 @@ describe('Weather Server E2E', () => {
134
135
  - Unit testing tools by mocking `this.fetch()`, `this.fail()`, and other context methods
135
136
  - Using `Object.assign(tool, ctx)` to inject mock context into the tool instance
136
137
  - E2E testing with `TestServer.start()` and `McpTestClient.create()`
137
- - Using `toContainTool()` custom matcher for asserting tool presence
138
+ - Asserting tool presence via `expect(tools.map((t) => t.name)).toContain(...)` and parsing resource JSON via `result.json<T>()`
138
139
  - Proper cleanup with `client.disconnect()` and `server.stop()` in `afterAll`
139
140
 
140
141
  ## Related