Provides a production-ready template for deploying MCP servers on Cloudflare's edge network with interactive UI widgets, asset management, and CSP configuration.
Includes an example implementation that queries the Jikan API to search for anime and display results in interactive widgets.
MCP App Workers Template
A production-ready template for building Model Context Protocol (MCP) servers on Cloudflare Workers with interactive UI widgets. This template demonstrates how to create MCP tools that return rich, interactive HTML widgets using React, Tailwind CSS, and the MCP Extensions Apps API.
Overview
This template provides a complete foundation for building MCP servers that expose:
MCP Tools: Server-side functions that can be called by MCP clients
UI Widgets: Interactive HTML widgets that can be rendered in MCP-compatible hosts
Resource Handlers: Dynamic resource endpoints that serve widget HTML with proper CSP configuration
The example implementation includes an anime search tool that queries the Jikan API (MyAnimeList) and displays results in a beautiful, interactive widget.
Features
✅ MCP Server Implementation: Full MCP server using
@modelcontextprotocol/sdk✅ Interactive Widgets: React-based UI widgets with Tailwind CSS styling
✅ Cloudflare Workers: Deploy to Cloudflare's edge network for global performance
✅ Asset Management: Built-in asset serving for widget HTML files
✅ Type Safety: Full TypeScript support with Cloudflare Workers type generation
✅ Modern Build Pipeline: Vite-based build system with single-file output
✅ CSP Configuration: Content Security Policy support for widget security
✅ MCP Extensions Apps: Integration with
@modelcontextprotocol/ext-appsfor widget communication
Prerequisites
Node.js 18+ and npm
Cloudflare Account (for deployment)
Wrangler CLI (installed via npm)
Installation
Clone the repository:
git clone https://github.com/MCPJam/mcp-app-workers-template.git cd mcp-app-workers-templateInstall dependencies:
npm installGenerate Cloudflare Workers types:
npm run cf-typegenThis generates TypeScript types for Cloudflare Workers bindings. The types are used in
server/index.tswhen instantiating Hono withCloudflareBindings.
Development
Local Development
Build widgets (required before running dev server):
npm run buildStart the development server:
npm run devThis starts Wrangler's development server. The MCP endpoint will be available at
http://localhost:8787/mcp.
Building Widgets
Widgets are built using Vite and output as single-file HTML bundles:
The build process:
Compiles React/TypeScript components
Bundles all dependencies into a single file
Applies Tailwind CSS
Outputs to
web/dist/widgets/
To build a specific widget, set the INPUT environment variable:
Deployment
Deploy to Cloudflare Workers
Authenticate with Wrangler (first time only):
npx wrangler loginBuild widgets:
npm run buildDeploy:
npm run deployThis will:
Build the widgets
Deploy the Worker to Cloudflare
Upload widget assets to the Worker's ASSETS binding
Get your deployment URL: After deployment, Wrangler will output your Worker URL. Your MCP endpoint will be at:
https://<your-worker-name>.<your-subdomain>.workers.dev/mcp
Environment Configuration
The project uses wrangler.jsonc for configuration. Key settings:
name: Worker name (change this to your project name)
main: Entry point (
server/index.ts)assets: Directory containing built widgets (
./web/dist/widgets)compatibility_date: Cloudflare Workers compatibility date
Project Structure
How It Works
MCP Server Setup
The MCP server (server/mcp.ts) registers:
Tools: Server-side functions that can be called by MCP clients
Example:
get-anime-detail- searches for anime and returns structured data
Resources: Dynamic endpoints that serve widget HTML
Example:
ui://widget/anime-detail-widget.html- serves the anime widget HTML
Widget Communication
Widgets use the MCP Extensions Apps API (@modelcontextprotocol/ext-apps) to:
Receive tool inputs: Listen for when tools are called
Receive tool results: Get structured data from tool execution
Send commands: Request actions from the host (e.g., open links)
Widget Registration
Widgets are registered in server/mcp.ts using registerWidget():
Tool-to-Widget Linking
Tools can specify which widget to display using _meta:
Adding New Widgets
Create widget HTML entry point in
web/widgets/:<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>My Widget</title> </head> <body> <div id="root"></div> <script type="module" src="./my-widget.tsx"></script> </body> </html>Create widget React component in
web/widgets/:import { useApp } from "@modelcontextprotocol/ext-apps/react"; // ... implement widget logicBuild the widget:
INPUT=widgets/my-widget.html npm run buildRegister the widget in
server/mcp.ts:registerWidget(server, assets, { name: "my-widget", htmlPath: "/my-widget.html", resourceUri: "ui://widget/my-widget.html", descripition: "My widget description", resourceDomains: ["https://example.com"], // Optional: CSP domains });Link tool to widget (optional):
server.registerTool( "my-tool", { // ... config _meta: { "ui/resourceUri": "ui://widget/my-widget.html", }, }, handler, );
Configuration
Widget Configuration Options
When registering a widget, you can configure:
name: Unique widget identifier
htmlPath: Path to HTML file in ASSETS binding
resourceUri: MCP resource URI (must start with
ui://widget/)descripition: Widget description
connectDomains: CSP allowed domains for fetch/XHR/WebSocket
resourceDomains: CSP allowed domains for images, scripts, etc.
domain: Custom domain for widget
prefersBorder: Whether widget prefers a border
CSP (Content Security Policy)
Widgets support CSP configuration for security:
Technologies Used
Hono: Fast web framework for Cloudflare Workers
Model Context Protocol SDK: MCP server implementation
MCP Extensions Apps: Widget communication API
React: UI framework for widgets
Tailwind CSS: Utility-first CSS framework
Vite: Build tool and dev server
TypeScript: Type-safe JavaScript
Cloudflare Workers: Edge computing platform
Wrangler: Cloudflare Workers CLI
Scripts
npm run dev- Start development servernpm run build- Build widgets (requiresINPUTenv var)npm run deploy- Deploy to Cloudflare Workersnpm run cf-typegen- Generate Cloudflare Workers TypeScript typesnpm run format- Format code with Prettier
Troubleshooting
Widget not loading
Ensure widgets are built:
npm run buildCheck that the HTML file exists in
web/dist/widgets/Verify the
htmlPathin widget registration matches the actual file path
MCP connection issues
Verify the endpoint URL is correct:
https://your-worker.workers.dev/mcpCheck Cloudflare Workers logs:
npx wrangler tailEnsure the MCP client supports HTTP/SSE transport
Type errors
Run
npm run cf-typegento regenerate typesEnsure
CloudflareBindingsis imported from generated types