Skip to main content
Glama
PhialsBasement

MCP Web Research Server

take_screenshot

Captures a visual image of a webpage to preserve layout and visual context when text alone is insufficient.

Instructions

Captures a visual image of the currently loaded webpage. Use this tool when you need to preserve visual information, analyze page layouts, or document the current state of a webpage. Perfect for situations where textual content alone doesn't convey the full context.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The main tool handler for 'take_screenshot' - captures a screenshot of the currently loaded webpage, saves it to disk, stores the result in the session, notifies clients, and returns a resource URI.
    case "take_screenshot": {
        try {
            // Step 1: Capture screenshot with retry mechanism
            const screenshot = await withRetry(async () => {
                // Take and optimize screenshot with default size limits
                return await takeScreenshotWithSizeLimit(page);
            });
    
            // Step 2: Initialize session if needed
            if (!currentSession) {
                currentSession = {
                    query: "Screenshot Session",            // Session identifier
                    results: [],                            // Empty results array
                    lastUpdated: new Date().toISOString(),  // Current timestamp
                };
            }
    
            // Step 3: Get current page information
            const pageUrl = await page.url();      // Current page URL
            const pageTitle = await page.title();  // Current page title
    
            // Step 4: Save screenshot to disk
            const screenshotPath = await saveScreenshot(screenshot, pageTitle || 'untitled');
    
            // Step 5: Create and store screenshot result
            const resultIndex = currentSession ? currentSession.results.length : 0;
            addResult({
                url: pageUrl,
                title: pageTitle || "Untitled Page",  // Fallback title if none available
                content: "Screenshot taken",          // Simple content description
                timestamp: new Date().toISOString(),  // Capture time
                      screenshotPath                        // Path to screenshot file
            });
    
            // Step 6: Notify clients about new screenshot resource
            server.notification({
                method: "notifications/resources/list_changed"
            });
    
            // Step 7: Return success message with resource URI
            const resourceUri = `research://screenshots/${resultIndex}`;
            return {
                content: [{
                    type: "text" as const,
                    text: `Screenshot taken successfully. You can view it via *MCP Resources* (Paperclip icon) @ URI: ${resourceUri}`
                }]
            };
        } catch (error) {
            // Handle and format screenshot errors
            return {
                content: [{
                    type: "text" as const,
                    text: `Failed to take screenshot: ${(error as Error).message}`
                }],
                isError: true
            };
        }
    }
  • Helper function that captures and optimizes a screenshot from the page. Uses Playwright's page.screenshot() and iteratively reduces viewport size if the PNG exceeds 5MB.
    async function takeScreenshotWithSizeLimit(page: Page): Promise<string> {
        const MAX_SIZE = 5 * 1024 * 1024;
        const MAX_DIMENSION = 1920;
        const MIN_DIMENSION = 800;
    
        // Set viewport size
        await page.setViewportSize({
            width: 1920,
            height: 1080
        });
    
        // Take initial screenshot
        let screenshot = await page.screenshot({
            type: 'png',
            fullPage: false
        });
    
        // Handle buffer conversion
        let buffer = screenshot;
        let attempts = 0;
        const MAX_ATTEMPTS = 3;
    
        // While screenshot is too large, reduce size
        while (buffer.length > MAX_SIZE && attempts < MAX_ATTEMPTS) {
            // Get current viewport size
            const viewport = page.viewportSize();
            if (!viewport) continue;
    
            // Calculate new dimensions
            const scaleFactor = Math.pow(0.75, attempts + 1);
            let newWidth = Math.round(viewport.width * scaleFactor);
            let newHeight = Math.round(viewport.height * scaleFactor);
    
            // Ensure dimensions are within bounds
            newWidth = Math.max(MIN_DIMENSION, Math.min(MAX_DIMENSION, newWidth));
            newHeight = Math.max(MIN_DIMENSION, Math.min(MAX_DIMENSION, newHeight));
    
            // Update viewport with new dimensions
            await page.setViewportSize({
                width: newWidth,
                height: newHeight
            });
    
            // Take new screenshot
            screenshot = await page.screenshot({
                type: 'png',
                fullPage: false
            });
    
            // Update buffer with new screenshot
            buffer = screenshot;
    
            // Increment retry attempts
            attempts++;
        }
    
        // Final attempt with minimum settings
        if (buffer.length > MAX_SIZE) {
            await page.setViewportSize({
                width: MIN_DIMENSION,
                height: MIN_DIMENSION
            });
    
            // Take final screenshot
            screenshot = await page.screenshot({
                type: 'png',
                fullPage: false
            });
    
            // Update buffer with final screenshot
            buffer = screenshot;
    
            // Throw error if final screenshot is still too large
            if (buffer.length > MAX_SIZE) {
                throw new McpError(
                    ErrorCode.InvalidRequest,
                    `Failed to reduce screenshot to under 5MB even with minimum settings`
                );
            }
        }
    
        // Convert Buffer to base64 string before returning
        return buffer.toString('base64');
    }
  • Helper function that saves a base64-encoded screenshot to disk as a PNG file. Validates size (max 5MB), generates a safe filename with timestamp, and returns the filepath.
    async function saveScreenshot(screenshot: string, title: string): Promise<string> {
        // Convert screenshot from base64 to buffer
        const buffer = Buffer.from(screenshot, 'base64');
    
        // Check size before saving
        const MAX_SIZE = 5 * 1024 * 1024;  // 5MB
        if (buffer.length > MAX_SIZE) {
            throw new McpError(
                ErrorCode.InvalidRequest,
                `Screenshot too large: ${Math.round(buffer.length / (1024 * 1024))}MB exceeds ${MAX_SIZE / (1024 * 1024)}MB limit`
            );
        }
    
        // Generate a safe filename
        const timestamp = new Date().getTime();
        const safeTitle = title.replace(/[^a-z0-9]/gi, '_').toLowerCase();
        const filename = `${safeTitle}-${timestamp}.png`;
        const filepath = path.join(SCREENSHOTS_DIR, filename);
    
        // Save the validated screenshot
        await fs.promises.writeFile(filepath, buffer);
    
        // Return the filepath to the saved screenshot
        return filepath;
    }
  • index.ts:167-174 (registration)
    The tool registration/schema definition for 'take_screenshot' in the TOOLS array. Defines the name, description, and an empty input schema (no parameters needed).
    {
        name: "take_screenshot",
        description: "Captures a visual image of the currently loaded webpage. Use this tool when you need to preserve visual information, analyze page layouts, or document the current state of a webpage. Perfect for situations where textual content alone doesn't convey the full context.",
        inputSchema: {
            type: "object",
            properties: {},  // No parameters needed
        },
    },
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, and the description lacks details about side effects, image format, or behavior if no page is loaded, leaving significant behavioral gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two efficient sentences, front-loaded with the verb 'Captures', and every word adds value without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

While the purpose is clear, the description omits details about output (e.g., format, full-page vs viewport), which would help completeness for a simple tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With zero parameters, baseline is 4; the description correctly implies no configuration is needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool captures a visual image of the currently loaded webpage, and it is distinct from sibling tools like search_google, search_scholar, and visit_page.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear use cases (preserve visual info, analyze layouts, document state) but does not explicitly mention when not to use it or alternatives, though siblings are different.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other 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/PhialsBasement/mcp-webresearch-stealthified'

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