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 OpenAPI adapter and the Skilled OpenAPI plugin both turn an OpenAPI spec into MCP-callable surface — but they do it for different audiences and ship different contracts.

At a glance

OpenAPI AdapterSkilled OpenAPI Plugin
Discovery unitOne MCP tool per operationIdOne MCP skill bundling many ops
Visible to MCP clientEvery operation (in tools/list)Three meta-tools only; per-op tools hidden
When the spec changesServer redeployBundle hot-swap (signed, atomic)
Bundle origin trustNone — spec is localSigned bundles from CI / SaaS
ABAC per operationVia @FrontMcp({ authorities }) on the adapter-mounted toolsNative; requiredAuthorities on the bundle’s operations
Runtime costmcp-from-openapi parser at bootPre-parsed bundle (parsing happens in your CI)
Sweet spot5–20 hand-curated endpoints50+ endpoints, multi-service, customer-facing

When to use each

OpenAPI adapter

  • You’re wrapping a small internal API (≤20 ops) and the LLM should see every endpoint.
  • You control the spec and ship it inside your repo.
  • You want every op to appear in tools/list and be callable by name.
  • You’re not yet ready for a CI-driven bundle pipeline.

Skilled OpenAPI plugin

  • You’re wrapping a large API (50+ ops) where flat exposure breaks the agent.
  • The spec changes faster than your server redeploys (multiple times per day).
  • You need per-skill curation — the LLM should see “billing” and “customers” as named capabilities, not 47 individual endpoints.
  • You need ABAC at the operation granularity, with policies that travel with the bundle.
  • You need bundle origin trust — your CI signs, the runtime verifies.

Running both in the same server

Both can register simultaneously without conflict — they don’t share registries or fight over tools/list:
  • The adapter writes to scope.tools (visible).
  • The plugin writes to scope.skills (visible) and a plugin-private HiddenOpRegistry (not visible).
The two paths never interact at runtime. A natural pattern: small handcrafted internal tools through the adapter, large customer-facing API surface through the plugin.
src/main.ts
import { FrontMcp } from '@frontmcp/sdk';
import OpenApiAdapter from '@frontmcp/adapters/openapi';
import SkilledOpenApiPlugin from '@frontmcp/plugin-skilled-openapi';

@FrontMcp({
  info: { name: 'Acme MCP', version: '1.0.0' },
  apps: [
    OpenApiAdapter.fromSpec({
      name: 'admin-tools',
      spec: './specs/admin.openapi.yaml',
      // 6 internal admin endpoints, hand-curated, visible
    }),
  ],
  plugins: [
    SkilledOpenApiPlugin.init({
      source: { type: 'saas', /* ... */ },
      // 200+ customer-facing endpoints from a CI-published bundle
    }),
  ],
})
export default class Server {}
The MCP client sees:
tools/list:
  - search_skill, load_skill, execute_action   # from the plugin
  - admin:resetCache, admin:reindex, ...       # from the adapter
skills/list:
  - billing, customers, orders, ...            # from the plugin

Migration paths

From adapter to plugin

If you started with the adapter and your spec grew past the point where flat exposure works:
  1. Don’t rip out the adapter — leave it serving the small internal ops.
  2. Move the public-facing surface into a bundle. The simplest path is a script in your CI that reads your existing OpenAPI spec, runs the same mcp-from-openapi parser the adapter uses to produce mapper[] for each op, groups operations into skills (probably by tag or by URL path prefix), wraps the result in a ResolvedBundle, and signs it.
  3. Register the plugin with a static source pointing at the bundle artifact your CI produces.
  4. Phase: deploy with both running, remove operations from the adapter as the bundle covers them, eventually drop adapter-managed ops the bundle now owns.
A future v1.2.x release may ship a CLI helper (frontmcp openapi-to-bundle) that does step 2 mechanically; for now it’s a small script.

From plugin to adapter

Rare, but possible — if you decide a particular surface should be flatly exposed (e.g. a debugging tool), drop those operations from the bundle and add them to an adapter-mounted app.

What if both register the same tool name?

The adapter writes to scope.tools; the plugin only ever writes meta-tool names (search_skill, load_skill, execute_action) to scope.tools. Your adapter-mounted ops and the meta-tools cannot collide unless you deliberately name an adapter tool search_skill. For per-operation collisions inside the plugin (one bundle declaring two skills that both reference the same operationId), the bundle’s Zod cross-validator rejects at apply time.