MCP Apps Testing Server

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.

Category
Visit Server

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

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

    1. Current Conditions (1s) - Live temperature, humidity, wind, pressure
    2. Pattern Analysis (2s) - Temperature trends, precipitation risk
    3. Historical Comparison (3s) - Deviations from averages, unusual factors
    4. Forecast Predictions (4s) - Short-term and medium-term forecasts
    5. 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-stream is 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. from which 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:

  1. Say: "Show me the weather in Tokyo"
  2. Then ask: "What's the current temperature?" or "Should I bring an umbrella?"
  3. 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:

  1. First get the weather dashboard loaded (use prompt above)
  2. In the search box, type: Tokyo
  3. 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:

  1. Load weather dashboard
  2. 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:

  1. Load weather dashboard for any location
  2. 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:

  1. Load weather dashboard for any location
  2. 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:

  1. Load weather dashboard
  2. Perform various actions (search, click cities, tell Claude, etc.)
  3. 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:

  1. Load weather dashboard
  2. 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:

  1. Load weather dashboard
  2. 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:

  1. Load weather dashboard for any location
  2. Click the fullscreen button (β›Ά) in the top-right corner
  3. 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:

  1. Load weather dashboard
  2. 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:

  1. Load weather dashboard
  2. Press Ctrl+Enter (or Cmd+Enter on Mac)
  3. 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:

  1. Load weather dashboard or globe viewer
  2. Call the test-tools-notification tool (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:

  1. Refresh its tool list automatically
  2. Forward the notification to connected apps (as demonstrated here)
  3. 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 name
  • latitude (number, optional) - Latitude coordinate
  • longitude (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 name
  • latitude (number, optional) - Latitude coordinate
  • longitude (number, optional) - Longitude coordinate

Example:

{
  "location": "Tokyo"
}

Returns: Streaming analysis with 5 phases:

  1. Current Conditions (temperature, humidity, wind, pressure)
  2. Pattern Analysis (trends, precipitation risk)
  3. Historical Comparison (deviations, unusual factors)
  4. Forecast Predictions (short-term, medium-term)
  5. 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 longitude
  • south (number) - Southern latitude
  • east (number) - Eastern longitude
  • north (number) - Northern latitude
  • label (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_changed to 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

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.

Official
Featured
TypeScript
Magic Component Platform (MCP)

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.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

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.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

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.

Official
Featured
TypeScript
Kagi MCP Server

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.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

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.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured