@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
@@ -145,17 +145,22 @@ Add a `## Examples` section at the bottom of each reference file (before `## Ref
145
145
 
146
146
  ## Resource Access
147
147
 
148
- Skills are accessible via the `skills://` URI scheme as MCP resources with auto-complete:
149
-
150
- | URI | Returns |
151
- | ------------------------------------------------- | ----------------------------------------- |
152
- | `skills://catalog` | JSON list of all available skills |
153
- | `skills://{skillName}` | Full SKILL.md content (formatted for LLM) |
154
- | `skills://{skillName}/SKILL.md` | Same as above (explicit path alias) |
155
- | `skills://{skillName}/references` | JSON list of references for this skill |
156
- | `skills://{skillName}/references/{referenceName}` | Reference markdown content |
157
- | `skills://{skillName}/examples` | JSON list of examples for this skill |
158
- | `skills://{skillName}/examples/{exampleName}` | Example markdown content |
148
+ Skills are accessible via the `skill://` URI scheme as MCP resources per
149
+ [SEP-2640 (Skills Extension)](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640),
150
+ with auto-complete on `skillPath`:
151
+
152
+ | URI | Returns |
153
+ | ------------------------------------------ | ------------------------------------------------------------------------ |
154
+ | `skill://index.json` | SEP-2640 discovery document (agentskills.io schema) |
155
+ | `skill://{skillPath}/SKILL.md` | Raw SKILL.md (YAML frontmatter + markdown body, identical to filesystem) |
156
+ | `skill://{skillPath}/references/{file}.md` | Reference markdown content |
157
+ | `skill://{skillPath}/examples/{file}.md` | Example markdown content |
158
+ | `skill://{skillPath}/scripts/{file}` | Script asset (any media type) |
159
+ | `skill://{skillPath}/assets/{file}` | Bundled asset (any media type) |
160
+
161
+ `{skillPath}` may be a single segment (`git-workflow`) or nested
162
+ (`acme/billing/refunds`). Its final segment must equal the skill's
163
+ frontmatter `name`.
159
164
 
160
165
  ## Reference
161
166
 
@@ -106,7 +106,12 @@ authorities: {
106
106
  }
107
107
  ```
108
108
 
109
- If no `claimsMapping` is provided, the engine falls back to `authInfo.user.roles` and `authInfo.user.permissions`. For non-standard token shapes, use `claimsResolver` instead (see Common Patterns below).
109
+ If no `claimsMapping` is provided, the engine falls back to (in order):
110
+
111
+ - **roles**: `authInfo.user.roles` → `authInfo.extra.authorization.scopes` → `[]`
112
+ - **permissions**: `authInfo.user.permissions` → `[]`
113
+
114
+ The OAuth-scopes-as-roles fallback means a token with no `roles` claim but with `scope: "admin read"` will be treated as having `roles: ['admin', 'read']`. Configure explicit `claimsMapping.roles` to opt out. For non-standard token shapes, use `claimsResolver` instead (see Common Patterns below).
110
115
 
111
116
  ### Step 3: Register Named Profiles
112
117
 
@@ -198,6 +203,87 @@ export default class PublishContentTool extends ToolContext { ... }
198
203
  export default class SensitiveActionTool extends ToolContext { ... }
199
204
  ```
200
205
 
206
+ **Async guards (one-shot DB/Redis/API checks):**
207
+
208
+ For dynamic, async authorization that does not warrant a reusable custom evaluator, use the
209
+ `guards` field. Each guard receives the same `AuthoritiesEvaluationContext` and returns
210
+ `true` on grant, or `false`/a denial string on deny. Guards run in sequence and combine with
211
+ other policy fields via `operator` (default AND).
212
+
213
+ ```typescript
214
+ import type { AuthorityGuardFn } from '@frontmcp/auth';
215
+
216
+ const requireActiveSubscription: AuthorityGuardFn = async (ctx) => {
217
+ const active = await db.isSubscriptionActive(ctx.user.sub);
218
+ return active ? true : 'subscription is not active';
219
+ };
220
+
221
+ @Tool({
222
+ name: 'premium_feature',
223
+ authorities: {
224
+ roles: { any: ['user'] },
225
+ guards: [requireActiveSubscription],
226
+ },
227
+ })
228
+ export default class PremiumFeatureTool extends ToolContext { ... }
229
+ ```
230
+
231
+ Use `guards` for one-off async checks; promote to a registered custom evaluator when the
232
+ same logic is reused across many entries (see `references/custom-evaluators.md`).
233
+
234
+ ### Optional: Map Denials to OAuth Scope Challenges (`scopeMapping`)
235
+
236
+ If your transport layer issues OAuth scope challenges (RFC 6750 `insufficient_scope`),
237
+ declare a `scopeMapping` so authority denials are converted into the right `WWW-Authenticate`
238
+ challenge with the required scopes. Mapping is explicit only — no automatic
239
+ permission-to-scope inference.
240
+
241
+ ```typescript
242
+ authorities: {
243
+ scopeMapping: {
244
+ roles: { admin: ['admin:all'] },
245
+ permissions: { 'repo:write': ['repo'] },
246
+ profiles: { admin: ['admin:all'] },
247
+ },
248
+ }
249
+ ```
250
+
251
+ When a request is denied because the user lacks role `admin`, the response surfaces
252
+ the `admin:all` scope as the required challenge.
253
+
254
+ ### Optional: Extract Custom Auth Context Fields (`pipes`)
255
+
256
+ `pipes` are functions that run during auth context construction and merge their output into
257
+ `FrontMcpAuthContext`. Use them to extract custom typed fields from JWT claims so they are
258
+ available to your tools as strongly typed accessors. Declare the resulting fields by
259
+ augmenting `ExtendFrontMcpAuthContext`:
260
+
261
+ A pipe receives the **raw JWT claims** (a `Readonly<Record<string, unknown>>`) and
262
+ returns a `Partial<ExtendFrontMcpAuthContext>` (sync or async). It does **not**
263
+ receive the `AuthInfo` envelope — there is no `.user` accessor on the input.
264
+
265
+ ```typescript
266
+ // Pipe signature (defined inline; do not import — AuthContextPipe is not
267
+ // re-exported from `@frontmcp/auth`):
268
+ // (claims: Readonly<Record<string, unknown>>) =>
269
+ // Partial<ExtendFrontMcpAuthContext> | Promise<Partial<ExtendFrontMcpAuthContext>>
270
+
271
+ const tenantPipe = (claims: Readonly<Record<string, unknown>>) => ({
272
+ tenantId: claims['tenantId'] as string | undefined,
273
+ });
274
+
275
+ declare global {
276
+ interface ExtendFrontMcpAuthContext {
277
+ tenantId?: string;
278
+ }
279
+ }
280
+
281
+ // In @FrontMcp({ authorities: { ... } })
282
+ authorities: {
283
+ pipes: [tenantPipe],
284
+ }
285
+ ```
286
+
201
287
  ## Scenario Routing Table
202
288
 
203
289
  | Scenario | Approach | Reference |
@@ -253,16 +339,35 @@ export default class SensitiveActionTool extends ToolContext { ... }
253
339
 
254
340
  ## Troubleshooting
255
341
 
256
- | Problem | Cause | Solution |
257
- | ----------------------------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
258
- | `profile 'admin' is not registered` | Profile used in decorator but not in `authorities.profiles` config | Add the profile to the `profiles` field in `@FrontMcp({ authorities })` |
259
- | All users denied despite correct roles | `claimsMapping.roles` path does not match the actual JWT claim path | Decode a real JWT and verify the dot-path resolves to the roles array |
260
- | `authorities` field not recognized on decorator | `@frontmcp/auth` not imported (metadata augmentation not active) | Add `import '@frontmcp/auth'` or import any type from `@frontmcp/auth/authorities` |
261
- | ABAC condition always fails | `{ fromInput: 'tenantId' }` but tool input field is named `tenant_id` | The `fromInput` key must exactly match the tool's input schema field name |
262
- | ReBAC always denies | No `relationshipResolver` provided | Implement `RelationshipResolver` and pass it to plugin options |
263
- | Custom evaluator not found | Key in `custom.*` policy does not match registered evaluator name | Ensure the evaluator is registered with the same key used in the policy |
264
- | List endpoints show all entries | No `authorities` config in `@FrontMcp()` or hook priority conflict | Verify `authorities: { ... }` is set on `@FrontMcp()` decorator |
265
- | `AuthorityDeniedError` has no detail | `deniedBy` field shows generic message | Check the `evaluatedPolicies` array on the error for which policy type failed |
342
+ | Problem | Cause | Solution |
343
+ | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
344
+ | `profile 'admin' is not registered` | Profile used in decorator but not in `authorities.profiles` config | Add the profile to the `profiles` field in `@FrontMcp({ authorities })` |
345
+ | All users denied despite correct roles | `claimsMapping.roles` path does not match the actual JWT claim path | Decode a real JWT and verify the dot-path resolves to the roles array |
346
+ | `authorities` field not recognized on decorator | `@frontmcp/auth` not imported (metadata augmentation not active) | Add `import '@frontmcp/auth'` (or `import type ... from '@frontmcp/auth'`) anywhere in your project to activate the metadata augmentation. There is no `@frontmcp/auth/authorities` subpath. |
347
+ | ABAC condition always fails | `{ fromInput: 'tenantId' }` but tool input field is named `tenant_id` | The `fromInput` key must exactly match the tool's input schema field name |
348
+ | ReBAC always denies | No `relationshipResolver` provided | Implement `RelationshipResolver` and pass it to plugin options |
349
+ | Custom evaluator not found | Key in `custom.*` policy does not match registered evaluator name | Ensure the evaluator is registered with the same key used in the policy |
350
+ | List endpoints show all entries | No `authorities` config in `@FrontMcp()` or hook priority conflict | Verify `authorities: { ... }` is set on `@FrontMcp()` decorator |
351
+ | `AuthorityDeniedError` has no detail | `deniedBy` field shows generic message | Check the `evaluatedPolicies` array on the error for which policy type failed |
352
+ | TS error: `evaluators`/`relationshipResolver`/`claimsResolver` not on `AuthoritiesConfig` | The runtime Zod schema accepts these keys but the exported `AuthoritiesConfig` interface in `authorities.profiles.ts` only declares `claimsMapping`, `profiles`, `scopeMapping`, `pipes`. | Pass the config inline (TS infers from the decorator's broader type) or cast the typed config as the interface catches up. |
353
+
354
+ ## Examples
355
+
356
+ This skill currently exposes only references; see [`references/`](./references/) for guidance.
357
+
358
+ ## Accessing This Skill
359
+
360
+ Skills are distributed as plain SKILL.md files plus a sibling `references/`
361
+ and `examples/` tree, so consumers can pick whichever access mode fits:
362
+
363
+ | Mode | How it works |
364
+ | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
365
+ | **Filesystem** | Read `libs/skills/catalog/frontmcp-authorities/` directly from a clone of the catalog repo, or from a published `@frontmcp/skills` install. SKILL.md is the entry point. |
366
+ | **`frontmcp` CLI** | `frontmcp skills list`, `frontmcp skills read frontmcp-authorities`, `frontmcp skills read frontmcp-authorities:references/<file>.md`, `frontmcp skills install frontmcp-authorities` — no server required. |
367
+ | **MCP `skill://`** | When a developer mounts this skill into their own FrontMCP server (`@FrontMcp({ skills: [...] })`), the SDK exposes it via SEP-2640 resources: `skill://frontmcp-authorities/SKILL.md`, `skill://frontmcp-authorities/references/{file}.md`, etc. The server’s `skill://index.json` returns the SEP-2640 discovery document for everything mounted on it. |
368
+
369
+ The catalog itself is **not** an MCP server. The `skill://` URIs only resolve
370
+ when a server has been configured to host this skill.
266
371
 
267
372
  ## Reference
268
373
 
@@ -17,40 +17,40 @@ import { FrontMcp } from '@frontmcp/sdk';
17
17
  @FrontMcp({
18
18
  name: 'my-server',
19
19
  authorities: {
20
- claimsMapping: { roles: 'realm_access.roles', permissions: 'scope' },
20
+ claimsMapping: {
21
+ roles: 'realm_access.roles',
22
+ permissions: 'resource_access.my-client.roles',
23
+ },
21
24
  profiles: {
22
- // RBAC: user must have at least one of these roles
23
- admin: {
24
- roles: { any: ['admin', 'superadmin'] },
25
- },
25
+ // RBAC: user must have at least one of these roles
26
+ admin: {
27
+ roles: { any: ['admin', 'superadmin'] },
28
+ },
26
29
 
27
- // ABAC: user must be authenticated (sub exists)
28
- authenticated: {
29
- attributes: {
30
- conditions: [{ path: 'user.sub', op: 'exists', value: true }],
31
- },
30
+ // ABAC: user must be authenticated (sub exists)
31
+ authenticated: {
32
+ attributes: {
33
+ conditions: [{ path: 'user.sub', op: 'exists', value: true }],
32
34
  },
35
+ },
33
36
 
34
- // ABAC: tenant from JWT must match the tenantId input argument
35
- matchTenant: {
36
- attributes: {
37
- conditions: [
38
- { path: 'claims.org_id', op: 'eq', value: { fromInput: 'tenantId' } },
39
- ],
40
- },
37
+ // ABAC: tenant from JWT must match the tenantId input argument
38
+ matchTenant: {
39
+ attributes: {
40
+ conditions: [{ path: 'claims.org_id', op: 'eq', value: { fromInput: 'tenantId' } }],
41
41
  },
42
+ },
42
43
 
43
- // RBAC: permission-based
44
- canPublish: {
45
- permissions: { all: ['content:publish'] },
46
- },
44
+ // RBAC: permission-based
45
+ canPublish: {
46
+ permissions: { all: ['content:publish'] },
47
+ },
47
48
 
48
- // Combined: role AND permission
49
- editorWithPublish: {
50
- roles: { any: ['editor'] },
51
- permissions: { all: ['content:publish'] },
52
- // operator defaults to 'AND', so both must pass
53
- },
49
+ // Combined: role AND permission
50
+ editorWithPublish: {
51
+ roles: { any: ['editor'] },
52
+ permissions: { all: ['content:publish'] },
53
+ // operator defaults to 'AND', so both must pass
54
54
  },
55
55
  },
56
56
  },
@@ -78,8 +78,11 @@ export default class DeleteUserTool extends ToolContext {
78
78
  authorities: 'admin',
79
79
  })
80
80
  export default class InternalMetricsResource extends ResourceContext {
81
- async read() {
82
- // only admin can read this resource
81
+ async execute(uri: string, _params: Record<string, string>) {
82
+ // only admin can reach here
83
+ return {
84
+ contents: [{ uri, mimeType: 'application/json', text: JSON.stringify({ ok: true }) }],
85
+ };
83
86
  }
84
87
  }
85
88
 
@@ -246,13 +249,13 @@ This filtering happens automatically. No additional configuration is needed. Ent
246
249
 
247
250
  ## Profile Design Guidelines
248
251
 
249
- | Guideline | Example |
250
- | --- | --- |
251
- | Name profiles after the role or intent, not the technical check | `admin` not `hasAdminRole` |
252
- | Keep profiles single-purpose | `matchTenant` does tenant check only; combine with `['authenticated', 'matchTenant']` |
253
- | Use `allOf`/`anyOf` for complex compositions in inline policies | Do not create profiles that duplicate combinator logic |
254
- | Document your profiles in a central file | `types/authorities.d.ts` with augmentation and comments |
255
- | Test profiles with both authorized and unauthorized users | See `frontmcp-testing` skill for auth testing patterns |
252
+ | Guideline | Example |
253
+ | --------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
254
+ | Name profiles after the role or intent, not the technical check | `admin` not `hasAdminRole` |
255
+ | Keep profiles single-purpose | `matchTenant` does tenant check only; combine with `['authenticated', 'matchTenant']` |
256
+ | Use `allOf`/`anyOf` for complex compositions in inline policies | Do not create profiles that duplicate combinator logic |
257
+ | Document your profiles in a central file | `types/authorities.d.ts` with augmentation and comments |
258
+ | Test profiles with both authorized and unauthorized users | See `frontmcp-testing` skill for auth testing patterns |
256
259
 
257
260
  ## Reference
258
261
 
@@ -234,6 +234,13 @@ authorities: {
234
234
  return {
235
235
  roles,
236
236
  permissions,
237
+ // Merge order matches the engine's default in
238
+ // `authorities.context.ts` (`{ ...authorizationClaims, ...user }`):
239
+ // spread the raw `authorization.claims` first, then `authInfo.user` so
240
+ // IdP-provided user fields (`sub`, `name`, `email`, `tenantId`, ...)
241
+ // override any same-named server-side authorization claim on conflict.
242
+ // Reverse this order only if you intentionally want authorization
243
+ // claims to win over user identity fields.
237
244
  claims: { ...claims, ...user },
238
245
  };
239
246
  },
@@ -12,7 +12,7 @@ When the built-in RBAC, ABAC, and ReBAC models do not cover your authorization r
12
12
  Every custom evaluator must implement the `AuthoritiesEvaluator` interface from `@frontmcp/auth`.
13
13
 
14
14
  ```typescript
15
- import type { AuthoritiesEvaluator, AuthoritiesEvaluationContext, AuthoritiesResult } from '@frontmcp/auth';
15
+ import type { AuthoritiesEvaluationContext, AuthoritiesEvaluator, AuthoritiesResult } from '@frontmcp/auth';
16
16
 
17
17
  interface AuthoritiesEvaluator {
18
18
  /** Evaluator name (must match the key under `custom.*` in policies) */
@@ -30,13 +30,28 @@ The return value must be an `AuthoritiesResult`:
30
30
  interface AuthoritiesResult {
31
31
  /** Whether access was granted */
32
32
  granted: boolean;
33
- /** Human-readable reason for denial */
33
+ /** Human-readable reason for denial (kept for backward compatibility) */
34
34
  deniedBy?: string;
35
+ /** Structured denial data (machine-parsable) */
36
+ denial?: AuthoritiesDenial;
35
37
  /** List of policy types that were evaluated (for audit) */
36
38
  evaluatedPolicies: string[];
37
39
  /** Optional detailed message */
38
40
  message?: string;
39
41
  }
42
+
43
+ interface AuthoritiesDenial {
44
+ /** Which policy type caused the denial */
45
+ kind: 'roles' | 'permissions' | 'attributes' | 'relationships' | 'custom' | 'profile' | 'not' | 'allOf' | 'anyOf';
46
+ /** Dot-path into the policy that failed (e.g., "custom.ipAllowList") */
47
+ path: string;
48
+ /** Values that were required but missing */
49
+ missing?: string[];
50
+ /** Expected value */
51
+ expected?: unknown;
52
+ /** Actual value found */
53
+ actual?: unknown;
54
+ }
40
55
  ```
41
56
 
42
57
  ## Registering Custom Evaluators
@@ -45,8 +60,9 @@ Custom evaluators are registered in the `evaluators` field of the `authorities`
45
60
 
46
61
  ```typescript
47
62
  import { FrontMcp } from '@frontmcp/sdk';
48
- import { ipAllowListEvaluator } from './evaluators/ip-allow-list';
63
+
49
64
  import { featureFlagEvaluator } from './evaluators/feature-flag';
65
+ import { ipAllowListEvaluator } from './evaluators/ip-allow-list';
50
66
  import { timeWindowEvaluator } from './evaluators/time-window';
51
67
 
52
68
  @FrontMcp({
@@ -123,13 +139,41 @@ const featureFlagGuard: AuthoritiesEvaluator = {
123
139
  };
124
140
  ```
125
141
 
126
- ### When to Use Custom Evaluators vs Hooks
142
+ ### When to Use Custom Evaluators vs Guards vs Hooks
143
+
144
+ | Approach | When to Use |
145
+ | ---------------------------------------- | ------------------------------------------------------------------------------------------------- |
146
+ | **Custom evaluator** | Reusable async check across many tools — register once, reference via `custom.<name>` in policies |
147
+ | **`guards: AuthorityGuardFn[]`** | One-off async check on a single entry — declare inline, no registration required |
148
+ | **`Will('checkEntryAuthorities')` hook** | Cross-cutting pre/post logic across the whole flow stage (audit, logging, replacement) |
149
+ | **Static `authorities` policy** | Roles, permissions, attributes — no I/O needed |
150
+
151
+ #### Inline `guards` example
152
+
153
+ ```typescript
154
+ import type { AuthorityGuardFn } from '@frontmcp/auth';
155
+
156
+ const tenantInAllowlist: AuthorityGuardFn = async (ctx) => {
157
+ const tenantId = ctx.input['tenantId'] as string | undefined;
158
+ if (!tenantId) return 'tenantId missing from input';
159
+ const ok = await redis.sismember('allowed-tenants', tenantId);
160
+ return ok ? true : `tenant '${tenantId}' is not allowlisted`;
161
+ };
162
+
163
+ @Tool({
164
+ name: 'tenant_action',
165
+ authorities: {
166
+ roles: { any: ['user'] },
167
+ guards: [tenantInAllowlist],
168
+ },
169
+ })
170
+ export default class TenantActionTool extends ToolContext { ... }
171
+ ```
127
172
 
128
- | Approach | When to Use |
129
- | ---------------------------------------- | ------------------------------------------------------------------------------------ |
130
- | **Custom evaluator** | Reusable async check across many tools register once, reference via `custom` field |
131
- | **`Will('checkEntryAuthorities')` hook** | One-off async check for a specific plugin/app, not tied to a specific tool |
132
- | **Static `authorities` policy** | Roles, permissions, attributes — no I/O needed |
173
+ Guards combine with sibling policy fields via `operator` (default AND). They are the
174
+ simplest async authorization mechanism — no registry, no `name` field, no `custom.*`
175
+ indirection and are preferred over hooks for "this single entry needs an extra
176
+ async check" scenarios.
133
177
 
134
178
  ## Using Custom Evaluators in Policies
135
179
 
@@ -156,7 +200,7 @@ Restricts access to requests from specific CIDR ranges.
156
200
 
157
201
  ```typescript
158
202
  // evaluators/ip-allow-list.ts
159
- import type { AuthoritiesEvaluator, AuthoritiesEvaluationContext, AuthoritiesResult } from '@frontmcp/auth';
203
+ import type { AuthoritiesEvaluationContext, AuthoritiesEvaluator, AuthoritiesResult } from '@frontmcp/auth';
160
204
 
161
205
  interface IpAllowListPolicy {
162
206
  cidr: string[];
@@ -174,12 +218,17 @@ export const ipAllowListEvaluator: AuthoritiesEvaluator = {
174
218
  name: 'ipAllowList',
175
219
  async evaluate(policy: unknown, ctx: AuthoritiesEvaluationContext): Promise<AuthoritiesResult> {
176
220
  const { cidr } = policy as IpAllowListPolicy;
221
+ // The SDK does not populate ctx.env by default — the engine's `env` defaults to `{}`.
222
+ // To use this evaluator, populate `env.remoteIp` yourself: register an
223
+ // `Around('checkEntryAuthorities')` hook (or transport adapter middleware) that reads
224
+ // the request's remote IP (e.g., from `X-Forwarded-For`) and merges it into the
225
+ // evaluation context env before the engine runs.
177
226
  const remoteIp = ctx.env['remoteIp'] as string | undefined;
178
227
 
179
228
  if (!remoteIp) {
180
229
  return {
181
230
  granted: false,
182
- deniedBy: 'custom.ipAllowList: remoteIp not available in env',
231
+ deniedBy: 'custom.ipAllowList: remoteIp not populated in env (configure a hook/middleware to set it)',
183
232
  evaluatedPolicies: ['custom.ipAllowList'],
184
233
  };
185
234
  }
@@ -215,7 +264,7 @@ Gates access behind a feature flag service.
215
264
 
216
265
  ```typescript
217
266
  // evaluators/feature-flag.ts
218
- import type { AuthoritiesEvaluator, AuthoritiesEvaluationContext, AuthoritiesResult } from '@frontmcp/auth';
267
+ import type { AuthoritiesEvaluationContext, AuthoritiesEvaluator, AuthoritiesResult } from '@frontmcp/auth';
219
268
 
220
269
  interface FeatureFlagPolicy {
221
270
  flag: string;
@@ -264,7 +313,7 @@ Restricts access to specific time windows (e.g., business hours only).
264
313
 
265
314
  ```typescript
266
315
  // evaluators/time-window.ts
267
- import type { AuthoritiesEvaluator, AuthoritiesEvaluationContext, AuthoritiesResult } from '@frontmcp/auth';
316
+ import type { AuthoritiesEvaluationContext, AuthoritiesEvaluator, AuthoritiesResult } from '@frontmcp/auth';
268
317
 
269
318
  interface TimeWindowPolicy {
270
319
  /** Allowed days (0=Sunday, 6=Saturday) */
@@ -334,7 +383,7 @@ Denies access when a per-user rate limit is exceeded.
334
383
 
335
384
  ```typescript
336
385
  // evaluators/rate-limit.ts
337
- import type { AuthoritiesEvaluator, AuthoritiesEvaluationContext, AuthoritiesResult } from '@frontmcp/auth';
386
+ import type { AuthoritiesEvaluationContext, AuthoritiesEvaluator, AuthoritiesResult } from '@frontmcp/auth';
338
387
 
339
388
  interface RateLimitPolicy {
340
389
  /** Maximum calls allowed */
@@ -115,6 +115,42 @@ Build push-based notification channels that stream real-time events into Claude
115
115
  | Duplicate notifications | Multiple sessions subscribed | This is correct behavior -- each session gets its own copy |
116
116
  | Events lost on reconnect | Channels are in-memory | Channel state resets on server restart; use persistent sources |
117
117
 
118
+ ## Examples
119
+
120
+ Each reference has matching examples under [`examples/<reference>/`](./examples/):
121
+
122
+ ### `channel-sources`
123
+
124
+ | Example | Level | Description |
125
+ | ---------------------------------------------------------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------- |
126
+ | [`webhook-github`](./examples/channel-sources/webhook-github.md) | Basic | Forward GitHub webhook events (PRs, pushes, CI) into Claude Code |
127
+ | [`app-errors`](./examples/channel-sources/app-errors.md) | Basic | Forward application errors to Claude Code via the in-process event bus |
128
+ | [`agent-notify`](./examples/channel-sources/agent-notify.md) | Intermediate | Notify Claude Code when AI agents complete their tasks |
129
+ | [`job-completion`](./examples/channel-sources/job-completion.md) | Intermediate | Notify Claude Code when background jobs and workflows complete |
130
+ | [`service-connector`](./examples/channel-sources/service-connector.md) | Advanced | Build a persistent service connector that lets Claude send and receive messages through WhatsApp, Telegram, or any messaging API |
131
+ | [`file-watcher`](./examples/channel-sources/file-watcher.md) | Intermediate | Watch files for changes and notify Claude Code in real-time |
132
+ | [`replay-buffer`](./examples/channel-sources/replay-buffer.md) | Advanced | Buffer channel events so Claude Code receives them when it connects, even if events occurred while offline |
133
+
134
+ ### `channel-two-way`
135
+
136
+ | Example | Level | Description |
137
+ | ------------------------------------------------------------------ | -------- | -------------------------------------------------------------------------------------- |
138
+ | [`whatsapp-bridge`](./examples/channel-two-way/whatsapp-bridge.md) | Advanced | Full WhatsApp Business API bridge allowing users to chat with Claude Code via WhatsApp |
139
+
140
+ ## Accessing This Skill
141
+
142
+ Skills are distributed as plain SKILL.md files plus a sibling `references/`
143
+ and `examples/` tree, so consumers can pick whichever access mode fits:
144
+
145
+ | Mode | How it works |
146
+ | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
147
+ | **Filesystem** | Read `libs/skills/catalog/frontmcp-channels/` directly from a clone of the catalog repo, or from a published `@frontmcp/skills` install. SKILL.md is the entry point. |
148
+ | **`frontmcp` CLI** | `frontmcp skills list`, `frontmcp skills read frontmcp-channels`, `frontmcp skills read frontmcp-channels:references/<file>.md`, `frontmcp skills install frontmcp-channels` — no server required. |
149
+ | **MCP `skill://`** | When a developer mounts this skill into their own FrontMCP server (`@FrontMcp({ skills: [...] })`), the SDK exposes it via SEP-2640 resources: `skill://frontmcp-channels/SKILL.md`, `skill://frontmcp-channels/references/{file}.md`, etc. The server’s `skill://index.json` returns the SEP-2640 discovery document for everything mounted on it. |
150
+
151
+ The catalog itself is **not** an MCP server. The `skill://` URIs only resolve
152
+ when a server has been configured to host this skill.
153
+
118
154
  ## Reference
119
155
 
120
156
  - [Claude Code Channels Reference](https://code.claude.com/docs/en/channels-reference)
@@ -19,9 +19,15 @@ Watch files for changes and notify Claude Code in real-time
19
19
 
20
20
  ```typescript
21
21
  // src/apps/monitoring/channels/log-watcher.channel.ts
22
- import { Channel, ChannelContext } from '@frontmcp/sdk';
23
- import type { ChannelNotification } from '@frontmcp/sdk';
22
+
23
+ // NOTE: We normally read/write files via `@frontmcp/utils`, but it does not
24
+ // expose a file-watcher helper because watching is platform-specific (inotify
25
+ // on Linux, FSEvents on macOS, ReadDirectoryChangesW on Windows) and not
26
+ // available in browser/edge runtimes. `node:fs` is the right call here; this
27
+ // channel is Node-only by design.
24
28
  import { watch } from 'node:fs';
29
+
30
+ import { Channel, ChannelContext, type ChannelNotification } from '@frontmcp/sdk';
25
31
  import { readFile } from '@frontmcp/utils';
26
32
 
27
33
  @Channel({