From 81210292422fa081be0a725260fede4c6f6a5ccd Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Fri, 23 Jan 2026 20:17:33 +0000 Subject: [PATCH 1/3] feat(map-server): add screenshot to updateModelContext and remove rounded corners - Remove border-radius and overflow: hidden from cesiumContainer CSS - Capture map canvas as base64 PNG and include in updateModelContext - Only include image if host supports image content blocks --- examples/map-server/mcp-app.html | 2 -- examples/map-server/src/mcp-app.ts | 36 +++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/examples/map-server/mcp-app.html b/examples/map-server/mcp-app.html index 8cba8394..473eb50f 100644 --- a/examples/map-server/mcp-app.html +++ b/examples/map-server/mcp-app.html @@ -19,8 +19,6 @@ #cesiumContainer { width: 100%; height: 100%; - border-radius: .75rem; - overflow: hidden; } #fullscreen-btn { position: absolute; diff --git a/examples/map-server/src/mcp-app.ts b/examples/map-server/src/mcp-app.ts index 73d7aa16..bcf28a47 100644 --- a/examples/map-server/src/mcp-app.ts +++ b/examples/map-server/src/mcp-app.ts @@ -412,17 +412,41 @@ function scheduleLocationUpdate(cesiumViewer: any): void { const { widthKm, heightKm } = getScaleDimensions(extent); const places = await getVisiblePlaces(extent); - // Update the model's context with the current map location. + // Update the model's context with the current map location and screenshot. // If the host doesn't support this, the request will silently fail. - const content = [ + const text = [ `The map view of ${app.getHostContext()?.toolInfo?.id} is now ${widthKm.toFixed(1)}km wide × ${heightKm.toFixed(1)}km tall `, `and has changed to the following location: [${places.join(", ")}] `, `lat. / long. of center of map = [${center.lat.toFixed(4)}, ${center.lon.toFixed(4)}]`, ].join("\n"); - log.info("Updating model context:", content); - app.updateModelContext({ - content: [{ type: "text", text: content }], - }); + log.info("Updating model context:", text); + + // Build content array with text and optional screenshot + const content: Array< + { type: "text"; text: string } | { type: "image"; data: string; mimeType: string } + > = [{ type: "text", text }]; + + // Add screenshot if host supports image content + if (app.getHostCapabilities()?.updateModelContext?.image) { + try { + // Canvas has preserveDrawingBuffer: true, so we can capture directly + const dataUrl = cesiumViewer.canvas.toDataURL("image/png"); + // Extract base64 data (remove "data:image/png;base64," prefix) + const base64Data = dataUrl.split(",")[1]; + if (base64Data) { + content.push({ + type: "image", + data: base64Data, + mimeType: "image/png", + }); + log.info("Added screenshot to model context"); + } + } catch (err) { + log.warn("Failed to capture screenshot:", err); + } + } + + app.updateModelContext({ content }); }, 1500); } From d6db0c40e9b587f5176c3a755576c9845fe025dc Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Fri, 23 Jan 2026 23:57:52 +0000 Subject: [PATCH 2/3] feat(map-server): reduce screenshot size for fewer tokens - Scale down to max 256px (longest dimension) - Use PNG for better quality with map graphics --- examples/map-server/src/mcp-app.ts | 180 +++++------------------------ 1 file changed, 31 insertions(+), 149 deletions(-) diff --git a/examples/map-server/src/mcp-app.ts b/examples/map-server/src/mcp-app.ts index bcf28a47..ddc6a0f1 100644 --- a/examples/map-server/src/mcp-app.ts +++ b/examples/map-server/src/mcp-app.ts @@ -6,6 +6,7 @@ * a navigate-to tool for the host to control navigation. */ import { App } from "@modelcontextprotocol/ext-apps"; +import type { ContentBlock } from "@modelcontextprotocol/sdk/spec.types.js"; // TypeScript declaration for Cesium loaded from CDN // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -14,6 +15,8 @@ declare let Cesium: any; const CESIUM_VERSION = "1.123"; const CESIUM_BASE_URL = `https://cesium.com/downloads/cesiumjs/releases/${CESIUM_VERSION}/Build/Cesium`; +const MAX_MODEL_CONTEXT_UPDATE_IMAGE_DIMENSION = 768; // Max width/height for screenshots in pixels for updateModelContext + /** * Dynamically load CesiumJS from CDN * This is necessary because external