Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
26 changes: 11 additions & 15 deletions src/tools/screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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({
Expand All @@ -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
Expand All @@ -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
});
}
});

Expand Down
Loading