Build and artifacts
The recommended build declares an apps collection and runs
mountly-mcp build. Each View gets an isolated Vite environment, while all
Views share one versioned App manifest.
import react from "@vitejs/plugin-react";import { defineConfig } from "vite";import { mountlyMcpViews } from "mountly-mcp/vite";
export default defineConfig({ plugins: [ react(), mountlyMcpViews({ apps: [ { entry: "src/dashboard.tsx", uri: "ui://weather/dashboard", name: "weather_dashboard", displayModes: ["inline", "fullscreen"], }, { entry: "src/settings.tsx", uri: "ui://weather/settings", name: "weather_settings", }, ], // Optional. Defaults to dist/mountly-mcp.manifest.json. manifest: "dist/mountly-mcp.manifest.json", }), ],});npx mountly-mcp buildUse --config <path> when Vite cannot discover the config automatically.
Output contract
Section titled “Output contract”The default output is:
dist/├── mountly-mcp.manifest.json├── weather_dashboard.html├── weather_dashboard.html.meta.json├── weather_settings.html└── weather_settings.html.meta.jsonEach App artifact contains self-contained HTML plus its resource declaration.
The per-View .meta.json file is transitional compatibility output. The App
manifest is canonical: build, development, registration, and verification all
consume the same identities and paths.
App manifest paths are relative to the manifest, so the complete dist
directory can move as one deployable unit. Do not edit generated declarations
independently; rebuild them from the Vite configuration.
View options
Section titled “View options”Every View requires:
entry: source file that callscreateMcpView(...)(orpublishMcpView);name: unique developer key and default output filename;uri: unique protocol identity beginning withui://.
Resource options include description, displayModes, prefersBorder, csp,
permissions, awaitToolResult, and streamToolInput. Declare external
network, resource, frame, and base origins in csp; undeclared origins are
blocked by a conforming host.
Set an individual output to override a View’s HTML path. Set manifest: false
only when another system owns the artifact collection; it disables the
canonical contract used by the Mountly CLI.
Web Workers
Section titled “Web Workers”A View is one HTML document, so a worker cannot be a separate file. Start workers the standard Vite way and the build bundles each one into the View:
const worker = new Worker(new URL("./match.worker.ts", import.meta.url), { type: "module",});The worker’s own imports come with it, and it starts from a blob: URL, so the
host’s CSP must allow worker-src blob:. Workers created any other way, such as
new Worker("/workers/split.js") or a hand-built Blob, are left as they are.
mountly-mcp doctor lists them.
Views as a module
Section titled “Views as a module”Set module: true to also write every View, HTML included, as an ES module.
This is for a server that cannot read files, such as a Cloudflare Worker:
mountlyMcpViews({ module: true, apps: [/* … */] });dist/├── mountly-mcp.views.js # export default [{ name, uri, declaration, html }]└── mountly-mcp.views.d.tsA string names a different path. See Cloudflare Workers for the server side.
Single-View compatibility
Section titled “Single-View compatibility”Existing projects can keep the original options and vite build:
mountlyMcpViews({ entry: "src/view.tsx", uri: "ui://example/view", name: "example_view",});This still emits the View HTML, metadata, and default App manifest. Prefer the collection shape for new code so adding a second View is configuration-only.
Other bundlers
Section titled “Other bundlers”mountly-mcp/build exposes buildMcpResource() and
buildMcpResourceFromSource() for build systems that cannot use the Vite
plugin. mountly-mcp/artifact exposes readMcpAppArtifact(),
readMcpAppManifest(), and writeMcpAppManifest() so custom pipelines can
produce and consume the same contract.
Use these lower-level interfaces only when the Vite adapter is not suitable; the adapter earns its depth by handling dependency bundling, CSS inlining, bridge injection, metadata, isolated environments, and cleanup together.