@frontmcp/skills 1.1.2 → 1.2.1

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
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: verify-chain
3
+ reference: skill-audit-log
4
+ level: intermediate
5
+ description: Verify a stored chain offline using verifyChain and the bundle-signing key registry.
6
+ tags: [extensibility, audit, verification, chain, rs256]
7
+ features:
8
+ - 'verifyChain returns { ok, breakAt?, reason? } and exits with the first detected break'
9
+ - 'defaultAuditSignatureVerifier dispatches on record.signatureAlg (HS256 or RS256)'
10
+ - 'Trusted-keys registry maps signatureKeyId → public key PEM'
11
+ - 'iterate() reads the chain in order from any SkillAuditStore implementation'
12
+ ---
13
+
14
+ # Verify Audit Chain
15
+
16
+ Verify a stored chain offline using verifyChain and the bundle-signing key registry.
17
+
18
+ ## Code
19
+
20
+ ```typescript
21
+ // scripts/verify-audit-chain.ts
22
+ import { defaultAuditSignatureVerifier, StorageAdapterAuditStore, verifyChain } from '@frontmcp/adapters/skills';
23
+ import { createStorageAdapter } from '@frontmcp/utils';
24
+
25
+ async function main() {
26
+ const storage = await createStorageAdapter({
27
+ provider: 'redis',
28
+ host: process.env.REDIS_HOST!,
29
+ port: 6379,
30
+ keyPrefix: 'mcp:skill-audit:',
31
+ });
32
+
33
+ const store = new StorageAdapterAuditStore(storage);
34
+ const records = await store.iterate();
35
+
36
+ const trustedKeys: Record<string, string> = {
37
+ // Map every keyId you have ever rotated through, not just the current one.
38
+ 'bundle-signing-2026-01': process.env.BUNDLE_SIGNING_PUBLIC_KEY_2026_01!,
39
+ 'bundle-signing-2025-12': process.env.BUNDLE_SIGNING_PUBLIC_KEY_2025_12!,
40
+ };
41
+
42
+ const result = verifyChain(records, trustedKeys, defaultAuditSignatureVerifier);
43
+
44
+ if (!result.ok) {
45
+ console.error(`Chain broken at sequence ${result.breakAt}: ${result.reason}`);
46
+ process.exit(1);
47
+ }
48
+
49
+ console.log(`Verified ${records.length} records, chain intact.`);
50
+ }
51
+
52
+ main().catch((err) => {
53
+ console.error(err);
54
+ process.exit(1);
55
+ });
56
+ ```
57
+
58
+ ## What This Demonstrates
59
+
60
+ - verifyChain returns { ok, breakAt?, reason? } and exits with the first detected break
61
+ - defaultAuditSignatureVerifier dispatches on record.signatureAlg (HS256 or RS256)
62
+ - Trusted-keys registry maps signatureKeyId → public key PEM
63
+ - iterate() reads the chain in order from any SkillAuditStore implementation
64
+
65
+ ## Related
66
+
67
+ - See `skill-audit-log` for architecture and threat model
68
+ - See `custom-store` for streaming records to S3
@@ -25,8 +25,6 @@ import { FileStorageAdapter, VectoriaDB, type DocumentMetadata } from 'vectoriad
25
25
 
26
26
  import { Provider, ProviderScope } from '@frontmcp/sdk';
27
27
 
28
- export const ProductSearch = Symbol('ProductSearch');
29
-
30
28
  // Typed metadata for product documents
31
29
  interface ProductDoc extends DocumentMetadata {
32
30
  name: string;
@@ -35,7 +33,7 @@ interface ProductDoc extends DocumentMetadata {
35
33
  inStock: boolean;
36
34
  }
37
35
 
38
- @Provider({ name: 'product-search', provide: ProductSearch, scope: ProviderScope.GLOBAL })
36
+ @Provider({ name: 'product-search', scope: ProviderScope.GLOBAL })
39
37
  export class ProductSearchProvider {
40
38
  private db: VectoriaDB<ProductDoc>;
41
39
  private ready: Promise<void>;
@@ -106,7 +104,7 @@ export class ProductSearchProvider {
106
104
  // src/tools/find-products.tool.ts
107
105
  import { Tool, ToolContext, z } from '@frontmcp/sdk';
108
106
 
109
- import { ProductSearch } from '../providers/product-search.provider';
107
+ import { ProductSearchProvider } from '../providers/product-search.provider';
110
108
 
111
109
  @Tool({
112
110
  name: 'find_products',
@@ -134,7 +132,7 @@ import { ProductSearch } from '../providers/product-search.provider';
134
132
  })
135
133
  export class FindProductsTool extends ToolContext {
136
134
  async execute(input: { query: string; category?: string; maxPrice?: number; inStockOnly: boolean; limit: number }) {
137
- const search = this.get(ProductSearch);
135
+ const search = this.get(ProductSearchProvider);
138
136
 
139
137
  const results = await search.search(
140
138
  input.query,
@@ -25,14 +25,12 @@ import { FileStorageAdapter, VectoriaDB, type DocumentMetadata } from 'vectoriad
25
25
 
26
26
  import { Provider, ProviderScope } from '@frontmcp/sdk';
27
27
 
28
- export const KnowledgeBase = Symbol('KnowledgeBase');
29
-
30
28
  interface Article extends DocumentMetadata {
31
29
  title: string;
32
30
  category: string;
33
31
  }
34
32
 
35
- @Provider({ name: 'knowledge-base', provide: KnowledgeBase, scope: ProviderScope.GLOBAL })
33
+ @Provider({ name: 'knowledge-base', scope: ProviderScope.GLOBAL })
36
34
  export class KnowledgeBaseProvider {
37
35
  private db: VectoriaDB<Article>;
38
36
  private ready: Promise<void>;
@@ -67,14 +65,9 @@ export class KnowledgeBaseProvider {
67
65
  } else {
68
66
  await this.db.add(id, text, metadata);
69
67
  }
70
- // Persist to disk — restored without re-embedding on next startup
68
+ // Persist to disk — initialize() automatically restores from cache on next startup
71
69
  await this.db.saveToStorage();
72
70
  }
73
-
74
- async loadFromDisk() {
75
- await this.ready;
76
- await this.db.loadFromStorage();
77
- }
78
71
  }
79
72
  ```
80
73
 
@@ -82,7 +75,7 @@ export class KnowledgeBaseProvider {
82
75
  // src/tools/semantic-search.tool.ts
83
76
  import { Tool, ToolContext, z } from '@frontmcp/sdk';
84
77
 
85
- import { KnowledgeBase } from '../providers/knowledge-base.provider';
78
+ import { KnowledgeBaseProvider } from '../providers/knowledge-base.provider';
86
79
 
87
80
  @Tool({
88
81
  name: 'semantic_search',
@@ -105,7 +98,7 @@ import { KnowledgeBase } from '../providers/knowledge-base.provider';
105
98
  })
106
99
  export class SemanticSearchTool extends ToolContext {
107
100
  async execute(input: { query: string; category?: string; limit: number }) {
108
- const kb = this.get(KnowledgeBase);
101
+ const kb = this.get(KnowledgeBaseProvider);
109
102
 
110
103
  const results = await kb.search(input.query, {
111
104
  category: input.category,
@@ -2,19 +2,28 @@
2
2
  name: tfidf-keyword-search
3
3
  reference: vectoriadb
4
4
  level: basic
5
- description: 'Shows how to use `TFIDFVectoria` for zero-dependency keyword search in a FrontMCP provider, with field weights and index building.'
6
- tags: [extensibility, vectoriadb, keyword-search, tfidf, keyword, search]
5
+ description: Shows how to use `TFIDFVectoria` for zero-dependency keyword search in a FrontMCP provider. `TFIDFVectoria` indexes a single text string per document, so multi-field documents are concatenated into one searchable blob; the original fields are kept in `metadata` for use on search results.
6
+ tags:
7
+ - extensibility
8
+ - vectoriadb
9
+ - keyword-search
10
+ - tfidf
11
+ - keyword
12
+ - search
7
13
  features:
8
- - 'Using `TFIDFVectoria` for zero-dependency keyword search (no model downloads)'
9
- - 'Configuring field weights to control scoring influence'
10
- - 'Calling `buildIndex()` after adding documents (required for TFIDFVectoria)'
11
- - 'Wrapping the search engine in a FrontMCP provider with `ProviderScope.GLOBAL`'
12
- - 'Injecting the provider into tools via `this.get(FAQSearch)`'
14
+ - Using `TFIDFVectoria` for zero-dependency keyword search (no model downloads)
15
+ - Calling `addDocument(id, text, metadata)` with a single concatenated text string
16
+ - Calling `reindex()` after adding documents (required for TFIDFVectoria)
17
+ - Wrapping the search engine in a FrontMCP provider with `ProviderScope.GLOBAL`
18
+ - Injecting the provider into tools via `this.get(FAQSearchProvider)`
13
19
  ---
14
20
 
15
21
  # TFIDFVectoria: Lightweight Keyword Search Provider
16
22
 
17
- Shows how to use `TFIDFVectoria` for zero-dependency keyword search in a FrontMCP provider, with field weights and index building.
23
+ Shows how to use `TFIDFVectoria` for zero-dependency keyword search in a FrontMCP
24
+ provider. `TFIDFVectoria` indexes a single text string per document, so multi-field
25
+ documents are concatenated into one searchable blob; the original fields are kept
26
+ in `metadata` for use on search results.
18
27
 
19
28
  ## Code
20
29
 
@@ -24,32 +33,32 @@ import { TFIDFVectoria } from 'vectoriadb';
24
33
 
25
34
  import { Provider, ProviderScope } from '@frontmcp/sdk';
26
35
 
27
- export const FAQSearch = Symbol('FAQSearch');
36
+ interface FaqDoc {
37
+ id: string;
38
+ question: string;
39
+ answer: string;
40
+ tags: string;
41
+ }
28
42
 
29
- @Provider({ name: 'faq-search', provide: FAQSearch, scope: ProviderScope.GLOBAL })
43
+ @Provider({ name: 'faq-search', scope: ProviderScope.GLOBAL })
30
44
  export class FAQSearchProvider {
31
- private db = new TFIDFVectoria({
32
- fields: {
33
- question: { weight: 3 }, // Question matches are 3x more important
34
- answer: { weight: 1 }, // Answer matches are baseline
35
- tags: { weight: 2 }, // Tag matches are 2x
36
- },
45
+ private db = new TFIDFVectoria<FaqDoc>({
46
+ defaultTopK: 10,
37
47
  });
38
48
 
39
- async initialize(faqs: Array<{ id: string; question: string; answer: string; tags: string }>) {
49
+ async initialize(faqs: FaqDoc[]) {
40
50
  for (const faq of faqs) {
41
- this.db.addDocument(faq.id, {
42
- question: faq.question,
43
- answer: faq.answer,
44
- tags: faq.tags,
45
- });
51
+ // Concatenate fields into a single searchable text string;
52
+ // preserve the original fields in metadata.
53
+ const text = `${faq.question} ${faq.answer} ${faq.tags}`;
54
+ this.db.addDocument(faq.id, text, faq);
46
55
  }
47
- // Required after adding documents — builds the TF-IDF index
48
- this.db.buildIndex();
56
+ // Required after adding documents — rebuilds IDF and embeddings
57
+ this.db.reindex();
49
58
  }
50
59
 
51
60
  search(query: string, limit = 5) {
52
- return this.db.search(query, limit);
61
+ return this.db.search(query, { topK: limit });
53
62
  }
54
63
  }
55
64
  ```
@@ -58,7 +67,7 @@ export class FAQSearchProvider {
58
67
  // src/tools/search-faq.tool.ts
59
68
  import { Tool, ToolContext, z } from '@frontmcp/sdk';
60
69
 
61
- import { FAQSearch } from '../providers/faq-search.provider';
70
+ import { FAQSearchProvider } from '../providers/faq-search.provider';
62
71
 
63
72
  @Tool({
64
73
  name: 'search_faq',
@@ -72,19 +81,21 @@ import { FAQSearch } from '../providers/faq-search.provider';
72
81
  z.object({
73
82
  id: z.string(),
74
83
  score: z.number(),
84
+ question: z.string(),
75
85
  }),
76
86
  ),
77
87
  },
78
88
  })
79
89
  export class SearchFaqTool extends ToolContext {
80
90
  async execute(input: { query: string; limit: number }) {
81
- const faqSearch = this.get(FAQSearch);
91
+ const faqSearch = this.get(FAQSearchProvider);
82
92
  const results = faqSearch.search(input.query, input.limit);
83
93
 
84
94
  return {
85
95
  results: results.map((r) => ({
86
96
  id: r.id,
87
97
  score: r.score,
98
+ question: r.metadata.question,
88
99
  })),
89
100
  };
90
101
  }
@@ -94,10 +105,10 @@ export class SearchFaqTool extends ToolContext {
94
105
  ## What This Demonstrates
95
106
 
96
107
  - Using `TFIDFVectoria` for zero-dependency keyword search (no model downloads)
97
- - Configuring field weights to control scoring influence
98
- - Calling `buildIndex()` after adding documents (required for TFIDFVectoria)
108
+ - Calling `addDocument(id, text, metadata)` with a single concatenated text string
109
+ - Calling `reindex()` after adding documents (required for TFIDFVectoria)
99
110
  - Wrapping the search engine in a FrontMCP provider with `ProviderScope.GLOBAL`
100
- - Injecting the provider into tools via `this.get(FAQSearch)`
111
+ - Injecting the provider into tools via `this.get(FAQSearchProvider)`
101
112
 
102
113
  ## Related
103
114
 
@@ -0,0 +1,233 @@
1
+ ---
2
+ name: skill-audit-log
3
+ description: Tamper-evident, hash-chained audit log for skill action executions — pluggable signer, pluggable store, offline verification.
4
+ tags: [extensibility, audit, skills, tamper-evident, signature, chain]
5
+ ---
6
+
7
+ # Skill Audit Log
8
+
9
+ The `@frontmcp/adapters/skills` module provides a tamper-evident, hash-chained audit log for skill action executions. Every authority pass / authority fail / HTTP success / HTTP failure phase emitted by `execute-action.tool.ts` is captured, signed, and chained so any later mutation breaks signature verification.
10
+
11
+ ## Architecture
12
+
13
+ The writer exposes one method per phase rather than a generic `append`. Each
14
+ phase method assembles its payload internally and routes through a shared
15
+ chain pipeline:
16
+
17
+ ```text
18
+ ExecuteActionTool.execute()
19
+ ├── writer.writeAuthorityPass(ctx) // authority-check-pass
20
+ ├── writer.writeAuthorityFail(ctx, { reason }) // authority-check-fail
21
+ ├── writer.writeHttpCallSuccess(ctx, { status, output }) // http-call-success
22
+ └── writer.writeHttpCallFailure(ctx, { status, error }) // http-call-failure
23
+ └── shared pipeline:
24
+ ├── store.tail() → previous record
25
+ ├── store.nextSequence() → atomic monotonic counter
26
+ ├── compute prevHash from previous record
27
+ ├── assemble SkillAuditRecord { sequence, prevHash, phase, ... }
28
+ ├── SkillAuditSigner.sign(record) → { signature, keyId, alg }
29
+ └── store.appendAtSequence(signedRecord)
30
+ ```
31
+
32
+ Each `SkillAuditRecord` carries:
33
+
34
+ | Field | Description |
35
+ | ---------------- | ------------------------------------------------------------------------------------------------------- |
36
+ | `sequence` | Strictly increasing position in the chain |
37
+ | `prevHash` | SHA-256 hex of the previous record's canonical bytes (genesis sentinel `'0'.repeat(64)` for sequence 1) |
38
+ | `signature` | Base64url signature over the canonical record bytes |
39
+ | `signatureKeyId` | The signer key identifier — used by verifiers to look up the public key |
40
+ | `signatureAlg` | `'HS256'` or `'RS256'` |
41
+ | `phase` | `'authority-check-pass' \| 'authority-check-fail' \| 'http-call-success' \| 'http-call-failure'` |
42
+ | `skillId` | The skill that owns the action |
43
+ | `actionId` | The action that was executed |
44
+ | `subject` | Authenticated principal — redacted per `subjectMode` |
45
+ | `bundleVersion` | The bundle version active at the time of the call |
46
+
47
+ ## Configuration
48
+
49
+ Wire the audit subsystem through `skillsConfig.audit` on `@FrontMcp`:
50
+
51
+ ```typescript
52
+ import {
53
+ Hs256AuditSigner,
54
+ MemoryAuditStore,
55
+ setSkillAuditFactory,
56
+ SkillAuditWriter,
57
+ SkillAuditWriterToken,
58
+ } from '@frontmcp/adapters/skills';
59
+
60
+ // Inject the audit module into the SDK at boot. The factory returns the
61
+ // module record; the SDK itself constructs SkillAuditWriter from
62
+ // (store, signer, logger, metrics?, options?) so that subjectMode and other
63
+ // options pass through skillsConfig.audit verbatim.
64
+ setSkillAuditFactory(() => ({
65
+ SkillAuditWriterToken,
66
+ SkillAuditWriter,
67
+ Hs256AuditSigner,
68
+ MemoryAuditStore,
69
+ }));
70
+
71
+ @FrontMcp({
72
+ info: { name: 'svr', version: '1.0.0' },
73
+ apps: [MainApp],
74
+ skillsConfig: {
75
+ enabled: true,
76
+ audit: {
77
+ enabled: true,
78
+ signer: new Hs256AuditSigner(secret, 'dev'),
79
+ store: new MemoryAuditStore(),
80
+ subjectMode: 'hash', // 'plain' | 'hash' | 'omit'
81
+ },
82
+ },
83
+ })
84
+ class Server {}
85
+ ```
86
+
87
+ `setSkillAuditFactory(...)` injects the audit module into the SDK at boot. The SDK does **not** statically depend on `@frontmcp/adapters/skills` — this keeps the static dependency graph clean and works in Edge / CSP runtimes.
88
+
89
+ | `skillsConfig.audit` field | Type | Default |
90
+ | -------------------------- | ----------------------------- | --------- |
91
+ | `enabled` | `boolean` | `false` |
92
+ | `signer` | `SkillAuditSigner` | dev HS256 |
93
+ | `store` | `SkillAuditStore` | memory |
94
+ | `subjectMode` | `'plain' \| 'hash' \| 'omit'` | `'hash'` |
95
+ | `headAnchorIntervalMs` | `number \| undefined` | unset |
96
+
97
+ ## Built-in Signers
98
+
99
+ | Signer | Key | When to use |
100
+ | ------------------ | --------------------------------------------------- | ------------------------------------------------------------------------------------ |
101
+ | `Hs256AuditSigner` | Symmetric HMAC-SHA-256 | Dev / tests only. Refuses to fire when `NODE_ENV === 'production'` with a random key |
102
+ | `Rs256AuditSigner` | Asymmetric RSA (RS256, RSASSA-PKCS1-v1_5 + SHA-256) | **Production.** Reuse the bundle-signing keypair so the same trust root covers both |
103
+
104
+ ```typescript
105
+ import { Rs256AuditSigner } from '@frontmcp/adapters/skills';
106
+
107
+ // Constructor signature: new Rs256AuditSigner(privateJwk, keyId)
108
+ // The signer accepts a JWK directly so the same key registry that backs
109
+ // bundle signing can be reused. If your key material lives as PEM, convert
110
+ // it to a JWK first (e.g. via `crypto.createPrivateKey(pem).export({ format: 'jwk' })`
111
+ // or `pemToPrivateJwk` from `@frontmcp/utils`).
112
+ const privateJwk = JSON.parse(process.env.BUNDLE_SIGNING_PRIVATE_JWK!) as JsonWebKey;
113
+ const signer = new Rs256AuditSigner(privateJwk, 'bundle-signing-2026-01');
114
+ ```
115
+
116
+ `Rs256AuditSigner` uses `rsaSignBase64Url` from `@frontmcp/utils` under the hood.
117
+
118
+ ## Built-in Stores
119
+
120
+ | Store | Persistence | When to use |
121
+ | -------------------------- | --------------------------------------------------------- | ---------------- |
122
+ | `MemoryAuditStore` | In-process; lost on restart | Tests, local dev |
123
+ | `StorageAdapterAuditStore` | Any `@frontmcp/utils` storage adapter (Redis, KV, SQLite) | Production |
124
+
125
+ ```typescript
126
+ import { StorageAdapterAuditStore } from '@frontmcp/adapters/skills';
127
+ import { createStorageAdapter } from '@frontmcp/utils';
128
+
129
+ const storage = await createStorageAdapter({ provider: 'redis', host: 'localhost', port: 6379 });
130
+ const store = new StorageAdapterAuditStore(storage);
131
+ ```
132
+
133
+ A custom store implements:
134
+
135
+ ```typescript
136
+ interface SkillAuditStore {
137
+ /** Allocate the next monotonic sequence atomically. Maps to StorageAdapter.incr in production. */
138
+ nextSequence(): Promise<number>;
139
+
140
+ /** Persist a record at its claimed sequence. MUST refuse / throw if the slot is taken. */
141
+ appendAtSequence(record: SkillAuditRecord): Promise<void>;
142
+
143
+ /** Most recent record (or undefined for empty chain). Drives prevHash for the next write. */
144
+ tail(): Promise<SkillAuditRecord | undefined>;
145
+
146
+ /** Read records in sequence order; supports `{ from, limit }` for incremental verification. */
147
+ read(opts?: { from?: number; limit?: number }): Promise<SkillAuditRecord[]>;
148
+ }
149
+ ```
150
+
151
+ See [`custom-store`](../examples/skill-audit-log/custom-store.md) for an S3-backed implementation.
152
+
153
+ ## Verifying the Chain
154
+
155
+ ```typescript
156
+ import { defaultAuditSignatureVerifier, verifyChain, type AuditTrustedKey } from '@frontmcp/adapters/skills';
157
+
158
+ // `read()` walks the chain in sequence order; pass `{ from, limit }` for
159
+ // incremental verification in CI.
160
+ const records = await store.read();
161
+
162
+ // Trusted keys are passed as an array (per-record `signatureKeyId` selects
163
+ // which entry to use). Supply `publicJwk` or `publicKeyPem` for RS256, or
164
+ // `secret` for HS256.
165
+ const trustedKeys: AuditTrustedKey[] = [
166
+ { keyId: 'bundle-signing-2026-01', alg: 'RS256', publicKeyPem: PUBLIC_KEY_PEM },
167
+ ];
168
+
169
+ const result = verifyChain(records, trustedKeys, defaultAuditSignatureVerifier);
170
+
171
+ if (result.ok) {
172
+ console.log(`Chain verified: ${result.verified} record(s) checked`);
173
+ } else {
174
+ console.error('Chain broken at sequence', result.breakAt, '—', result.reason);
175
+ }
176
+ ```
177
+
178
+ `verifyChain` returns `{ ok: true; verified: number } | { ok: false; breakAt: number; reason: string }`. The `verified` count is the number of records whose signature + prevHash checked out — useful for dashboards and CI assertions. `defaultAuditSignatureVerifier` understands HS256 and RS256 records and dispatches based on `record.signatureAlg`.
179
+
180
+ ## DI Integration
181
+
182
+ `SkillAuditWriterToken` is the DI token for the active writer. Plugins that need to emit additional audit records (e.g., a custom authority gate) can resolve it:
183
+
184
+ ```typescript
185
+ import { SkillAuditWriterToken } from '@frontmcp/adapters/skills';
186
+
187
+ class MyPlugin extends DynamicPlugin {
188
+ @ToolHook.Will('execute')
189
+ willExecute(flowCtx: FlowCtxOf<'tools:call-tool'>): void {
190
+ const writer = flowCtx.scope.tryGet(SkillAuditWriterToken);
191
+ // Use the phase-specific method matching the event you're recording.
192
+ // The writer assembles the canonical record (sequence, prevHash,
193
+ // signature, signatureKeyId, signatureAlg) for you.
194
+ writer?.writeAuthorityPass({
195
+ subject: 'user-id',
196
+ skillId: 'my-skill',
197
+ actionId: 'my-action',
198
+ bundleId: 'bundle:id',
199
+ bundleVersion: '1.0.0',
200
+ input: {},
201
+ });
202
+ }
203
+ }
204
+ ```
205
+
206
+ Plugins should always go through `SkillAuditWriterToken` rather than rolling their own audit log so the chain stays unified.
207
+
208
+ ## Threat Model
209
+
210
+ What the audit log catches:
211
+
212
+ - **Record mutation** — any byte-level change breaks the signature.
213
+ - **Record reordering** — the `prevHash` chain breaks.
214
+ - **Record deletion in the middle** — `prevHash` mismatch on the next record.
215
+
216
+ What it does **not** catch by default:
217
+
218
+ - **Tail truncation** — if an attacker deletes the tail, no record survives to flag it. Mitigation: `headAnchorIntervalMs` writes the latest `(sequence, hash)` pair to an out-of-band notarization channel (queued for v1.3.0 to be wired into the CAS-based atomic head update).
219
+ - **Multi-pod races** — v1.2.0 is **single-writer only**. Multiple pods writing to the same store will produce a loud warning and may interleave sequences. Route writes to a single elected leader pod or use per-pod chains and stitch offline. CAS-based atomic chain head is queued for v1.3.0.
220
+
221
+ ## Examples
222
+
223
+ | Example | Level | Description |
224
+ | ------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------- |
225
+ | [`verify-chain`](../examples/skill-audit-log/verify-chain.md) | Intermediate | Verify a stored chain offline using verifyChain and the bundle-signing key registry. |
226
+ | [`custom-store`](../examples/skill-audit-log/custom-store.md) | Advanced | Implement a custom SkillAuditStore that streams records to S3 with one object per sequence. |
227
+
228
+ > See all examples in [`examples/skill-audit-log/`](../examples/skill-audit-log/)
229
+
230
+ ## Reference
231
+
232
+ - [Skill Audit Log](https://docs.agentfront.dev/frontmcp/extensibility/skill-audit-log)
233
+ - Related skills: `configure-skills-http`, `create-plugin`