Skip to main content
Glama
omgwtfwow

MCP Server for Crawl4AI

by omgwtfwow

capture_screenshot

Capture webpage screenshots as base64-encoded PNG images. Use this tool to visually document web content, wait for page loading, and optionally save screenshots to local directories for web analysis and documentation.

Instructions

[STATELESS] Capture webpage screenshot. Returns base64-encoded PNG data. Creates new browser each time. Optionally saves screenshot to local directory. IMPORTANT: Chained calls (execute_js then capture_screenshot) will NOT work - the screenshot won't see JS changes! For JS changes + screenshot use create_session + crawl(session_id, js_code, screenshot:true) in ONE call.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
save_to_directoryNoDirectory path to save screenshot (e.g., ~/Desktop, /tmp). Do NOT include filename - it will be auto-generated. Large screenshots (>800KB) won't be returned inline when saved.
screenshot_wait_forNoSeconds to wait before taking screenshot (allows page loading/animations)
urlYesThe URL to capture

Implementation Reference

  • Primary MCP handler for 'capture_screenshot' tool. Handles input validation response formatting, optional local file saving, size-based image return logic, and delegates core screenshot capture to service.
    async captureScreenshot(options: ScreenshotEndpointOptions) { try { const result: ScreenshotEndpointResponse = await this.service.captureScreenshot(options); // Response has { success: true, screenshot: "base64string" } if (!result.success || !result.screenshot) { throw new Error('Screenshot capture failed - no screenshot data in response'); } let savedFilePath: string | undefined; // Save to local directory if requested if (options.save_to_directory) { try { // Resolve home directory path let resolvedPath = options.save_to_directory; if (resolvedPath.startsWith('~')) { const homedir = os.homedir(); resolvedPath = path.join(homedir, resolvedPath.slice(1)); } // Check if user provided a file path instead of directory if (resolvedPath.endsWith('.png') || resolvedPath.endsWith('.jpg')) { console.warn( `Warning: save_to_directory should be a directory path, not a file path. Using parent directory.`, ); resolvedPath = path.dirname(resolvedPath); } // Ensure directory exists await fs.mkdir(resolvedPath, { recursive: true }); // Generate filename from URL and timestamp const url = new URL(options.url); const hostname = url.hostname.replace(/[^a-z0-9]/gi, '-'); const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5); const filename = `${hostname}-${timestamp}.png`; savedFilePath = path.join(resolvedPath, filename); // Convert base64 to buffer and save const buffer = Buffer.from(result.screenshot, 'base64'); await fs.writeFile(savedFilePath, buffer); } catch (saveError) { // Log error but don't fail the operation console.error('Failed to save screenshot locally:', saveError); } } const textContent = savedFilePath ? `Screenshot captured for: ${options.url}\nSaved to: ${savedFilePath}` : `Screenshot captured for: ${options.url}`; // If saved locally and screenshot is large (>800KB), don't return the base64 data const screenshotSize = Buffer.from(result.screenshot, 'base64').length; const shouldReturnImage = !savedFilePath || screenshotSize < 800 * 1024; // 800KB threshold const content = []; if (shouldReturnImage) { content.push({ type: 'image', data: result.screenshot, mimeType: 'image/png', }); } content.push({ type: 'text', text: shouldReturnImage ? textContent : `${textContent}\n\nNote: Screenshot data not returned due to size (${Math.round(screenshotSize / 1024)}KB). View the saved file instead.`, }); return { content }; } catch (error) { throw this.formatError(error, 'capture screenshot'); } }
  • Core service method that performs the actual HTTP POST request to Crawl4AI's /screenshot endpoint, returning base64 PNG data. Includes URL validation and error handling.
    async captureScreenshot(options: ScreenshotEndpointOptions): Promise<ScreenshotEndpointResponse> { // Validate URL if (!validateURL(options.url)) { throw new Error('Invalid URL format'); } try { const response = await this.axiosClient.post('/screenshot', { url: options.url, screenshot_wait_for: options.screenshot_wait_for, // output_path is omitted to get base64 response }); return response.data; } catch (error) { return handleAxiosError(error); } }
  • Zod schema for validating capture_screenshot tool inputs, using createStatelessSchema to reject session_id.
    export const CaptureScreenshotSchema = createStatelessSchema( z.object({ url: z.string().url(), screenshot_wait_for: z.number().optional(), save_to_directory: z.string().optional().describe('Local directory to save screenshot file'), // output_path not exposed as MCP needs base64 data }), 'capture_screenshot', );
  • src/server.ts:829-835 (registration)
    Server switch case registration mapping 'capture_screenshot' tool calls to the contentHandlers.captureScreenshot method with schema validation.
    case 'capture_screenshot': return await this.validateAndExecute( 'capture_screenshot', args, CaptureScreenshotSchema, async (validatedArgs) => this.contentHandlers.captureScreenshot(validatedArgs), );
  • src/server.ts:150-174 (registration)
    Tool registration in listTools response: defines name, description, and inputSchema for capture_screenshot.
    { name: 'capture_screenshot', description: "[STATELESS] Capture webpage screenshot. Returns base64-encoded PNG data. Creates new browser each time. Optionally saves screenshot to local directory. IMPORTANT: Chained calls (execute_js then capture_screenshot) will NOT work - the screenshot won't see JS changes! For JS changes + screenshot use create_session + crawl(session_id, js_code, screenshot:true) in ONE call.", inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'The URL to capture', }, screenshot_wait_for: { type: 'number', description: 'Seconds to wait before taking screenshot (allows page loading/animations)', default: 2, }, save_to_directory: { type: 'string', description: "Directory path to save screenshot (e.g., ~/Desktop, /tmp). Do NOT include filename - it will be auto-generated. Large screenshots (>800KB) won't be returned inline when saved.", }, }, required: ['url'], }, },

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/omgwtfwow/mcp-crawl4ai-ts'

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