MCP App Workers Template
A production-ready template for building MCP servers on Cloudflare Workers that expose tools with interactive React-based UI widgets, demonstrating anime search functionality using the Jikan API.
README
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-template -
Install dependencies:
npm install -
Generate 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 build -
Start 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:
npm run build
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:
INPUT=widgets/anime-detail-widget.html npm run build
Deployment
Deploy to Cloudflare Workers
-
Authenticate with Wrangler (first time only):
npx wrangler login -
Build widgets:
npm run build -
Deploy:
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
mcp-app-workers-template/
├── server/ # Server-side code
│ ├── index.ts # Hono router and MCP endpoint handler
│ └── mcp.ts # MCP server implementation
├── web/ # Frontend/widget code
│ ├── components/ # React components
│ │ ├── anime-card.tsx # Anime display component
│ │ └── ui/ # UI component library
│ ├── widgets/ # Widget entry points
│ │ ├── anime-detail-widget.html
│ │ └── anime-widget.tsx
│ ├── lib/ # Utilities
│ └── index.css # Global styles
├── wrangler.jsonc # Cloudflare Workers configuration
├── vite.config.ts # Vite build configuration
├── tsconfig.json # TypeScript configuration
└── package.json # Dependencies and scripts
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
- Example:
-
Resources: Dynamic endpoints that serve widget HTML
- Example:
ui://widget/anime-detail-widget.html- serves the anime widget HTML
- Example:
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():
registerWidget(server, assets, {
name: "anime-detail-widget",
htmlPath: "/anime-detail-widget.html",
resourceUri: "ui://widget/anime-detail-widget.html",
descripition: "Interactive anime detail widget UI",
resourceDomains: ["https://cdn.myanimelist.net/"], // CSP allowed domains
});
Tool-to-Widget Linking
Tools can specify which widget to display using _meta:
server.registerTool(
"get-anime-detail",
{
// ... tool config
_meta: {
"ui/resourceUri": "ui://widget/anime-detail-widget.html",
},
},
// ... handler
);
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 logic -
Build the widget:
INPUT=widgets/my-widget.html npm run build -
Register 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:
registerWidget(server, assets, {
// ...
connectDomains: ["https://api.example.com"], // For API calls
resourceDomains: ["https://cdn.example.com"], // For images/assets
});
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 build - Check 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/mcp - Check Cloudflare Workers logs:
npx wrangler tail - Ensure the MCP client supports HTTP/SSE transport
Type errors
- Run
npm run cf-typegento regenerate types - Ensure
CloudflareBindingsis imported from generated types
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。