* fix(map-server): simplify location update message format
* fix(say-server): pass host to streamable_http_app for non-localhost deployments
* refactor(pdf-server): simplify to stateless range-query architecture
- Remove caching/indexing in favor of direct HTTP Range requests
- Use HEAD requests to get file size (no full download)
- Use Range requests to proxy byte chunks (no caching)
- Local files: fs.read with offset/length
- Remote files: HTTP Range header
- Zero memory footprint (no PDF caching)
- Truly stateless (no session management needed)
- Single server.ts (~350 lines) + main.ts CLI entry point
- Instant startup (no preloading)
- Security: whitelist local files, allowed origins
Removed files:
- src/pdf-indexer.ts
- src/pdf-loader.ts
- src/types.ts
* feat(pdf-server): add dark mode support
- Add CSS variables with light-dark() function for automatic theme switching
- Sync theme with host via applyDocumentTheme()
- Apply host CSS variables via applyHostStyleVariables()
* feat(pdf-server): add list_pdfs tool back
Lists local files and allowed remote origins.
Also moves CHUNK_SIZE to module level constant.
* feat(pdf-server): improve tool descriptions and increase context limit
- display_pdf: list all allowed domains in description
- Increase MAX_MODEL_CONTEXT_LENGTH to 15000
- Move CHUNK_SIZE to module level constant
* chore(say-server): remove deployment docs from repo
Keep server.py fix for non-localhost deployments.
Deployment docs kept locally but not in repo.
* refactor(pdf-server): simplify updateModelContext format
- Add widget ID for multi-widget disambiguation
- Use concise header: 'PDF viewer (id) | title | Current Page: X/Y'
- Add 'Page content:' prefix before text
- Keep selection markers (<pdf-selection>...</pdf-selection>)
* refactor: rename widgetUUID to viewUUID for consistency
Aligns with main's standardization on 'view' terminology (PR #325).
Also dynamically generate allowed domains in display_pdf description.
* viewUUID
* fix(map-server): fix syntax error in location update message
* fix(pdf-server): restore package.json, improve server docs
- Restore --external pdfjs-dist in build
- Rewrite server.ts header for newcomers (list tools, not implementation details)
- Minimize main.ts diff
* chore(pdf-server): remove unused addAllowedOrigin/addAllowedLocalFile
* docs(pdf-server): update README for new architecture
* docs(pdf-server): restore full README, add theming section, remove get_pdf_info
* rm
* fix(pdf-server): restore createMcpExpressApp and error handling
- Use createMcpExpressApp for DNS rebinding protection
- Restore error callback in app.listen()
* fix(say-server): pass host to streamable_http_app for non-localhost deployments
* chore(say-server): remove deployment docs from repo
* widgetId->tool id
* fix(map-server): add null check for center in location update
chore(pdf-server): dedupe and sort allowed origins
* fix(map-server): use transparent background for rounded corners
* prettier
* docs: standardize UI terminology to use "view" consistently
Replaces "widget" and "Guest UI" terminology with "view" across
the codebase as decided in the community survey.
This change updates:
- Specification document
- SDK source code and JSDoc comments
- Example servers and documentation
- Plugin documentation and skills
Closes#71
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After commit 65a62a9f, the server startup code was moved from server.ts
to main.ts, but the serve:http script was not updated accordingly.
This caused 9 example servers to fail to start when running npm start:
- budget-allocator-server
- cohort-heatmap-server
- customer-segmentation-server
- integration-server
- map-server
- scenario-modeler-server
- system-monitor-server
- threejs-server
- wiki-explorer-server
The server.ts file now only exports createServer(), while main.ts
contains the actual server startup logic.
Add stdio transport configuration snippets near the top of each example
README to help users quickly set up the servers in their MCP clients.
- Node.js examples use npx with the published npm packages
- Python qr-server uses uv with local path
- Removed Claude Desktop-specific references from qr-server
* fix(examples): resolve DIST_DIR path for npm package execution
When servers are compiled to dist/server.js and published to npm,
`import.meta.dirname` already points to dist/, so joining with "dist"
results in dist/dist/ which doesn't exist.
This fix detects whether we're running from TypeScript source or
compiled JavaScript and adjusts the path accordingly:
- From source (server.ts): use dist/ subdirectory
- From compiled (dist/server.js): use current directory
Fixes ENOENT errors like:
"ENOENT: no such file or directory, open '.../dist/dist/mcp-app.html'"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(pdf-server): mark pdfjs-dist as external in bundle
The pdf.worker.mjs file wasn't being found when running from npm
because bun bundled pdfjs-dist but didn't include the worker file.
By marking pdfjs-dist as external, it uses the installed package
from node_modules at runtime where the worker is available.
🤖 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>
* feat: compile example servers to JavaScript for npm consumption
Add TypeScript compilation for server code so the example packages can be
imported and used by consumers without requiring TypeScript compilation.
Changes:
- Add tsconfig.server.json to each example for compiling server code
- Update package.json exports to point to compiled dist/server/server.js
- Add types field pointing to dist/server/server.d.ts
- Update build scripts to include server compilation step
- Fix .ts import extensions to .js in customer-segmentation-server
This enables importing the createServer function from published packages:
import { createServer } from '@modelcontextprotocol/server-basic-react';
* fix: add type assertion for Nominatim API response
* chore: regenerate schemas
* refactor: split server examples into library and binary entry points
- server.ts: exports createServer() only (library entry point)
- main.ts: entry point with main() that runs the server (binary)
- package.json: adds bin field for npx support, uses inline bun build
- tsconfig.server.json: emitDeclarationOnly, outputs to dist/
This allows:
1. Importing the server as a library: import { createServer } from '@modelcontextprotocol/server-basic-react'
2. Running with npx: npx @modelcontextprotocol/server-basic-react [--stdio]
Added migration script at scripts/migrate-server-examples.ts
* refactor: migrate remaining server examples to library/binary structure
Apply the same refactoring to all 13 remaining server examples:
- scenario-modeler-server, shadertoy-server, map-server
- cohort-heatmap-server, customer-segmentation-server, video-resource-server
- system-monitor-server, budget-allocator-server, sheet-music-server
- threejs-server, integration-server, transcript-server, wiki-explorer-server
Each now has:
- server.ts: exports createServer() (library)
- main.ts: runs the server (binary with shebang)
- bin field in package.json for npx support
* chore: remove unused server-utils.ts from video-resource-server/src
* update
* fix(build): make Windows-compatible by removing chmod and fixing bun externals
- Remove 'chmod +x dist/index.js' which doesn't exist on Windows
- Add '--external ./server.js' to prevent bun from treating the import as a second entry point
* fix(build): use .ts import for bun compatibility
- Change import from './server.js' to './server.ts' in main.ts files
- Remove --external flag since bun should inline everything
- Fixes Windows build where bun couldn't resolve .js to .ts properly
* fix(build): use --external for Windows bun compatibility
Bun on Windows incorrectly treats imported .ts files as entry points.
Use --external './server.js' to work around this, creating a runtime
dependency between index.js and server.js.
* style: fix prettier formatting in pdf-server/main.ts
* fix(build): remove quotes from --external for Windows cmd.exe compatibility
* fix(build): use glob pattern for --external to work on all platforms
The literal path --external ./server.js was not matching the import.
Using glob pattern --external "./server*" correctly externalizes the server module.
* fix(build): use */server.js pattern for --external
The "./server*" pattern was not matching on Windows.
Using "*/server.js" matches any path ending in /server.js which works cross-platform.
* fix(build): use *server.js pattern without slash for Windows compatibility
* update package-lock
* chore: regenerate package-lock.json for cross-platform compatibility
* fix(build): use ./server.js instead of glob pattern for Windows compatibility
* fix(build): use double quotes for banner to fix Windows cmd.exe compatibility
---------
Co-authored-by: Olivier Chafik <ochafik@anthropic.com>
* map-server: fix async/await in ontoolresult, remove unused getViewStorageKey
* fix(map-server): improve updateModelContext and fix initialization
- Use structured YAML frontmatter format for model context (like pdf-server)
- Add tool name, altitude, and cleaner data format
- Fix initialization deadlock: app.connect() was inside ontoolresult handler
which could never fire until connected
- Fix view state persistence: widgetUUID now properly extracted from
ontoolresult and used to restore persisted camera position
- Server now includes widgetUUID in tool result _meta for widget identification
* fix(pdf-server): use widgetUUID for page persistence
- Add widgetUUID to tool result _meta for widget identification
- Use widgetUUID instead of generated key (pdfUrl+toolId) for localStorage
- Enables reliable page restoration when revisiting PDF widgets
* fix(transcript-server): use structured YAML frontmatter for model context
- Add tool name, listening status, and unsent entry count in frontmatter
- Consistent format with pdf-server and map-server
* update names
* drop bogus altitude
* Update mcp-app.ts
- Add `.gitignore` files to all 19 examples (`node_modules/`, `dist/`)
- Replace custom `log` objects with standard `console` methods
- Add `ontoolcancelled` handler to all `basic-server-*` examples
- Add host styling integration (`applyDocumentTheme`, `applyHostFonts`,
`applyHostStyleVariables`) to non-React `basic-server-*` examples
- Add section headers for better code organization in feature examples
- Update READMEs with Build System section explaining single-file
bundling
These changes make examples more consistent and easier to adapt.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* 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 \ 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
* 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.
* 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
* 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>