@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.
- package/README.md +38 -29
- package/catalog/TEMPLATE.md +26 -0
- package/catalog/create-tool/SKILL.md +318 -0
- package/catalog/create-tool/examples/01-basic-class-tool.md +112 -0
- package/catalog/create-tool/examples/02-basic-function-tool.md +80 -0
- package/catalog/create-tool/examples/03-tool-with-zod-shape-output.md +78 -0
- package/catalog/create-tool/examples/04-tool-with-zod-schema-output.md +97 -0
- package/catalog/create-tool/examples/05-tool-with-primitive-output.md +93 -0
- package/catalog/create-tool/examples/06-tool-with-media-output.md +109 -0
- package/catalog/create-tool/examples/08-tool-with-provider-injection.md +110 -0
- package/catalog/create-tool/examples/09-tool-with-multiple-providers.md +107 -0
- package/catalog/create-tool/examples/11-tool-with-fetch.md +94 -0
- package/catalog/create-tool/examples/12-tool-with-fetch-and-retries.md +115 -0
- package/catalog/create-tool/examples/13-tool-with-single-auth-provider.md +85 -0
- package/catalog/create-tool/examples/14-tool-with-multiple-auth-providers.md +105 -0
- package/catalog/create-tool/examples/15-tool-with-credential-vault.md +115 -0
- package/catalog/create-tool/examples/16-tool-with-rate-limit.md +71 -0
- package/catalog/create-tool/examples/17-tool-with-concurrency-and-timeout.md +101 -0
- package/catalog/create-tool/examples/18-tool-with-progress-and-notify.md +96 -0
- package/catalog/create-tool/examples/19-tool-with-elicitation.md +102 -0
- package/catalog/create-tool/examples/20-tool-with-annotations.md +125 -0
- package/catalog/create-tool/examples/21-tool-with-availability-constraints.md +107 -0
- package/catalog/create-tool/examples/22-tool-with-ui-html-template.md +93 -0
- package/catalog/create-tool/examples/23-tool-with-ui-filesource-tsx.md +112 -0
- package/catalog/create-tool/examples/24-tool-with-ui-csp-and-bridge.md +127 -0
- package/catalog/create-tool/examples/25-tool-handing-off-to-job.md +143 -0
- package/catalog/create-tool/examples/26-tool-with-resource-link-output.md +94 -0
- package/catalog/create-tool/examples/27-tool-with-examples-metadata.md +90 -0
- package/catalog/create-tool/references/annotations.md +96 -0
- package/catalog/create-tool/references/auth-providers.md +167 -0
- package/catalog/create-tool/references/availability.md +106 -0
- package/catalog/create-tool/references/decorator-options.md +95 -0
- package/catalog/create-tool/references/derived-types.md +102 -0
- package/catalog/create-tool/references/elicitation.md +128 -0
- package/catalog/create-tool/references/error-handling.md +128 -0
- package/catalog/create-tool/references/execution-context.md +158 -0
- package/catalog/create-tool/references/file-layout.md +96 -0
- package/catalog/create-tool/references/function-style-builder.md +118 -0
- package/catalog/create-tool/references/input-schema.md +141 -0
- package/catalog/create-tool/references/output-schema.md +175 -0
- package/catalog/create-tool/references/quick-start.md +124 -0
- package/catalog/create-tool/references/registration.md +132 -0
- package/catalog/create-tool/references/remote-and-esm.md +68 -0
- package/catalog/create-tool/references/testing.md +59 -0
- package/catalog/create-tool/references/throttling.md +109 -0
- package/catalog/create-tool/references/ui-widgets.md +198 -0
- package/catalog/create-tool/rules/always-define-output-schema.md +77 -0
- package/catalog/create-tool/rules/derive-execute-types.md +57 -0
- package/catalog/create-tool/rules/input-schema-is-raw-shape.md +76 -0
- package/catalog/create-tool/rules/no-toolcontext-generics.md +50 -0
- package/catalog/create-tool/rules/no-try-catch-around-execute.md +79 -0
- package/catalog/create-tool/rules/register-in-app.md +76 -0
- package/catalog/create-tool/rules/snake-case-tool-names.md +45 -0
- package/catalog/create-tool/rules/use-this-fail-for-business-errors.md +75 -0
- package/catalog/create-tool/rules/widget-paths-anchor-with-import-meta-url.md +76 -0
- package/catalog/create-tool/rules/widget-resource-mode-host-detect.md +61 -0
- package/catalog/frontmcp-auth-ui/SKILL.md +146 -0
- package/catalog/frontmcp-auth-ui/examples/custom-auth-ui/login-slot.md +97 -0
- package/catalog/frontmcp-auth-ui/examples/custom-auth-ui/multi-step-auth-extra.md +133 -0
- package/catalog/frontmcp-auth-ui/references/custom-auth-ui.md +162 -0
- package/catalog/frontmcp-authorities/SKILL.md +55 -18
- package/catalog/frontmcp-authorities/references/authority-profiles.md +25 -1
- package/catalog/frontmcp-authorities/references/custom-evaluators.md +1 -1
- package/catalog/frontmcp-authorities/references/rbac-abac-rebac.md +9 -0
- package/catalog/frontmcp-channels/SKILL.md +7 -1
- package/catalog/frontmcp-config/SKILL.md +9 -2
- package/catalog/frontmcp-config/examples/configure-auth/local-credential-vault.md +94 -0
- package/catalog/frontmcp-config/examples/configure-auth/local-secure-store.md +138 -0
- package/catalog/frontmcp-config/examples/configure-auth/remote-oauth-with-vault.md +45 -23
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-behind-tunnel.md +73 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-consent-enforcement.md +87 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-dcr-control.md +67 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-minimal.md +62 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-multi-provider-orchestration.md +93 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-self-signed-tokens.md +18 -20
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-single-operator.md +66 -0
- package/catalog/frontmcp-config/examples/configure-auth-modes/remote-enterprise-oauth.md +37 -23
- package/catalog/frontmcp-config/examples/configure-http/custom-http-routes.md +98 -0
- package/catalog/frontmcp-config/examples/configure-skills-http/audit-log-redis.md +17 -9
- package/catalog/frontmcp-config/references/configure-auth-modes.md +86 -23
- package/catalog/frontmcp-config/references/configure-auth.md +296 -50
- package/catalog/frontmcp-config/references/configure-http.md +149 -15
- package/catalog/frontmcp-deployment/SKILL.md +15 -13
- package/catalog/frontmcp-deployment/references/deploy-manifest-yaml.md +308 -0
- package/catalog/frontmcp-deployment/references/deploy-to-cloudflare-skills-only.md +174 -0
- package/catalog/frontmcp-deployment/references/mcp-client-integration.md +38 -2
- package/catalog/frontmcp-development/SKILL.md +30 -44
- package/catalog/frontmcp-development/references/decorators-guide.md +15 -15
- package/catalog/frontmcp-extensibility/SKILL.md +1 -1
- package/catalog/frontmcp-extensibility/examples/skill-audit-log/verify-chain.md +8 -6
- package/catalog/frontmcp-extensibility/references/skill-audit-log.md +7 -2
- package/catalog/frontmcp-guides/SKILL.md +1 -1
- package/catalog/frontmcp-observability/SKILL.md +1 -1
- package/catalog/frontmcp-production-readiness/SKILL.md +1 -1
- package/catalog/frontmcp-production-readiness/examples/common-checklist/security-hardening.md +3 -2
- package/catalog/frontmcp-setup/SKILL.md +1 -1
- package/catalog/frontmcp-setup/examples/multi-app-composition/per-app-auth-and-isolation.md +7 -4
- package/catalog/frontmcp-setup/references/multi-app-composition.md +6 -5
- package/catalog/frontmcp-testing/SKILL.md +9 -1
- package/catalog/frontmcp-testing/references/test-auth.md +24 -0
- package/catalog/skills-manifest.json +653 -149
- package/package.json +1 -1
- package/src/manifest.d.ts +72 -1
- package/src/manifest.js +4 -1
- package/src/manifest.js.map +1 -1
- package/catalog/frontmcp-development/examples/create-tool/basic-class-tool.md +0 -80
- package/catalog/frontmcp-development/examples/create-tool/tool-with-di-and-errors.md +0 -132
- package/catalog/frontmcp-development/examples/create-tool/tool-with-rate-limiting-and-progress.md +0 -110
- package/catalog/frontmcp-development/examples/create-tool-annotations/destructive-delete-tool.md +0 -92
- package/catalog/frontmcp-development/examples/create-tool-annotations/readonly-query-tool.md +0 -59
- package/catalog/frontmcp-development/examples/create-tool-output-schema-types/primitive-and-media-outputs.md +0 -101
- package/catalog/frontmcp-development/examples/create-tool-output-schema-types/zod-raw-shape-output.md +0 -62
- package/catalog/frontmcp-development/examples/create-tool-output-schema-types/zod-schema-advanced-output.md +0 -101
- package/catalog/frontmcp-development/references/create-tool-annotations.md +0 -48
- package/catalog/frontmcp-development/references/create-tool-output-schema-types.md +0 -71
- 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,
|
|
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,
|
|
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
|
|
258
|
-
|
|
|
259
|
-
| `EADDRINUSE` on startup
|
|
260
|
-
| CORS errors in the browser console
|
|
261
|
-
| Unix socket file not created
|
|
262
|
-
| Routes return 404 after setting `entryPath`
|
|
263
|
-
| Server binds but external clients cannot connect
|
|
264
|
-
| `413 Payload Too Large` with JSON-RPC envelope
|
|
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
|
-
| [`
|
|
272
|
-
| [`
|
|
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
|
|
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
|
|
57
|
-
| ------------------------------------------------- |
|
|
58
|
-
| Long-running server on VPS, Docker, or bare metal | `deploy-to-node`
|
|
59
|
-
| Serverless with zero config and Vercel KV | `deploy-to-vercel`
|
|
60
|
-
| AWS serverless with API Gateway | `deploy-to-lambda`
|
|
61
|
-
| Edge computing with global distribution | `deploy-to-cloudflare`
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
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
|