From cd43ebc732b1e28d8c1ae54ecbfb346aeee79623 Mon Sep 17 00:00:00 2001 From: Kedlub Date: Mon, 8 Sep 2025 13:26:36 +0200 Subject: [PATCH] feat(screenshot): remove fullpage option and verify image size --- package-lock.json | 13 +++++++++++++ package.json | 1 + src/tools/screenshot.ts | 26 +++++++++++--------------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 50706b882..379a7924e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "commander": "^13.1.0", "debug": "^4.4.1", "dotenv": "^17.2.0", + "image-size": "^2.0.2", "mime": "^4.0.7", "playwright": "1.56.0-alpha-1756505518000", "playwright-core": "1.56.0-alpha-1756505518000", @@ -2753,6 +2754,18 @@ "node": ">= 4" } }, + "node_modules/image-size": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz", + "integrity": "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==", + "license": "MIT", + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", diff --git a/package.json b/package.json index babe5f7b2..ffd171a30 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "commander": "^13.1.0", "debug": "^4.4.1", "dotenv": "^17.2.0", + "image-size": "^2.0.2", "mime": "^4.0.7", "playwright": "1.56.0-alpha-1756505518000", "playwright-core": "1.56.0-alpha-1756505518000", diff --git a/src/tools/screenshot.ts b/src/tools/screenshot.ts index e7297aef7..3d0315099 100644 --- a/src/tools/screenshot.ts +++ b/src/tools/screenshot.ts @@ -16,6 +16,7 @@ import { z } from 'zod'; +import { imageSize } from 'image-size'; import { defineTabTool } from './tool.js'; import * as javascript from '../utils/codegen.js'; import { generateLocator } from './utils.js'; @@ -27,17 +28,11 @@ const screenshotSchema = z.object({ filename: z.string().optional().describe('File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified.'), element: z.string().optional().describe('Human-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too.'), ref: z.string().optional().describe('Exact target element reference from the page snapshot. If not provided, the screenshot will be taken of viewport. If ref is provided, element must be provided too.'), - fullPage: z.boolean().optional().describe('When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Cannot be used with element screenshots.'), }).refine(data => { return !!data.element === !!data.ref; }, { message: 'Both element and ref must be provided or neither.', path: ['ref', 'element'] -}).refine(data => { - return !(data.fullPage && (data.element || data.ref)); -}, { - message: 'fullPage cannot be used with element screenshots.', - path: ['fullPage'] }); const screenshot = defineTabTool({ @@ -58,11 +53,10 @@ const screenshot = defineTabTool({ quality: fileType === 'png' ? undefined : 90, scale: 'css', path: fileName, - ...(params.fullPage !== undefined && { fullPage: params.fullPage }) }; const isElementScreenshot = params.element && params.ref; - const screenshotTarget = isElementScreenshot ? params.element : (params.fullPage ? 'full page' : 'viewport'); + const screenshotTarget = isElementScreenshot ? params.element : 'viewport'; response.addCode(`// Screenshot ${screenshotTarget} and save it as ${fileName}`); // Only get snapshot when element screenshot is needed @@ -76,14 +70,16 @@ const screenshot = defineTabTool({ const buffer = locator ? await locator.screenshot(options) : await tab.page.screenshot(options); response.addResult(`Took the ${screenshotTarget} screenshot and saved it as ${fileName}`); - // https://github.com/microsoft/playwright-mcp/issues/817 - // Never return large images to LLM, saving them to the file system is enough. - if (!params.fullPage) { - response.addImage({ - contentType: fileType === 'png' ? 'image/png' : 'image/jpeg', - data: buffer - }); + const dimensions = imageSize(buffer); + if (dimensions.width > 3000 && dimensions.height > 3000) { + response.addResult('Screenshot is too big (larger than 3000x3000 pixels).'); + return; } + + response.addImage({ + contentType: fileType === 'png' ? 'image/png' : 'image/jpeg', + data: buffer + }); } });