aharvard/mcp-bubble-wrap
If you are the rightful owner of mcp-bubble-wrap and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
MCP Bubble Wrap is a sophisticated MCP server with React-based interactive widgets, designed for seamless integration with ChatGPT and OpenAI Apps SDK.
MCP Bubble Wrap
A sophisticated MCP (Model Context Protocol) server with React-based interactive widgets, inspired by the OpenAI Apps SDK examples.
Features
- 🫧 Interactive Bubble Wrap Widget: Pop virtual bubbles with smooth CSS animations
- ⚡ Modern Build System: Vite-powered development and production builds
- 🎨 React-based Widgets: Easy to create and maintain UI components
- 🎨 Tailwind CSS: Utility-first CSS framework with theme support
- 🔄 Hot Module Replacement: Fast development with instant updates
- 📦 Optimized Builds: Inlined assets for easy deployment
- 🌐 Apps SDK Compatible: Works seamlessly with ChatGPT and OpenAI Apps SDK
Project Structure
mcp-bubble-wrap/
├── src/
│ ├── widgets/ # React-based widgets
│ │ ├── styles.css # Shared Tailwind styles
│ │ ├── components/ # Shared widget components
│ │ │ └── Layout.tsx
│ │ ├── hooks/ # Shared hooks
│ │ │ ├── types.ts
│ │ │ └── use-openai-global.ts
│ │ └── bubble-wrap/
│ │ ├── BubbleWrap.tsx # Widget component
│ │ ├── index.tsx # Widget entry point
│ │ └── types.ts # Widget types
│ ├── utils/ # Shared utilities
│ │ └── logger.ts
│ ├── mcp-server.ts # MCP server implementation
│ └── index.ts # Server entry point
├── build-widgets.mts # Widget build orchestrator
├── assets/ # Built widget assets (generated)
├── dist/ # Compiled server code (generated)
├── vite.config.mts # Vite configuration for dev/build
├── tailwind.config.mjs # Tailwind CSS configuration
├── postcss.config.mjs # PostCSS configuration
└── package.json
Setup
pnpm install
Development
Start Everything
Run the complete development stack with hot reloading:
pnpm dev
This starts:
- Widget Dev Server (port 4444) - Vite dev server with HMR
- MCP Server (port 5678) - TypeScript server with vite-node
- MCP Inspector - Interactive testing UI
Individual Commands
# Widget development only
pnpm dev:widgets
# Build widgets
pnpm build:widgets
# Build server
pnpm build:server
# Serve built widgets
pnpm serve:widgets
Build
Build both the server and widgets for production:
pnpm build
This will:
- Compile TypeScript server code to
dist/ - Bundle React widgets to
assets/with hashed filenames - Generate HTML files for each widget
Environment Variables
BASE_URL- Base URL for widget assets in HTML generation (default:http://localhost:5678)- Note: Not currently used as assets are inlined in HTML
- For production, set this to your deployed assets URL if serving external resources
PORT- MCP server port (default:5678)
Example:
BASE_URL=https://your-cdn.com pnpm run build:widgets
PORT=3000 pnpm start
Production
pnpm start
Creating New Widgets
- Create a new directory under
src/widgets/:
src/widgets/my-widget/
├── MyWidget.tsx # React component
└── index.tsx # Entry point (imports shared styles.css)
- Entry point template (
index.tsx):
import { createRoot } from "react-dom/client"
import MyWidget from "./MyWidget"
const rootEl = document.getElementById("my-widget-root")
if (rootEl) {
createRoot(rootEl).render(<MyWidget />)
}
export { MyWidget }
export default MyWidget
- Widget component template (
MyWidget.tsx):
import { useOpenAiGlobal } from "../hooks/use-openai-global.js"
import { Layout } from "../components/Layout.js"
interface MyWidgetProps {
// Your props from the MCP tool
message?: string
}
export function MyWidget() {
// Get the structured content passed from the MCP tool
const toolOutput = useOpenAiGlobal("toolOutput") as MyWidgetProps
return (
<Layout>
<div className="p-6 text-center">
<h1 className="text-2xl font-bold text-gray-900">
{toolOutput?.message || "Hello World"}
</h1>
</div>
</Layout>
)
}
export default MyWidget
- Build and test:
pnpm build:widgets
pnpm dev
The widget will automatically be discovered and built!
Styling with Tailwind CSS
All widgets have access to Tailwind CSS utility classes. The Layout component automatically handles:
- Theme detection: Automatically detects and applies theme from OpenAI global data
- Layout constraints: Reports size changes to parent window
- Responsive design: Full Tailwind responsive utilities available
Example styling:
<div className="flex items-center justify-center min-h-[200px]">
<p className="text-gray-500 animate-pulse">Loading...</p>
</div>
Widget Gallery
During development, visit http://localhost:4444 to see all available widgets.
MCP Inspector
The MCP Inspector provides an interactive UI for testing your MCP server:
# Development mode (connects to local server)
pnpm inspect:dev
# Production mode
pnpm inspect:prod
Architecture
Widget Build System
The build system is inspired by the OpenAI Apps SDK examples:
- Discovery: Automatically finds all
src/widgets/**/index.{tsx,jsx}files - Bundling: Each widget is bundled as a standalone module with Vite
- Hashing: Assets are versioned with content hashes for cache busting
- HTML Generation: Creates standalone HTML files that can be served directly
MCP Server Integration
The MCP server loads and serves the built widget HTML:
- Widget HTML is read from the
assets/directory - Passed to the Apps SDK via
createUIResource - Rendered inline in ChatGPT or other Apps SDK clients
Props Communication
Widgets receive data via the OpenAI global object:
// In your widget - access toolOutput from OpenAI globals
const toolOutput = useOpenAiGlobal("toolOutput") as MyProps
// The server passes data via structuredContent
return {
structuredContent: {
bubbleCount: validBubbleCount,
},
}
// This structuredContent becomes available as toolOutput in the widget
Deployment
Render.com
The project includes a render.yaml for easy deployment to Render:
- Push your code to GitHub
- Connect your repository to Render
- Set environment variables:
BASE_URL: URL where your assets will be served
Custom Deployment
- Build the project:
pnpm run build
- Deploy:
- Upload
dist/directory to your server - Upload
assets/directory (HTML files with inlined JS/CSS) - Start the server:
node dist/index.js - Server will run on port 5678 by default (configure with
PORTenv var)
- Upload
Dependencies
Runtime
react&react-dom: UI framework@mcp-ui/server: MCP UI resource creation@modelcontextprotocol/sdk: MCP server SDKexpress: HTTP server for MCP protocolcors: CORS middlewarezod: Schema validationchalk: Terminal colors and logging
Development
vite: Build tool and dev server@vitejs/plugin-react: React support for Vitetsx: TypeScript executionvite-node: Run TypeScript server with hot reloadfast-glob: File discovery for build systemtailwindcss: Utility-first CSS frameworkpostcss: CSS transformation toolautoprefixer: Automatic vendor prefix handlingconcurrently: Run multiple commands in parallelprettier: Code formatting
Inspiration
This project structure is heavily inspired by the excellent OpenAI Apps SDK Examples, particularly their approach to:
- Widget build orchestration
- Multi-entry point development
- Asset hashing and versioning
- Development server setup
License
MIT