MCP Apps Testing Server
A comprehensive testing suite demonstrating all Model Context Protocol (MCP) Apps features through interactive Weather Dashboard and 3D Globe viewer applications.
README
MCP Apps Testing Server
Comprehensive MCP Apps capability testing suite featuring a Weather Dashboard and 3D Globe viewer. This project systematically tests and demonstrates all Model Context Protocol (MCP) Apps features.
Table of Contents
- Project Purpose
- Recent Updates
- What's Included
- MCP Apps Features - Testing Progress
- Weather Dashboard Features
- Globe Viewer Features
- Getting Started
- Conformance Tests
- Testing
- How to See Each MCP Apps Function Being Tested
- Testing Checklist
- Available Tools
- Architecture
- MCP Client Configuration
- Learning Resources
- Project Structure
- Deployment
- Roadmap
- Contributing
- License
- Links
π― Project Purpose
This server demonstrates and tests the full spectrum of MCP Apps capabilities through interactive UI applications that communicate bidirectionally with MCP servers and host applications.
π Recent Updates
Progressive Weather Streaming Analysis (Latest)
- β¨ New Tool:
uzir-weather-stream- Progressive 5-phase weather analysis - π Real-time Updates: Data streams in at 1-second intervals
- π¨ Beautiful UI: Full-screen modal with progress bar and animated phase arrivals
- π 5 Analysis Phases: Conditions β Patterns β Historical β Forecast β Recommendations
- π App-Only: Tool is hidden from model, only callable by the app
- π± Compact Design: Optimized viewport (790px base, 20% smaller on mobile)
- β Persistence: Favorites and search history with localStorage
- π Documentation: New CUSTOM-API-GUIDE.md with implementation details
Try it: Load weather for any city, click "π Stream Analysis" button!
π¦ What's Included
1. Weather Dashboard (Primary Test App)
Interactive weather application with comprehensive MCP Apps API testing.
2. 3D Globe Viewer
CesiumJS-based globe with OpenStreetMap tiles for geographic visualization.
β MCP Apps Features - Testing Progress
Fully Implemented & Tested β
| Feature | API | Implementation | Status |
|---|---|---|---|
| Tool Calling from UI | callServerTool() |
Search box + Quick city buttons | β Complete |
| Chat Integration | sendMessage() |
"Tell Claude" button | β Complete |
| External Links | sendOpenLink() |
"Open Weather.com" button | β Complete |
| Structured Logging | sendLog() |
Activity log panel (3 levels) | β Complete |
| Size Hints | sendSizeChanged() |
Dynamic viewport height | β Complete |
| Tool Results | ontoolresult |
Initial weather data handler | β Complete |
| Tool Input | ontoolinput |
Parameter handling | β Complete |
| Error Handling | onerror |
App-level error handler | β Complete |
| Teardown | onteardown |
Cleanup handler | β Complete |
| UI Resources | registerAppResource() |
2 UI resources (weather + map) | β Complete |
| CSP Configuration | _meta.ui.csp |
External domain whitelisting | β Complete |
| Tool Metadata | _meta |
Weather data + viewUUID | β Complete |
| Display Modes | requestDisplayMode() |
Fullscreen/inline with toggle button | β Complete |
| Host Context | onhostcontextchanged |
Display mode and theme detection | β Complete |
| Keyboard Shortcuts | Event handlers | Esc (exit fullscreen), Ctrl+Enter (toggle) | β Complete |
| Theme Detection | onhostcontextchanged |
Light/dark theme adaptation | β Complete |
| State Persistence | localStorage | Favorites, history, bookmarks with notes | β Complete |
| Progressive Streaming | Custom tool | 5-phase streaming analysis | β Complete |
| Model Context Updates | updateModelContext() |
Weather summary sent to Claude | β Complete |
| Bookmarks with Notes | localStorage + UI | Save locations with custom notes | β Complete |
| Tool List Changes | setNotificationHandler() |
Animated toast notifications for tool updates | β Complete |
Partially Implemented π§
| Feature | Status | Notes |
|---|---|---|
| PiP Display Mode | π‘ Partial | CSS ready, awaiting host support |
Not Yet Implemented β
| Feature | Priority | Effort | Notes |
|---|---|---|---|
| Real-time Updates | Medium | Medium | Auto-refresh, live weather data |
| Comparison Mode | Low | High | Multiple locations side-by-side |
| Advanced Forms | Low | Medium | Multi-step forms, validation |
| Accessibility | Low | Medium | Full ARIA, screen reader support |
| Offline Mode | Low | High | Service worker, caching |
| Performance Metrics | Low | Low | Telemetry and monitoring |
π¦οΈ Weather Dashboard Features
The Weather Dashboard is the primary testing application demonstrating core MCP Apps capabilities:
Interactive Features
- π Location Search - Search any city or place using
callServerTool() - π Quick Cities - One-click weather for 6 popular cities
- π¬ Tell Claude - Send weather summaries to chat via
sendMessage() - π Open Weather.com - External browser links via
sendOpenLink() - π Activity Log - Real-time structured logging with
sendLog() - βΆ Fullscreen Mode - Toggle display modes with
requestDisplayMode() - π¨ Theme Detection - Responds to light/dark mode changes
- β¨οΈ Keyboard Shortcuts - Ctrl+Enter (toggle fullscreen), Escape (exit)
- π Progressive Streaming Analysis - Live 5-phase weather analysis with real-time updates
- β Favorites & History - Save favorite locations and search history (localStorage)
- π§ Model Context Updates - Sends weather data to Claude's context via
updateModelContext() - π Bookmarks with Notes - Save locations with custom notes, timestamps, and full edit/delete support
Weather Data
- Current conditions with temperature, humidity, wind speed, UV index
- 7-day forecast with high/low temperatures (collapsible)
- Weather condition icons
- Geo-coordinates display
Progressive Streaming Analysis π
The weather dashboard includes an advanced streaming tool that demonstrates progressive data delivery:
-
5 Streaming Phases - Data arrives in real-time over 5 seconds
- Current Conditions (1s) - Live temperature, humidity, wind, pressure
- Pattern Analysis (2s) - Temperature trends, precipitation risk
- Historical Comparison (3s) - Deviations from averages, unusual factors
- Forecast Predictions (4s) - Short-term and medium-term forecasts
- Recommendations (5s) - Clothing and activity suggestions
-
Beautiful Streaming UI
- Full-screen modal with animated phase arrivals
- Progress bar showing completion status
- Real-time timestamps for each phase
- Color-coded sections with green gradient headers
- Responsive grid layouts for data display
-
App-Only Tool -
uzir-weather-streamis hidden from the model and only callable by the app -
Simulated Real-Time Updates - Demonstrates "multiple values over time" pattern
How to test: Load any weather location, click "π Stream Analysis" button, watch phases arrive progressively!
Technical Details
- Uses Open-Meteo API (no API key required)
- OpenStreetMap Nominatim for geocoding
- Compact viewport height (790px base, expands dynamically)
- Mobile-optimized design (20% smaller on β€600px screens)
- Responsive design with media queries
- Theme adaptation (light/dark backgrounds)
- Error handling and recovery
- localStorage persistence for favorites and search history
πΊοΈ Globe Viewer Features
Interactive 3D globe with geographic visualization:
- 3D Globe Rendering - CesiumJS with OpenStreetMap tiles
- Geocoding Integration - Search and locate places
- Camera Persistence - Saves view state in localStorage
- Display Modes - Fullscreen and inline support
- Model Context Updates - Sends screenshots to Claude
- Shuffle Cities - Random city exploration
- Keyboard Shortcuts - Esc, Ctrl+Enter for fullscreen control
π Getting Started
Installation
npm install
Build
npm run build
Development
npm run dev
Runs both Vite watcher and HTTP server concurrently with hot reload.
Production
npm run start # or npm run start:http
Server runs at http://localhost:3001/mcp
For stdio transport:
npm run start:stdio
π§ͺ Conformance Tests
The project includes 5 conformance test apps that run as a separate MCP server, testing core MCP Apps spec compliance:
| Test App | Tool | What It Tests |
|---|---|---|
| Lifecycle | show-lifecycle |
MCP Apps Β§3 β init, teardown, tool input/result |
| Host Context | show-host-context |
MCP Apps Β§4 β theme, display mode, context changes |
| Messaging | show-messaging |
MCP Apps Β§5 β sendMessage, sendLog, sendOpenLink |
| Domain & CORS | show-domain-cors |
MCP Apps Β§2.4 β domain declaration, CORS preflight |
| Theming | show-theming |
MCP Apps Β§4.5 β CSS variables, theme adaptation |
Additional server-only tools: echo-tool, slow-task, slow-echo, test-resources-notification, test-tools-notification.
Running with Docker
# Build and start the conformance server on port 3002
docker compose up -d --build
# Verify it's running
curl http://localhost:3002/health
# β {"status":"ok"}
# View logs
docker compose logs -f
# Stop
docker compose down
Running without Docker
npm run build
npm run start:conformance
Claude Desktop Configuration (WSL2)
Add both servers to claude_desktop_config.json (%APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"mcp-map-server": {
"command": "wsl",
"args": ["/home/<user>/.nvm/versions/node/<version>/bin/node", "/path/to/mcp-map-server-ui/dist/index.js", "--stdio"]
},
"mcp-conformance-tests": {
"command": "wsl",
"args": ["/home/<user>/.nvm/versions/node/<version>/bin/node", "/path/to/mcp-map-server-ui/dist/conformance-index.js", "--stdio"]
}
}
}
Note: Use the full path to
node(e.g. fromwhich node) since WSL launched by Claude Desktop doesn't load your shell profile.
Test Prompts
- "Show lifecycle tests"
- "Show host context tests"
- "Show messaging tests"
- "Show domain cors tests"
- "Show theming tests"
π§ͺ Testing
Option 1: Basic-Host Test Interface
The ext-apps basic-host provides a simple test UI:
# Clone ext-apps repo
git clone https://github.com/modelcontextprotocol/ext-apps
cd ext-apps/examples/basic-host
# Install and start
npm install
SERVERS='["http://localhost:3001/mcp"]' npm start
Open http://localhost:8080 and test the tools.
Option 2: Claude (Web or Desktop) - Recommended for Model Context Testing
Use custom connectors to connect Claude to your deployed server.
For local testing with Claude Desktop:
// Add to claude_desktop_config.json
{
"mcpServers": {
"weather-map": {
"command": "node",
"args": ["/path/to/mcp-map-server-ui/dist/index.js", "--stdio"]
}
}
}
For Claude Web with local server:
npx cloudflared tunnel --url http://localhost:3001
Add the generated URL as a custom connector in Claude settings.
For Claude Web with Azure deployment:
- Add custom connector with URL:
https://mcp-apps-020426.azurewebsites.net/mcp
Testing Model Context Updates:
- Say: "Show me the weather in Tokyo"
- Then ask: "What's the current temperature?" or "Should I bring an umbrella?"
- Claude should answer using the model context! β¨
See TESTING_GUIDE.md for detailed testing instructions.
Option 3: VS Code (Insiders)
VS Code Insiders supports MCP Apps. Configure your server in VS Code settings.
π¬ How to See Each MCP Apps Function Being Tested
This section provides specific prompts and observable behaviors for testing each MCP Apps API.
1. ontoolresult - Initial Tool Result Handler
How It's Tested: Receives weather data when tool is first called
Prompt:
Show me the weather in Seattle
What to Observe:
- β Weather dashboard loads immediately
- β Current temperature, conditions, and 7-day forecast display
- β Activity log shows: "Initial weather data rendered for Seattle"
- β No errors in console
Behind the Scenes:
The ontoolresult handler receives the show-weather tool result containing weather data in _meta.weatherData, then renders the UI.
2. callServerTool() - Search Box
How It's Tested: Search input calls show-weather tool from the UI
Prompt:
- First get the weather dashboard loaded (use prompt above)
- In the search box, type:
Tokyo - Click "π Search" or press Enter
What to Observe:
- β Search button shows loading spinner
- β Weather updates to Tokyo
- β
Activity log shows:
Searching for location: Tokyo Weather tool result received Weather rendered for Tokyo - β Search button re-enables after completion
Behind the Scenes:
The UI calls app.callServerTool({ name: "show-weather", arguments: { location: "Tokyo" }}) which makes a round-trip to the MCP server.
3. callServerTool() - Quick City Buttons
How It's Tested: City chips call show-weather tool with preset locations
Prompt:
- Load weather dashboard
- Click any city chip (e.g., "Paris", "London", "Dubai")
What to Observe:
- β Weather immediately updates to selected city
- β Activity log shows: "Searching for location: [City]"
- β All UI elements update (temp, forecast, location header)
- β Button remains clickable (no loading state needed for presets)
Behind the Scenes:
Each city chip triggers callServerTool() with a known city name, testing batch tool calls.
4. sendMessage() - Tell Claude Button
How It's Tested: Sends weather summary to chat
Prompt:
- Load weather dashboard for any location
- Click "π¬ Tell Claude" button
What to Observe:
- β
A new message appears in the chat from you (the user):
The weather in Tokyo is currently 12Β°C and partly cloudy. It feels like 10Β°C with 65% humidity. - β
Activity log shows:
Sending message to chat [message content] Message sent to chat successfully - β Claude can now respond to this weather information
Behind the Scenes:
The UI calls app.sendMessage({ content: [{ type: "text", text: message }], role: "user" }) which posts a message to the chat as if you typed it.
5. sendOpenLink() - Open Weather.com Button
How It's Tested: Opens external URL in browser
Prompt:
- Load weather dashboard for any location
- Click "π View on Weather.com" button
What to Observe:
- β Browser opens a new tab/window with Weather.com
- β
URL includes coordinates:
https://weather.com/weather/today/l/[lat],[lon] - β Weather.com shows the same location
- β
Activity log shows:
Opening Weather.com for Tokyo https://weather.com/weather/today/l/35.68,139.69 Link opened successfully
Behind the Scenes:
The UI calls app.sendOpenLink({ url: "https://weather.com/..." }) which requests the host to open the URL.
6. sendLog() - Activity Log Panel
How It's Tested: All app activities are logged with different levels
Prompt:
- Load weather dashboard
- Perform various actions (search, click cities, tell Claude, etc.)
- Click "π Activity Log" header to expand
What to Observe:
- β Log panel shows all activities with timestamps
- β
Color-coded entries:
- Blue (info): Normal operations (searches, renders)
- Yellow (warning): Warnings (no data, edge cases)
- Red (error): Errors (failed API calls, exceptions)
- β Auto-scrolls to latest entry
- β Log count updates: "(12)" shows number of log entries
- β Can collapse/expand with βΌ/βΆ arrow
Behind the Scenes:
Every significant action calls app.sendLog({ level: "info"|"warning"|"error", data: message, logger: "weather-app" }) which sends structured logs to the host.
7. sendSizeChanged() - Viewport Height Hint
How It's Tested: App requests preferred height on load
Prompt:
Show me the weather in any city
What to Observe:
- β Weather dashboard renders at 1200px height
- β No scrolling needed inside the viewport
- β All content (search, forecast, log) is visible without scrolling
- β Activity log shows: "Sent initial size 1200"
Behind the Scenes:
On initialization, the app calls app.sendSizeChanged({ height: 1200 }) to tell the host its preferred size.
8. ontoolinput - Tool Parameter Handler
How It's Tested: Receives tool parameters before result
Prompt:
Show me the weather in Paris with coordinates 48.8566, 2.3522
What to Observe:
- β Weather loads for Paris
- β Activity log may show tool input received (if logged)
- β Parameters are processed correctly
Behind the Scenes:
The ontoolinput handler receives parameters before the tool executes, allowing the UI to prepare or show loading states.
9. onerror - Error Handler
How It's Tested: Handles app-level errors gracefully
Prompt:
- Load weather dashboard
- Search for invalid/nonsense location:
asdfghjkl12345
What to Observe:
- β Error message displays in the UI
- β App doesn't crash
- β Activity log shows red error entry
- β Search box remains functional
- β Can search for valid location after error
Behind the Scenes:
The onerror handler catches unhandled errors and logs them via sendLog() instead of crashing.
10. onteardown - Cleanup Handler
How It's Tested: Called when app is being destroyed
Prompt:
- Load weather dashboard
- Navigate away or close the chat
What to Observe:
- β Activity log shows: "App is being torn down" (before navigation)
- β No memory leaks or errors
- β Clean shutdown
Behind the Scenes:
The onteardown handler performs cleanup (clear timers, close connections) before the app is removed.
11. UI Resources - Weather Dashboard HTML
How It's Tested: Server serves bundled HTML via registerAppResource()
Prompt:
Show me the weather in Berlin
What to Observe:
- β Complete weather UI loads (not raw HTML)
- β All styles and scripts are embedded
- β Interactive elements work (buttons, inputs)
- β Single HTML file (no external JS/CSS)
Behind the Scenes:
The server's registerAppResource() serves the bundled weather-app.html which includes all CSS/JS inline (via vite-plugin-singlefile).
12. Tool Metadata - Weather Data in _meta
How It's Tested: Server includes weather data in tool result metadata
Prompt:
Show me the weather in Sydney
What to Observe:
- β Weather data loads correctly
- β All fields present (temp, humidity, forecast, etc.)
- β No "undefined" values in UI
Behind the Scenes:
The server's show-weather tool returns:
{
content: [...],
_meta: {
viewUUID: "...",
weatherData: { location: "Sydney", current: {...}, forecast: [...] }
}
}
13. CSP Configuration - External API Access
How It's Tested: App can fetch from Open-Meteo and OSM via CSP whitelist
Prompt:
Show me the weather in Mumbai
What to Observe:
- β Weather data loads (from Open-Meteo API)
- β Geocoding works (from OSM Nominatim)
- β No CSP errors in browser console
- β All images/icons load
Behind the Scenes: The server's resource registration includes:
_meta: {
ui: {
csp: {
connectDomains: ["https://api.open-meteo.com", "https://*.openstreetmap.org"],
resourceDomains: [...]
}
}
}
14. requestDisplayMode() - Fullscreen Toggle
How It's Tested: Fullscreen button switches display modes
Prompt:
- Load weather dashboard for any location
- Click the fullscreen button (βΆ) in the top-right corner
- Or press Ctrl+Enter (or Cmd+Enter on Mac)
What to Observe:
- β Weather dashboard expands to fullscreen
- β Fullscreen button icon changes to compress icon (βΆ β β)
- β Button tooltip updates: "Exit fullscreen"
- β Activity log shows: "Requesting display mode: fullscreen"
- β Press Escape or click button again to exit fullscreen
- β Activity log shows: "Requesting display mode: inline"
Behind the Scenes:
The UI calls app.requestDisplayMode({ mode: "fullscreen" }) which asks the host to change the display mode. The host responds via onhostcontextchanged.
15. onhostcontextchanged - Display Mode & Theme
How It's Tested: App responds to host context changes
Prompt:
- Load weather dashboard
- Change your system theme (light β dark) or display mode
What to Observe:
- β Activity log shows: "Host context changed { theme: 'light'|'dark', displayMode: '...' }"
- β
Background gradient adapts:
- Light theme: Purple gradient (#667eea β #764ba2)
- Dark theme: Dark blue gradient (#2c3e50 β #34495e)
- β Display mode CSS classes applied to body
- β UI responds immediately without reload
Behind the Scenes:
The onhostcontextchanged handler receives context updates from the host and applies theme/mode classes to document.body.
16. Keyboard Shortcuts - Display Mode Control
How It's Tested: Keyboard commands for fullscreen
Actions:
- Load weather dashboard
- Press Ctrl+Enter (or Cmd+Enter on Mac)
- Press Escape when in fullscreen
What to Observe:
- β Ctrl+Enter: Toggles fullscreen on/off
- β Escape: Exits fullscreen (only works when in fullscreen)
- β Activity log shows mode change requests
- β Fullscreen button state syncs with keyboard actions
- β Search input shortcuts still work (Enter to search)
Behind the Scenes:
Global keydown event listener detects shortcuts and calls toggleFullscreen() which uses requestDisplayMode().
17. Tool List Changed Notifications - Dynamic Tool Updates
How It's Tested: Apps receive and display notifications when server tools change
Prompt:
- Load weather dashboard or globe viewer
- Call the
test-tools-notificationtool (this simulates the server adding/removing tools)
What to Observe:
- β Beautiful animated toast notification slides in from top-right
- β Purple gradient background with spinning refresh icon (π)
- β Message displays: "Tools Updated - New tools are now available"
- β Notification auto-dismisses after 5 seconds
- β Can manually close with Γ button
- β Activity log shows: "Received notifications/tools/list_changed"
- β Multiple notifications stack properly if tools change frequently
Behind the Scenes:
- Apps register notification handler:
app.setNotificationHandler(ToolListChangedNotificationSchema, handler) - When server calls
server.server.notification({ method: "notifications/tools/list_changed" }), all connected apps receive it - The
showToolsChangedNotification()function creates an animated DOM element with the notification UI - CSS animations provide smooth slide-in from right and fade-out on dismiss
Note: This notification is primarily intended for MCP host applications. In production, the host receives the notification and can either:
- Refresh its tool list automatically
- Forward the notification to connected apps (as demonstrated here)
- Show its own UI notification to the user
See TEST_RESULTS.md for detailed testing documentation with Playwright MCP.
π― Testing Checklist
Use this checklist to verify all MCP Apps features:
Core APIs (Phase 1):
- [ ] ontoolresult - Weather loads on initial call
- [ ] callServerTool - Search box updates weather
- [ ] callServerTool - Quick city buttons work
- [ ] sendMessage - Tell Claude sends message to chat
- [ ] sendOpenLink - Weather.com opens in browser
- [ ] sendLog - Activity log shows all actions
- [ ] sendSizeChanged - UI is 1200px tall, no scrolling
- [ ] ontoolinput - Parameters handled correctly
- [ ] onerror - Invalid searches show errors gracefully
- [ ] onteardown - Clean shutdown on navigation
- [ ] UI Resources - Complete dashboard loads
- [ ] Tool Metadata - All weather data displays
- [ ] CSP Config - External APIs work without errors
Display & Themes (Phase 2):
- [ ] requestDisplayMode - Fullscreen button toggles mode
- [ ] onhostcontextchanged - Theme and display mode changes applied
- [ ] Keyboard Shortcuts - Ctrl+Enter toggles, Escape exits fullscreen
- [ ] Theme Detection - Light/dark theme switching works
- [ ] Fullscreen Button - Icon updates, tooltip changes
Notifications (Phase 4):
- [ ] Tool List Changed - Toast notification appears when tools update
- [ ] Animated UI - Notification slides in smoothly with spinning icon
- [ ] Auto-dismiss - Notification disappears after 5 seconds
- [ ] Manual Close - Γ button closes notification immediately
All features passing? β MCP Apps APIs fully tested!
π§ Available Tools
show-weather
Display weather dashboard for a location.
Parameters:
location(string, optional) - City or place namelatitude(number, optional) - Latitude coordinatelongitude(number, optional) - Longitude coordinate
Example:
{
"location": "Paris"
}
Returns weather dashboard UI with current conditions and 7-day forecast.
uzir-weather-stream (App-Only)
Progressive weather analysis streaming tool with 5 phases of data delivered over time.
Visibility: App-only (hidden from model)
Parameters:
location(string, optional) - City or place namelatitude(number, optional) - Latitude coordinatelongitude(number, optional) - Longitude coordinate
Example:
{
"location": "Tokyo"
}
Returns: Streaming analysis with 5 phases:
- Current Conditions (temperature, humidity, wind, pressure)
- Pattern Analysis (trends, precipitation risk)
- Historical Comparison (deviations, unusual factors)
- Forecast Predictions (short-term, medium-term)
- Recommendations (clothing, activities)
Data arrives progressively at 1-second intervals, demonstrating "multiple values over time" streaming pattern.
show-map
Display 3D globe at a bounding box location.
Parameters:
west(number) - Western longitudesouth(number) - Southern latitudeeast(number) - Eastern longitudenorth(number) - Northern latitudelabel(string, optional) - Location label
Example:
{
"west": 2.29,
"south": 48.85,
"east": 2.3,
"north": 48.86,
"label": "Eiffel Tower"
}
shuffle-cities
Display a random city on the map.
Parameters: None
geocode
Search for places and get coordinates.
Parameters:
query(string) - Place name or address
Example:
{
"query": "Golden Gate Bridge"
}
Returns up to 5 matches with coordinates and bounding boxes.
test-tools-notification
Trigger a tools/list_changed notification to test dynamic tool list updates.
Parameters: None
What It Does:
- Sends
notifications/tools/list_changedto all connected clients - Simulates what happens when the server dynamically adds or removes tools
- Connected apps display a notification: "Tools Updated - New tools are now available"
- Demonstrates protocol-level notifications from server to apps
Example Usage:
Call the test-tools-notification tool
Expected Result:
- Tool returns: "Sent tools/list_changed notification to all connected clients"
- Apps show animated toast notification in top-right corner
- Notification auto-dismisses after 5 seconds
Use Case: Testing notification handlers and demonstrating that apps can respond to server-side tool list changes in real-time.
ποΈ Architecture
βββββββββββββββββββββββββββββββββββββββββββ
β MCP Host (Claude, VS Code, etc.) β
β β
β βββββββββββββββββββββββββββββββββββββ β
β β MCP App UI (Sandboxed iframe) β β
β β βββββββββββββββββββββββββββββββ β β
β β β Weather Dashboard β β β
β β β - Search box β β β
β β β - Quick cities β β β
β β β - Tell Claude button β β β
β β β - Open web button β β β
β β β - Activity log β β β
β β βββββββββββββββββββββββββββββββ β β
β β β β
β β postMessage β AppBridge β β
β βββββββββββββββββββββββββββββββββββββ β
β β
β HTTP/SSE β β
βββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββ
β MCP Server (Node.js + Express) β
β - show-weather tool β
β - show-map tool β
β - geocode tool β
β - UI resources (bundled HTML) β
β - Open-Meteo API integration β
β - Nominatim geocoding β
βββββββββββββββββββββββββββββββββββββββββββ
π MCP Client Configuration
For stdio transport:
{
"mcpServers": {
"weather-map": {
"command": "node",
"args": ["/path/to/dist/index.js", "--stdio"]
}
}
}
For HTTP transport with Claude:
Add as a custom connector:
- Name: Weather & Maps
- URL:
https://your-server.com/mcp(or cloudflared tunnel URL)
π Learning Resources
π Project Structure
mcp-map-server-ui/
βββ apps/
β βββ globe/ # CesiumJS 3D globe app
β βββ weather/ # Weather dashboard app
β βββ clock/ # Clock timer app
β βββ lifecycle/ # Conformance: lifecycle tests
β βββ host-context/ # Conformance: host context tests
β βββ messaging/ # Conformance: messaging tests
β βββ domain-cors/ # Conformance: domain & CORS tests
β βββ theming/ # Conformance: theming tests
β βββ shared/ # Shared test utilities
βββ server.ts # Main MCP server (globe, weather, clock)
βββ main.ts # Main server HTTP entrypoint
βββ conformance-server.ts # Conformance MCP server (5 test apps)
βββ conformance-main.ts # Conformance server HTTP entrypoint
βββ Dockerfile # Multi-stage Docker build
βββ docker-compose.yml # Runs conformance server on port 3002
βββ .dockerignore
βββ dist/ # Built artifacts
β βββ apps/ # Bundled HTML apps
β βββ server.js # Compiled main server
β βββ index.js # Compiled main entrypoint
β βββ conformance-server.js # Compiled conformance server
β βββ conformance-index.js # Compiled conformance entrypoint
βββ package.json
βββ vite.config.ts
βββ tsconfig.json
βββ TESTING_GUIDE.md # Detailed testing instructions
βββ CUSTOM-API-GUIDE.md # Progressive streaming API extension guide
βββ README.md # This file
π’ Deployment
This server can be deployed to any Node.js hosting platform:
- Azure App Service (see
.github/workflows/) - AWS Lambda / ECS
- Google Cloud Run
- Heroku
- Railway
- Vercel / Netlify (with serverless functions)
Ensure your deployment exposes the /mcp endpoint and supports:
- HTTP POST requests
- SSE (Server-Sent Events) for streaming
- CORS headers
- JSON request/response bodies
π Roadmap
Phase 1: Core Features (β Complete)
- [x] Tool calling from UI
- [x] Chat integration
- [x] External links
- [x] Structured logging
- [x] Error handling
Phase 2: Display & Themes (β Complete)
- [x] Inline display mode
- [x] Fullscreen mode (both apps)
- [x] Theme detection (light/dark)
- [x] Keyboard shortcuts (Esc, Ctrl+Enter)
- [x] Host context change handling
- [x] Responsive layouts per mode
- [x] PiP mode CSS (ready for host support)
Phase 3: Persistence & Context (β Complete)
- [x] Favorites management (β star button)
- [x] Search history (localStorage)
- [x] Cross-session persistence (viewUUID-based keys)
- [x] Progressive streaming analysis (5 phases)
- [x] Compact viewport design (790px, mobile-optimized)
- [x] Model context updates (weather app sends current weather to Claude)
- [x] Bookmark locations with notes (π button with custom notes)
Phase 4: Advanced Features (π§ Partially Complete)
- [x] Progressive streaming tool (uzir-weather-stream)
- [x] Real-time phase-based updates
- [x] Tool list change notifications (animated toast UI)
- [x] Notification handler registration (
setNotificationHandler) - [x] Test tool for notifications (
test-tools-notification) - [ ] Comparison mode (multiple locations)
- [ ] Advanced forms and validation
- [ ] Keyboard shortcuts (weather-specific)
Phase 5: Polish & Production
- [ ] Full accessibility (ARIA, screen reader)
- [ ] Offline mode with service workers
- [ ] Performance monitoring
- [ ] Analytics and telemetry
- [ ] E2E testing suite
π€ Contributing
This is a testing and demonstration project for MCP Apps capabilities. Contributions welcome!
π License
MIT
π Links
- Live Demo: TBD (coming soon)
- MCP Apps Docs: https://modelcontextprotocol.io/docs/extensions/apps
- GitHub Issues: Report bugs and request features
- Testing Guide: See TESTING_GUIDE.md for detailed testing instructions
Built with: Node.js, TypeScript, Express, Vite, CesiumJS, MCP SDK, Open-Meteo API, OpenStreetMap
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.