Skip to main content
Glama
ananddtyagi

Webpage Screenshot MCP Server

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
NameRequiredDescriptionDefault
delayNoAdditional delay in milliseconds to wait after page load
formatNoImage format for the screenshotpng
fullPageNoWhether to capture the full page or just the viewport
heightNoViewport height in pixels
qualityNoQuality of the image (0-100), only applicable for jpeg and webp
reuseAuthPageNoWhether to use the existing authenticated page instead of creating a new one
urlYesThe URL of the webpage to screenshot
useDefaultBrowserNoWhether to use the system's default browser instead of Puppeteer's bundled Chromium
useSavedAuthNoWhether to use saved cookies from previous login
visibleBrowserNoWhether to show the browser window (non-headless mode)
waitForNoWhen to consider the page loadednetworkidle2
widthNoViewport width in pixels

Implementation Reference

  • 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(() => {});
            }
        }
    }
  • 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(() => {});
                }
            }
        }
    );
  • 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 [];
        }
    }
  • 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));
    }
Install Server

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ananddtyagi/webpage-screenshot-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server