@frontmcp/skills 1.3.0 → 1.4.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 (116) hide show
  1. package/README.md +38 -29
  2. package/catalog/TEMPLATE.md +26 -0
  3. package/catalog/create-tool/SKILL.md +318 -0
  4. package/catalog/create-tool/examples/01-basic-class-tool.md +112 -0
  5. package/catalog/create-tool/examples/02-basic-function-tool.md +80 -0
  6. package/catalog/create-tool/examples/03-tool-with-zod-shape-output.md +78 -0
  7. package/catalog/create-tool/examples/04-tool-with-zod-schema-output.md +97 -0
  8. package/catalog/create-tool/examples/05-tool-with-primitive-output.md +93 -0
  9. package/catalog/create-tool/examples/06-tool-with-media-output.md +109 -0
  10. package/catalog/create-tool/examples/08-tool-with-provider-injection.md +110 -0
  11. package/catalog/create-tool/examples/09-tool-with-multiple-providers.md +107 -0
  12. package/catalog/create-tool/examples/11-tool-with-fetch.md +94 -0
  13. package/catalog/create-tool/examples/12-tool-with-fetch-and-retries.md +115 -0
  14. package/catalog/create-tool/examples/13-tool-with-single-auth-provider.md +85 -0
  15. package/catalog/create-tool/examples/14-tool-with-multiple-auth-providers.md +105 -0
  16. package/catalog/create-tool/examples/15-tool-with-credential-vault.md +115 -0
  17. package/catalog/create-tool/examples/16-tool-with-rate-limit.md +71 -0
  18. package/catalog/create-tool/examples/17-tool-with-concurrency-and-timeout.md +101 -0
  19. package/catalog/create-tool/examples/18-tool-with-progress-and-notify.md +96 -0
  20. package/catalog/create-tool/examples/19-tool-with-elicitation.md +102 -0
  21. package/catalog/create-tool/examples/20-tool-with-annotations.md +125 -0
  22. package/catalog/create-tool/examples/21-tool-with-availability-constraints.md +107 -0
  23. package/catalog/create-tool/examples/22-tool-with-ui-html-template.md +93 -0
  24. package/catalog/create-tool/examples/23-tool-with-ui-filesource-tsx.md +112 -0
  25. package/catalog/create-tool/examples/24-tool-with-ui-csp-and-bridge.md +127 -0
  26. package/catalog/create-tool/examples/25-tool-handing-off-to-job.md +143 -0
  27. package/catalog/create-tool/examples/26-tool-with-resource-link-output.md +94 -0
  28. package/catalog/create-tool/examples/27-tool-with-examples-metadata.md +90 -0
  29. package/catalog/create-tool/references/annotations.md +96 -0
  30. package/catalog/create-tool/references/auth-providers.md +167 -0
  31. package/catalog/create-tool/references/availability.md +106 -0
  32. package/catalog/create-tool/references/decorator-options.md +95 -0
  33. package/catalog/create-tool/references/derived-types.md +102 -0
  34. package/catalog/create-tool/references/elicitation.md +128 -0
  35. package/catalog/create-tool/references/error-handling.md +128 -0
  36. package/catalog/create-tool/references/execution-context.md +158 -0
  37. package/catalog/create-tool/references/file-layout.md +96 -0
  38. package/catalog/create-tool/references/function-style-builder.md +118 -0
  39. package/catalog/create-tool/references/input-schema.md +141 -0
  40. package/catalog/create-tool/references/output-schema.md +175 -0
  41. package/catalog/create-tool/references/quick-start.md +124 -0
  42. package/catalog/create-tool/references/registration.md +132 -0
  43. package/catalog/create-tool/references/remote-and-esm.md +68 -0
  44. package/catalog/create-tool/references/testing.md +59 -0
  45. package/catalog/create-tool/references/throttling.md +109 -0
  46. package/catalog/create-tool/references/ui-widgets.md +198 -0
  47. package/catalog/create-tool/rules/always-define-output-schema.md +77 -0
  48. package/catalog/create-tool/rules/derive-execute-types.md +57 -0
  49. package/catalog/create-tool/rules/input-schema-is-raw-shape.md +76 -0
  50. package/catalog/create-tool/rules/no-toolcontext-generics.md +50 -0
  51. package/catalog/create-tool/rules/no-try-catch-around-execute.md +79 -0
  52. package/catalog/create-tool/rules/register-in-app.md +76 -0
  53. package/catalog/create-tool/rules/snake-case-tool-names.md +45 -0
  54. package/catalog/create-tool/rules/use-this-fail-for-business-errors.md +75 -0
  55. package/catalog/create-tool/rules/widget-paths-anchor-with-import-meta-url.md +76 -0
  56. package/catalog/create-tool/rules/widget-resource-mode-host-detect.md +61 -0
  57. package/catalog/frontmcp-auth-ui/SKILL.md +146 -0
  58. package/catalog/frontmcp-auth-ui/examples/custom-auth-ui/login-slot.md +97 -0
  59. package/catalog/frontmcp-auth-ui/examples/custom-auth-ui/multi-step-auth-extra.md +133 -0
  60. package/catalog/frontmcp-auth-ui/references/custom-auth-ui.md +162 -0
  61. package/catalog/frontmcp-authorities/SKILL.md +55 -18
  62. package/catalog/frontmcp-authorities/references/authority-profiles.md +25 -1
  63. package/catalog/frontmcp-authorities/references/custom-evaluators.md +1 -1
  64. package/catalog/frontmcp-authorities/references/rbac-abac-rebac.md +9 -0
  65. package/catalog/frontmcp-channels/SKILL.md +7 -1
  66. package/catalog/frontmcp-config/SKILL.md +9 -2
  67. package/catalog/frontmcp-config/examples/configure-auth/local-credential-vault.md +94 -0
  68. package/catalog/frontmcp-config/examples/configure-auth/local-secure-store.md +138 -0
  69. package/catalog/frontmcp-config/examples/configure-auth/remote-oauth-with-vault.md +45 -23
  70. package/catalog/frontmcp-config/examples/configure-auth-modes/local-behind-tunnel.md +73 -0
  71. package/catalog/frontmcp-config/examples/configure-auth-modes/local-consent-enforcement.md +87 -0
  72. package/catalog/frontmcp-config/examples/configure-auth-modes/local-dcr-control.md +67 -0
  73. package/catalog/frontmcp-config/examples/configure-auth-modes/local-minimal.md +62 -0
  74. package/catalog/frontmcp-config/examples/configure-auth-modes/local-multi-provider-orchestration.md +93 -0
  75. package/catalog/frontmcp-config/examples/configure-auth-modes/local-self-signed-tokens.md +18 -20
  76. package/catalog/frontmcp-config/examples/configure-auth-modes/local-single-operator.md +66 -0
  77. package/catalog/frontmcp-config/examples/configure-auth-modes/remote-enterprise-oauth.md +37 -23
  78. package/catalog/frontmcp-config/examples/configure-http/custom-http-routes.md +98 -0
  79. package/catalog/frontmcp-config/examples/configure-skills-http/audit-log-redis.md +17 -9
  80. package/catalog/frontmcp-config/references/configure-auth-modes.md +86 -23
  81. package/catalog/frontmcp-config/references/configure-auth.md +296 -50
  82. package/catalog/frontmcp-config/references/configure-http.md +149 -15
  83. package/catalog/frontmcp-deployment/SKILL.md +15 -13
  84. package/catalog/frontmcp-deployment/references/deploy-manifest-yaml.md +308 -0
  85. package/catalog/frontmcp-deployment/references/deploy-to-cloudflare-skills-only.md +174 -0
  86. package/catalog/frontmcp-deployment/references/mcp-client-integration.md +38 -2
  87. package/catalog/frontmcp-development/SKILL.md +30 -44
  88. package/catalog/frontmcp-development/references/decorators-guide.md +15 -15
  89. package/catalog/frontmcp-extensibility/SKILL.md +1 -1
  90. package/catalog/frontmcp-extensibility/examples/skill-audit-log/verify-chain.md +8 -6
  91. package/catalog/frontmcp-extensibility/references/skill-audit-log.md +7 -2
  92. package/catalog/frontmcp-guides/SKILL.md +1 -1
  93. package/catalog/frontmcp-observability/SKILL.md +1 -1
  94. package/catalog/frontmcp-production-readiness/SKILL.md +1 -1
  95. package/catalog/frontmcp-production-readiness/examples/common-checklist/security-hardening.md +3 -2
  96. package/catalog/frontmcp-setup/SKILL.md +1 -1
  97. package/catalog/frontmcp-setup/examples/multi-app-composition/per-app-auth-and-isolation.md +7 -4
  98. package/catalog/frontmcp-setup/references/multi-app-composition.md +6 -5
  99. package/catalog/frontmcp-testing/SKILL.md +9 -1
  100. package/catalog/frontmcp-testing/references/test-auth.md +24 -0
  101. package/catalog/skills-manifest.json +653 -149
  102. package/package.json +1 -1
  103. package/src/manifest.d.ts +72 -1
  104. package/src/manifest.js +4 -1
  105. package/src/manifest.js.map +1 -1
  106. package/catalog/frontmcp-development/examples/create-tool/basic-class-tool.md +0 -80
  107. package/catalog/frontmcp-development/examples/create-tool/tool-with-di-and-errors.md +0 -132
  108. package/catalog/frontmcp-development/examples/create-tool/tool-with-rate-limiting-and-progress.md +0 -110
  109. package/catalog/frontmcp-development/examples/create-tool-annotations/destructive-delete-tool.md +0 -92
  110. package/catalog/frontmcp-development/examples/create-tool-annotations/readonly-query-tool.md +0 -59
  111. package/catalog/frontmcp-development/examples/create-tool-output-schema-types/primitive-and-media-outputs.md +0 -101
  112. package/catalog/frontmcp-development/examples/create-tool-output-schema-types/zod-raw-shape-output.md +0 -62
  113. package/catalog/frontmcp-development/examples/create-tool-output-schema-types/zod-schema-advanced-output.md +0 -101
  114. package/catalog/frontmcp-development/references/create-tool-annotations.md +0 -48
  115. package/catalog/frontmcp-development/references/create-tool-output-schema-types.md +0 -71
  116. package/catalog/frontmcp-development/references/create-tool.md +0 -806
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: configure-http
3
- description: Configure HTTP server port, CORS policy, unix sockets, entry path prefix, and request body limits
3
+ description: Configure HTTP server port, CORS policy, unix sockets, entry path prefix, request body limits, and custom HTTP routes
4
4
  ---
5
5
 
6
6
  # Configuring HTTP Options
7
7
 
8
- Configure the HTTP server — port, CORS policy, unix sockets, entry path prefix, and request body limits.
8
+ Configure the HTTP server — port, CORS policy, unix sockets, entry path prefix, request body limits, and first-class custom HTTP routes.
9
9
 
10
10
  ## When to Use This Skill
11
11
 
@@ -16,6 +16,8 @@ Configure the HTTP server — port, CORS policy, unix sockets, entry path prefix
16
16
  - Binding to a unix socket for local daemon or process-manager integrations
17
17
  - Raising or tightening the request body limit (default `'4mb'`) for tools that
18
18
  accept base64-encoded blobs (PDFs, DOCXes, large HTML payloads)
19
+ - Adding a custom HTTP route (download endpoint, webhook, health-beyond-`/health`)
20
+ on the same listener as the MCP endpoint via `http.routes`
19
21
 
20
22
  ### Recommended
21
23
 
@@ -51,6 +53,16 @@ Configure the HTTP server — port, CORS policy, unix sockets, entry path prefix
51
53
  },
52
54
  bodyLimit: '4mb', // default: '4mb' — body-parser-compatible string or bytes (number)
53
55
  urlencodedLimit: undefined, // default: falls back to bodyLimit
56
+ routes: [
57
+ // First-class custom HTTP routes (see "Custom HTTP Routes" below)
58
+ {
59
+ method: 'GET',
60
+ path: '/download/:id',
61
+ handler: (req, res) => {
62
+ /* ... */
63
+ },
64
+ },
65
+ ],
54
66
  },
55
67
  })
56
68
  class Server {}
@@ -181,6 +193,116 @@ affected** by `bodyLimit`/`urlencodedLimit` — those options are consumed only
181
193
  by the built-in `ExpressHostAdapter`. Custom-host deployments must configure
182
194
  their own body limits.
183
195
 
196
+ ## Custom HTTP Routes
197
+
198
+ `http.routes` mounts first-class custom HTTP handlers on the **same listener**
199
+ as the MCP JSON-RPC endpoint. Use them for byte delivery (file/stream/binary
200
+ downloads), webhooks, health probes beyond `/health`, or any non-JSON-RPC
201
+ surface — the MCP channel cannot serve those.
202
+
203
+ ```typescript
204
+ import type { ServerRequest, ServerResponse } from '@frontmcp/sdk';
205
+
206
+ http: {
207
+ routes: [
208
+ // Public route (default) — no auth.
209
+ {
210
+ method: 'GET',
211
+ path: '/download/:id',
212
+ handler: (req: ServerRequest, res: ServerResponse) => {
213
+ res.setHeader('Content-Type', 'application/pdf'); // see Content-Type note
214
+ res.status(200).send(loadPdfBytes(req.params.id));
215
+ },
216
+ },
217
+ // Auth-gated route — runs the MCP `session:verify` flow first.
218
+ {
219
+ method: 'POST',
220
+ path: '/webhooks/billing',
221
+ auth: true,
222
+ handler: (req: ServerRequest, res: ServerResponse) => {
223
+ // req.authSession is populated when auth: true and verification passed
224
+ res.status(202).json({ accepted: true, user: req.authSession?.user?.sub });
225
+ },
226
+ },
227
+ ],
228
+ }
229
+ ```
230
+
231
+ | Field | Type | Default | Description |
232
+ | --------- | ---------------------- | ---------------- | ------------------------------------------------------------------------ |
233
+ | `method` | `HttpMethod` | — | `'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE' \| 'OPTIONS' \| 'HEAD'` |
234
+ | `path` | `string` | — | Express-style path (`/files/:id`); must not collide with reserved paths |
235
+ | `handler` | `ServerRequestHandler` | — | `(req, res, next) => void \| Promise<void>` |
236
+ | `auth` | `boolean` | `false` (public) | When `true`, gate behind the MCP `session:verify` flow |
237
+
238
+ ### Handler signature
239
+
240
+ The handler uses the framework-agnostic `(req, res, next)` signature. Respond
241
+ with `res.status(...).json(...)` / `res.send(...)`, or call `next()` to fall
242
+ through. `req` and `res` are exported as `ServerRequest` / `ServerResponse`
243
+ from `@frontmcp/sdk`, and `ServerRequestHandler` types the handler directly.
244
+
245
+ Routes share the configured **CORS policy, body limits, and security
246
+ middleware** with the MCP endpoint — they ride the same Express app.
247
+
248
+ ### `auth` opt-in
249
+
250
+ Routes are **public by default**. Set `auth: true` to run the request through
251
+ the exact same `session:verify` flow the MCP endpoint uses:
252
+
253
+ - **Unauthorized** → short-circuits with `401` + a `WWW-Authenticate` header.
254
+ - **Forbidden** (valid token, insufficient scope) → `403` + `WWW-Authenticate`.
255
+ - **Authorized** → the verified authorization is attached to `req.authSession`
256
+ before your handler runs.
257
+
258
+ In **public auth mode** (or transparent with `allowAnonymous`), `auth: true`
259
+ routes receive an anonymous session and the handler still runs. Under auth
260
+ modes with no anonymous fallback (e.g. `local` with `allowDefaultPublic: false`),
261
+ unauthenticated requests get the `401`.
262
+
263
+ ### Reserved-path guard
264
+
265
+ Custom paths that collide with FrontMCP's own surfaces are **rejected at
266
+ startup** (fail-fast) — they would otherwise shadow or be shadowed by the MCP
267
+ endpoint. Reserved:
268
+
269
+ - the resolved MCP entry path (and its `/sse` + `/message` siblings) — split-by-app
270
+ scope bases are included (e.g. `/mcp/billing`),
271
+ - anything under `/oauth/*` and `/.well-known/*`,
272
+ - `/health` and `/metrics`.
273
+
274
+ ```typescript
275
+ // ❌ Throws at startup: collides with the MCP entry path when entryPath: '/mcp'
276
+ http: { entryPath: '/mcp', routes: [{ method: 'POST', path: '/mcp', handler }] }
277
+ ```
278
+
279
+ ### Content-Type gotcha
280
+
281
+ The built-in `ExpressHostAdapter` defaults **every** response to
282
+ `application/json; charset=utf-8`. HTML, binary, and streaming handlers MUST
283
+ set their own content type **before** sending the body:
284
+
285
+ ```typescript
286
+ {
287
+ method: 'GET',
288
+ path: '/report',
289
+ handler: (req, res) => {
290
+ res.setHeader('Content-Type', 'text/html; charset=utf-8'); // or res.type('html')
291
+ res.status(200).send('<!doctype html><h1>Report</h1>');
292
+ },
293
+ }
294
+ ```
295
+
296
+ ### Large payloads: prefer a custom route over `@Resource`
297
+
298
+ > **Decision:** When a tool needs to hand the client a **large** payload, return
299
+ > a [`resource_link`](https://docs.agentfront.dev/frontmcp/servers/resources)
300
+ > that points at a custom `http.routes` **GET** handler, and serve the bytes
301
+ > from that handler (it supports stream/binary delivery). A `@Resource` rides
302
+ > the MCP JSON-RPC channel and is **not** out-of-band — large reads block the
303
+ > protocol stream and inflate token usage. The custom route delivers bytes on a
304
+ > separate HTTP request the client fetches directly.
305
+
184
306
  ## Entry Path Prefix
185
307
 
186
308
  Mount the MCP server under a URL prefix:
@@ -246,30 +368,42 @@ curl --unix-socket /tmp/my-mcp-server.sock http://localhost/
246
368
  - [ ] `maxAge` is set to a reasonable value for production (e.g., `86400` for 24 hours)
247
369
  - [ ] Dynamic origin function handles `undefined` origin (non-browser requests)
248
370
 
371
+ ### Custom Routes
372
+
373
+ - [ ] No custom `path` collides with the MCP entry path, `/sse`, `/message`, `/oauth/*`, `/.well-known/*`, `/health`, or `/metrics`
374
+ - [ ] HTML/binary/stream handlers call `res.setHeader('Content-Type', ...)` (or `res.type(...)`) before `res.send(...)`
375
+ - [ ] `auth: true` is set on any route that must require a verified session
376
+ - [ ] Large payloads are served via a custom GET route + `resource_link`, not a `@Resource`
377
+
249
378
  ### Runtime
250
379
 
251
380
  - [ ] Server starts and binds to the expected port or socket path
252
381
  - [ ] `curl -v -H "Origin: <your-origin>" <url>` returns correct `Access-Control-Allow-Origin`
253
382
  - [ ] Preflight `OPTIONS` requests return `204` with expected CORS headers
383
+ - [ ] Custom routes respond as expected (`curl <url>/<your-route>`)
254
384
 
255
385
  ## Troubleshooting
256
386
 
257
- | Problem | Cause | Solution |
258
- | ------------------------------------------------ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- |
259
- | `EADDRINUSE` on startup | Another process is already using the configured port | Change the port, stop the other process, or use `port: 0` for a random available port |
260
- | CORS errors in the browser console | Origin not included in the `cors.origin` list or `credentials: true` with wildcard origin | Add the frontend origin to the `origin` array and ensure credentials and origin settings are compatible |
261
- | Unix socket file not created | Missing write permissions on the target directory or stale socket file from a previous run | Check directory permissions and remove the stale `.sock` file before restarting |
262
- | Routes return 404 after setting `entryPath` | Client is still requesting the root path without the prefix | Update client base URL to include the entry path (e.g., `http://localhost:3000/api/mcp`) |
263
- | Server binds but external clients cannot connect | Server bound to `localhost` or `127.0.0.1` inside a container | Set `host: '0.0.0.0'` or use Docker port mapping to expose the container port |
264
- | `413 Payload Too Large` with JSON-RPC envelope | Request body exceeded `bodyLimit` (default `'4mb'`) | Raise `http.bodyLimit` to fit the payload, or move large blobs to a separate upload endpoint |
387
+ | Problem | Cause | Solution |
388
+ | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
389
+ | `EADDRINUSE` on startup | Another process is already using the configured port | Change the port, stop the other process, or use `port: 0` for a random available port |
390
+ | CORS errors in the browser console | Origin not included in the `cors.origin` list or `credentials: true` with wildcard origin | Add the frontend origin to the `origin` array and ensure credentials and origin settings are compatible |
391
+ | Unix socket file not created | Missing write permissions on the target directory or stale socket file from a previous run | Check directory permissions and remove the stale `.sock` file before restarting |
392
+ | Routes return 404 after setting `entryPath` | Client is still requesting the root path without the prefix | Update client base URL to include the entry path (e.g., `http://localhost:3000/api/mcp`) |
393
+ | Server binds but external clients cannot connect | Server bound to `localhost` or `127.0.0.1` inside a container | Set `host: '0.0.0.0'` or use Docker port mapping to expose the container port |
394
+ | `413 Payload Too Large` with JSON-RPC envelope | Request body exceeded `bodyLimit` (default `'4mb'`) | Raise `http.bodyLimit` to fit the payload, or move large blobs to a separate upload endpoint |
395
+ | Server throws at startup mentioning a "reserved" path | A custom `http.routes` path collides with the MCP entry path, `/oauth/*`, `/.well-known/*`, `/health`, or `/metrics` | Rename the custom route to a non-reserved path |
396
+ | Custom route returns JSON when HTML/bytes expected | The Express adapter defaults responses to `application/json` | Set `res.setHeader('Content-Type', ...)` (or `res.type(...)`) in the handler before sending the body |
397
+ | Custom `auth: true` route always returns `401` | Auth mode has no anonymous fallback and the request carries no valid bearer token | Send a valid `Authorization: Bearer <jwt>`, or use `auth` mode `public`/transparent-anon for open routes |
265
398
 
266
399
  ## Examples
267
400
 
268
- | Example | Level | Description |
269
- | ------------------------------------------------------------------------------------ | ------------ | ------------------------------------------------------------------------------------ |
270
- | [`cors-restricted-origins`](../examples/configure-http/cors-restricted-origins.md) | Basic | Configure CORS to allow only specific frontend origins with credentials. |
271
- | [`entry-path-reverse-proxy`](../examples/configure-http/entry-path-reverse-proxy.md) | Intermediate | Mount the MCP server under a URL prefix for reverse proxy or multi-service setups. |
272
- | [`unix-socket-local`](../examples/configure-http/unix-socket-local.md) | Intermediate | Bind the server to a unix socket instead of a TCP port for local-only communication. |
401
+ | Example | Level | Description |
402
+ | ------------------------------------------------------------------------------------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------- |
403
+ | [`cors-restricted-origins`](../examples/configure-http/cors-restricted-origins.md) | Basic | Configure CORS to allow only specific frontend origins with credentials. |
404
+ | [`custom-http-routes`](../examples/configure-http/custom-http-routes.md) | Intermediate | Mount first-class custom HTTP routes (download, secret-validation POST, auth-gated webhook) on the MCP listener via http.routes. |
405
+ | [`entry-path-reverse-proxy`](../examples/configure-http/entry-path-reverse-proxy.md) | Intermediate | Mount the MCP server under a URL prefix for reverse proxy or multi-service setups. |
406
+ | [`unix-socket-local`](../examples/configure-http/unix-socket-local.md) | Intermediate | Bind the server to a unix socket instead of a TCP port for local-only communication. |
273
407
 
274
408
  > See all examples in [`examples/configure-http/`](../examples/configure-http/)
275
409
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: frontmcp-deployment
3
- description: 'Use when you need to deploy, build for production, containerize, or ship a FrontMCP server. Covers Vercel, Lambda, Cloudflare, Docker, edge runtime, serverless, bundle for CLI, and Node targets. Triggers: deploy, build for production, dockerize, serverless, go live.'
3
+ description: 'Use when deploying, building for production, packaging, or shipping a FrontMCP server. Covers build targets (node, cli SEA binary, browser, embeddable SDK, mcpb archive for Claude Desktop, serverless) and deploying to Vercel (with Vercel KV), AWS Lambda (API Gateway, SAM, CDK), Cloudflare Workers (KV, D1, Durable Objects, v1.3 skills-only), and Node (multi-stage Docker, docker-compose, PM2, nginx). Also the frontmcp.deploy.yaml manifest plus GitHub Action push-resync, and MCP client integration / .mcp.json for Claude Desktop, Claude Code, Cursor, and VS Code over stdio or HTTP. Triggers: deploy, build for production, dockerize, containerize, serverless, edge runtime, go live, ship it.'
4
4
  tags: [router, deployment, node, vercel, lambda, cloudflare, cli, browser, sdk, guide]
5
5
  category: deployment
6
6
  targets: [all]
@@ -53,18 +53,20 @@ Entry point for deploying and building FrontMCP servers. This skill helps you ch
53
53
 
54
54
  ## Scenario Routing Table
55
55
 
56
- | Scenario | Reference | Description |
57
- | ------------------------------------------------- | --------------------------- | ----------------------------------------------------------------------- |
58
- | Long-running server on VPS, Docker, or bare metal | `deploy-to-node` | Node.js with stdio or HTTP transport, PM2/Docker for process management |
59
- | Serverless with zero config and Vercel KV | `deploy-to-vercel` | Vercel Functions with Streamable HTTP, Vercel KV for storage |
60
- | AWS serverless with API Gateway | `deploy-to-lambda` | Lambda + API Gateway with Streamable HTTP, DynamoDB or ElastiCache |
61
- | Edge computing with global distribution | `deploy-to-cloudflare` | Cloudflare Workers with KV or Durable Objects for storage |
62
- | Standalone executable binary for distribution | `build-for-cli` | Single-binary CLI with stdio transport, embedded storage |
63
- | Run MCP in a web browser | `build-for-browser` | Browser-compatible bundle with in-memory transport |
64
- | Embed MCP into an existing Node.js application | `build-for-sdk` | Library build for programmatic usage without standalone server |
65
- | Write a Dockerfile for Node.js deployment | `deploy-to-node-dockerfile` | Dockerfile configuration for Node.js deployment |
66
- | Configure Vercel-specific settings (vercel.json) | `deploy-to-vercel-config` | Vercel-specific configuration (vercel.json) |
67
- | Connect MCP clients (Claude, Cursor, VS Code) | `mcp-client-integration` | Configure .mcp.json for stdio, HTTP, or Unix socket transport |
56
+ | Scenario | Reference | Description |
57
+ | ------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
58
+ | Long-running server on VPS, Docker, or bare metal | `deploy-to-node` | Node.js with stdio or HTTP transport, PM2/Docker for process management |
59
+ | Serverless with zero config and Vercel KV | `deploy-to-vercel` | Vercel Functions with Streamable HTTP, Vercel KV for storage |
60
+ | AWS serverless with API Gateway | `deploy-to-lambda` | Lambda + API Gateway with Streamable HTTP, DynamoDB or ElastiCache |
61
+ | Edge computing with global distribution | `deploy-to-cloudflare` | Cloudflare Workers with KV or Durable Objects for storage |
62
+ | Hosted FrontMCP (v1.3 skills-only model) | `deploy-to-cloudflare-skills-only` | Cloudflare Worker as the MCP control plane; OpenAPI is capability inventory; agent uses 4 meta-tools + AgentScript; hot-reload via GitHub Action |
63
+ | Author `frontmcp.deploy.yaml` | `deploy-manifest-yaml` | v1 schema reference: runtime, server, specs, skills, tags, classification, bindings, signing, auth, secrets, environments |
64
+ | Standalone executable binary for distribution | `build-for-cli` | Single-binary CLI with stdio transport, embedded storage |
65
+ | Run MCP in a web browser | `build-for-browser` | Browser-compatible bundle with in-memory transport |
66
+ | Embed MCP into an existing Node.js application | `build-for-sdk` | Library build for programmatic usage without standalone server |
67
+ | Write a Dockerfile for Node.js deployment | `deploy-to-node-dockerfile` | Dockerfile configuration for Node.js deployment |
68
+ | Configure Vercel-specific settings (vercel.json) | `deploy-to-vercel-config` | Vercel-specific configuration (vercel.json) |
69
+ | Connect MCP clients (Claude, Cursor, VS Code) | `mcp-client-integration` | Configure .mcp.json for stdio, HTTP, or Unix socket transport |
68
70
 
69
71
  ### CLI Commands for Deployment and Operations
70
72
 
@@ -0,0 +1,308 @@
1
+ ---
2
+ name: deploy-manifest-yaml
3
+ description: The frontmcp.deploy.yaml v1 schema — declarative manifest the GitHub Action consumes on every push to build, sign, and hot-reload the Cloudflare Worker
4
+ ---
5
+
6
+ # `frontmcp.deploy.yaml` — Schema Reference
7
+
8
+ This is the declarative manifest the GitHub Action ingests on every push. It is the source of truth for what your Cloudflare Worker serves. The schema is strict — unknown keys fail validation.
9
+
10
+ For the runtime that consumes the bundle, see `deploy-to-cloudflare-skills-only.md` in this same folder.
11
+ For the live docs version, see https://docs.agentfront.dev/frontmcp/deployment/deploy-manifest.
12
+
13
+ ## Minimum Manifest
14
+
15
+ ```yaml
16
+ $schema: https://schemas.agentfront.dev/frontmcp-deploy/v1.json
17
+ version: 1
18
+ name: acme-mcp
19
+
20
+ runtime:
21
+ target: cloudflare-worker
22
+ compatibilityDate: '2026-05-01'
23
+
24
+ server:
25
+ info: { name: acme-mcp, version: 1.0.0 }
26
+
27
+ specs: ./openapi/
28
+ skills: { source: ./skills/ }
29
+
30
+ bindings:
31
+ durableObjects:
32
+ - { binding: SESSIONS, className: SessionDO }
33
+ kvNamespaces:
34
+ - { binding: REPLAY_NONCE, id: '${env:KV_REPLAY_NONCE_ID}' }
35
+
36
+ signing:
37
+ algorithm: ed25519
38
+ trustRoots:
39
+ - { kid: prod-2026-05, publicKeySecret: TRUSTED_PUBKEY_PROD }
40
+ replay: { windowSeconds: 300, nonceKv: REPLAY_NONCE }
41
+
42
+ auth: { provider: none }
43
+
44
+ secrets:
45
+ - { name: TRUSTED_PUBKEY_PROD, required: true }
46
+ ```
47
+
48
+ ## Top-Level Keys
49
+
50
+ | Field | Required | Notes |
51
+ | ---------------- | -------- | ---------------------------------------------------------------- |
52
+ | `$schema` | optional | URL pointer for editor autocomplete |
53
+ | `version` | yes | Literal `1` only in v1.3 |
54
+ | `name` | yes | Identifier: `[A-Za-z][A-Za-z0-9_-]*` |
55
+ | `runtime` | yes | `target` + `compatibilityDate` + optional `compatibilityFlags[]` |
56
+ | `server` | yes | `info` + optional `instructions` (≤ 16 KB) |
57
+ | `specs` | yes | Directory string OR `{ id, spec, baseUrl?, bindingName? }[]` |
58
+ | `skills` | optional | Defaults to `{ source: './skills/' }` |
59
+ | `tags` | optional | `[{ name, description? }]` OpenAPI-shaped |
60
+ | `classification` | optional | Override rules over the auto-classifier |
61
+ | `bindings` | yes | CF DO / D1 / KV / R2 / vars (camelCase) |
62
+ | `signing` | yes | Algorithm + trust roots + replay-guard |
63
+ | `auth` | yes | `provider: none \| frontegg \| oauth \| apiKey` |
64
+ | `secrets` | optional | Names-only; cross-validator enforces references |
65
+ | `environments` | optional | Per-env overlay (deep-merge; bindings replace) |
66
+
67
+ ## `runtime`
68
+
69
+ ```yaml
70
+ runtime:
71
+ target: cloudflare-worker
72
+ compatibilityDate: '2026-05-01' # ISO-8601 YYYY-MM-DD
73
+ compatibilityFlags: [nodejs_compat] # optional
74
+ ```
75
+
76
+ ## `server`
77
+
78
+ ```yaml
79
+ server:
80
+ info:
81
+ name: acme-mcp
82
+ version: 1.0.0
83
+ title: ACME MCP # optional
84
+ instructions: | # optional, max 16 KB
85
+ Capabilities are organized as SKILLS...
86
+ ```
87
+
88
+ ## `specs`
89
+
90
+ ```yaml
91
+ specs: ./openapi/ # directory; specId = filename stem
92
+ ```
93
+
94
+ ```yaml
95
+ specs:
96
+ - ./openapi/acme.yaml
97
+ - id: billing
98
+ spec: ./openapi/billing.yaml
99
+ baseUrl: https://billing.acme.com
100
+ bindingName: billing # optional override for AgentScript namespace
101
+ ```
102
+
103
+ ## `skills`
104
+
105
+ ```yaml
106
+ skills:
107
+ source: ./skills/
108
+ alwaysLoad: # forced-load skill ids (kebab-case)
109
+ - auth-helpers
110
+ - observability-helpers
111
+ tags:
112
+ include: [public, billing]
113
+ exclude: [admin]
114
+ ```
115
+
116
+ A skill can also self-opt-in via its SKILL.md frontmatter:
117
+
118
+ ```yaml
119
+ ---
120
+ name: auth-helpers
121
+ description: Helpers every agent needs.
122
+ alwaysLoad: true
123
+ hideFromDiscovery: true # load without showing in search
124
+ ---
125
+ ```
126
+
127
+ ## `tags`
128
+
129
+ ```yaml
130
+ tags:
131
+ - { name: public, description: Always exposed }
132
+ - { name: billing, description: Billing flows }
133
+ - { name: admin, description: Admin only }
134
+ ```
135
+
136
+ ## `classification` Overrides
137
+
138
+ ```yaml
139
+ classification:
140
+ rules:
141
+ - { match: 'POST **/reset-password', emits: parent }
142
+ - { match: 'GET /metrics', expose: tool }
143
+ - { match: 'DELETE /users/{id}', emits: none }
144
+ ```
145
+
146
+ `match` = `METHOD path-glob`. Method may be `*`. `*` matches a single segment, `**` matches across `/`. First match wins.
147
+
148
+ ## `bindings`
149
+
150
+ Mirror wrangler shapes (camelCased). Strict — unknown keys reject.
151
+
152
+ ```yaml
153
+ bindings:
154
+ durableObjects:
155
+ - { binding: SESSIONS, className: SessionDO }
156
+ - { binding: EVENTS, className: EventStoreDO }
157
+ - { binding: BUNDLE, className: BundleDO }
158
+ d1Databases:
159
+ - { binding: AUDIT, databaseName: acme-audit, databaseId: '${env:D1_AUDIT_ID}' }
160
+ kvNamespaces:
161
+ - { binding: BUNDLE_CACHE, id: '${env:KV_BUNDLE_CACHE_ID}' }
162
+ - { binding: REPLAY_NONCE, id: '${env:KV_REPLAY_NONCE_ID}' }
163
+ r2Buckets:
164
+ - { binding: SKILL_DATA, bucketName: acme-skill-data }
165
+ vars:
166
+ LOG_LEVEL: info
167
+ ```
168
+
169
+ Binding names: SCREAMING_SNAKE_CASE.
170
+
171
+ ## `signing`
172
+
173
+ ```yaml
174
+ signing:
175
+ algorithm: ed25519 # or rs256
176
+ trustRoots:
177
+ - kid: prod-2026-05
178
+ publicKeySecret: TRUSTED_PUBKEY_PROD
179
+ replay:
180
+ windowSeconds: 300 # default 300; [10, 3600]
181
+ nonceKv: REPLAY_NONCE # MUST match a kvNamespaces[].binding
182
+ ```
183
+
184
+ Cross-validator enforces `replay.nonceKv` resolves to a KV binding name and every `publicKeySecret` appears in `secrets[]`.
185
+
186
+ ## `auth` (Discriminated Union)
187
+
188
+ ```yaml
189
+ auth: { provider: none }
190
+ ```
191
+
192
+ ```yaml
193
+ auth:
194
+ provider: frontegg
195
+ frontegg:
196
+ tenantResolver: subdomain # or 'header' / 'jwt-claim'
197
+ audience: acme-mcp
198
+ issuerSecret: FRONTEGG_ISSUER_URL
199
+ ```
200
+
201
+ ```yaml
202
+ auth:
203
+ provider: oauth
204
+ oauth:
205
+ issuer: https://issuer.example.com
206
+ audience: acme-mcp
207
+ credentialsSecret: M2M_CREDS # optional, M2M
208
+ ```
209
+
210
+ ```yaml
211
+ auth:
212
+ provider: apiKey
213
+ apiKey:
214
+ header: X-API-Key
215
+ allowlistSecret: ACME_API_KEYS
216
+ ```
217
+
218
+ ## `secrets`
219
+
220
+ ```yaml
221
+ secrets:
222
+ - { name: TRUSTED_PUBKEY_PROD, required: true, description: 'Signing trust root (PEM)' }
223
+ - { name: FRONTEGG_ISSUER_URL, required: true }
224
+ - { name: ACME_API_TOKEN, required: true, description: 'ACME API bearer' }
225
+ ```
226
+
227
+ SCREAMING_SNAKE_CASE names only. Inline values are forbidden by the schema.
228
+
229
+ ## `environments`
230
+
231
+ ```yaml
232
+ environments:
233
+ staging:
234
+ specs:
235
+ - id: acme
236
+ spec: ./openapi/acme.yaml
237
+ baseUrl: https://api.staging.acme.com
238
+ skills: { tags: { include: [public, billing, ops] } }
239
+ bindings: { vars: { LOG_LEVEL: debug } }
240
+ production:
241
+ skills: { tags: { include: [public, billing, ops], exclude: [admin, experimental] } }
242
+ bindings: { vars: { LOG_LEVEL: info } }
243
+ ```
244
+
245
+ Deep-merge for scalars + nested objects; `bindings` REPLACES (Wrangler non-inheritance semantics).
246
+
247
+ ## Cross-Field Validation
248
+
249
+ After per-field schema parse, run `crossValidateManifest(parsed)`:
250
+
251
+ | Check | Error shape |
252
+ | --------------------------------------------------------- | --------------------------------------------------------------------------------- |
253
+ | Secret referenced from auth/signing but not declared | `Secret "<NAME>" referenced at <path> is not declared in secrets[]` |
254
+ | `signing.replay.nonceKv` not in `bindings.kvNamespaces[]` | `signing.replay.nonceKv "<X>" does not match any bindings.kvNamespaces[].binding` |
255
+ | `skills.alwaysLoad[]` entry not kebab-case | `skills.alwaysLoad entry "<X>" is not a valid kebab-case skill id` |
256
+ | Tag filter references undeclared tag | `skills.tags references unknown tag "<X>" (not in tags[])` |
257
+
258
+ All errors aggregate in one report — not throw-on-first.
259
+
260
+ ```ts
261
+ import * as YAML from 'yaml';
262
+
263
+ import { crossValidateManifest, deployManifestSchema } from '@frontmcp/adapters/skills';
264
+
265
+ const parsed = deployManifestSchema.parse(YAML.parse(raw));
266
+ const cross = crossValidateManifest(parsed);
267
+ if (!cross.ok) cross.errors.forEach((e) => console.error('manifest:', e));
268
+ ```
269
+
270
+ ## Auto-Classification Table (HTTP → MCP)
271
+
272
+ | Method | Path | Matching GET? | Surface | Notify on success |
273
+ | ----------- | ---------------------- | ------------- | -------- | ---------------------------- |
274
+ | GET | `/users/{id}` | (self) | both | — |
275
+ | GET | `/users` | (self) | resource | — |
276
+ | POST | `/users` | yes | tool | `list_changed` on self |
277
+ | POST | `/users/{id}` | yes | tool | `updated` on self |
278
+ | POST | `/users/{id}/reset-pw` | no | tool | `updated` on parent |
279
+ | POST | any | no | tool | — |
280
+ | PUT / PATCH | any | yes | tool | `updated` on self |
281
+ | PUT / PATCH | any | no | tool | `updated` on parent (if any) |
282
+ | DELETE | singular | — | tool | `list_changed` on parent |
283
+ | DELETE | collection | yes | tool | `list_changed` on self |
284
+
285
+ The notification fires once per call regardless of which skill made it. Two skills calling the same PUT → still one event.
286
+
287
+ ## TypeScript Imports
288
+
289
+ ```ts
290
+ import {
291
+ applyClassificationOverrides,
292
+ buildResourceChangeNotification,
293
+ ClassificationRegistry,
294
+ classifyOperations,
295
+ crossValidateManifest,
296
+ deployManifestSchema,
297
+ extractOpReferences,
298
+ renderResourceUri,
299
+ validateOpReferences,
300
+ type DeployManifest,
301
+ } from '@frontmcp/adapters/skills';
302
+ ```
303
+
304
+ ## See Also
305
+
306
+ - `references/deploy-to-cloudflare-skills-only.md` — the runtime that consumes the manifest
307
+ - Docs: https://docs.agentfront.dev/frontmcp/deployment/deploy-manifest
308
+ - Docs: https://docs.agentfront.dev/frontmcp/features/skills-only-deployment