Skip to main content
A skill bundle is the contract between whatever produced it (your CI, a SaaS analyzer, a hand-crafted JSON file) and the FrontMCP server that consumes it. The plugin validates every bundle with a strict Zod schema and cross-references service IDs, authBinding refs, and operation IDs before any skill is registered.

Two equivalent shapes

The plugin accepts either:
  1. A bare bundle JSON (the simplest form, used in the Quick Start and the e2e suite).
  2. An OpenAPI Overlay (per the OAI Overlay spec 1.0/1.1) carrying the bundle under info["x-frontmcp-bundle"] or at the overlay root under x-frontmcp-bundle.
Both project to the same internal ResolvedBundle. The Overlay shape exists so customers can hand-author bundles in any OpenAPI tool, layered on top of an existing spec they already maintain.
overlay.yaml

TypeScript shape

ServiceDescriptor

One entry per upstream microservice. The bundle can wrap several services into one MCP surface.

AuthBinding

Reusable auth bindings, referenced by OperationDescriptor.authBindingRef. Credentials are resolved at execute time from the configured CredentialResolver.
passthroughCallerToken: true on a bearer binding tells the executor to forward the MCP client’s JWT to the upstream API instead of resolving a vault credential. Useful for “the upstream is this customer’s own service and trusts our caller’s token directly.”

BundledSkill

The discoverable unit. Each skill bundles a curated set of operationIds and ships markdown instructions the LLM reads before invoking any action.
AuthoritiesPolicy is the same shape @frontmcp/auth uses across the rest of FrontMCP — roles, permissions, attributes, relationships, custom, operator, not, anyOf, allOf. See the authorities docs for the full grammar.

OperationDescriptor

One descriptor per OpenAPI operation. The plugin executes these by projecting them onto the McpOpenAPITool shape and calling @frontmcp/adapters/openapi’s buildRequest — the executor doesn’t reinvent path interpolation, header injection defenses, or body building.
The mapper array is the structure mcp-from-openapi produces when parsing an OpenAPI spec — each entry maps an inputKey from the JSON Schema to a slot (path / query / header / cookie / body). The SaaS analyzer (or whatever produces your bundle) runs the parser once at CI time so the runtime plugin doesn’t re-derive parameter locations.

BundleIntegrity

Detached signature envelope, modeled on OPA’s signed-bundle pattern.
The plugin verifies (a) the digest matches a recomputed sha256 of the canonicalized bundle minus the integrity field, (b) the signature is valid for that digest under a trusted public key in trustedKeys[]. Any failure rejects the bundle and keeps the previous one — never partial apply.

Validation rules the plugin enforces

Defense-in-depth, applied even after signature verification (CVE-2025-6514 lesson — treat every string as adversarial):
  • Path templates: must start with /, no whitespace, no ?/#, no .., no shell metacharacters (` / $( / ${)
  • Service / skill / operation ids: alphanumeric + - / _ (skill ids also allow .; operation ids also allow . / :)
  • API key names: must match RFC 7230 token grammar
  • Source digest: must be hex (sha256)
  • Generated timestamp: must be ISO 8601 parsable
  • Cross-references: every OperationDescriptor.serviceId must reference a known service, every authBindingRef must reference a known auth binding, every BundledSkill.operationIds[] entry must reference a known operation
  • Skill ids: must be unique within the bundle
A bundle that fails any of these rejects with a structured error containing the offending JSON path, and the previous bundle stays active.

Worked example

The full e2e fixture bundle lives at apps/e2e/demo-e2e-skilled-openapi/src/fixtures/billing-bundle.json — a single invoices skill bundling three operations against a billing service, plus a guarded skill demonstrating the ABAC denial path. Use it as a starting point and adapt to your API.

Multi-service bundles

One bundle can wrap several microservices natively — declare each service in services[] and point each operation at its serviceId. The plugin’s host allowlist for outbound HTTP is built from the union of services[].baseUrl hostnames in the active bundle, so a bundle that mixes api.billing.acme.com and api.crm.acme.com produces a two-host allowlist for the executor’s SSRF gate.

What’s NOT in v1.2.0

These are the same caveats the underlying mcp-from-openapi parser carries; bundles that include them will fail validation.