Each HTML file is an independent widget. A host creates an instance of the widget associated with the tool it calls.
1. Add the sales tool
Replaceserver/tools.ts with the two-tool version:
server/tools.ts
createApp<typeof tools>() now knows both tool names. In the quickstart’s Weather component, select its tool explicitly so TypeScript narrows the result:
weather by name.
2. Add the sales component and entry
src/Sales.tsx
src/sales-main.tsx
sales.html
3. Build each entry separately
The Vite configuration from the quickstart selects one HTML input from--mode:
vite.config.ts
build script in package.json:
dist/widgets; the sales build preserves it. The result contains both weather.html and sales.html, each with its own inlined JavaScript/CSS.
Use one Vite build per HTML input with vite-plugin-singlefile. The plugin is designed for one HTML entry at a time; separate runs give each resource its own bundled dependencies. For a longer list of widgets, the repository’s build script runs the same sequence in a loop.
4. Register the second resource
Inserver/index.ts, add salesWidgetUri to the import from ./tools.ts. Before createServer, add the second resource:
widgetUi settings here. Give a resource its own metadata configuration when it needs different permissions or network origins.
Rebuild, reload the host’s connector, and call weather and sales. Each tool points to its own resource URI and HTML entry.
Assets and development
Import local JavaScript, CSS, and assets from your widget’s source so the bundler can include them. This recipe setspublicDir: false. If you enable Vite’s public folder, its copied files are not automatically inlined by the single-file plugin. External scripts, fonts, images, and APIs need the appropriate CSP origins.
npm run dev serves /weather.html and /sales.html during development. A normal browser tab has no MCP host connection. Rebuild the HTML and reload it in the host to test tool results and interactions. The repository example also has a dev:ui watch build for its shared entry.
If several tools should intentionally render the same HTML application, use a shared entry with explicit routing instead.