Skip to main content
The plugin loads bundles through a SkillBundleSource interface. Three implementations are available; you choose by setting source.type in the plugin options.

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).
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.
The package’s exported value must conform to the ResolvedBundle shape; the plugin parses it through the same Zod validator the static source uses. verifyProvenance defaults to true, and npm provenance verification is not implemented yet, so with true the source refuses to load the package (it is never imported) and logs why. Set verifyProvenance: false to load it without a provenance check.
With verifyProvenance: false the package is imported, and its code runs, before the bundle is parsed. Bundle signing (the integrity envelope, requireSignature + trustedKeys) protects the bundle’s content, not the import: a compromised package runs its code even if its bundle then fails verification. Only load a package you trust, pin its exact version in package.json, and install it from a lockfile with integrity hashes.

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. Before every pull the pinned authToken is verified against the SaaS: signed by a key served at jwksUrl (fetched without the token, redirects refused), iss equal to expectedIssuer, aud including expectedAudience, not expired. A token that fails is refused with [saas-source] pull token rejected: …: nothing is pulled, and the cached bundle is not used instead. The JWKS being unreachable, or serving no usable signing key (no RSA, EC or OKP public key for signatures), counts as an ordinary pull failure, so the cache fallback still applies.

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. A rejected authToken is not a pull failure: the cache is not used, and the source reports an error.
  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 your SaaS-side metrics to catch a stalled pipeline.

Redirects

The pull carries authToken as a bearer token, so it never follows a redirect: endpoint must serve the bundle directly. A 3xx (or a browser runtime’s status-0 opaqueredirect) fails the pull like any other pull error, with the boot fallback described above.

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).

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:
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
The plugin constructs a single source from options.source, so this policy only takes effect when more than one source registers the same bundleId.