screenshot-page
Capture screenshots of any webpage as base64 encoded images with customizable settings like viewport size, image format, and loading conditions. Supports using saved cookies for authenticated pages.
Instructions
Captures a screenshot of a given URL and returns it as base64 encoded image. Can use saved cookies from login-and-wait.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| delay | No | Additional delay in milliseconds to wait after page load | |
| format | No | Image format for the screenshot | png |
| fullPage | No | Whether to capture the full page or just the viewport | |
| height | No | Viewport height in pixels | |
| quality | No | Quality of the image (0-100), only applicable for jpeg and webp | |
| reuseAuthPage | No | Whether to use the existing authenticated page instead of creating a new one | |
| url | Yes | The URL of the webpage to screenshot | |
| useDefaultBrowser | No | Whether to use the system's default browser instead of Puppeteer's bundled Chromium | |
| useSavedAuth | No | Whether to use saved cookies from previous login | |
| visibleBrowser | No | Whether to show the browser window (non-headless mode) | |
| waitFor | No | When to consider the page loaded | networkidle2 |
| width | No | Viewport width in pixels |
Implementation Reference
- src/index.ts:514-650 (handler)The handler function that implements the core logic for capturing screenshots of web pages using Puppeteer. Supports authentication via saved cookies, full-page screenshots, custom dimensions, formats, delays, browser visibility, and default system browser usage.async ({ url, fullPage, width, height, format, quality, waitFor, delay, useSavedAuth, reuseAuthPage, useDefaultBrowser, visibleBrowser }) => { let page: Page | null = null; let shouldClosePage = true; try { // Initialize browser with appropriate options const isHeadless = !visibleBrowser; const browserInstance = await initBrowser(isHeadless, useDefaultBrowser && visibleBrowser); // Check if we should reuse the authenticated page if (reuseAuthPage && persistentPage && !persistentPage.isClosed()) { page = persistentPage; shouldClosePage = false; // Navigate to the new URL if different const currentUrl = page.url(); if (currentUrl !== url) { await page.goto(url, { waitUntil: waitFor as any, timeout: 30000 }); } } else { // Create a new page page = await browserInstance.newPage(); // Load saved cookies if requested if (useSavedAuth) { const cookies = await loadCookies(url); if (cookies.length > 0) { await page.setCookie(...cookies); } } // Set viewport await page.setViewport({ width, height }); // Set user agent to avoid bot detection await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); // Additional anti-detection measures for Google await page.evaluateOnNewDocument(() => { // Remove webdriver property delete (window.navigator as any).webdriver; // Override the plugins property to add fake plugins Object.defineProperty(window.navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] }); // Override the languages property Object.defineProperty(window.navigator, 'languages', { get: () => ['en-US', 'en'] }); // Override permissions Object.defineProperty(window.navigator, 'permissions', { get: () => ({ query: () => Promise.resolve({ state: 'granted' }) }) }); }); // Navigate to the URL await page.goto(url, { waitUntil: waitFor as any, timeout: 30000 }); } // Optional delay if (delay > 0) { await new Promise(resolve => setTimeout(resolve, delay)); } // Prepare screenshot options const screenshotOptions: any = { encoding: 'base64', fullPage, type: format }; // Add quality option for jpeg and webp if ((format === 'jpeg' || format === 'webp') && quality !== undefined) { screenshotOptions.quality = quality; } // Take screenshot const screenshot = await page.screenshot(screenshotOptions) as string; // Get page title and final URL for context const pageTitle = await page.title(); const finalUrl = page.url(); // If using a new page, save any new cookies if (!reuseAuthPage && useSavedAuth) { const currentCookies = await page.cookies(); if (currentCookies.length > 0) { await saveCookies(url, currentCookies); } } // Determine browser type for response const browserType = useDefaultBrowser && visibleBrowser ? 'default browser' : 'Puppeteer browser'; const browserMode = visibleBrowser ? 'visible' : 'headless'; return { content: [ { type: "text", text: `Screenshot captured successfully!\n\nBrowser: ${browserType} (${browserMode})\nPage Title: ${pageTitle}\nFinal URL: ${finalUrl}\nFormat: ${format}\nDimensions: ${width}x${height}\nFull Page: ${fullPage}\nUsed saved auth: ${useSavedAuth}\nReused auth page: ${reuseAuthPage}` }, { type: "image", data: screenshot, mimeType: `image/${format}` } ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { isError: true, content: [ { type: "text", text: `Error capturing screenshot: ${errorMessage}`, }, ], }; } finally { // Only close the page if it's not the persistent one or if we should close it if (page && shouldClosePage && page !== persistentPage) { await page.close().catch(() => {}); } } }
- src/index.ts:500-513 (schema)Zod schema defining the input parameters for the screenshot-page tool, including URL, screenshot options, authentication flags, and browser configuration.{ url: z.string().url().describe("The URL of the webpage to screenshot"), fullPage: z.boolean().optional().default(true).describe("Whether to capture the full page or just the viewport"), width: z.number().optional().default(1920).describe("Viewport width in pixels"), height: z.number().optional().default(1080).describe("Viewport height in pixels"), format: z.enum(['png', 'jpeg', 'webp']).optional().default('png').describe("Image format for the screenshot"), quality: z.number().min(0).max(100).optional().describe("Quality of the image (0-100), only applicable for jpeg and webp"), waitFor: z.enum(['load', 'domcontentloaded', 'networkidle0', 'networkidle2']).optional().default('networkidle2').describe("When to consider the page loaded"), delay: z.number().optional().default(0).describe("Additional delay in milliseconds to wait after page load"), useSavedAuth: z.boolean().optional().default(true).describe("Whether to use saved cookies from previous login"), reuseAuthPage: z.boolean().optional().default(false).describe("Whether to use the existing authenticated page instead of creating a new one"), useDefaultBrowser: z.boolean().optional().default(false).describe("Whether to use the system's default browser instead of Puppeteer's bundled Chromium"), visibleBrowser: z.boolean().optional().default(false).describe("Whether to show the browser window (non-headless mode)") },
- src/index.ts:496-651 (registration)Registration of the screenshot-page tool on the MCP server, including name, description, input schema, and handler function.// Updated screenshot-page tool with authentication support server.tool( "screenshot-page", "Captures a screenshot of a given URL and returns it as base64 encoded image. Can use saved cookies from login-and-wait.", { url: z.string().url().describe("The URL of the webpage to screenshot"), fullPage: z.boolean().optional().default(true).describe("Whether to capture the full page or just the viewport"), width: z.number().optional().default(1920).describe("Viewport width in pixels"), height: z.number().optional().default(1080).describe("Viewport height in pixels"), format: z.enum(['png', 'jpeg', 'webp']).optional().default('png').describe("Image format for the screenshot"), quality: z.number().min(0).max(100).optional().describe("Quality of the image (0-100), only applicable for jpeg and webp"), waitFor: z.enum(['load', 'domcontentloaded', 'networkidle0', 'networkidle2']).optional().default('networkidle2').describe("When to consider the page loaded"), delay: z.number().optional().default(0).describe("Additional delay in milliseconds to wait after page load"), useSavedAuth: z.boolean().optional().default(true).describe("Whether to use saved cookies from previous login"), reuseAuthPage: z.boolean().optional().default(false).describe("Whether to use the existing authenticated page instead of creating a new one"), useDefaultBrowser: z.boolean().optional().default(false).describe("Whether to use the system's default browser instead of Puppeteer's bundled Chromium"), visibleBrowser: z.boolean().optional().default(false).describe("Whether to show the browser window (non-headless mode)") }, async ({ url, fullPage, width, height, format, quality, waitFor, delay, useSavedAuth, reuseAuthPage, useDefaultBrowser, visibleBrowser }) => { let page: Page | null = null; let shouldClosePage = true; try { // Initialize browser with appropriate options const isHeadless = !visibleBrowser; const browserInstance = await initBrowser(isHeadless, useDefaultBrowser && visibleBrowser); // Check if we should reuse the authenticated page if (reuseAuthPage && persistentPage && !persistentPage.isClosed()) { page = persistentPage; shouldClosePage = false; // Navigate to the new URL if different const currentUrl = page.url(); if (currentUrl !== url) { await page.goto(url, { waitUntil: waitFor as any, timeout: 30000 }); } } else { // Create a new page page = await browserInstance.newPage(); // Load saved cookies if requested if (useSavedAuth) { const cookies = await loadCookies(url); if (cookies.length > 0) { await page.setCookie(...cookies); } } // Set viewport await page.setViewport({ width, height }); // Set user agent to avoid bot detection await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); // Additional anti-detection measures for Google await page.evaluateOnNewDocument(() => { // Remove webdriver property delete (window.navigator as any).webdriver; // Override the plugins property to add fake plugins Object.defineProperty(window.navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] }); // Override the languages property Object.defineProperty(window.navigator, 'languages', { get: () => ['en-US', 'en'] }); // Override permissions Object.defineProperty(window.navigator, 'permissions', { get: () => ({ query: () => Promise.resolve({ state: 'granted' }) }) }); }); // Navigate to the URL await page.goto(url, { waitUntil: waitFor as any, timeout: 30000 }); } // Optional delay if (delay > 0) { await new Promise(resolve => setTimeout(resolve, delay)); } // Prepare screenshot options const screenshotOptions: any = { encoding: 'base64', fullPage, type: format }; // Add quality option for jpeg and webp if ((format === 'jpeg' || format === 'webp') && quality !== undefined) { screenshotOptions.quality = quality; } // Take screenshot const screenshot = await page.screenshot(screenshotOptions) as string; // Get page title and final URL for context const pageTitle = await page.title(); const finalUrl = page.url(); // If using a new page, save any new cookies if (!reuseAuthPage && useSavedAuth) { const currentCookies = await page.cookies(); if (currentCookies.length > 0) { await saveCookies(url, currentCookies); } } // Determine browser type for response const browserType = useDefaultBrowser && visibleBrowser ? 'default browser' : 'Puppeteer browser'; const browserMode = visibleBrowser ? 'visible' : 'headless'; return { content: [ { type: "text", text: `Screenshot captured successfully!\n\nBrowser: ${browserType} (${browserMode})\nPage Title: ${pageTitle}\nFinal URL: ${finalUrl}\nFormat: ${format}\nDimensions: ${width}x${height}\nFull Page: ${fullPage}\nUsed saved auth: ${useSavedAuth}\nReused auth page: ${reuseAuthPage}` }, { type: "image", data: screenshot, mimeType: `image/${format}` } ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { isError: true, content: [ { type: "text", text: `Error capturing screenshot: ${errorMessage}`, }, ], }; } finally { // Only close the page if it's not the persistent one or if we should close it if (page && shouldClosePage && page !== persistentPage) { await page.close().catch(() => {}); } } } );
- src/index.ts:273-282 (helper)Helper function to load authentication cookies for a given URL/domain from persistent storage, used by screenshot-page for auth support.async function loadCookies(url: string): Promise<Cookie[]> { try { const domain = getDomainFromUrl(url); const cookiesPath = path.join(cookiesDir, `${domain}.json`); const cookiesData = await fsPromises.readFile(cookiesPath, 'utf-8'); return JSON.parse(cookiesData); } catch { return []; } }
- src/index.ts:265-270 (helper)Helper function to save cookies for a domain after page load, enabling persistent authentication across tool calls.async function saveCookies(url: string, cookies: Cookie[]) { await ensureCookiesDir(); const domain = getDomainFromUrl(url); const cookiesPath = path.join(cookiesDir, `${domain}.json`); await fsPromises.writeFile(cookiesPath, JSON.stringify(cookies, null, 2)); }