Skip to content

Commit 3100ea2

Browse files
committed
feat(pdf-server): send screenshot to updateModelContext
Apply the same pattern as map-server: capture the PDF canvas as a scaled-down screenshot and include it in the model context update when the host supports image content. - Check host capability via getHostCapabilities().updateModelContext.image - Scale canvas to max 768px dimension to reduce token usage - Convert to base64 PNG and include with text content
1 parent 47a5787 commit 3100ea2

1 file changed

Lines changed: 45 additions & 1 deletion

File tree

examples/pdf-server/src/mcp-app.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ import {
1313
applyHostStyleVariables,
1414
} from "@modelcontextprotocol/ext-apps";
1515
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
16+
import type { ContentBlock } from "@modelcontextprotocol/sdk/spec.types.js";
1617
import * as pdfjsLib from "pdfjs-dist";
1718
import { TextLayer } from "pdfjs-dist";
1819
import "./global.css";
1920
import "./mcp-app.css";
2021

2122
const MAX_MODEL_CONTEXT_LENGTH = 15000;
23+
const MAX_MODEL_CONTEXT_UPDATE_IMAGE_DIMENSION = 768; // Max screenshot dimension
2224
const CHUNK_SIZE = 500 * 1024; // 500KB chunks
2325

2426
// Configure PDF.js worker
@@ -298,7 +300,49 @@ async function updatePageContext() {
298300

299301
const contextText = `${header}\n\nPage content:\n${content}`;
300302

301-
app.updateModelContext({ content: [{ type: "text", text: contextText }] });
303+
// Build content array with text and optional screenshot
304+
const contentBlocks: ContentBlock[] = [
305+
{ type: "text", text: contextText },
306+
];
307+
308+
// Add screenshot if host supports image content
309+
if (app.getHostCapabilities()?.updateModelContext?.image) {
310+
try {
311+
// Scale down to reduce token usage (tokens depend on dimensions)
312+
const sourceCanvas = canvasEl;
313+
const scale = Math.min(
314+
1,
315+
MAX_MODEL_CONTEXT_UPDATE_IMAGE_DIMENSION /
316+
Math.max(sourceCanvas.width, sourceCanvas.height),
317+
);
318+
const targetWidth = Math.round(sourceCanvas.width * scale);
319+
const targetHeight = Math.round(sourceCanvas.height * scale);
320+
321+
const tempCanvas = document.createElement("canvas");
322+
tempCanvas.width = targetWidth;
323+
tempCanvas.height = targetHeight;
324+
const ctx = tempCanvas.getContext("2d");
325+
if (ctx) {
326+
ctx.drawImage(sourceCanvas, 0, 0, targetWidth, targetHeight);
327+
const dataUrl = tempCanvas.toDataURL("image/png");
328+
const base64Data = dataUrl.split(",")[1];
329+
if (base64Data) {
330+
contentBlocks.push({
331+
type: "image",
332+
data: base64Data,
333+
mimeType: "image/png",
334+
});
335+
log.info(
336+
`Added screenshot to model context (${targetWidth}x${targetHeight})`,
337+
);
338+
}
339+
}
340+
} catch (err) {
341+
log.info("Failed to capture screenshot:", err);
342+
}
343+
}
344+
345+
app.updateModelContext({ content: contentBlocks });
302346
} catch (err) {
303347
log.error("Error updating context:", err);
304348
}

0 commit comments

Comments
 (0)