Skip to main content
Glama
amotivv

cloudflare-browser-rendering-mcp

take_screenshot

Capture screenshots of web pages as images using specified URL, viewport dimensions, and full-page option for web content processing and analysis.

Instructions

Takes a screenshot of a web page and returns it as an image

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
fullPageNoWhether to take a screenshot of the full page or just the viewport (default: false)
heightNoHeight of the viewport in pixels (default: 800)
urlYesURL to take a screenshot of
widthNoWidth of the viewport in pixels (default: 1280)

Implementation Reference

  • MCP tool handler for 'take_screenshot': validates args, delegates to BrowserClient.takeScreenshot(), returns screenshot URL as text content.
    private async handleTakeScreenshot(args: any) {
      // Validate arguments
      if (typeof args !== 'object' || args === null || typeof args.url !== 'string') {
        throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments for take_screenshot');
      }
    
      const { 
        url, 
        width = 1280, 
        height = 800, 
        fullPage = false
      } = args;
    
      try {
        console.error(`[API] Taking screenshot of ${url} with parameters:`, { width, height, fullPage });
        console.error(`[API] Using endpoint: ${process.env.BROWSER_RENDERING_API}`);
        
        // Take the screenshot - returns only the URL
        const screenshotUrl = await this.browserClient.takeScreenshot(url, {
          width,
          height,
          fullPage,
        });
        
        console.error('[API] Screenshot taken successfully, URL:', screenshotUrl);
        
        // Return just the URL as text (without embedding the image)
        return {
          content: [
            {
              type: 'text',
              text: `Screenshot of ${url} is available at: ${screenshotUrl}\n\n(URL provided as text to prevent potential rendering issues)`
            }
          ]
        };
      } catch (error) {
        console.error('[Error] Error taking screenshot:', error);
        return {
          content: [
            {
              type: 'text',
              text: `Error taking screenshot: ${error instanceof Error ? error.message : String(error)}`,
            }
          ],
          isError: true,
        };
      }
    }
  • Input schema for take_screenshot tool defining parameters: url (required), width, height, fullPage.
    inputSchema: {
      type: 'object',
      properties: {
        url: {
          type: 'string',
          description: 'URL to take a screenshot of',
        },
        width: {
          type: 'number',
          description: 'Width of the viewport in pixels (default: 1280)',
        },
        height: {
          type: 'number',
          description: 'Height of the viewport in pixels (default: 800)',
        },
        fullPage: {
          type: 'boolean',
          description: 'Whether to take a screenshot of the full page or just the viewport (default: false)',
        },
      },
      required: ['url'],
  • src/server.ts:147-172 (registration)
    Registration of the take_screenshot tool in the ListTools response, including name, description, and inputSchema.
    {
      name: 'take_screenshot',
      description: 'Takes a screenshot of a web page and returns it as an image',
      inputSchema: {
        type: 'object',
        properties: {
          url: {
            type: 'string',
            description: 'URL to take a screenshot of',
          },
          width: {
            type: 'number',
            description: 'Width of the viewport in pixels (default: 1280)',
          },
          height: {
            type: 'number',
            description: 'Height of the viewport in pixels (default: 800)',
          },
          fullPage: {
            type: 'boolean',
            description: 'Whether to take a screenshot of the full page or just the viewport (default: false)',
          },
        },
        required: ['url'],
      },
    },
  • Helper method in BrowserClient that performs the actual screenshot by POSTing to Cloudflare Browser Rendering API /screenshot endpoint and returns the image URL.
    async takeScreenshot(url: string, options: {
      width?: number;
      height?: number;
      fullPage?: boolean;
      waitUntil?: string;
      timeout?: number;
    } = {}): Promise<string> {
      try {
        console.error(`[API] Taking screenshot of: ${url}`);
        
        // Validate URL before sending
        try {
          new URL(url); // Will throw if URL is invalid
        } catch (e) {
          throw new Error(`Invalid URL provided: ${url}`);
        }
        
        // Add timeout for the request
        const requestTimeout = options.timeout || 30000;
        
        // Make the API call to the Cloudflare Worker with timeout
        const response = await axios.post(`${this.apiEndpoint}/screenshot`, {
          url,
          width: options.width || 1280,
          height: options.height || 800,
          fullPage: options.fullPage || false,
          waitUntil: options.waitUntil || 'networkidle0',
          timeout: requestTimeout,
        }, {
          timeout: requestTimeout + 5000, // Add 5 seconds to the request timeout
        });
        
        // Check if the response has the expected structure with a URL
        if (response.data && response.data.url) {
          // Validate the returned URL
          try {
            new URL(response.data.url);
            return response.data.url;
          } catch (e) {
            throw new Error(`Invalid screenshot URL returned: ${response.data.url}`);
          }
        }
        
        // If we can't find the URL, log the response and throw an error
        console.error('[Error] Unexpected response structure:', JSON.stringify(response.data, null, 2));
        throw new Error('Screenshot URL not found in Cloudflare Worker response');
      } catch (error: any) {
        console.error('[Error] Error taking screenshot:', error);
        
        // If API is unavailable, throw an error
        if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND' || !process.env.BROWSER_RENDERING_API) {
          console.error('[Error] Cloudflare worker API is unavailable or not configured');
          throw new Error('Cloudflare worker API is unavailable or not configured. Please check your BROWSER_RENDERING_API environment variable.');
        }
        
        // Handle timeout errors specifically
        if (error.code === 'ETIMEDOUT' || error.code === 'ESOCKETTIMEDOUT' || error.message?.includes('timeout')) {
          throw new Error(`Screenshot request timed out for URL: ${url}. Try increasing the timeout value.`);
        }
        
        // Log more detailed error information if available
        if (error.response) {
          console.error('[Error] Response status:', error.response.status);
          console.error('[Error] Response data:', JSON.stringify(error.response.data, null, 2));
        }
        
        throw new Error(`Failed to take screenshot: ${error instanceof Error ? error.message : String(error)}`);
      }
    }
Behavior2/5

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

With no annotations provided, the description carries the full burden but lacks behavioral details. It doesn't disclose potential issues like authentication needs for restricted pages, rate limits, performance impacts, or what happens with invalid URLs. The phrase 'returns it as an image' hints at output but doesn't specify format (e.g., PNG, JPEG) or handling of errors.

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 a single, efficient sentence that front-loads the core purpose. Every word earns its place, with no redundant or vague phrasing. It's appropriately sized for a straightforward tool.

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

Completeness2/5

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

Given the tool's complexity (capturing web pages with 4 parameters) and lack of annotations or output schema, the description is incomplete. It doesn't cover error cases, output format details, or prerequisites (e.g., network access). For a tool that interacts with external resources and returns binary data, more context is needed.

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

Parameters3/5

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

The description adds no parameter-specific information beyond what's in the schema, which has 100% coverage. It doesn't explain interactions between parameters (e.g., how 'fullPage' affects 'height'/'width') or provide usage examples. Since schema coverage is high, the baseline is 3, but no extra value is added.

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 action ('takes a screenshot') and resource ('of a web page'), with the specific output format ('returns it as an image'). It distinguishes from sibling tools like 'fetch_page' (which likely retrieves HTML) and 'extract_structured_content' (which processes content rather than capturing visuals).

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

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus alternatives. It doesn't mention scenarios like needing visual verification, capturing dynamic content, or comparing with text-based tools like 'summarize_content' or 'fetch_page'. The description only states what it does, not when it's appropriate.

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

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/amotivv/cloudflare-browser-rendering-mcp'

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