Skip to main content
Glama
uzirthapa

MCP Apps Testing Server

by uzirthapa

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

Related MCP server: MCP Server Basic Example

🎯 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)

  • Tool calling from UI

  • Chat integration

  • External links

  • Structured logging

  • Error handling

Phase 2: Display & Themes (βœ… Complete)

  • Inline display mode

  • Fullscreen mode (both apps)

  • Theme detection (light/dark)

  • Keyboard shortcuts (Esc, Ctrl+Enter)

  • Host context change handling

  • Responsive layouts per mode

  • PiP mode CSS (ready for host support)

Phase 3: Persistence & Context (βœ… Complete)

  • Favorites management (⭐ star button)

  • Search history (localStorage)

  • Cross-session persistence (viewUUID-based keys)

  • Progressive streaming analysis (5 phases)

  • Compact viewport design (790px, mobile-optimized)

  • Model context updates (weather app sends current weather to Claude)

  • Bookmark locations with notes (πŸ“Œ button with custom notes)

Phase 4: Advanced Features (🚧 Partially Complete)

  • Progressive streaming tool (uzir-weather-stream)

  • Real-time phase-based updates

  • Tool list change notifications (animated toast UI)

  • Notification handler registration (setNotificationHandler)

  • 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



Built with: Node.js, TypeScript, Express, Vite, CesiumJS, MCP SDK, Open-Meteo API, OpenStreetMap

F
license - not found
-
quality - not tested
D
maintenance

Maintenance

–Maintainers
–Response time
–Release cycle
–Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/uzirthapa/mcp-map-server-ui'

If you have feedback or need assistance with the MCP directory API, please join our Discord server