@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
@@ -2,88 +2,67 @@
2
2
  name: wrangler-config
3
3
  reference: production-cloudflare
4
4
  level: basic
5
- description: 'Shows how to configure `wrangler.toml` with correct routes, KV bindings for session storage, and secret management for a FrontMCP Cloudflare Worker.'
6
- tags: [production, cloudflare, cache, session, wrangler, config]
5
+ description: 'Checklist for verifying the `wrangler.toml` produced by `frontmcp build --target cloudflare` is production-ready. **Note:** configuration authoring lives in `frontmcp-deployment references/deploy-to-cloudflare.md`; this file is checklist-only.'
6
+ tags:
7
+ - production
8
+ - cloudflare
9
+ - cache
10
+ - session
11
+ - wrangler
12
+ - checklist
7
13
  features:
8
- - 'Complete `wrangler.toml` with KV bindings for sessions and cache'
9
- - 'Separate staging/production environment configs'
10
- - 'Cloudflare Worker entry point via `createCloudflareHandler`'
11
- - 'Secrets managed via `wrangler secret put` (not in config files)'
14
+ - Verify `main = "dist/cloudflare/index.js"` (the build adapter writes this never override)
15
+ - Verify KV bindings for sessions and cache exist
16
+ - Verify staging / production environment configs are separated
17
+ - Verify secrets are NOT in `wrangler.toml` — use `wrangler secret put`
12
18
  ---
13
19
 
14
- # Wrangler Configuration with KV Bindings
15
-
16
- Shows how to configure `wrangler.toml` with correct routes, KV bindings for session storage, and secret management for a FrontMCP Cloudflare Worker.
17
-
18
- ## Code
19
-
20
- ```toml
21
- # wrangler.toml
22
- name = "my-mcp-worker"
23
- main = "dist/worker.js"
24
- compatibility_date = "2024-01-01"
25
-
26
- # Custom domain routing
27
- routes = [
28
- { pattern = "mcp.example.com/*", zone_name = "example.com" }
29
- ]
30
-
31
- # KV namespace for session storage
32
- [[kv_namespaces]]
33
- binding = "MCP_SESSIONS"
34
- id = "abc123def456"
35
-
36
- # KV namespace for cache
37
- [[kv_namespaces]]
38
- binding = "MCP_CACHE"
39
- id = "def456ghi789"
40
-
41
- # Environment-specific config
42
- [env.staging]
43
- name = "my-mcp-worker-staging"
44
- routes = [
45
- { pattern = "mcp-staging.example.com/*", zone_name = "example.com" }
46
- ]
47
-
48
- [env.production]
49
- name = "my-mcp-worker-production"
50
- routes = [
51
- { pattern = "mcp.example.com/*", zone_name = "example.com" }
52
- ]
53
- ```
54
-
55
- ```typescript
56
- // src/main.ts
57
- import { FrontMcp } from '@frontmcp/sdk';
58
- import { MyApp } from './my.app';
59
-
60
- @FrontMcp({
61
- info: { name: 'cf-mcp', version: '1.0.0' },
62
- apps: [MyApp],
63
-
64
- // CORS: use the workers.dev or custom domain
65
- cors: {
66
- origin: ['https://app.example.com'],
67
- },
68
- })
69
- export default class CloudflareMcpServer {}
70
- ```
71
-
72
- ```typescript
73
- // src/worker.ts — Cloudflare Worker entry point
74
- import { createCloudflareHandler } from '@frontmcp/adapters/cloudflare';
75
- import Server from './main';
76
-
77
- export default createCloudflareHandler(Server);
78
- ```
20
+ # Wrangler Configuration: Production-Readiness Checklist
21
+
22
+ Checklist for verifying the `wrangler.toml` produced by `frontmcp build --target cloudflare` is production-ready. **Note:** configuration authoring lives in `frontmcp-deployment references/deploy-to-cloudflare.md`; this file is checklist-only.
23
+
24
+ ## Build artifact checks
25
+
26
+ - [ ] `frontmcp build --target cloudflare` runs cleanly with no warnings
27
+ - [ ] The build adapter wrote `main = "dist/cloudflare/index.js"` to `wrangler.toml` — **do not hand-edit this line**; the adapter overwrites it on every build (PR #374 — overriding silently breaks `wrangler deploy`)
28
+ - [ ] `dist/cloudflare/index.js` exists after build and is what `wrangler deploy` uploads
29
+ - [ ] No hand-written `src/worker.ts` with a fictional `createCloudflareHandler(...)` — the build emits the entry; your code stays the decorated `@FrontMcp` class
30
+ - [ ] Bundle size is < 10 MB compressed (Workers limit)
31
+
32
+ ## Routes & domains
33
+
34
+ - [ ] `routes = [{ pattern = "<host>/*", zone_name = "<zone>" }]` set for the right hostnames
35
+ - [ ] Custom domain or `*.workers.dev` subdomain matches what `cors.origin` accepts in your `@FrontMcp` config
36
+ - [ ] Separate `[env.staging]` and `[env.production]` blocks with distinct names + routes
37
+
38
+ ## KV / Durable Objects / R2
39
+
40
+ - [ ] At least one `[[kv_namespaces]]` block bound for sessions if HA / multi-region (e.g. `binding = "MCP_SESSIONS"`)
41
+ - [ ] Cache binding (KV or Cache API) exists if `CachePlugin` is configured
42
+ - [ ] Durable Objects only used when stateful coordination is required (rate limiting, locks)
43
+ - [ ] R2 binding exists if the server reads/writes blobs (no filesystem in Workers)
44
+
45
+ ## Secrets & environment
46
+
47
+ - [ ] No secrets in `wrangler.toml` — all set via `wrangler secret put <NAME>`
48
+ - [ ] `[vars]` block contains only non-sensitive config (region names, feature flags)
49
+ - [ ] `compatibility_date` set to a recent date and locked
50
+
51
+ ## Deploy & observability
52
+
53
+ - [ ] Deploy with `wrangler deploy --env production` (not the unscoped form)
54
+ - [ ] `wrangler tail` works against the production worker for live debugging
55
+ - [ ] Dashboard shows recent successful deploys
79
56
 
80
57
  ## What This Demonstrates
81
58
 
82
- - Complete `wrangler.toml` with KV bindings for sessions and cache
83
- - Separate staging/production environment configs
84
- - Cloudflare Worker entry point via `createCloudflareHandler`
85
- - Secrets managed via `wrangler secret put` (not in config files)
59
+ - Verify `main = "dist/cloudflare/index.js"` (the build adapter writes this never override)
60
+ - Verify KV bindings for sessions and cache exist
61
+ - Verify staging / production environment configs are separated
62
+ - Verify secrets are NOT in `wrangler.toml` — use `wrangler secret put`
86
63
 
87
64
  ## Related
88
65
 
89
- - See `production-cloudflare` for the full Cloudflare Workers checklist
66
+ - Configuration source of truth: `frontmcp-deployment/references/deploy-to-cloudflare.md`
67
+ - Build adapter source: `libs/cli/src/commands/build/adapters/cloudflare.ts`
68
+ - See `production-cloudflare` for the Cloudflare runtime / scaling checklist
@@ -2,18 +2,26 @@
2
2
  name: cold-start-connection-reuse
3
3
  reference: production-lambda
4
4
  level: intermediate
5
- description: 'Shows how to minimize Lambda cold starts with lazy initialization, tree-shaking, and the connection reuse pattern for external services.'
6
- tags: [production, lambda, performance, cold, start, connection]
5
+ description: Shows how to minimize Lambda cold starts with lazy initialization on first call and the module-scope connection-reuse pattern for external services.
6
+ tags:
7
+ - production
8
+ - lambda
9
+ - performance
10
+ - cold
11
+ - start
12
+ - connection
7
13
  features:
8
- - 'Connection reuse pattern: caching connections in module scope across warm invocations'
9
- - 'Lazy-loading heavy dependencies (`pg`) via dynamic `import()` to reduce cold start'
10
- - 'Not closing connections in `onDestroy()` for Lambda (they survive freeze/thaw)'
11
- - 'Keeping module scope lightweight with no heavy initialization'
14
+ - 'Connection reuse pattern: caching the connection promise in module scope so it survives Lambda freeze/thaw'
15
+ - Lazy-loading heavy dependencies (`pg`) via dynamic `import()` on first use, not at module load
16
+ - Not closing connections on shutdown for Lambda (they survive freeze/thaw — and providers have no `onDestroy` hook anyway)
17
+ - Keeping module scope lightweight with no heavy initialization
12
18
  ---
13
19
 
14
20
  # Cold Start Optimization and Connection Reuse
15
21
 
16
- Shows how to minimize Lambda cold starts with lazy initialization, tree-shaking, and the connection reuse pattern for external services.
22
+ Shows how to minimize Lambda cold starts with lazy initialization on first call and the module-scope connection-reuse pattern for external services.
23
+
24
+ > `@Provider`-decorated classes do NOT have `onInit` / `onDestroy` lifecycle hooks. Initialize lazily on first method call. For Lambda specifically, do **not** wire any shutdown hook for DB connections — Lambda freezes the execution context between invocations and your connection survives, so explicit close is wrong.
17
25
 
18
26
  ## Code
19
27
 
@@ -23,38 +31,34 @@ import { Provider, ProviderScope } from '@frontmcp/sdk';
23
31
 
24
32
  export const DB_CLIENT = Symbol('DbClient');
25
33
 
26
- // Connection reuse pattern: connections survive between warm invocations
27
- // but must handle cold starts and reconnection gracefully
28
- let cachedConnection: unknown | undefined;
34
+ // Module-scope cache survives freeze/thaw between Lambda invocations.
35
+ let cachedConnectionPromise: Promise<unknown> | undefined;
29
36
 
30
37
  @Provider({ token: DB_CLIENT, scope: ProviderScope.GLOBAL })
31
38
  export class DbConnectionProvider {
32
- private connection: unknown;
33
-
34
- async onInit(): Promise<void> {
35
- // Reuse connection across warm invocations
36
- if (cachedConnection) {
37
- this.connection = cachedConnection;
38
- return;
39
+ // Lazy on first getConnection() — heavy SDK import does not run at module load.
40
+ async getConnection(): Promise<unknown> {
41
+ if (!cachedConnectionPromise) {
42
+ const promise = (async () => {
43
+ const { Client } = await import('pg');
44
+ const client = new Client({
45
+ host: process.env.DB_HOST,
46
+ connectionTimeoutMillis: 5000, // Don't hang on connection attempts
47
+ });
48
+ await client.connect();
49
+ return client;
50
+ })();
51
+ // Reset on failure so the next warm invocation can retry instead of
52
+ // permanently caching a rejected promise.
53
+ promise.catch(() => {
54
+ if (cachedConnectionPromise === promise) cachedConnectionPromise = undefined;
55
+ });
56
+ cachedConnectionPromise = promise;
39
57
  }
40
-
41
- // Lazy-load the database driver — reduces cold start time
42
- const { Client } = await import('pg');
43
- this.connection = new Client({
44
- host: process.env.DB_HOST,
45
- connectionTimeoutMillis: 5000, // Don't hang on connection attempts
46
- });
47
- await (this.connection as { connect: () => Promise<void> }).connect();
48
-
49
- // Cache for warm invocations
50
- cachedConnection = this.connection;
51
- }
52
-
53
- getConnection() {
54
- return this.connection;
58
+ return cachedConnectionPromise;
55
59
  }
56
60
 
57
- // Note: Don't close in onDestroy for Lambda — connection survives freeze/thaw
61
+ // Note: Do NOT close in any shutdown hook for Lambda — connection survives freeze/thaw.
58
62
  }
59
63
  ```
60
64
 
@@ -77,12 +81,11 @@ import { DB_CLIENT } from '../providers/db-connection.provider';
77
81
  })
78
82
  export class OptimizedQueryTool extends ToolContext {
79
83
  async execute(input: { id: string }) {
80
- const db = this.get(DB_CLIENT);
84
+ const db = this.get(DB_CLIENT) as { getConnection: () => Promise<{ query: Function }> };
81
85
 
82
86
  // Parameterized query — prevents SQL injection
83
- const result = await (db as { getConnection: () => { query: Function } })
84
- .getConnection()
85
- .query('SELECT * FROM records WHERE id = $1', [input.id]);
87
+ const conn = await db.getConnection();
88
+ const result = await conn.query('SELECT * FROM records WHERE id = $1', [input.id]);
86
89
 
87
90
  if (!result.rows[0]) {
88
91
  this.fail(new Error(`Record not found: ${input.id}`));
@@ -113,9 +116,9 @@ export default class FastLambdaServer {}
113
116
 
114
117
  ## What This Demonstrates
115
118
 
116
- - Connection reuse pattern: caching connections in module scope across warm invocations
117
- - Lazy-loading heavy dependencies (`pg`) via dynamic `import()` to reduce cold start
118
- - Not closing connections in `onDestroy()` for Lambda (they survive freeze/thaw)
119
+ - Connection reuse pattern: caching the connection promise in module scope so it survives Lambda freeze/thaw
120
+ - Lazy-loading heavy dependencies (`pg`) via dynamic `import()` on first use, not at module load
121
+ - Not closing connections on shutdown for Lambda (they survive freeze/thaw — and providers have no `onDestroy` hook anyway)
119
122
  - Keeping module scope lightweight with no heavy initialization
120
123
 
121
124
  ## Related
@@ -2,106 +2,75 @@
2
2
  name: sam-template
3
3
  reference: production-lambda
4
4
  level: basic
5
- description: 'Shows a complete SAM/CloudFormation template for deploying a FrontMCP server to AWS Lambda with API Gateway routing, DynamoDB for session storage, and proper environment configuration.'
6
- tags: [production, lambda, session, sam, template]
5
+ description: 'Checklist for verifying the SAM template pairs correctly with the bundle produced by `frontmcp build --target lambda`. **Note:** configuration authoring lives in `frontmcp-deployment references/deploy-to-lambda.md`; this file is checklist-only.'
6
+ tags:
7
+ - production
8
+ - lambda
9
+ - session
10
+ - sam
11
+ - checklist
7
12
  features:
8
- - 'Complete SAM template with API Gateway, Lambda function, and DynamoDB table'
9
- - 'DynamoDB for session storage with TTL-based automatic cleanup'
10
- - 'Lambda handler entry point via `createLambdaHandler`'
11
- - 'Pay-per-request billing for cost-effective scaling'
12
- - 'IAM policies scoped to the specific DynamoDB table'
13
+ - 'Verify `Handler: handler.handler` with `CodeUri: dist/lambda/` (the build emits `dist/lambda/handler.cjs`)'
14
+ - No hand-written `src/lambda.ts` with a fictional `createLambdaHandler` import
15
+ - DynamoDB session table has TTL enabled for automatic cleanup
16
+ - IAM policies are scoped (no `*` resources / actions)
17
+ - API Gateway proxy route forwards to the function
13
18
  ---
14
19
 
15
- # SAM Template with API Gateway and DynamoDB
16
-
17
- Shows a complete SAM/CloudFormation template for deploying a FrontMCP server to AWS Lambda with API Gateway routing, DynamoDB for session storage, and proper environment configuration.
18
-
19
- ## Code
20
-
21
- ```yaml
22
- # ci/template.yaml
23
- AWSTemplateFormatVersion: '2010-09-09'
24
- Transform: AWS::Serverless-2016-10-31
25
- Description: FrontMCP Lambda deployment
26
-
27
- Globals:
28
- Function:
29
- Runtime: nodejs20.x
30
- Timeout: 30
31
- MemorySize: 256
32
- Environment:
33
- Variables:
34
- NODE_ENV: production
35
- SESSION_TABLE: !Ref SessionTable
36
-
37
- Resources:
38
- McpFunction:
39
- Type: AWS::Serverless::Function
40
- Properties:
41
- Handler: dist/lambda.handler
42
- CodeUri: .
43
- Events:
44
- McpApi:
45
- Type: Api
46
- Properties:
47
- Path: /mcp/{proxy+}
48
- Method: ANY
49
- Policies:
50
- - DynamoDBCrudPolicy:
51
- TableName: !Ref SessionTable
52
-
53
- SessionTable:
54
- Type: AWS::DynamoDB::Table
55
- Properties:
56
- TableName: mcp-sessions
57
- BillingMode: PAY_PER_REQUEST
58
- AttributeDefinitions:
59
- - AttributeName: sessionId
60
- AttributeType: S
61
- KeySchema:
62
- - AttributeName: sessionId
63
- KeyType: HASH
64
- TimeToLiveSpecification:
65
- AttributeName: ttl
66
- Enabled: true
67
-
68
- Outputs:
69
- ApiEndpoint:
70
- Description: API Gateway endpoint URL
71
- Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/mcp/'
72
- ```
73
-
74
- ```typescript
75
- // src/lambda.ts — Lambda handler entry point
76
- import { createLambdaHandler } from '@frontmcp/adapters/lambda';
77
- import Server from './main';
78
-
79
- export const handler = createLambdaHandler(Server);
80
- ```
81
-
82
- ```typescript
83
- // src/main.ts
84
- import { FrontMcp } from '@frontmcp/sdk';
85
- import { MyApp } from './my.app';
86
-
87
- @FrontMcp({
88
- info: { name: 'lambda-mcp', version: '1.0.0' },
89
- apps: [MyApp],
90
- cors: {
91
- origin: ['https://app.example.com'],
92
- },
93
- })
94
- export default class LambdaMcpServer {}
95
- ```
20
+ # SAM Template: Production-Readiness Checklist
21
+
22
+ Checklist for verifying the SAM template pairs correctly with the bundle produced by `frontmcp build --target lambda`. **Note:** configuration authoring lives in `frontmcp-deployment references/deploy-to-lambda.md`; this file is checklist-only.
23
+
24
+ ## Build artifact checks
25
+
26
+ - [ ] `frontmcp build --target lambda` succeeded with no warnings
27
+ - [ ] `dist/lambda/handler.cjs` exists — this is the bundled handler the build adapter writes
28
+ - [ ] No hand-written `src/lambda.ts` importing a fictional `createLambdaHandler` from `@frontmcp/adapters/lambda` — the build adapter generates the entry; your code stays the decorated `@FrontMcp` class
29
+ - [ ] `Handler: handler.handler` with `CodeUri: dist/lambda/` in `template.yaml` (filename `handler.cjs` → handler symbol `handler`). NOT `dist/lambda.handler` or `index.handler`
30
+ - [ ] `CodeUri: .` (or pointed at the project root containing `dist/`) so SAM packages the bundled handler
31
+
32
+ ## Function configuration
33
+
34
+ - [ ] `Runtime: nodejs20.x` (or current LTS)
35
+ - [ ] `MemorySize` and `Timeout` sized to your workload (defaults: 256 MB / 30 s)
36
+ - [ ] `Environment.Variables` includes `NODE_ENV: production` and any required app env
37
+ - [ ] Reserved or provisioned concurrency set for latency-sensitive endpoints
38
+
39
+ ## Session / state
40
+
41
+ - [ ] DynamoDB session table has `BillingMode: PAY_PER_REQUEST` (or capacity sized correctly)
42
+ - [ ] `TimeToLiveSpecification.AttributeName: ttl` and `Enabled: true` for automatic session cleanup
43
+ - [ ] In `@FrontMcp`, sessions point at DynamoDB / ElastiCache — never in-memory in Lambda
44
+ - [ ] No filesystem writes outside `/tmp` (default 512 MB; configurable up to 10 GB via SAM `EphemeralStorage` if needed)
45
+
46
+ ## API Gateway / routing
47
+
48
+ - [ ] Path is `/mcp/{proxy+}` with `Method: ANY` so MCP transport reaches the handler
49
+ - [ ] CORS configured at API Gateway OR via `@FrontMcp` `cors`, not both
50
+ - [ ] Stage names (`Prod` / `Staging`) match deploy pipeline
51
+
52
+ ## IAM hardening
53
+
54
+ - [ ] No `Action: '*'` or `Resource: '*'` in the function's policies
55
+ - [ ] DynamoDB access scoped to `!Ref SessionTable` only
56
+ - [ ] Secrets read via SSM / Secrets Manager scoped to `/<app>/<env>/*`
57
+
58
+ ## Observability
59
+
60
+ - [ ] CloudWatch alarm on `Errors` metric
61
+ - [ ] CloudWatch alarm on `Throttles` metric
62
+ - [ ] Dead Letter Queue (SQS) configured for failed async invocations
96
63
 
97
64
  ## What This Demonstrates
98
65
 
99
- - Complete SAM template with API Gateway, Lambda function, and DynamoDB table
100
- - DynamoDB for session storage with TTL-based automatic cleanup
101
- - Lambda handler entry point via `createLambdaHandler`
102
- - Pay-per-request billing for cost-effective scaling
103
- - IAM policies scoped to the specific DynamoDB table
66
+ - Verify `Handler: handler.handler` with `CodeUri: dist/lambda/` (the build emits `dist/lambda/handler.cjs`)
67
+ - No hand-written `src/lambda.ts` with a fictional `createLambdaHandler` import
68
+ - DynamoDB session table has TTL enabled for automatic cleanup
69
+ - IAM policies are scoped (no `*` resources / actions)
70
+ - API Gateway proxy route forwards to the function
104
71
 
105
72
  ## Related
106
73
 
107
- - See `production-lambda` for the full SAM/CloudFormation and Lambda runtime checklist
74
+ - Configuration source of truth: `frontmcp-deployment/references/deploy-to-lambda.md`
75
+ - Build adapter source: `libs/cli/src/commands/build/adapters/lambda.ts`
76
+ - See `production-lambda` for the runtime / scaling checklist
@@ -27,7 +27,7 @@ Resources:
27
27
  McpFunction:
28
28
  Type: AWS::Serverless::Function
29
29
  Properties:
30
- Handler: dist/lambda.handler
30
+ Handler: dist/handler.handler # Build adapter emits dist/handler.cjs → handler symbol
31
31
  CodeUri: .
32
32
  Runtime: nodejs20.x
33
33
  Timeout: 30
@@ -92,32 +92,42 @@ import { Provider, ProviderScope } from '@frontmcp/sdk';
92
92
 
93
93
  export const SECRETS = Symbol('Secrets');
94
94
 
95
+ // Providers do NOT have onInit/onDestroy — load lazily on first read.
95
96
  @Provider({ token: SECRETS, scope: ProviderScope.GLOBAL })
96
97
  export class SecretsProvider {
97
- private cache = new Map<string, string>();
98
+ private cache: Map<string, string> | undefined;
98
99
 
99
- async onInit(): Promise<void> {
100
- // Load secrets from AWS SSM Parameter Store (not env vars for sensitive data)
100
+ private async ensureLoaded(): Promise<Map<string, string>> {
101
+ if (this.cache) return this.cache;
102
+ const cache = new Map<string, string>();
101
103
  const { SSMClient, GetParametersByPathCommand } = await import('@aws-sdk/client-ssm');
102
104
  const ssm = new SSMClient({});
103
105
  const path = process.env.SECRETS_PATH ?? '/mcp/production/';
104
106
 
105
- const result = await ssm.send(
106
- new GetParametersByPathCommand({
107
- Path: path,
108
- WithDecryption: true,
109
- }),
110
- );
111
-
112
- for (const param of result.Parameters ?? []) {
113
- const key = param.Name?.replace(path, '') ?? '';
114
- this.cache.set(key, param.Value ?? '');
115
- }
107
+ // Walk every page — GetParametersByPath caps results and returns NextToken
108
+ // when more parameters exist. Without this loop, large /<env>/ namespaces
109
+ // silently lose secrets after the first page.
110
+ let nextToken: string | undefined;
111
+ do {
112
+ const result = await ssm.send(
113
+ new GetParametersByPathCommand({ Path: path, WithDecryption: true, NextToken: nextToken }),
114
+ );
115
+ for (const param of result.Parameters ?? []) {
116
+ const key = param.Name?.replace(path, '') ?? '';
117
+ cache.set(key, param.Value ?? '');
118
+ }
119
+ nextToken = result.NextToken;
120
+ } while (nextToken);
121
+ this.cache = cache;
122
+ return cache;
116
123
  }
117
124
 
118
- get(key: string): string {
119
- const value = this.cache.get(key);
120
- if (!value) {
125
+ async get(key: string): Promise<string> {
126
+ const cache = await this.ensureLoaded();
127
+ const value = cache.get(key);
128
+ // `cache.has` / `value === undefined` so empty-string secrets are still
129
+ // returned (a falsy `!value` check would treat `""` as missing).
130
+ if (value === undefined) {
121
131
  throw new Error(`Secret not found: ${key}`);
122
132
  }
123
133
  return value;
@@ -2,18 +2,24 @@
2
2
  name: multi-instance-cleanup
3
3
  reference: production-node-sdk
4
4
  level: advanced
5
- description: 'Shows how multiple SDK instances can coexist without conflicts, and how to implement proper cleanup to prevent memory leaks from event listeners, timers, and provider resources.'
6
- tags: [production, sdk, node, multi, instance, cleanup]
5
+ description: 'Shows how multiple SDK instances can coexist without conflicts, and how to clean up timers and listeners given that `@Provider` classes have **no** `onInit` / `onDestroy` lifecycle hooks. The pattern is: initialize in the constructor, expose an explicit `stop()` method, and have the host app call it before `server.dispose()`.'
6
+ tags:
7
+ - production
8
+ - sdk
9
+ - node
10
+ - multi
11
+ - instance
12
+ - cleanup
7
13
  features:
8
- - 'Implementing `onDestroy()` in providers to clean up timers and listeners'
9
- - 'Ensuring multiple instances coexist without sharing global state'
10
- - 'Testing that dispose removes all event listeners (no leaks)'
11
- - 'Verifying one instance still works after another is disposed'
14
+ - Explicit `stop()` method on providers (since `@Provider` classes have no `onDestroy` lifecycle hook)
15
+ - Ensuring multiple instances coexist without sharing global state
16
+ - Testing that dispose removes all event listeners (no leaks)
17
+ - Verifying one instance still works after another is disposed
12
18
  ---
13
19
 
14
20
  # Multi-Instance Coexistence and Cleanup
15
21
 
16
- Shows how multiple SDK instances can coexist without conflicts, and how to implement proper cleanup to prevent memory leaks from event listeners, timers, and provider resources.
22
+ Shows how multiple SDK instances can coexist without conflicts, and how to clean up timers and listeners given that `@Provider` classes have **no** `onInit` / `onDestroy` lifecycle hooks. The pattern is: initialize in the constructor, expose an explicit `stop()` method, and have the host app call it before `server.dispose()`.
17
23
 
18
24
  ## Code
19
25
 
@@ -28,24 +34,28 @@ export class PollingProvider {
28
34
  private intervalId: ReturnType<typeof setInterval> | undefined;
29
35
  private listeners: Array<() => void> = [];
30
36
 
31
- async onInit(): Promise<void> {
32
- // Start a polling interval
37
+ constructor() {
38
+ // Init at construction time — there is no async onInit hook on providers.
33
39
  this.intervalId = setInterval(() => {
34
40
  this.listeners.forEach((fn) => fn());
35
41
  }, 10_000);
42
+ // Don't keep the event loop alive on its own.
43
+ this.intervalId.unref?.();
36
44
  }
37
45
 
38
46
  addListener(fn: () => void): void {
39
47
  this.listeners.push(fn);
40
48
  }
41
49
 
42
- async onDestroy(): Promise<void> {
43
- // Clean up timer prevents dangling intervals after dispose
50
+ /**
51
+ * Explicit cleanup. Host app calls this before `server.dispose()`.
52
+ * (Providers have no onDestroy hook, so this is the explicit pattern.)
53
+ */
54
+ stop(): void {
44
55
  if (this.intervalId) {
45
56
  clearInterval(this.intervalId);
46
57
  this.intervalId = undefined;
47
58
  }
48
- // Remove all listener references — prevents memory leaks
49
59
  this.listeners.length = 0;
50
60
  }
51
61
  }
@@ -71,7 +81,11 @@ describe('Multi-instance coexistence', () => {
71
81
  expect(tools1.tools.length).toBeGreaterThan(0);
72
82
  expect(tools2.tools.length).toBeGreaterThan(0);
73
83
 
74
- // Clean up both no shared global state
84
+ // Clean up instance 1: stop providers (cancels timers / clears listeners),
85
+ // then dispose the server. The framework does NOT call provider.stop() for
86
+ // you — it's the host app's responsibility, which is why the provider
87
+ // exposes the explicit method.
88
+ server1.scope.providers.get(BackgroundJobProvider).stop();
75
89
  await client1.close();
76
90
  await server1.dispose();
77
91
 
@@ -79,6 +93,7 @@ describe('Multi-instance coexistence', () => {
79
93
  const result = await client2.callTool('my_tool', { input: 'still-alive' });
80
94
  expect(result).toBeDefined();
81
95
 
96
+ server2.scope.providers.get(BackgroundJobProvider).stop();
82
97
  await client2.close();
83
98
  await server2.dispose();
84
99
  });
@@ -100,7 +115,7 @@ describe('Multi-instance coexistence', () => {
100
115
 
101
116
  ## What This Demonstrates
102
117
 
103
- - Implementing `onDestroy()` in providers to clean up timers and listeners
118
+ - Explicit `stop()` method on providers (since `@Provider` classes have no `onDestroy` lifecycle hook)
104
119
  - Ensuring multiple instances coexist without sharing global state
105
120
  - Testing that dispose removes all event listeners (no leaks)
106
121
  - Verifying one instance still works after another is disposed