This example demonstrates the MCP Apps Extension (SEP-1865) support in the PulseEngine MCP Framework with two UI implementations:
- Simple HTML Template (
templates/greeting.html) - Basic interactive UI with vanilla JavaScript - React + TypeScript UI (
ui/) - Full-featured React app using@mcp-ui/clientSDK
The MCP Apps Extension allows MCP servers to deliver interactive HTML user interfaces that can be displayed inline when tools are called. Instead of just returning text, servers can provide rich, interactive experiences.
- ✅ Tool with UI Link - The
greet_with_uitool references a UI resource via_meta.ui/resourceUri - ✅ UI Resources - HTML interface served with
text/html+mcpMIME type - ✅ Resource URIs - Using the
ui://URI scheme for UI resources - ✅ Mixed Tools - Both UI-enabled and text-only tools in the same server
- ✅ React Integration - Using
@mcp-ui/clientSDK with React hooks - ✅ Host Context - Receives theme, viewport, device capabilities, tool info
- ✅ Bidirectional Communication - UI can call tools back on the server
- ✅ Connection Management - Handles connection state and errors
- ✅ Responsive Design - Mobile-friendly with dark mode support
cargo run --bin ui-enabled-serverThe server will serve the basic HTML template from templates/greeting.html.
# 1. Build the React UI
./build-ui.sh
# 2. Run the server
cargo run --bin ui-enabled-serverThe server will automatically serve the built React app from static/ if it exists, otherwise falls back to the simple template.
See UI_README.md for detailed React UI documentation.
# Install MCP Inspector
npx @modelcontextprotocol/inspector
# Run this server
cargo run --bin ui-enabled-serverIn MCP Inspector:
- List tools - you'll see
greet_with_uiwith_meta.ui/resourceUri - List resources - you'll see
ui://greetings/interactive - Read the resource - you'll get the HTML content
- Call the tool - the UI should be displayed (if client supports it)
ui-enabled-server/
├── src/
│ └── main.rs # Rust MCP server backend
├── templates/
│ └── greeting.html # Simple HTML template (fallback)
├── ui/ # React UI application
│ ├── src/
│ │ ├── GreetingUI.tsx # Main React component with MCP integration
│ │ ├── GreetingUI.css # Component styles
│ │ ├── main.tsx # React entry point
│ │ └── index.css # Global styles
│ ├── index.html # HTML shell
│ ├── package.json # Node dependencies
│ ├── vite.config.ts # Build configuration
│ └── tsconfig.json # TypeScript config
├── static/ # Built React UI (generated by build-ui.sh)
├── build-ui.sh # UI build script
├── README.md # This file
├── UI_README.md # Detailed React UI documentation
└── Cargo.toml
Tool {
name: "greet_with_ui".to_string(),
description: "Greet someone with an interactive button UI".to_string(),
// ... other fields ...
_meta: Some(ToolMeta::with_ui_resource("ui://greetings/interactive")),
}Resource::ui_resource(
"ui://greetings/interactive",
"Interactive Greeting UI",
"Interactive HTML interface for greeting with a button",
)ResourceContents::html_ui(params.uri, html)This automatically sets:
- MIME type:
text/html+mcp - Content: HTML string
The React implementation (ui/) demonstrates:
function GreetingUI() {
const [context, setContext] = useState(null);
useEffect(() => {
if (window.mcp) {
window.mcp.getContext().then(setContext);
}
}, []);
// context provides: hostInfo, theme, displayMode, viewport,
// locale, timezone, platform, device, tool
// Call tools from the UI
const result = await window.mcp.callTool({
name: "greet_with_ui",
arguments: { name: "Alice" },
});
}- Displays host name, version, theme, display mode
- Shows viewport dimensions and locale
- Adapts to host theme (light/dark)
- Shows connection status
- Connection state management
- Loading states during tool calls
- User-friendly error messages
- Input validation
- UIs run in sandboxed iframes
- Content Security Policy (CSP) controls network access
- No direct DOM access to parent
- Uses
postMessagewith JSON-RPC protocol @mcp-ui/clientSDK handles the protocol- Bidirectional: UI → Host tool calls, Host → UI context updates
- Always provide text content in tool results
- Not all clients support UI rendering
- Simple HTML template as graceful degradation
Server Side (Rust):
- Use
Resource::ui_resource()to create UI resources - Link tools to UIs with
ToolMeta::with_ui_resource() - Serve HTML with
ResourceContents::html_ui()
Client Side (React):
- Install
@mcp-ui/client:npm install @mcp-ui/client - Use
useMCPClient()hook to access MCP host - Call
client.callTool()to invoke server tools - Access
contextfor host information - Build with Vite or your preferred bundler
- Add more tools with different UI patterns
- Implement form validation and better UX
- Add data visualization (charts, graphs)
- Use external APIs (configure CSP)
- Add state management (Redux, Zustand)
- Implement real-time updates
See TESTING.md for comprehensive testing instructions with MCP Inspector and manual JSON-RPC commands.