Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.agentfront.dev/llms.txt

Use this file to discover all available pages before exploring further.

The plugin loads bundles through a SkillBundleSource interface. Three implementations ship in v1.2.0; you choose by setting source.type in the plugin options.
SourceRefreshProduction-readyUse when
staticfs.watch (optional)✅ for self-hostedBundle lives on the FrontMCP server’s filesystem; you control deployments
npmServer redeploy onlyBundle ships as an npm package pinned in your package.json
saasBoot pull + interval polling✅ when paired with signingBundle is produced by an external service (FrontMCP Cloud or your own analyzer)

static

Loads from a local filesystem path. Optional watch: true re-fetches on file change (debounced 250ms). Falls back to a 2-second poll if fs.watch rejects the file (some platforms reject watch on certain filesystems).
SkilledOpenApiPlugin.init({
  source: {
    type: 'static',
    path: path.resolve(__dirname, '../bundle.json'),
    watch: true,
  },
  // ...
})
Bundle file extensions:
  • .json → JSON
  • .yaml / .yml → YAML
  • anything else → format sniffed from the first non-whitespace byte

npm

Loads from a published npm package’s default (or named) export. Pinned by your package.json — updates require a server redeploy, which is intentional: the lower-blast-radius distribution mode.
SkilledOpenApiPlugin.init({
  source: {
    type: 'npm',
    packageName: '@acme/frontmcp-billing-bundle',
    exportName: 'frontmcpBundle',  // optional; default is the package's default export
    verifyProvenance: true,        // logs a warning until v1.2.x ships verification
  },
  // ...
})
The package’s exported value must conform to the ResolvedBundle shape; the plugin parses it through the same Zod validator the static source uses.
v1.2.0 honors verifyProvenance: true by emitting a startup warning when no GitHub artifact attestation / Sigstore provenance is found. Actual provenance verification ships in v1.2.x. Do not rely on this flag as your only supply-chain control yet — sign your bundles via the integrity envelope and pin the npm version.

saas

Pulls bundles from a configured HTTPS endpoint with a pinned JWT. Boot pull is mandatory; interval polling refreshes; a last-good cached bundle on disk is the fallback if a fresh pull fails.
SkilledOpenApiPlugin.init({
  source: {
    type: 'saas',
    endpoint: 'https://cloud.frontmcp.dev/v1/bundles/acme-prod',
    authToken: process.env.FRONTMCP_CLOUD_TOKEN!,
    expectedAudience: 'acme:prod',                 // RFC 8707 aud claim must match
    expectedIssuer: 'https://cloud.frontmcp.dev',
    jwksUrl: 'https://cloud.frontmcp.dev/.well-known/jwks.json',
    pollIntervalMs: 300_000,                       // 5 min default
    enableWebhook: false,                          // v1.2.x — interval-only in v1.2.0
  },
  bundleCacheDir: '.frontmcp/skilled-openapi',     // last-good bundle persisted here
  // ...
})

Boot semantics

  1. Initial pull runs synchronously when the plugin’s BundleSyncService factory boots.
  2. If the pull succeeds, the bundle is persisted to bundleCacheDir and applied via the sync service.
  3. If the pull fails AND a cached bundle exists, the cache is loaded with a startup warning. The server stays healthy.
  4. If the pull fails AND no cache exists, the source throws — the plugin reports a startup error but does not kill the server.
This prevents a SaaS outage at boot from killing every customer’s MCP server. The trade-off is that a long-broken SaaS will leave the server serving an old bundle indefinitely; monitor lastPullAt from /healthz (planned in v1.2.x) and your own SaaS-side metrics.

Polling

Default pollIntervalMs: 300_000 (5 min). Overlapping polls are skipped via a single-flight gate — if a previous poll is still in flight when the next interval fires, the new poll is dropped (not queued).

Webhook channel

enableWebhook: true declares intent but is a no-op in v1.2.0 — the plugin’s HTTP route extension hook lands in v1.2.x. Until then, the plugin only refreshes via the configured pollIntervalMs.

Source-conflict policy

If multiple sources somehow register the same bundleId (e.g. you wire both static and saas simultaneously), the plugin’s sourceConflictPolicy controls resolution:
SkilledOpenApiPlugin.init({
  source: { /* ... */ },
  sourceConflictPolicy: 'static-wins',  // default: locally pinned beats remote
})
Values:
  • 'static-wins' (default): static beats npm beats saas
  • 'last-wins': most recent apply wins (use with caution; race-prone)
  • 'reject': fail to apply when a conflict is detected
In v1.2.0 the plugin only constructs one source instance from options.source, so this policy is documented for future use when multi-source configurations land.