Skip to content

@belgie/vite

@belgie/vite is Belgie's Vite package for React widgets. It covers three modes:

  • a Vite plugin for path-based MCP App widgets;
  • a CLI that builds one widget file into self-contained HTML;
  • the CLI-backed path used by agent render_widget tools.

Use this page for the Vite plugin, CLI, and agent rendering contract. Use @belgie/mcp for browser Widget APIs (Widget, host hooks, modals, typed tool callers). Use MCP Apps for Python BelgieExtension registration.

Choose the widget model

Widget ownership Package / tool Delivery
A Python MCP server project @belgie/vite plugin + @belgie/mcp browser APIs A registered Path to widget.tsx, served by Vite in development or read from built output in production.
An agent run render_widget (backed by @belgie/vite) One self-contained HTML document returned as the framework tool result.

The two flows share React and Vite, but they have different lifecycles. render_widget does not register an MCP tool, open a development server, or create a reusable widget route.

Vite plugin mode

Configure the plugin in a normal Vite configuration:

vite.config.ts
import { belgie } from "@belgie/vite";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [belgie({ srcDir: "src/widgets" })],
});

Widgets live at <srcDir>/<name>/widget.tsx and must default-export a React component. Development serves each widget at /widgets/<name>/index.html. The default production build emits a self-contained file at dist/widgets/<name>/index.html.

Use bundle: "shared" when widget HTML should reference the host Vite asset graph instead of inlining everything. See MCP Apps and @belgie/mcp for the full path-based workflow.

CLI mode

Build one widget file to HTML without a Vite config:

@belgie/vite --widget path/to/widget.tsx --out widget.html --plugins npm:@tailwindcss/vite@latest

From Belgie Python:

await runtime(Command("@belgie/vite"))(
    "--widget",
    "path/to/widget.tsx",
    "--out",
    "widget.html",
    "--plugins",
    "npm:@tailwindcss/vite@latest",
)

The widget file must default-export a React component. Host-configured plugin specifiers are loaded for the server-side Vite build; do not call a render() helper from widget source.

Agent rendering

Agent integrations expose a dedicated render_widget tool. Enable it on the sandbox or middleware, optionally with Vite plugin specifiers:

from belgie.pydantic_ai import BelgieSandbox

capability = BelgieSandbox(
    enable_rendering=True,
    plugins=["npm:@tailwindcss/vite@latest"],
)
from belgie.langchain import BelgieMiddleware

middleware = BelgieMiddleware(
    enable_rendering=True,
    plugins=["npm:@tailwindcss/vite@latest"],
)

plugins requires enable_rendering=True. Rendering installs @belgie/vite into a separate renderer Environment; it does not enable npm/JSR/URL imports for model scripts. Pass the complete TSX module source to render_widget. Default-export a React component — do not import or call render():

export default function Widget() {
  return <main>Hello from Belgie</main>;
}

Belgie writes that source to a temporary widget file and runs @belgie/vite on a privileged renderer side channel. The tool result is one self-contained HTML document with inline JavaScript, CSS, and supported assets.

Plugins are a privilege boundary

Configured plugins run in the renderer with workspace read/write, FFI under node_modules, localhost network access Vite's build path needs, and the limited allow_sys grants Vite loaders need. Host environment variables are denied. Treat plugin code as reviewed application code. Use plugins=() for untrusted agents.

Model-visible run_typescript / run_code scripts stay on a separate Environment and remain workspace-restricted. They do not receive host system paths, FFI, package installs from rendering, or other renderer-only grants. Custom caller-owned runtimes do not provide the rendering side channel.

Contrast with @belgie/mcp

Concern @belgie/vite @belgie/mcp
Role Vite plugin, CLI, and agent HTML build Browser MCP Apps bridge
Typical import import { belgie } from "@belgie/vite" import { Widget, useCallTool } from "@belgie/mcp"
Widget source Default-export React component Default-export component wrapped in Widget for host connection
Host bridge Not included Tool results, host context, modals, host actions
Agent inline HTML render_widget tool Not used

Keep path-based MCP widgets on @belgie/mcp plus the @belgie/vite plugin. Keep agent-authored inline widgets on render_widget.

Develop the package

The package is an ESM package for Node.js 22 or newer and keeps its npm lockfile in version control:

cd packages/vite
npm ci
npm test
npm run check
npm pack --dry-run

See also