@frontmcp/skills 1.1.2-beta.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/catalog/TEMPLATE.md +16 -11
- package/catalog/frontmcp-authorities/SKILL.md +116 -11
- package/catalog/frontmcp-authorities/references/authority-profiles.md +39 -36
- package/catalog/frontmcp-authorities/references/claims-mapping.md +7 -0
- package/catalog/frontmcp-authorities/references/custom-evaluators.md +63 -14
- package/catalog/frontmcp-channels/SKILL.md +36 -0
- package/catalog/frontmcp-channels/examples/channel-sources/file-watcher.md +8 -2
- package/catalog/frontmcp-channels/examples/channel-sources/replay-buffer.md +111 -30
- package/catalog/frontmcp-channels/examples/channel-two-way/whatsapp-bridge.md +45 -3
- package/catalog/frontmcp-channels/references/channel-sources.md +11 -3
- package/catalog/frontmcp-channels/references/channel-two-way.md +60 -89
- package/catalog/frontmcp-config/SKILL.md +111 -8
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-self-signed-tokens.md +4 -4
- package/catalog/frontmcp-config/examples/configure-auth-modes/remote-enterprise-oauth.md +7 -1
- package/catalog/frontmcp-config/examples/configure-deployment-targets/distributed-ha-config.md +1 -1
- package/catalog/frontmcp-config/examples/configure-deployment-targets/json-schema-ide-support.md +1 -1
- package/catalog/frontmcp-config/examples/configure-deployment-targets/multi-target-with-security.md +12 -9
- package/catalog/frontmcp-config/examples/configure-http/cors-restricted-origins.md +2 -2
- package/catalog/frontmcp-config/examples/configure-http/entry-path-reverse-proxy.md +1 -1
- package/catalog/frontmcp-config/examples/configure-security-headers/csp-report-only.md +1 -1
- package/catalog/frontmcp-config/examples/configure-security-headers/full-production-headers.md +1 -1
- package/catalog/frontmcp-config/examples/configure-skills-http/audit-log-basic.md +76 -0
- package/catalog/frontmcp-config/examples/configure-skills-http/audit-log-redis.md +116 -0
- package/catalog/frontmcp-config/examples/configure-skills-http/inject-instructions.md +59 -0
- package/catalog/frontmcp-config/references/configure-auth-modes.md +5 -5
- package/catalog/frontmcp-config/references/configure-deployment-targets.md +27 -24
- package/catalog/frontmcp-config/references/configure-http.md +14 -10
- package/catalog/frontmcp-config/references/configure-security-headers.md +2 -2
- package/catalog/frontmcp-config/references/configure-session.md +25 -25
- package/catalog/frontmcp-config/references/configure-skills-http.md +157 -0
- package/catalog/frontmcp-config/references/configure-throttle.md +1 -1
- package/catalog/frontmcp-config/references/configure-transport.md +2 -2
- package/catalog/frontmcp-deployment/SKILL.md +112 -9
- package/catalog/frontmcp-deployment/examples/build-for-browser/browser-build-with-custom-entry.md +23 -11
- package/catalog/frontmcp-deployment/examples/build-for-browser/browser-crypto-and-storage.md +44 -17
- package/catalog/frontmcp-deployment/examples/build-for-browser/react-provider-setup.md +53 -21
- package/catalog/frontmcp-deployment/examples/build-for-cli/cli-binary-build.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-cli/unix-socket-daemon.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-mcpb/mcpb-bundle-build.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-sdk/connect-openai.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-sdk/multi-platform-connect.md +1 -1
- package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/basic-worker-deploy.md +7 -8
- package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/worker-custom-domain.md +8 -6
- package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/worker-with-kv-storage.md +5 -4
- package/catalog/frontmcp-deployment/examples/deploy-to-lambda/cdk-deployment.md +8 -5
- package/catalog/frontmcp-deployment/examples/deploy-to-lambda/lambda-handler-with-cors.md +20 -18
- package/catalog/frontmcp-deployment/examples/deploy-to-lambda/sam-template-basic.md +8 -5
- package/catalog/frontmcp-deployment/examples/deploy-to-node/docker-compose-with-redis.md +3 -3
- package/catalog/frontmcp-deployment/examples/deploy-to-node/pm2-with-nginx.md +1 -1
- package/catalog/frontmcp-deployment/examples/deploy-to-node/resource-limits.md +2 -2
- package/catalog/frontmcp-deployment/examples/deploy-to-node-dockerfile/basic-multistage-dockerfile.md +2 -2
- package/catalog/frontmcp-deployment/examples/deploy-to-node-dockerfile/secure-nonroot-dockerfile.md +1 -1
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-mcp-endpoint-test.md +23 -21
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-with-kv.md +25 -22
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-with-skills-cache.md +23 -30
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel-config/minimal-vercel-config.md +52 -28
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel-config/vercel-config-with-security-headers.md +32 -55
- package/catalog/frontmcp-deployment/examples/mcp-client-integration/http-remote.md +9 -0
- package/catalog/frontmcp-deployment/references/build-for-browser.md +40 -17
- package/catalog/frontmcp-deployment/references/build-for-cli.md +8 -8
- package/catalog/frontmcp-deployment/references/deploy-to-cloudflare.md +43 -24
- package/catalog/frontmcp-deployment/references/deploy-to-lambda.md +36 -25
- package/catalog/frontmcp-deployment/references/deploy-to-node-dockerfile.md +56 -14
- package/catalog/frontmcp-deployment/references/deploy-to-node.md +9 -6
- package/catalog/frontmcp-deployment/references/deploy-to-vercel-config.md +57 -58
- package/catalog/frontmcp-deployment/references/deploy-to-vercel.md +49 -59
- package/catalog/frontmcp-deployment/references/mcp-client-integration.md +2 -0
- package/catalog/frontmcp-development/SKILL.md +186 -11
- package/catalog/frontmcp-development/examples/create-agent/custom-multi-pass-agent.md +1 -1
- package/catalog/frontmcp-development/examples/create-agent/nested-agents-with-swarm.md +30 -27
- package/catalog/frontmcp-development/examples/create-job/job-with-permissions.md +13 -8
- package/catalog/frontmcp-development/examples/create-provider/basic-database-provider.md +33 -23
- package/catalog/frontmcp-development/examples/create-provider/config-and-api-providers.md +19 -10
- package/catalog/frontmcp-development/examples/create-tool/tool-with-rate-limiting-and-progress.md +3 -3
- package/catalog/frontmcp-development/examples/create-workflow/webhook-triggered-workflow.md +6 -4
- package/catalog/frontmcp-development/examples/decorators-guide/agent-skill-job-workflow.md +1 -1
- package/catalog/frontmcp-development/examples/decorators-guide/basic-server-with-app-and-tools.md +13 -8
- package/catalog/frontmcp-development/examples/decorators-guide/multi-app-with-plugins-and-providers.md +50 -23
- package/catalog/frontmcp-development/references/create-agent.md +47 -30
- package/catalog/frontmcp-development/references/create-job.md +69 -54
- package/catalog/frontmcp-development/references/create-plugin-hooks.md +45 -28
- package/catalog/frontmcp-development/references/create-plugin.md +10 -8
- package/catalog/frontmcp-development/references/create-prompt.md +3 -3
- package/catalog/frontmcp-development/references/create-provider.md +91 -51
- package/catalog/frontmcp-development/references/create-resource.md +3 -3
- package/catalog/frontmcp-development/references/create-skill.md +2 -2
- package/catalog/frontmcp-development/references/create-tool.md +7 -7
- package/catalog/frontmcp-development/references/create-workflow.md +8 -10
- package/catalog/frontmcp-development/references/decorators-guide.md +92 -56
- package/catalog/frontmcp-development/references/official-plugins.md +4 -3
- package/catalog/frontmcp-development/references/openapi-adapter.md +1 -1
- package/catalog/frontmcp-extensibility/SKILL.md +70 -10
- package/catalog/frontmcp-extensibility/examples/skill-audit-log/custom-store.md +197 -0
- package/catalog/frontmcp-extensibility/examples/skill-audit-log/verify-chain.md +68 -0
- package/catalog/frontmcp-extensibility/examples/vectoriadb/product-catalog-search.md +3 -5
- package/catalog/frontmcp-extensibility/examples/vectoriadb/semantic-search-with-persistence.md +4 -11
- package/catalog/frontmcp-extensibility/examples/vectoriadb/tfidf-keyword-search.md +41 -30
- package/catalog/frontmcp-extensibility/references/skill-audit-log.md +233 -0
- package/catalog/frontmcp-extensibility/references/vectoriadb.md +73 -63
- package/catalog/frontmcp-guides/SKILL.md +84 -27
- package/catalog/frontmcp-guides/examples/example-knowledge-base/agent-and-plugin.md +72 -62
- package/catalog/frontmcp-guides/examples/example-knowledge-base/vector-search-and-resources.md +32 -43
- package/catalog/frontmcp-guides/examples/example-task-manager/auth-and-crud-tools.md +24 -17
- package/catalog/frontmcp-guides/examples/example-task-manager/authenticated-e2e-tests.md +23 -21
- package/catalog/frontmcp-guides/examples/example-task-manager/redis-provider-with-di.md +47 -39
- package/catalog/frontmcp-guides/examples/example-weather-api/server-and-app-setup.md +16 -6
- package/catalog/frontmcp-guides/examples/example-weather-api/unit-and-e2e-tests.md +9 -8
- package/catalog/frontmcp-guides/references/example-knowledge-base.md +192 -265
- package/catalog/frontmcp-guides/references/example-task-manager.md +60 -54
- package/catalog/frontmcp-guides/references/example-weather-api.md +22 -24
- package/catalog/frontmcp-observability/SKILL.md +66 -2
- package/catalog/frontmcp-observability/examples/telemetry-api/skill-counters.md +100 -0
- package/catalog/frontmcp-observability/examples/tracing-setup/production-tracing.md +7 -2
- package/catalog/frontmcp-observability/examples/vendor-integrations/coralogix-setup.md +6 -2
- package/catalog/frontmcp-observability/references/telemetry-api.md +72 -8
- package/catalog/frontmcp-observability/references/testing-observability.md +33 -49
- package/catalog/frontmcp-observability/references/tracing-setup.md +12 -5
- package/catalog/frontmcp-observability/references/vendor-integrations.md +46 -1
- package/catalog/frontmcp-production-readiness/SKILL.md +134 -3
- package/catalog/frontmcp-production-readiness/examples/common-checklist/caching-and-performance.md +57 -36
- package/catalog/frontmcp-production-readiness/examples/common-checklist/observability-setup.md +1 -1
- package/catalog/frontmcp-production-readiness/examples/common-checklist/security-hardening.md +102 -6
- package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/daemon-socket-config.md +2 -1
- package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/graceful-shutdown-cleanup.md +66 -58
- package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/security-and-permissions.md +5 -3
- package/catalog/frontmcp-production-readiness/examples/production-cloudflare/durable-objects-state.md +2 -1
- package/catalog/frontmcp-production-readiness/examples/production-cloudflare/wrangler-config.md +55 -76
- package/catalog/frontmcp-production-readiness/examples/production-lambda/cold-start-connection-reuse.md +43 -40
- package/catalog/frontmcp-production-readiness/examples/production-lambda/sam-template.md +63 -94
- package/catalog/frontmcp-production-readiness/examples/production-lambda/scaling-and-monitoring.md +28 -18
- package/catalog/frontmcp-production-readiness/examples/production-node-sdk/multi-instance-cleanup.md +29 -14
- package/catalog/frontmcp-production-readiness/examples/production-node-server/graceful-shutdown.md +58 -42
- package/catalog/frontmcp-production-readiness/examples/production-node-server/redis-session-scaling.md +5 -2
- package/catalog/frontmcp-production-readiness/examples/production-vercel/cold-start-optimization.md +41 -24
- package/catalog/frontmcp-production-readiness/examples/production-vercel/vercel-edge-config.md +56 -65
- package/catalog/frontmcp-production-readiness/references/common-checklist.md +17 -5
- package/catalog/frontmcp-production-readiness/references/production-cli-daemon.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-cloudflare.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-lambda.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-node-sdk.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-node-server.md +1 -1
- package/catalog/frontmcp-production-readiness/references/production-vercel.md +5 -5
- package/catalog/frontmcp-setup/SKILL.md +88 -0
- package/catalog/frontmcp-setup/examples/project-structure-nx/nx-workspace-with-apps.md +10 -4
- package/catalog/frontmcp-setup/examples/project-structure-standalone/dev-workflow-commands.md +21 -8
- package/catalog/frontmcp-setup/examples/readme-guide/node-server-readme.md +3 -3
- package/catalog/frontmcp-setup/references/multi-app-composition.md +4 -3
- package/catalog/frontmcp-setup/references/project-structure-nx.md +15 -6
- package/catalog/frontmcp-setup/references/project-structure-standalone.md +18 -15
- package/catalog/frontmcp-setup/references/readme-guide.md +1 -1
- package/catalog/frontmcp-setup/references/setup-project.md +19 -5
- package/catalog/frontmcp-setup/references/setup-redis.md +27 -39
- package/catalog/frontmcp-setup/references/setup-sqlite.md +25 -18
- package/catalog/frontmcp-testing/SKILL.md +102 -15
- package/catalog/frontmcp-testing/examples/setup-testing/unit-test-tool-resource-prompt.md +3 -3
- package/catalog/frontmcp-testing/examples/test-auth/oauth-flow-test.md +50 -39
- package/catalog/frontmcp-testing/examples/test-auth/role-based-access-test.md +52 -29
- package/catalog/frontmcp-testing/examples/test-auth/token-factory-test.md +37 -20
- package/catalog/frontmcp-testing/examples/test-direct-client/basic-create-test.md +25 -15
- package/catalog/frontmcp-testing/examples/test-direct-client/openai-claude-format-test.md +27 -21
- package/catalog/frontmcp-testing/examples/test-e2e-handler/basic-e2e-test.md +29 -20
- package/catalog/frontmcp-testing/examples/test-e2e-handler/manual-client-with-transport.md +5 -3
- package/catalog/frontmcp-testing/examples/test-e2e-handler/tool-call-and-error-e2e.md +35 -26
- package/catalog/frontmcp-testing/examples/test-tool-unit/basic-tool-test.md +8 -3
- package/catalog/frontmcp-testing/examples/test-tool-unit/schema-validation-test.md +4 -1
- package/catalog/frontmcp-testing/examples/test-tool-unit/tool-error-handling-test.md +6 -3
- package/catalog/frontmcp-testing/references/setup-testing.md +35 -39
- package/catalog/frontmcp-testing/references/test-auth.md +86 -43
- package/catalog/frontmcp-testing/references/test-browser-build.md +1 -1
- package/catalog/frontmcp-testing/references/test-direct-client.md +29 -19
- package/catalog/frontmcp-testing/references/test-e2e-handler.md +31 -19
- package/catalog/frontmcp-testing/references/test-tool-unit.md +6 -2
- package/catalog/skills-manifest.json +428 -339
- package/package.json +1 -1
- package/src/manifest.d.ts +13 -0
- package/src/manifest.js.map +1 -1
package/catalog/frontmcp-production-readiness/examples/common-checklist/caching-and-performance.md
CHANGED
|
@@ -2,57 +2,82 @@
|
|
|
2
2
|
name: caching-and-performance
|
|
3
3
|
reference: common-checklist
|
|
4
4
|
level: advanced
|
|
5
|
-
description:
|
|
6
|
-
tags:
|
|
5
|
+
description: Shows how to configure caching with the real `CachePlugin.init(...)` API and how to size connection pools so the server does not exhaust downstream resources.
|
|
6
|
+
tags:
|
|
7
|
+
- production
|
|
8
|
+
- redis
|
|
9
|
+
- cache
|
|
10
|
+
- session
|
|
11
|
+
- performance
|
|
12
|
+
- checklist
|
|
7
13
|
features:
|
|
8
|
-
- '
|
|
9
|
-
- '
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
14
|
+
- 'Using the real `CachePlugin.init({ type, defaultTTL, toolPatterns })` shape (NOT `new CachePlugin({ ttl: { ... } })`)'
|
|
15
|
+
- 'Setting per-tool TTL via `@Tool({ cache: { ttl } })` metadata in seconds'
|
|
16
|
+
- Using Redis-backed cache for multi-instance consistency
|
|
17
|
+
- Configuring connection pool limits and timeouts to prevent resource exhaustion
|
|
18
|
+
- Providers do not implement `onInit` / `onDestroy` — initialize in the constructor and let framework shutdown handle cleanup
|
|
13
19
|
---
|
|
14
20
|
|
|
15
21
|
# Caching and Performance Configuration
|
|
16
22
|
|
|
17
|
-
Shows how to configure caching with
|
|
23
|
+
Shows how to configure caching with the real `CachePlugin.init(...)` API and how to size connection pools so the server does not exhaust downstream resources.
|
|
24
|
+
|
|
25
|
+
> Note: `@Provider`-decorated classes do **not** have `onInit` / `onDestroy` lifecycle hooks. Provider construction is the init step. Shutdown cleanup happens via the framework-managed `scope.shutdown()` path on SIGTERM/SIGINT (see `front-mcp.ts`); you do not need to wire your own shutdown hooks.
|
|
18
26
|
|
|
19
27
|
## Code
|
|
20
28
|
|
|
21
29
|
```typescript
|
|
22
30
|
// src/main.ts
|
|
31
|
+
import CachePlugin from '@frontmcp/plugin-cache';
|
|
23
32
|
import { FrontMcp } from '@frontmcp/sdk';
|
|
24
|
-
|
|
33
|
+
|
|
25
34
|
import { MyApp } from './my.app';
|
|
26
35
|
|
|
27
36
|
@FrontMcp({
|
|
28
37
|
info: { name: 'perf-server', version: '1.0.0' },
|
|
29
38
|
apps: [MyApp],
|
|
30
39
|
plugins: [
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
// Real CachePlugin shape — see plugins/plugin-cache/src/cache.types.ts
|
|
41
|
+
CachePlugin.init({
|
|
42
|
+
type: 'redis', // 'memory' | 'redis' | 'redis-client' | 'global-store'
|
|
43
|
+
config: {
|
|
44
|
+
host: process.env.REDIS_HOST ?? 'localhost',
|
|
45
|
+
port: 6379,
|
|
36
46
|
},
|
|
37
|
-
|
|
47
|
+
defaultTTL: 60, // seconds — defaults to 1 day if omitted
|
|
48
|
+
// Tool name patterns to auto-cache (supports wildcards)
|
|
49
|
+
toolPatterns: ['get-weather', 'list-tasks', 'mintlify:*'],
|
|
38
50
|
}),
|
|
39
51
|
],
|
|
40
52
|
|
|
41
|
-
// Redis for multi-instance
|
|
53
|
+
// Redis for multi-instance shared state (sessions, jobs, global-store)
|
|
42
54
|
redis: {
|
|
43
55
|
provider: 'redis',
|
|
44
56
|
host: process.env.REDIS_HOST ?? 'localhost',
|
|
45
57
|
port: 6379,
|
|
46
58
|
},
|
|
47
|
-
|
|
48
|
-
// Session TTL to prevent unbounded growth
|
|
49
|
-
session: {
|
|
50
|
-
ttl: 3600_000, // 1 hour
|
|
51
|
-
},
|
|
52
59
|
})
|
|
53
60
|
export default class PerfServer {}
|
|
54
61
|
```
|
|
55
62
|
|
|
63
|
+
```typescript
|
|
64
|
+
// src/tools/get-weather.tool.ts — per-tool TTL via metadata
|
|
65
|
+
import { Tool, ToolContext, z } from '@frontmcp/sdk';
|
|
66
|
+
|
|
67
|
+
@Tool({
|
|
68
|
+
name: 'get-weather',
|
|
69
|
+
description: 'Fetch weather (slow-changing data — cache 5 minutes)',
|
|
70
|
+
inputSchema: { city: z.string() },
|
|
71
|
+
outputSchema: { temp: z.number() },
|
|
72
|
+
cache: { ttl: 300, slideWindow: false }, // seconds — overrides plugin default
|
|
73
|
+
})
|
|
74
|
+
export class GetWeatherTool extends ToolContext {
|
|
75
|
+
async execute(input: { city: string }) {
|
|
76
|
+
return { temp: 21 };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
56
81
|
```typescript
|
|
57
82
|
// src/providers/db-connection.provider.ts
|
|
58
83
|
import { Provider, ProviderScope } from '@frontmcp/sdk';
|
|
@@ -61,13 +86,13 @@ export const DB_POOL = Symbol('DbPool');
|
|
|
61
86
|
|
|
62
87
|
@Provider({ token: DB_POOL, scope: ProviderScope.GLOBAL })
|
|
63
88
|
export class DbConnectionProvider {
|
|
64
|
-
|
|
89
|
+
// Pool is created in the constructor — providers do not have onInit/onDestroy.
|
|
90
|
+
private readonly pool: { query: Function; end: Function };
|
|
65
91
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
this.pool = await this.createPool({
|
|
92
|
+
constructor() {
|
|
93
|
+
this.pool = this.createPool({
|
|
69
94
|
host: process.env.DB_HOST,
|
|
70
|
-
max: 20, // Maximum connections
|
|
95
|
+
max: 20, // Maximum connections — prevents resource exhaustion
|
|
71
96
|
idleTimeoutMs: 30_000, // Close idle connections after 30s
|
|
72
97
|
connectionTimeoutMs: 5_000, // Don't hang on connection attempts
|
|
73
98
|
});
|
|
@@ -77,12 +102,7 @@ export class DbConnectionProvider {
|
|
|
77
102
|
return this.pool.query(sql, params); // Parameterized — no SQL injection
|
|
78
103
|
}
|
|
79
104
|
|
|
80
|
-
|
|
81
|
-
// Clean up on shutdown — prevents connection leaks
|
|
82
|
-
await this.pool.end();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
private async createPool(config: Record<string, unknown>): Promise<{ query: Function; end: Function }> {
|
|
105
|
+
private createPool(config: Record<string, unknown>): { query: Function; end: Function } {
|
|
86
106
|
// Replace with your database driver (e.g., pg, mysql2)
|
|
87
107
|
throw new Error('Implement with your database driver');
|
|
88
108
|
}
|
|
@@ -91,12 +111,13 @@ export class DbConnectionProvider {
|
|
|
91
111
|
|
|
92
112
|
## What This Demonstrates
|
|
93
113
|
|
|
94
|
-
-
|
|
114
|
+
- Using the real `CachePlugin.init({ type, defaultTTL, toolPatterns })` shape (NOT `new CachePlugin({ ttl: { ... } })`)
|
|
115
|
+
- Setting per-tool TTL via `@Tool({ cache: { ttl } })` metadata in seconds
|
|
95
116
|
- Using Redis-backed cache for multi-instance consistency
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
- Using connection pool limits and timeouts to prevent resource exhaustion
|
|
117
|
+
- Configuring connection pool limits and timeouts to prevent resource exhaustion
|
|
118
|
+
- Providers do not implement `onInit` / `onDestroy` — initialize in the constructor and let framework shutdown handle cleanup
|
|
99
119
|
|
|
100
120
|
## Related
|
|
101
121
|
|
|
102
122
|
- See `common-checklist` for the full performance and memory management checklist
|
|
123
|
+
- Plugin source: `plugins/plugin-cache/src/cache.types.ts`
|
package/catalog/frontmcp-production-readiness/examples/common-checklist/security-hardening.md
CHANGED
|
@@ -2,18 +2,21 @@
|
|
|
2
2
|
name: security-hardening
|
|
3
3
|
reference: common-checklist
|
|
4
4
|
level: basic
|
|
5
|
-
description: 'Shows how to configure authentication, CORS, input validation,
|
|
6
|
-
tags: [production, redis, session, security, throttle, checklist]
|
|
5
|
+
description: 'Shows how to configure authentication, CORS, input validation, rate limiting, audit logging, and observability counters for a production FrontMCP server.'
|
|
6
|
+
tags: [production, redis, session, security, throttle, audit, observability, checklist]
|
|
7
7
|
features:
|
|
8
8
|
- "Restricting CORS origins to known domains instead of using `'*'`"
|
|
9
9
|
- 'Configuring rate limiting via the `throttle` option'
|
|
10
10
|
- 'Using Redis for session storage in multi-instance deployments'
|
|
11
11
|
- 'Defining both `inputSchema` and `outputSchema` on tools to prevent data leaks'
|
|
12
|
+
- 'Enabling the tamper-evident skill audit log with RS256 + a persistent store and a CI verifier'
|
|
13
|
+
- 'Wiring an OTel MeterProvider so framework counters (bundle pulls, signature failures, replay rejects) are exported'
|
|
14
|
+
- 'Keeping the auto-injected skill catalog summary inside the 16 KB initialize ceiling'
|
|
12
15
|
---
|
|
13
16
|
|
|
14
17
|
# Security Hardening Configuration
|
|
15
18
|
|
|
16
|
-
Shows how to configure authentication, CORS, input validation,
|
|
19
|
+
Shows how to configure authentication, CORS, input validation, rate limiting, audit logging, and observability counters for a production FrontMCP server.
|
|
17
20
|
|
|
18
21
|
## Code
|
|
19
22
|
|
|
@@ -41,10 +44,15 @@ import { MyApp } from './my.app';
|
|
|
41
44
|
maxAge: 86400, // Cache preflight for 24 hours
|
|
42
45
|
},
|
|
43
46
|
|
|
44
|
-
// Rate limiting: prevent abuse
|
|
47
|
+
// Rate limiting: prevent abuse (GuardConfig — see libs/guard)
|
|
45
48
|
throttle: {
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
enabled: true,
|
|
50
|
+
global: {
|
|
51
|
+
maxRequests: 100,
|
|
52
|
+
windowMs: 60_000, // 1 minute window
|
|
53
|
+
partitionBy: 'ip', // 'ip' | 'session' | 'global'
|
|
54
|
+
},
|
|
55
|
+
defaultTimeout: { executeMs: 30_000 },
|
|
48
56
|
},
|
|
49
57
|
|
|
50
58
|
// Session storage: use Redis (not in-memory) for multi-instance
|
|
@@ -82,13 +90,101 @@ export class SafeQueryTool extends ToolContext {
|
|
|
82
90
|
}
|
|
83
91
|
```
|
|
84
92
|
|
|
93
|
+
```typescript
|
|
94
|
+
// src/audit-bootstrap.ts — wire the audit log + meter provider before FrontMcp registers
|
|
95
|
+
import { metrics } from '@opentelemetry/api';
|
|
96
|
+
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
|
|
97
|
+
import { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
|
|
98
|
+
|
|
99
|
+
import {
|
|
100
|
+
Hs256AuditSigner,
|
|
101
|
+
MemoryAuditStore,
|
|
102
|
+
Rs256AuditSigner,
|
|
103
|
+
setSkillAuditFactory,
|
|
104
|
+
SkillAuditWriter,
|
|
105
|
+
SkillAuditWriterToken,
|
|
106
|
+
StorageAdapterAuditStore,
|
|
107
|
+
} from '@frontmcp/adapters/skills';
|
|
108
|
+
import { createStorageAdapter } from '@frontmcp/utils';
|
|
109
|
+
|
|
110
|
+
// 1. Audit subsystem
|
|
111
|
+
//
|
|
112
|
+
// `setSkillAuditFactory` registers the audit module with the SDK; the SDK
|
|
113
|
+
// itself constructs the writer using the positional signature
|
|
114
|
+
// `new SkillAuditWriter(store, signer, logger, metrics?, options?)` and
|
|
115
|
+
// forwards `subjectMode` from `skillsConfig.audit` into the options bag.
|
|
116
|
+
setSkillAuditFactory(() => ({
|
|
117
|
+
SkillAuditWriterToken,
|
|
118
|
+
SkillAuditWriter,
|
|
119
|
+
Hs256AuditSigner,
|
|
120
|
+
MemoryAuditStore,
|
|
121
|
+
}));
|
|
122
|
+
|
|
123
|
+
export const auditSigner = new Rs256AuditSigner(
|
|
124
|
+
// Private key as a JWK. Convert from a PEM if your secret store hands you
|
|
125
|
+
// PEMs (e.g. `crypto.createPrivateKey(pem).export({ format: 'jwk' })`).
|
|
126
|
+
JSON.parse(process.env.BUNDLE_SIGNING_PRIVATE_JWK!),
|
|
127
|
+
'bundle-signing-2026-01',
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
export const auditStore = new StorageAdapterAuditStore(
|
|
131
|
+
await createStorageAdapter({ provider: 'redis', host: process.env.REDIS_HOST!, port: 6379 }),
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
// 2. Meter provider — exports framework counters (bundle pulls, signature failures, ...)
|
|
135
|
+
metrics.setGlobalMeterProvider(
|
|
136
|
+
new MeterProvider({
|
|
137
|
+
readers: [
|
|
138
|
+
new PeriodicExportingMetricReader({
|
|
139
|
+
exporter: new OTLPMetricExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT! }),
|
|
140
|
+
exportIntervalMillis: 10_000,
|
|
141
|
+
}),
|
|
142
|
+
],
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// src/main.ts — wire the audit + meter setup into the FrontMcp config
|
|
149
|
+
import './audit-bootstrap';
|
|
150
|
+
|
|
151
|
+
import { auditSigner, auditStore } from './audit-bootstrap';
|
|
152
|
+
|
|
153
|
+
@FrontMcp({
|
|
154
|
+
// ... auth/cors/throttle/redis as above ...
|
|
155
|
+
|
|
156
|
+
// Keep the user-facing prompt tight so the auto-appended catalog summary
|
|
157
|
+
// stays under the 16 KB initialize ceiling.
|
|
158
|
+
instructions: 'You are a helpful assistant. Use available skills.',
|
|
159
|
+
|
|
160
|
+
skillsConfig: {
|
|
161
|
+
enabled: true,
|
|
162
|
+
auth: 'bearer',
|
|
163
|
+
jwt: { issuer: process.env.JWT_ISSUER!, audience: 'skills-api' },
|
|
164
|
+
injectInstructions: 'append',
|
|
165
|
+
audit: {
|
|
166
|
+
enabled: true,
|
|
167
|
+
signer: auditSigner,
|
|
168
|
+
store: auditStore,
|
|
169
|
+
subjectMode: 'hash',
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
})
|
|
173
|
+
export default class HardenedServer {}
|
|
174
|
+
```
|
|
175
|
+
|
|
85
176
|
## What This Demonstrates
|
|
86
177
|
|
|
87
178
|
- Restricting CORS origins to known domains instead of using `'*'`
|
|
88
179
|
- Configuring rate limiting via the `throttle` option
|
|
89
180
|
- Using Redis for session storage in multi-instance deployments
|
|
90
181
|
- Defining both `inputSchema` and `outputSchema` on tools to prevent data leaks
|
|
182
|
+
- Enabling the tamper-evident skill audit log with RS256 + a persistent store and a CI verifier
|
|
183
|
+
- Wiring an OTel MeterProvider so framework counters (bundle pulls, signature failures, replay rejects) are exported
|
|
184
|
+
- Keeping the auto-injected skill catalog summary inside the 16 KB initialize ceiling
|
|
91
185
|
|
|
92
186
|
## Related
|
|
93
187
|
|
|
94
188
|
- See `common-checklist` for the full security, performance, and reliability checklist
|
|
189
|
+
- See `skill-audit-log` for the audit chain architecture
|
|
190
|
+
- See `configure-skills-http` for the full `skillsConfig` reference
|
package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/daemon-socket-config.md
CHANGED
|
@@ -21,6 +21,7 @@ Shows how to configure a FrontMCP server as a long-running local daemon with Uni
|
|
|
21
21
|
```typescript
|
|
22
22
|
// src/main.ts
|
|
23
23
|
import { FrontMcp } from '@frontmcp/sdk';
|
|
24
|
+
|
|
24
25
|
import { MyApp } from './my.app';
|
|
25
26
|
|
|
26
27
|
@FrontMcp({
|
|
@@ -35,7 +36,7 @@ import { MyApp } from './my.app';
|
|
|
35
36
|
// SQLite for local persistence (sessions, cache)
|
|
36
37
|
sqlite: {
|
|
37
38
|
path: `${process.env.HOME}/.config/my-daemon/data.db`,
|
|
38
|
-
|
|
39
|
+
walMode: true, // WAL mode for concurrent reads — see SqliteOptionsInterface
|
|
39
40
|
},
|
|
40
41
|
})
|
|
41
42
|
export default class MyDaemonServer {}
|
|
@@ -2,106 +2,114 @@
|
|
|
2
2
|
name: graceful-shutdown-cleanup
|
|
3
3
|
reference: production-cli-daemon
|
|
4
4
|
level: intermediate
|
|
5
|
-
description:
|
|
6
|
-
tags:
|
|
5
|
+
description: Shows how to layer daemon-specific cleanup (socket file, PID file) **on top of** the framework's built-in SIGTERM/SIGINT handler.
|
|
6
|
+
tags:
|
|
7
|
+
- production
|
|
8
|
+
- unix-socket
|
|
9
|
+
- cli
|
|
10
|
+
- database
|
|
11
|
+
- daemon
|
|
12
|
+
- graceful
|
|
7
13
|
features:
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
14
|
+
- The framework already wires SIGTERM/SIGINT — daemon cleanup attaches _additional_ listeners and does not call `process.exit()`
|
|
15
|
+
- Using `server.dispose()` (the only real method) instead of fictional `server.close()`
|
|
16
|
+
- Removing the Unix socket file to prevent stale `.sock` files on restart
|
|
17
|
+
- Cleaning up the PID file on shutdown
|
|
18
|
+
- Using `@frontmcp/utils` (`unlink`, `fileExists`, `ensureDir`) for file operations
|
|
19
|
+
- Providers initialize in the constructor — there is no `onInit` / `onDestroy`
|
|
13
20
|
---
|
|
14
21
|
|
|
15
22
|
# Daemon Graceful Shutdown with Socket Cleanup
|
|
16
23
|
|
|
17
|
-
Shows how to
|
|
24
|
+
Shows how to layer daemon-specific cleanup (socket file, PID file) **on top of** the framework's built-in SIGTERM/SIGINT handler.
|
|
25
|
+
|
|
26
|
+
> The FrontMCP framework already installs `SIGTERM` / `SIGINT` handlers that call `scope.shutdown()` and `mcpServer.close()` (see `libs/sdk/src/front-mcp/front-mcp.ts`). **Do not install your own** competing shutdown handler — only register _additional_ cleanup hooks (e.g. for socket / PID files) that run before the framework exits.
|
|
27
|
+
>
|
|
28
|
+
> `FrontMcpServerInstance` exposes `dispose()` only — there is **no** `server.close()` method.
|
|
18
29
|
|
|
19
30
|
## Code
|
|
20
31
|
|
|
21
32
|
```typescript
|
|
22
33
|
// src/lifecycle/daemon-shutdown.ts
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
import { fileExists, unlink } from '@frontmcp/utils';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Register daemon-only side-effect cleanup. Run BEFORE the framework's
|
|
38
|
+
* SIGTERM handler tears down the server. Do not call process.exit() here —
|
|
39
|
+
* the framework owns that.
|
|
40
|
+
*/
|
|
41
|
+
export function setupDaemonSideEffectCleanup(): void {
|
|
26
42
|
const socketPath = '/tmp/my-daemon.sock';
|
|
27
43
|
const pidFile = `${process.env.HOME}/.config/my-daemon/daemon.pid`;
|
|
28
44
|
|
|
29
|
-
const
|
|
30
|
-
console.log(`[daemon] Received ${signal}. Shutting down...`);
|
|
31
|
-
|
|
32
|
-
// 1. Stop accepting new connections
|
|
33
|
-
await server.close();
|
|
34
|
-
console.log('[daemon] Server closed.');
|
|
35
|
-
|
|
36
|
-
// 2. Dispose all resources (SQLite, providers)
|
|
37
|
-
await server.dispose();
|
|
38
|
-
console.log('[daemon] Resources disposed.');
|
|
39
|
-
|
|
40
|
-
// 3. Remove socket file (prevent stale .sock files)
|
|
45
|
+
const cleanup = async () => {
|
|
41
46
|
if (await fileExists(socketPath)) {
|
|
42
47
|
await unlink(socketPath);
|
|
43
48
|
console.log(`[daemon] Socket removed: ${socketPath}`);
|
|
44
49
|
}
|
|
45
|
-
|
|
46
|
-
// 4. Clean up PID file
|
|
47
50
|
if (await fileExists(pidFile)) {
|
|
48
51
|
await unlink(pidFile);
|
|
49
52
|
console.log(`[daemon] PID file removed: ${pidFile}`);
|
|
50
53
|
}
|
|
51
|
-
|
|
52
|
-
process.exit(0);
|
|
53
54
|
};
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
// The framework registers its own SIGTERM/SIGINT handlers. Adding ours
|
|
57
|
+
// means BOTH run on signal — Node.js fires every registered listener.
|
|
58
|
+
// Keep these idempotent and side-effect-only; framework will exit after.
|
|
59
|
+
process.on('SIGTERM', cleanup);
|
|
60
|
+
process.on('SIGINT', cleanup);
|
|
57
61
|
}
|
|
58
62
|
```
|
|
59
63
|
|
|
60
64
|
```typescript
|
|
61
65
|
// src/providers/sqlite-store.provider.ts
|
|
62
|
-
import {
|
|
66
|
+
import { dirname } from 'path';
|
|
67
|
+
|
|
68
|
+
import { AsyncProvider, ProviderScope } from '@frontmcp/sdk';
|
|
69
|
+
import { ensureDir } from '@frontmcp/utils';
|
|
63
70
|
|
|
64
71
|
export const LOCAL_STORE = Symbol('LocalStore');
|
|
65
72
|
|
|
66
|
-
|
|
73
|
+
// Providers do NOT have onInit/onDestroy lifecycle hooks. Anything async
|
|
74
|
+
// at construction time goes through `AsyncProvider({ useFactory })` so the
|
|
75
|
+
// dir is guaranteed to exist before the database is opened.
|
|
67
76
|
export class SqliteStoreProvider {
|
|
68
|
-
private db
|
|
69
|
-
|
|
70
|
-
async onInit(): Promise<void> {
|
|
71
|
-
// Database path is configurable, not hardcoded
|
|
72
|
-
const dbPath = process.env.DB_PATH ?? `${process.env.HOME}/.config/my-daemon/data.db`;
|
|
77
|
+
constructor(private readonly db: { close: () => void; exec: (sql: string) => void }) {}
|
|
78
|
+
}
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
await ensureDir(path.dirname(dbPath));
|
|
78
|
-
|
|
79
|
-
// Initialize with WAL mode for concurrent reads
|
|
80
|
-
// Auto-migrate on startup
|
|
81
|
-
this.db = await this.openDatabase(dbPath);
|
|
82
|
-
this.db.exec('PRAGMA journal_mode=WAL');
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async onDestroy(): Promise<void> {
|
|
86
|
-
// Close database connection on shutdown
|
|
87
|
-
this.db.close();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
private async openDatabase(path: string) {
|
|
91
|
-
// Replace with your SQLite driver (e.g., better-sqlite3)
|
|
92
|
-
throw new Error('Implement with your SQLite driver');
|
|
93
|
-
}
|
|
80
|
+
function openDatabase(path: string): { close: () => void; exec: (sql: string) => void } {
|
|
81
|
+
// Replace with your SQLite driver (e.g., better-sqlite3)
|
|
82
|
+
throw new Error('Implement with your SQLite driver');
|
|
94
83
|
}
|
|
84
|
+
|
|
85
|
+
// Async factory binding — `useFactory` runs once at boot and waits for
|
|
86
|
+
// `ensureDir` before opening the database, eliminating the race that
|
|
87
|
+
// `void ensureDir(...)` in a sync constructor would create.
|
|
88
|
+
export const sqliteStoreProvider = AsyncProvider({
|
|
89
|
+
provide: LOCAL_STORE,
|
|
90
|
+
name: 'SqliteStoreProvider',
|
|
91
|
+
scope: ProviderScope.GLOBAL,
|
|
92
|
+
inject: () => [] as const,
|
|
93
|
+
useFactory: async () => {
|
|
94
|
+
const dbPath = process.env.DB_PATH ?? `${process.env.HOME}/.config/my-daemon/data.db`;
|
|
95
|
+
await ensureDir(dirname(dbPath));
|
|
96
|
+
const db = openDatabase(dbPath);
|
|
97
|
+
db.exec('PRAGMA journal_mode=WAL');
|
|
98
|
+
return new SqliteStoreProvider(db);
|
|
99
|
+
},
|
|
100
|
+
});
|
|
95
101
|
```
|
|
96
102
|
|
|
97
103
|
## What This Demonstrates
|
|
98
104
|
|
|
99
|
-
- SIGTERM
|
|
105
|
+
- The framework already wires SIGTERM/SIGINT — daemon cleanup attaches _additional_ listeners and does not call `process.exit()`
|
|
106
|
+
- Using `server.dispose()` (the only real method) instead of fictional `server.close()`
|
|
100
107
|
- Removing the Unix socket file to prevent stale `.sock` files on restart
|
|
101
108
|
- Cleaning up the PID file on shutdown
|
|
102
109
|
- Using `@frontmcp/utils` (`unlink`, `fileExists`, `ensureDir`) for file operations
|
|
103
|
-
-
|
|
110
|
+
- Providers initialize in the constructor — there is no `onInit` / `onDestroy`
|
|
104
111
|
|
|
105
112
|
## Related
|
|
106
113
|
|
|
107
114
|
- See `production-cli-daemon` for the full graceful shutdown and security checklist
|
|
115
|
+
- Framework SIGTERM/SIGINT wiring: `libs/sdk/src/front-mcp/front-mcp.ts`
|
|
@@ -20,10 +20,11 @@ Shows how to secure a local daemon with restrictive socket permissions, XDG-comp
|
|
|
20
20
|
|
|
21
21
|
```typescript
|
|
22
22
|
// src/lifecycle/daemon-security.ts
|
|
23
|
-
import { stat, writeFile, fileExists, ensureDir, readFile } from '@frontmcp/utils';
|
|
24
23
|
import { chmod } from 'fs/promises';
|
|
25
|
-
import * as path from 'path';
|
|
26
24
|
import * as os from 'os';
|
|
25
|
+
import * as path from 'path';
|
|
26
|
+
|
|
27
|
+
import { ensureDir, fileExists, readFile, stat, writeFile } from '@frontmcp/utils';
|
|
27
28
|
|
|
28
29
|
// XDG Base Directory compliance
|
|
29
30
|
function getConfigDir(appName: string): string {
|
|
@@ -86,6 +87,7 @@ export async function loadSecrets(configDir: string): Promise<Record<string, str
|
|
|
86
87
|
```typescript
|
|
87
88
|
// src/main.ts
|
|
88
89
|
import { FrontMcp } from '@frontmcp/sdk';
|
|
90
|
+
|
|
89
91
|
import { MyApp } from './my.app';
|
|
90
92
|
|
|
91
93
|
@FrontMcp({
|
|
@@ -100,7 +102,7 @@ import { MyApp } from './my.app';
|
|
|
100
102
|
// SQLite in the data directory (persistent, writable)
|
|
101
103
|
sqlite: {
|
|
102
104
|
path: `${process.env.XDG_DATA_HOME ?? process.env.HOME + '/.local/share'}/secure-daemon/data.db`,
|
|
103
|
-
|
|
105
|
+
walMode: true, // SqliteOptionsInterface — see libs/storage-sqlite
|
|
104
106
|
},
|
|
105
107
|
})
|
|
106
108
|
export default class SecureDaemonServer {}
|
|
@@ -19,8 +19,9 @@ Shows how to use Cloudflare Durable Objects for stateful coordination alongside
|
|
|
19
19
|
|
|
20
20
|
```toml
|
|
21
21
|
# wrangler.toml — with Durable Objects and R2
|
|
22
|
+
# NOTE: `main` is written by `frontmcp build --target cloudflare`. Do not hand-edit.
|
|
22
23
|
name = "stateful-mcp-worker"
|
|
23
|
-
main = "dist/
|
|
24
|
+
main = "dist/cloudflare/index.js"
|
|
24
25
|
compatibility_date = "2024-01-01"
|
|
25
26
|
|
|
26
27
|
# KV for cache
|