diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18bb81cc..0b4ad0b2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,27 @@
+## [v0.6.2] - 2025-12-24
+
+### feat
+
+- Add static, dynamic, and hybrid UI build modes plus multi-platform bundling helpers so the same widget can hydrate differently on OpenAI, Claude, or Gemini without duplicate code.
+- Auto-enable transport persistence whenever `redis` is configured, wiring session storage without needing a separate `transport.persistence` block.
+- Teach `frontmcp build --adapter vercel` to detect npm, pnpm, yarn, or bun lockfiles, set the matching install/build commands, and emit Vercel Build Output API artifacts ready for deployment.
+
+### fix
+
+- Resolve dual-package hazards by lazily requiring `FrontMcpInstance` inside the decorator so runtime imports always reference the same module copy.
+- Default primary-auth transport options now reuse `DEFAULT_TRANSPORT_CONFIG`, eliminating drift between schema defaults and runtime behavior.
+- Serverless bundling loosens fully-specified import requirements, aliases optional React dependencies, and filters known rspack warnings so builds stay quiet but accurate.
+
+### build
+
+- All synchronized workspaces (sdk, cli, adapters, plugins) now publish dual CommonJS/ESM artifacts with `sideEffects: false` and shared typings for better tree-shaking.
+- Independent packages `json-schema-to-zod-v3@1.0.3` and `mcp-from-openapi@2.1.1` match the new export map layout, ensuring adapters and downstream CLIs consume a single source of truth.
+
+### docs
+
+- Published the Build Modes guide plus a new callout on the platforms page to explain when to reach for static, dynamic, or hybrid rendering.
+- Refreshed the live updates page with v0.6.2 highlights and links to the independent library releases.
+
## [v0.6.1] - 2025-12-22
### feat
@@ -91,7 +115,7 @@
### feat
-- Publish the standalone `mcp-from-openapi` generator and wire the OpenAPI adapter to it so every tool inherits request mappers, conflict-free schemas, and per-scheme authentication analysis.
+- Publish the standalone `mcp-from-openapi` generator and wire the OpenAPI adapter to it so every tool inherits conflict-free params, request mappers, and per-scheme authentication analysis.
- Allow `@Tool` metadata to declare literal primitives, tuple-style arrays, and MCP resources (plus `rawInputSchema`) so clients get typed responses without wrapping outputs in placeholder objects.
- Add a typed MCP error hierarchy and error handler so transports emit traceable IDs, consistent public/internal messages, and FlowControl-aware stop semantics.
- Extract `json-schema-to-zod-v3` with built-in regex guards so adapters and apps can reuse the hardened JSON Schema → Zod converter.
diff --git a/docs/live/docs/ui/advanced/build-modes.mdx b/docs/live/docs/ui/advanced/build-modes.mdx
new file mode 100644
index 00000000..805c3d7a
--- /dev/null
+++ b/docs/live/docs/ui/advanced/build-modes.mdx
@@ -0,0 +1,323 @@
+---
+title: Build Modes
+sidebarTitle: Build Modes
+icon: hammer
+description: Control how widget data is injected into HTML - static baking, dynamic subscription, or hybrid placeholder injection.
+---
+
+## Overview
+
+FrontMCP supports three build modes that control how tool input/output data is injected into the rendered HTML:
+
+| Mode | Description | Best For |
+| ----------- | ---------------------------------------------------------------------------- | --------------------------------- |
+| **static** | Data baked into HTML at build time | Default, simple widgets |
+| **dynamic** | Platform-aware - subscribes to events (OpenAI) or uses placeholders (Claude) | Real-time updates, multi-platform |
+| **hybrid** | Pre-built shell with placeholders, replace at runtime | Caching, high-performance |
+
+## Static Mode (Default)
+
+Data is serialized and embedded directly in the HTML at build time.
+
+```typescript
+const result = await bundler.bundleToStaticHTML({
+ source: componentCode,
+ toolName: 'get_weather',
+ output: { temperature: 72, unit: 'F' },
+ buildMode: 'static', // default
+});
+```
+
+The generated HTML includes the data inline:
+
+```html
+
+```
+
+**Use when:**
+
+- Widget content doesn't change after initial render
+- Simple tool responses
+- No caching requirements
+
+## Dynamic Mode
+
+Dynamic mode is **platform-aware** - it behaves differently depending on the target platform:
+
+### OpenAI (ESM)
+
+For OpenAI, dynamic mode subscribes to the `window.openai.canvas.onToolResult` event for real-time updates:
+
+```typescript
+const result = await bundler.bundleToStaticHTML({
+ source: componentCode,
+ toolName: 'get_weather',
+ output: { temperature: 72 }, // Optional initial data
+ buildMode: 'dynamic',
+ dynamicOptions: {
+ includeInitialData: true, // Include initial data (default: true)
+ subscribeToUpdates: true, // Subscribe to events (default: true)
+ },
+});
+```
+
+Generated HTML subscribes to OpenAI events:
+
+```html
+
+```
+
+### Claude/Non-OpenAI (UMD)
+
+For non-OpenAI platforms (Claude, etc.), dynamic mode uses **placeholders** since they can't subscribe to OpenAI events:
+
+```html
+
+```
+
+Use the `injectHybridDataFull` helper to replace placeholders before sending:
+
+```typescript
+import { injectHybridDataFull } from '@frontmcp/uipack/build';
+
+// Build once
+const shell = await bundler.bundleToStaticHTML({
+ source: componentCode,
+ toolName: 'get_weather',
+ buildMode: 'dynamic',
+ platform: 'claude',
+});
+
+// Inject data before sending
+const html = injectHybridDataFull(
+ shell.html,
+ { location: 'San Francisco' }, // input
+ { temperature: 72, unit: 'F' }, // output
+);
+```
+
+### Dynamic Options
+
+| Option | Type | Default | Description |
+| -------------------- | --------- | ------- | ------------------------------------------ |
+| `includeInitialData` | `boolean` | `true` | Include initial data in HTML |
+| `subscribeToUpdates` | `boolean` | `true` | Subscribe to platform events (OpenAI only) |
+
+**Behavior when `includeInitialData: false`:**
+
+- **OpenAI**: Shows loading state, waits for `onToolResult` event
+- **Claude**: Shows loading state if placeholder not replaced, error if expected data missing
+
+## Hybrid Mode
+
+Hybrid mode creates a pre-built shell with placeholders that you replace at runtime. This is ideal for caching - build the shell once, inject different data per request.
+
+```typescript
+import { injectHybridData, injectHybridDataFull } from '@frontmcp/uipack/build';
+
+// 1. Build shell ONCE at startup
+const shell = await bundler.bundleToStaticHTML({
+ source: componentCode,
+ toolName: 'get_weather',
+ buildMode: 'hybrid',
+});
+
+// Cache the shell
+const cachedShell = shell.html;
+
+// 2. On each request, just inject data (no rebuild!)
+const html1 = injectHybridDataFull(cachedShell, input1, output1);
+const html2 = injectHybridDataFull(cachedShell, input2, output2);
+```
+
+### Placeholders
+
+| Placeholder | Purpose |
+| --------------------------------- | ------------------------------ |
+| `__FRONTMCP_OUTPUT_PLACEHOLDER__` | Replaced with tool output JSON |
+| `__FRONTMCP_INPUT_PLACEHOLDER__` | Replaced with tool input JSON |
+
+### Helper Functions
+
+```typescript
+import {
+ injectHybridData,
+ injectHybridDataFull,
+ isHybridShell,
+ HYBRID_DATA_PLACEHOLDER,
+ HYBRID_INPUT_PLACEHOLDER,
+} from '@frontmcp/uipack/build';
+
+// Inject output only
+const html = injectHybridData(shell, { temperature: 72 });
+
+// Inject both input and output
+const html = injectHybridDataFull(shell, input, output);
+
+// Check if HTML is a hybrid shell
+if (isHybridShell(html)) {
+ // Contains placeholders - needs injection
+}
+```
+
+### Error Handling
+
+If placeholders are not replaced, the widget shows an error:
+
+```javascript
+// If placeholder not replaced:
+window.__frontmcp.setState({
+ loading: false,
+ error: 'No data provided. The output placeholder was not replaced.'
+});
+```
+
+## Multi-Platform Building
+
+Build for multiple platforms at once with platform-specific behavior:
+
+```typescript
+const result = await bundler.bundleForMultiplePlatforms({
+ source: componentCode,
+ toolName: 'get_weather',
+ buildMode: 'dynamic',
+ platforms: ['openai', 'claude'],
+});
+
+// OpenAI HTML: subscribes to onToolResult events
+const openaiHtml = result.platforms.openai.html;
+
+// Claude HTML: has placeholders - inject data before sending
+const claudeHtml = injectHybridDataFull(
+ result.platforms.claude.html,
+ input,
+ output,
+);
+```
+
+## Platform Behavior Summary
+
+| Mode | OpenAI (ESM) | Claude (UMD) |
+| ----------- | ------------------ | ------------- |
+| **static** | Data baked in | Data baked in |
+| **dynamic** | Event subscription | Placeholders |
+| **hybrid** | Placeholders | Placeholders |
+
+## Best Practices
+
+1. **Use static mode** for simple, one-off widgets
+2. **Use dynamic mode** for multi-platform apps that need the same build mode everywhere
+3. **Use hybrid mode** for high-performance scenarios where you cache the shell
+4. **Always inject data** before sending hybrid/dynamic (Claude) HTML to clients
+
+## TypeScript Types
+
+```typescript
+import type { BuildMode, DynamicModeOptions, HybridModeOptions } from '@frontmcp/ui/bundler';
+
+type BuildMode = 'static' | 'dynamic' | 'hybrid';
+
+interface DynamicModeOptions {
+ includeInitialData?: boolean; // default: true
+ subscribeToUpdates?: boolean; // default: true
+}
+
+interface HybridModeOptions {
+ placeholder?: string; // default: '__FRONTMCP_OUTPUT_PLACEHOLDER__'
+ inputPlaceholder?: string; // default: '__FRONTMCP_INPUT_PLACEHOLDER__'
+}
+```
+
+## API Reference
+
+### `bundleToStaticHTML(options)`
+
+```typescript
+interface StaticHTMLOptions {
+ // ... existing options ...
+
+ /** Build mode - controls data injection strategy */
+ buildMode?: BuildMode;
+
+ /** Options for dynamic mode */
+ dynamicOptions?: DynamicModeOptions;
+
+ /** Options for hybrid mode */
+ hybridOptions?: HybridModeOptions;
+}
+
+interface StaticHTMLResult {
+ // ... existing fields ...
+
+ /** The build mode used */
+ buildMode?: BuildMode;
+
+ /** Output placeholder (hybrid mode) */
+ dataPlaceholder?: string;
+
+ /** Input placeholder (hybrid mode) */
+ inputPlaceholder?: string;
+}
+```
+
+### `injectHybridData(shell, data, placeholder?)`
+
+Replaces the output placeholder with JSON data.
+
+```typescript
+function injectHybridData(
+ shell: string,
+ data: unknown,
+ placeholder?: string, // default: '__FRONTMCP_OUTPUT_PLACEHOLDER__'
+): string;
+```
+
+### `injectHybridDataFull(shell, input, output)`
+
+Replaces both input and output placeholders.
+
+```typescript
+function injectHybridDataFull(
+ shell: string,
+ input: unknown,
+ output: unknown,
+): string;
+```
+
+### `isHybridShell(html, placeholder?)`
+
+Checks if HTML contains the output placeholder.
+
+```typescript
+function isHybridShell(
+ html: string,
+ placeholder?: string,
+): boolean;
+```
diff --git a/docs/live/docs/ui/advanced/platforms.mdx b/docs/live/docs/ui/advanced/platforms.mdx
index eea33bd3..67814c34 100644
--- a/docs/live/docs/ui/advanced/platforms.mdx
+++ b/docs/live/docs/ui/advanced/platforms.mdx
@@ -7,16 +7,33 @@ description: FrontMCP UI adapts to different AI platform capabilities. Each plat
## Platform Capabilities
-| Platform | Network | External Scripts | Widget Modes | Response Format |
-|----------|---------|------------------|--------------|-----------------|
-| **OpenAI** | Open | CDN allowed | inline, fullscreen, pip | `_meta['ui/html']` |
-| **ext-apps** | Open | CDN allowed | inline, fullscreen, pip | `_meta['ui/html']` |
-| **Cursor** | Open | CDN allowed | inline | `_meta['ui/html']` |
-| **Claude** | Blocked | Cloudflare CDN only | Artifacts | Dual-payload |
-| **Continue** | Limited | Inline only | inline | `_meta['ui/html']` |
-| **Cody** | Limited | Inline only | inline | `_meta['ui/html']` |
-| **Gemini** | Limited | Inline preferred | Basic | JSON only |
-| **generic-mcp** | Varies | CDN/Inline | inline, static | `_meta['ui/html']` |
+| Platform | Network | External Scripts | Widget Modes | Response Format |
+| --------------- | ------- | ------------------- | ----------------------- | ------------------ |
+| **OpenAI** | Open | CDN allowed | inline, fullscreen, pip | `_meta['ui/html']` |
+| **ext-apps** | Open | CDN allowed | inline, fullscreen, pip | `_meta['ui/html']` |
+| **Cursor** | Open | CDN allowed | inline | `_meta['ui/html']` |
+| **Claude** | Blocked | Cloudflare CDN only | Artifacts | Dual-payload |
+| **Continue** | Limited | Inline only | inline | `_meta['ui/html']` |
+| **Cody** | Limited | Inline only | inline | `_meta['ui/html']` |
+| **Gemini** | Limited | Inline preferred | Basic | JSON only |
+| **generic-mcp** | Varies | CDN/Inline | inline, static | `_meta['ui/html']` |
+
+## Build Modes & Data Injection
+
+FrontMCP supports three build modes that behave differently per platform:
+
+| Mode | OpenAI | Claude/Other |
+| ----------- | ------------------ | ------------- |
+| **static** | Data baked in | Data baked in |
+| **dynamic** | Event subscription | Placeholders |
+| **hybrid** | Placeholders | Placeholders |
+
+For OpenAI, **dynamic mode** subscribes to `window.openai.canvas.onToolResult` for real-time updates.
+For Claude and other platforms, **dynamic mode** uses placeholders that must be replaced before sending.
+
+
+ Learn about static, dynamic, and hybrid build modes with platform-aware data injection.
+
## Platform Detection
@@ -106,14 +123,14 @@ Claude uses Artifacts with restricted capabilities and a special **dual-payload*
When `servingMode: 'auto'` detects a Claude client, FrontMCP returns a special two-block response:
-```json
+````json
{
"content": [
{ "type": "text", "text": "{\"temperature\":72,\"unit\":\"F\"}" },
{ "type": "text", "text": "Here is the visual result:\n\n```html\n...\n```" }
]
}
-```
+````
- **Block 0**: Pure JSON data for programmatic parsing
- **Block 1**: Markdown-wrapped HTML that Claude displays as an Artifact
@@ -124,7 +141,7 @@ Claude automatically detects the `html` code fence and offers to render it as an
Control the text shown before the HTML block:
-```typescript
+````typescript
@Tool({
name: 'get_weather',
ui: {
@@ -133,7 +150,7 @@ Control the text shown before the HTML block:
},
})
// Output: "Here is the weather dashboard:\n\n```html\n..."
-```
+````
Default: `'Here is the visual result'`
diff --git a/docs/live/docs/ui/getting-started.mdx b/docs/live/docs/ui/getting-started.mdx
index aadcb15d..69ce55e1 100644
--- a/docs/live/docs/ui/getting-started.mdx
+++ b/docs/live/docs/ui/getting-started.mdx
@@ -14,10 +14,10 @@ description: This guide walks you through adding visual widgets to your FrontMCP
FrontMCP UI is split into two packages:
-| Package | Use Case |
-|---------|----------|
+| Package | Use Case |
+| ------------------ | ----------------------------------------------- |
| `@frontmcp/uipack` | HTML components, build tools, themes (no React) |
-| `@frontmcp/ui` | React components, hooks, SSR rendering |
+| `@frontmcp/ui` | React components, hooks, SSR rendering |
```bash npm
@@ -25,8 +25,10 @@ FrontMCP UI is split into two packages:
npm install @frontmcp/uipack
# For React templates
+
npm install @frontmcp/ui react react-dom
-```
+
+````
```bash yarn
# For HTML templates only (no React required)
@@ -34,7 +36,7 @@ yarn add @frontmcp/uipack
# For React templates
yarn add @frontmcp/ui react react-dom
-```
+````
```bash pnpm
# For HTML templates only (no React required)
diff --git a/docs/live/docs/ui/integration/tools.mdx b/docs/live/docs/ui/integration/tools.mdx
index a6f19213..a6e22e70 100644
--- a/docs/live/docs/ui/integration/tools.mdx
+++ b/docs/live/docs/ui/integration/tools.mdx
@@ -147,12 +147,12 @@ ui: {
When `servingMode: 'auto'` (default), FrontMCP automatically selects the delivery method based on the client:
-| Platform | Effective Mode | Response Format |
-|----------|---------------|-----------------|
-| OpenAI / ext-apps | `inline` | HTML in `_meta['ui/html']` |
-| Claude | `inline` | Dual-payload (JSON + markdown-wrapped HTML) |
-| Cursor | `inline` | HTML in `_meta['ui/html']` |
-| Gemini / Unknown | (skipped) | JSON only |
+| Platform | Effective Mode | Response Format |
+| ----------------- | -------------- | ------------------------------------------- |
+| OpenAI / ext-apps | `inline` | HTML in `_meta['ui/html']` |
+| Claude | `inline` | Dual-payload (JSON + markdown-wrapped HTML) |
+| Cursor | `inline` | HTML in `_meta['ui/html']` |
+| Gemini / Unknown | (skipped) | JSON only |
If `'auto'` mode detects an unsupported client, UI rendering is skipped entirely. The tool returns JSON-only data to avoid broken widget experiences.
@@ -162,13 +162,13 @@ If `'auto'` mode detects an unsupported client, UI rendering is skipped entirely
Customize the text shown before HTML in dual-payload responses (Claude):
-```typescript
+````typescript
ui: {
template: WeatherWidget,
htmlResponsePrefix: 'Here is the weather dashboard',
}
// Claude output: "Here is the weather dashboard:\n\n```html\n...\n```"
-```
+````
Default prefix is `'Here is the visual result'`.
diff --git a/docs/live/docs/ui/overview.mdx b/docs/live/docs/ui/overview.mdx
index 22f877da..c99392a6 100644
--- a/docs/live/docs/ui/overview.mdx
+++ b/docs/live/docs/ui/overview.mdx
@@ -9,10 +9,10 @@ description: A platform-agnostic component library for building rich HTML widget
FrontMCP UI is split into two packages to support different use cases:
-| Package | Purpose | React Required |
-|---------|---------|----------------|
-| **@frontmcp/uipack** | HTML components, build tools, themes, platform adapters | No |
-| **@frontmcp/ui** | React components, hooks, SSR rendering | Yes |
+| Package | Purpose | React Required |
+| -------------------- | ------------------------------------------------------- | -------------- |
+| **@frontmcp/uipack** | HTML components, build tools, themes, platform adapters | No |
+| **@frontmcp/ui** | React components, hooks, SSR rendering | Yes |
Use `@frontmcp/uipack` when you only need HTML string components or build tools. Use `@frontmcp/ui` when you need React components or hooks.
@@ -68,13 +68,13 @@ When your MCP tools return data, AI platforms typically display it as raw text o
FrontMCP UI adapts to different AI platform capabilities:
-| Platform | Network | Widget Display | Response Format |
-|----------|---------|----------------|-----------------|
-| **OpenAI** | Full | Inline, Fullscreen, PiP | `_meta['ui/html']` |
-| **ext-apps** | Full | Inline, Fullscreen, PiP | `_meta['ui/html']` |
-| **Cursor** | Full | Inline | `_meta['ui/html']` |
-| **Claude** | Blocked | Artifacts | Dual-payload |
-| **Gemini** | Limited | Basic | JSON only |
+| Platform | Network | Widget Display | Response Format |
+| ------------ | ------- | ----------------------- | ------------------ |
+| **OpenAI** | Full | Inline, Fullscreen, PiP | `_meta['ui/html']` |
+| **ext-apps** | Full | Inline, Fullscreen, PiP | `_meta['ui/html']` |
+| **Cursor** | Full | Inline | `_meta['ui/html']` |
+| **Claude** | Blocked | Artifacts | Dual-payload |
+| **Gemini** | Limited | Basic | JSON only |
The library automatically detects the platform and selects the appropriate delivery format.
@@ -110,14 +110,14 @@ With `servingMode: 'auto'` (default), unsupported platforms automatically receiv
Every `@Tool` exposes a `ui` block that describes how the widget should render across hosts. Configure these settings once and the renderer keeps your UX consistent everywhere.
-| Setting | Controls | Use it when |
-| ------------------ | -------------------------------------------------------------------- | --------------------------------------------------------------------------- |
-| `displayMode` | Whether the widget renders inline, fullscreen, or picture-in-picture | Highlight dashboards inline or promote immersive flows into fullscreen/PiP. |
-| `servingMode` | How HTML is delivered (`auto`, `inline`, `static`, `hybrid`, URL-based). Default: `'auto'` | Let FrontMCP select the best format per platform, or force a specific mode. |
-| `htmlResponsePrefix` | Text shown before HTML in Claude's dual-payload format | Customize the artifact description for better Claude UX. |
-| `widgetAccessible` | Allows widgets to call tools through the MCP Bridge | Create follow-up actions (retry, escalate, schedule) directly from the UI. |
-| `csp` | Allowed domains for scripts, images, fonts, and network calls | Restrict remote dependencies per platform and satisfy Claude's strict CSP. |
-| `hydrate` | Ships the React runtime for client-side interactivity | Power forms, tabs, and charts that need local state or event handlers. |
+| Setting | Controls | Use it when |
+| -------------------- | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- |
+| `displayMode` | Whether the widget renders inline, fullscreen, or picture-in-picture | Highlight dashboards inline or promote immersive flows into fullscreen/PiP. |
+| `servingMode` | How HTML is delivered (`auto`, `inline`, `static`, `hybrid`, URL-based). Default: `'auto'` | Let FrontMCP select the best format per platform, or force a specific mode. |
+| `htmlResponsePrefix` | Text shown before HTML in Claude's dual-payload format | Customize the artifact description for better Claude UX. |
+| `widgetAccessible` | Allows widgets to call tools through the MCP Bridge | Create follow-up actions (retry, escalate, schedule) directly from the UI. |
+| `csp` | Allowed domains for scripts, images, fonts, and network calls | Restrict remote dependencies per platform and satisfy Claude's strict CSP. |
+| `hydrate` | Ships the React runtime for client-side interactivity | Power forms, tabs, and charts that need local state or event handlers. |
Pair metadata with a concise `widgetDescription` so clients can preview the UI before rendering it, just like Mintlify recommends leading with the most important context.
@@ -222,8 +222,10 @@ export class GetWeatherTool extends ToolContext {
npm install @frontmcp/uipack
# For React components and hooks
+
npm install @frontmcp/ui react react-dom
-```
+
+````
```bash yarn
# For HTML components only (no React)
@@ -231,7 +233,7 @@ yarn add @frontmcp/uipack
# For React components and hooks
yarn add @frontmcp/ui react react-dom
-```
+````
```bash pnpm
# For HTML components only (no React)
diff --git a/docs/live/updates.mdx b/docs/live/updates.mdx
index 8da467a2..e5dce59c 100644
--- a/docs/live/updates.mdx
+++ b/docs/live/updates.mdx
@@ -5,6 +5,53 @@ icon: 'sparkles'
mode: 'center'
---
+
+
+ 🚀 **Build modes everywhere** – Bundle widgets in static, dynamic, or hybrid mode and reuse the same component across OpenAI, Claude, and Gemini without rewriting HTML.
+
+ 🧩 **Auto Redis persistence** – Point `redis` at a store once and transport persistence now enables itself so stateful sessions survive restarts and serverless cold starts.
+
+ ⚡ **Vercel Build Output** – `frontmcp build --adapter vercel` detects npm/yarn/pnpm/bun lockfiles, wires the right install/build commands, and emits a `.vercel/output` tree ready for `vercel deploy --prebuilt`.
+
+ 🛠️ **Tree-shakable packages** – SDK, adapters, plugins, and CLI publish dual CJS/ESM entries with `sideEffects: false`, eliminating duplicate React imports and keeping bundles slim.
+
+
+
+
+
+
+ 🧱 **Dual module builds** – Import from ESM or require from CommonJS via the new `exports` map while sharing a single `dist/index.d.ts`.
+
+ ⚡ **Side-effect free** – `sideEffects: false` and flattened `dist/esm` output let bundlers drop unused converters automatically.
+
+ 🔧 **Workspace alignment** – Published metadata now mirrors the FrontMCP 0.6.2 toolchain so CLI scaffolds and adapters consume the converter without overrides.
+
+
+
+
+
+
+ 🧱 **Unified exports** – Require or import the generator thanks to the new dual CJS/ESM build, with typings shared across both entry points.
+
+ ⚙️ **Tree-shakable helpers** – Marking the package as side-effect free keeps bundlers from pulling the OpenAPI loader when you only need schema utilities.
+
+ 🔄 **Version sync** – The library now ships in lockstep with `@frontmcp/adapters`, so generated tools inherit the same input mappers and security metadata.
+
+
+
+
();
async getTools(apiUrl: string): Promise {
- if (this.cache.has(apiUrl)) {
+ if (this.cache has(apiUrl)) {
return this.cache.get(apiUrl)!;
}