Commit graph ext-apps/examples/map-server
Author SHA1 Message Date
Olivier Chafik
574a768e09
feat: add example gallery with auto-generated screenshots (#253)
* feat: add script to generate 300x300 grid-cell.png screenshots for examples

- Add generate-grid-screenshots.spec.ts Playwright test to capture screenshots
- Add npm run generate:screenshots command (Docker-based for Santa compatibility)
- Add sharp dependency for image resizing with centered-fill mode
- Generate grid-cell.png for 14 example servers (only React for basic-server-* series)

The screenshots are 300x300 PNG images cropped with centered fill mode,
suitable for use in a grid layout showcasing the examples.

* docs: add example gallery grid to README

Add a 3-column visual grid showcasing 14 example MCP Apps with:
- Thumbnail screenshots (300x300 grid-cell.png)
- Clickable links to example directories
- Hover tooltips with brief descriptions

Organized by visual impact: 3D/WebGL examples first, then
visualizations, charts, monitoring, and starter templates.

* fix: use aspect-fit instead of crop for screenshots

Change from fit: 'cover' (crops) to fit: 'contain' (letterbox)
so the full app content is visible without cropping.

* feat: improve screenshot generation

- Constrain viewport to 500px width for consistent rendering
- Wait 5 seconds for full app load (tiles, animations, data)
- Screenshot just the inner iframe (no extra whitespace)
- Save both screenshot.png (full-size) and grid-cell.png (300x300 thumbnail)
- Use contain mode to preserve aspect ratio

* fix: use cover mode with top alignment for grid thumbnails

No letterboxing - crops to fill 300x300, aligned to top so headers
and important content are always visible.

* feat: improve screenshot gallery

- Remove integration-server from gallery (it's for E2E testing only)
- Add 30s extra wait for Map and Video servers to load fully
- Improve Three.js default scene: isometric rotation + better lighting
- Update README: Starter Templates row with links to all framework variants
  (React, Vue, Svelte, Preact, Solid, Vanilla JS)
- Regenerate all screenshots with updated settings

* fix: improve README gallery layout

- Fix uneven column widths by using minimal separator
- Move Starter Templates to separate 2-cell table with description
- Add screenshot.png to top of each example README (13 examples)
- Shorten tooltips for cleaner table

* revert to document.write again; cesiumjs doesn't like srcdoc, period.

* fix: map-server screenshot now renders properly

- Merged ochafik/post-fixes which reverts sandbox from srcdoc to document.write
  (CesiumJS doesn't work with srcdoc iframes)
- Fixed map-server name in screenshot test ('Map Server' not 'CesiumJS Map Server')
- Simplified screenshot generation script (removed complex debugging code)
- Increased map-server wait time to 45s for reliable tile loading
- Regenerated all 13 screenshots

* fix: remove redundant screenshots from READMEs

Remove the simple \![Screenshot](screenshot.png) line from READMEs that
already had nicer HTML table screenshots. Keep it only for examples
that didn't have existing screenshots.

* docs: move gallery to Examples section

- Move screenshot gallery from top of README to Examples section
- Remove redundant list of basic examples (now shown visually in gallery)
- Clean up duplicate run instructions

* fix: remove empty header row from starter templates table

* fix: remove empty header rows from both tables

* fix: add prettier-ignore to prevent table header expansion

* feat: use custom screenshot for video-resource-server

- Use better screenshot from PR #253 comment showing actual video playback
- Skip video-resource-server in screenshot generation script
- Add SKIP_SERVERS set for manually maintained screenshots

* fix: revert unrelated map-server name change

* fix: use correct server name 'CesiumJS Map Server' in screenshot test
2026-01-13 15:12:18 +00:00
Olivier Chafik
231f23fd72
chore: release 0.4.0 (#249)
* chore: release 0.4.0

* chore: add new examples to npm publish workflow

Add map-server, shadertoy-server, and transcript-server to the
publish-examples matrix.
2026-01-12 22:40:24 +00:00
Olivier Chafik
9a9ecf27d4
feat(examples): add --watch to bun serve commands for auto-restart, and have npm start hit dev mode of all examples (#246)
* feat(examples): add --watch to bun serve commands for auto-restart on file changes

* Update package.json

* regen
2026-01-12 22:17:12 +00:00
Olivier Chafik
53142efd2d
refactor(map): use app.updateModelContext() instead of adhoc request (#245)
* feat(map): add keyboard shortcuts for fullscreen control

- Escape: exit fullscreen when in fullscreen mode
- Ctrl/Cmd+Enter: toggle fullscreen from any mode

* feat(map): persist view state to localStorage

- Save camera position/orientation on moveEnd (debounced 500ms)
- Restore persisted view when no explicit tool input is received
- Key by toolInfo.id (tool invocation ID) - localStorage is per-conversation
- Tool input (explicit bbox) takes precedence over persisted state

* refactor(map): use app.updateModelContext() instead of adhoc request
2026-01-12 20:47:07 +00:00
Olivier Chafik
366aa9b66e
examples: Add CesiumJS Map App example (#235)
* feat: Add CesiumJS map server example

A WebGL-based 3D globe example that demonstrates:
- CesiumJS integration with MCP Apps
- CSP configuration for external tile servers
- worker-src directive usage for tile decoding

Tools:
- geocode: Search places via OpenStreetMap Nominatim
- show-map: Display interactive 3D globe at coordinates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* comment out app.registerTool call for now

* prettier

* fix error handling in server-utils.ts

* refactor: rename cesium-map-server to map-server

- Rename examples/cesium-map-server to examples/map-server
- Update package name to @modelcontextprotocol/server-map
- Add README.md with documentation

* style: add min-height of 400px to map container

* feat(map-server): add fullscreen support, clean UI, sharp rendering

- Add fullscreen toggle button (only shown if host supports it)
- Use autoResize: false and manually send height of 400px
- Hide Cesium UI controls (home, scene mode picker)
- Remove location label (gets stale quickly)
- Use full device pixel ratio for sharp rendering on high-DPI displays
- Resize Cesium viewer when display mode changes

* feat(map-server): add reverse geocoding (logging only) and rounded corners

- Add camera move end listener for reverse geocoding
- Debounce Nominatim API calls (1.5s) to respect rate limits
- Log location name to console on camera move
- Add nominatim.openstreetmap.org to CSP connectDomains
- Add 8px rounded corners to map container

* fix(map-server): fix pixelated rendering on high-DPI displays

- Set canvas imageRendering to 'auto' (CesiumJS defaults to pixelated)
- Set resolutionScale to window.devicePixelRatio for native resolution

* tweaks

* update model context w/ current location

* fix(map-server): improve rendering quality and add visible extent logging

Rendering fixes:
- Remove incorrect resolutionScale = devicePixelRatio which was doubling
  the scaling factor on Retina displays (2x2=4x), causing blurriness
- Disable FXAA anti-aliasing which can cause blurriness on high-DPI displays
- Keep useBrowserRecommendedResolution: false to use native devicePixelRatio

Reverse geocoding improvements:
- Add getVisibleExtent() using camera.computeViewRectangle() to get the
  visible bounding box (west, south, east, north)
- Add getScaleDimensions() to calculate visible area in km
- Add calculateNominatimZoom() to map visible extent to appropriate
  Nominatim zoom level (3=country to 18=building)
- Log visible extent with dimensions on each camera move
- Pass zoom parameter to Nominatim for context-aware geocoding results
- Update model context with visible area dimensions

* fix(map-server): direct positioning + wait for tiles before showing

Changes:
- Remove zoom granularity logic from reverse geocoding (was not working)
- Keep extent logging in both console and model context
- Replace flyTo animation with instant setView positioning
- Add waitForTilesLoaded() to detect when tiles finish loading
- Keep loading spinner visible until:
  1. Tool input positions camera to destination
  2. Tiles at destination are fully loaded
- Add 5-second fallback timeout if no tool input received
- Add 10-second timeout for tile loading to prevent infinite wait

* feat(map-server): use viewbox search to find visible places

Replace center-point reverse geocoding with Nominatim viewbox search:
- Add searchPlacesInBox() that queries Nominatim with bounded viewbox
- Uses layer=address&featuretype=settlement to find cities/towns
- Returns up to 5 visible places in the current view
- Update model context with 'Visible places: City1, City2, ...'
- Still includes center coordinates and extent dimensions

This provides better context about what's actually visible on the map
rather than just the address at the center point.

* fix(map-server): use CARTO @2x retina tiles for sharp rendering

Root cause: Standard OSM tiles are 256x256 pixels. On Retina displays
(devicePixelRatio=2), these get scaled up 2x, making them look pixelated.

Solution: Switch to CARTO Voyager tiles which provide @2x retina support:
- Detect high-DPI displays using window.devicePixelRatio
- Use 512x512 tiles with @2x suffix on Retina displays
- Use 256x256 tiles on standard displays
- Set tileWidth/tileHeight to match actual tile size
- Use CARTO subdomains (a,b,c,d) for load balancing
- Update CSP to allow CARTO tile domains

CARTO Voyager provides clean OSM-based tiles with free @2x retina support,
no API key required.

* fix(map-server): use OSM tiles and fix reverse geocoding

- Switch back from CARTO to standard OSM tiles (tile.openstreetmap.org)
  for better detail and label rendering
- Fix geocoding: use reverse geocode API instead of search API
  (search API requires a q= parameter, returns 400 without it)
- Update CSP domains for OSM tile server

* fix(map-server): use *.openstreetmap.org wildcard in CSP

Simplify CSP to use wildcard for both tiles and geocoding:
- connectDomains: *.openstreetmap.org covers tile.* and nominatim.*
- resourceDomains: *.openstreetmap.org for tile images

* feat(map-server): multi-point sampling for visible places

- Sample multiple points in visible extent to discover places
- Adaptive sampling based on extent size:
  - < 30km: center only (city zoom)
  - 30-100km: center + 2 corners
  - > 100km: center + 4 quadrants
- Proper rate limiting for Nominatim (1.1s between requests)
- Shows 'Visible places: City1, City2, ...' in model context
- Fix: move geocode tool registration inside createServer()

* format

* fix(map-server): fix Express listen callback + add e2e tests

- Fix incorrect Express listen() callback signature (err param doesn't exist)
- Add map-server to e2e test suite with SLOW_SERVERS timeout (5s for tiles)
- Improve comment about experimental ui/update-model-context API

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 12:13:56 +00:00