capture-screenshot
Capture a screenshot of a webpage or specific element, store it in the MCP resource system, and return a resource URI. Optionally include a base64 encoded image in the response.
Instructions
Captures a screenshot of the current page or a specific element. Stores the screenshot in the MCP resource system and returns a resource URI. If ENABLE_BASE64 environment variable is set to 'true', also includes base64 encoded image in the response.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| selector | No | CSS selector to capture (captures full page if not provided) | |
| url | No | URL to navigate to before capturing screenshot. Do not provide if you want to capture the current page. |
Implementation Reference
- src/tools/browser-tools.ts:147-287 (handler)Main execution logic for capture-screenshot tool: retrieves browser context, optionally navigates, captures screenshot (full page or element), saves via screenshotHelpers, returns resource URI and optional base64 image.async ({ selector, url, contextId }) => { try { // Get browser for operation const browserStatus = getContextForOperation(contextId); if (!browserStatus.isStarted) { return browserStatus.error; } // Get current URL const currentUrl = browserStatus.page.url(); // If URL is provided and different from current URL, navigate to it if (url && url !== currentUrl) { Logger.info(`Navigating to ${url} before capturing screenshot`); await browserStatus.page.goto(url, { waitUntil: 'networkidle' }); } // Get current checkpoint ID const checkpointId = await getCurrentCheckpointId(browserStatus.page); let screenshot: Buffer; if (selector) { // Wait for element to appear await browserStatus.page.waitForSelector(selector, { state: 'visible', timeout: 5000 }); const element = await browserStatus.page.locator(selector).first(); if (!element) { return { content: [ { type: 'text', text: `Element with selector "${selector}" not found` } ], isError: true }; } screenshot = await element.screenshot(); } else { // Capture full page screenshot = await browserStatus.page.screenshot({ fullPage: true }); } // Get final URL (may be different after navigation) const finalUrl = browserStatus.page.url(); // Use screenshot helpers if available if (!screenshotHelpers) { return { content: [ { type: 'text', text: 'Screenshot helpers not available. Cannot save screenshot.' } ], isError: true }; } // Add screenshot using the resource system const description = selector ? `Screenshot of element ${selector} at ${finalUrl}` : `Screenshot of full page at ${finalUrl}`; // Get browser context from the actual browser instance let browserContext = {}; if (contextId) { const contextInstance = contextManager.getContext(contextId); if (contextInstance) { browserContext = { browser_id: contextInstance.id, browser_type: contextInstance.type, session_id: `${contextInstance.id}-${contextInstance.createdAt.getTime()}` }; } } else { const contextInstance = contextManager.getMostRecentContext(); if (contextInstance) { browserContext = { browser_id: contextInstance.id, browser_type: contextInstance.type, session_id: `${contextInstance.id}-${contextInstance.createdAt.getTime()}` }; } } const screenshotResult = await screenshotHelpers.addScreenshot( screenshot, description, checkpointId, finalUrl.replace(/^http(s)?:\/\//, ''), browserContext ); Logger.info(`Screenshot saved with ID: ${screenshotResult.id}, URI: ${screenshotResult.resourceUri}`); // Result message construction const resultMessage = { message: 'Screenshot captured successfully', id: screenshotResult.id, resourceUri: screenshotResult.resourceUri, checkpointId, url: finalUrl, }; // Build content array const content: Array<{ type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string }> = [ { type: 'text' as const, text: JSON.stringify(resultMessage, null, 2) } ]; // Add base64 image only if ENABLE_BASE64 is true if (ENABLE_BASE64) { content.push({ type: 'image' as const, data: screenshot.toString('base64'), mimeType: 'image/png' }); } return { content }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); Logger.error(`Failed to capture screenshot: ${errorMessage}`); return { content: [ { type: 'text', text: `Failed to capture screenshot: ${errorMessage}` } ], isError: true }; } }
- src/tools/browser-tools.ts:137-288 (registration)Registration of the 'capture-screenshot' tool using server.tool(), including description, input schema with Zod, and handler reference.server.tool( 'capture-screenshot', `Captures a screenshot of the current page or a specific element. Stores the screenshot in the MCP resource system and returns a resource URI. If ENABLE_BASE64 environment variable is set to 'true', also includes base64 encoded image in the response.`, { selector: z.string().optional().describe('CSS selector to capture (captures full page if not provided)'), url: z.string().optional().describe('URL to navigate to before capturing screenshot. Do not provide if you want to capture the current page.'), contextId: z.string().optional().describe('Browser ID to capture from (uses most recent browser if not provided)') }, async ({ selector, url, contextId }) => { try { // Get browser for operation const browserStatus = getContextForOperation(contextId); if (!browserStatus.isStarted) { return browserStatus.error; } // Get current URL const currentUrl = browserStatus.page.url(); // If URL is provided and different from current URL, navigate to it if (url && url !== currentUrl) { Logger.info(`Navigating to ${url} before capturing screenshot`); await browserStatus.page.goto(url, { waitUntil: 'networkidle' }); } // Get current checkpoint ID const checkpointId = await getCurrentCheckpointId(browserStatus.page); let screenshot: Buffer; if (selector) { // Wait for element to appear await browserStatus.page.waitForSelector(selector, { state: 'visible', timeout: 5000 }); const element = await browserStatus.page.locator(selector).first(); if (!element) { return { content: [ { type: 'text', text: `Element with selector "${selector}" not found` } ], isError: true }; } screenshot = await element.screenshot(); } else { // Capture full page screenshot = await browserStatus.page.screenshot({ fullPage: true }); } // Get final URL (may be different after navigation) const finalUrl = browserStatus.page.url(); // Use screenshot helpers if available if (!screenshotHelpers) { return { content: [ { type: 'text', text: 'Screenshot helpers not available. Cannot save screenshot.' } ], isError: true }; } // Add screenshot using the resource system const description = selector ? `Screenshot of element ${selector} at ${finalUrl}` : `Screenshot of full page at ${finalUrl}`; // Get browser context from the actual browser instance let browserContext = {}; if (contextId) { const contextInstance = contextManager.getContext(contextId); if (contextInstance) { browserContext = { browser_id: contextInstance.id, browser_type: contextInstance.type, session_id: `${contextInstance.id}-${contextInstance.createdAt.getTime()}` }; } } else { const contextInstance = contextManager.getMostRecentContext(); if (contextInstance) { browserContext = { browser_id: contextInstance.id, browser_type: contextInstance.type, session_id: `${contextInstance.id}-${contextInstance.createdAt.getTime()}` }; } } const screenshotResult = await screenshotHelpers.addScreenshot( screenshot, description, checkpointId, finalUrl.replace(/^http(s)?:\/\//, ''), browserContext ); Logger.info(`Screenshot saved with ID: ${screenshotResult.id}, URI: ${screenshotResult.resourceUri}`); // Result message construction const resultMessage = { message: 'Screenshot captured successfully', id: screenshotResult.id, resourceUri: screenshotResult.resourceUri, checkpointId, url: finalUrl, }; // Build content array const content: Array<{ type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string }> = [ { type: 'text' as const, text: JSON.stringify(resultMessage, null, 2) } ]; // Add base64 image only if ENABLE_BASE64 is true if (ENABLE_BASE64) { content.push({ type: 'image' as const, data: screenshot.toString('base64'), mimeType: 'image/png' }); } return { content }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); Logger.error(`Failed to capture screenshot: ${errorMessage}`); return { content: [ { type: 'text', text: `Failed to capture screenshot: ${errorMessage}` } ], isError: true }; } } );
- src/tools/browser-tools.ts:143-146 (schema)Input schema validation using Zod for selector (optional CSS), url (optional navigation), contextId (optional browser ID).selector: z.string().optional().describe('CSS selector to capture (captures full page if not provided)'), url: z.string().optional().describe('URL to navigate to before capturing screenshot. Do not provide if you want to capture the current page.'), contextId: z.string().optional().describe('Browser ID to capture from (uses most recent browser if not provided)') },
- src/resources/screenshot.ts:264-336 (helper)Key helper function addScreenshot called by the tool handler to persist screenshot to filesystem and database, generating resource URI used in response.addScreenshot: async ( imageData: string | Buffer, description: string, checkpointId: string | null = null, url?: string, browserContext?: { browser_id?: string; browser_type?: string; session_id?: string } ): Promise<{ id: string; resourceUri: string }> => { const id = randomUUID(); // Create filename and save const filename = `${id}.png`; const filePath = path.join(SCREENSHOTS_DIRECTORY, filename); // Save data to file if (typeof imageData === 'string') { // Convert base64 string if needed await fs.writeFile(filePath, Buffer.from(imageData, 'base64')); } else { // Save Buffer directly await fs.writeFile(filePath, imageData); } Logger.info(`External screenshot saved to file: ${filePath}`); // Save to database let resourceUri: string; if (url) { const parsed = db.parseUrl(url); Logger.info(`[addScreenshot] Saving screenshot with URL: ${url}`); Logger.info(`[addScreenshot] Parsed - hostname: ${parsed.hostname}, pathname: ${parsed.pathname}`); db.insert({ id, hostname: parsed.hostname, pathname: parsed.pathname, query: parsed.query || null, hash: parsed.hash || null, checkpoint_id: checkpointId, timestamp: new Date(), mime_type: 'image/png', description, browser_id: browserContext?.browser_id, browser_type: browserContext?.browser_type, session_id: browserContext?.session_id }); Logger.info(`[addScreenshot] Screenshot saved to database with ID: ${id}`); // Return hostname/path based URI resourceUri = `screenshot://${parsed.hostname}${parsed.pathname}`; } else { // If no URL, save with empty hostname/pathname db.insert({ id, hostname: 'unknown', pathname: '/', query: null, hash: null, checkpoint_id: checkpointId, timestamp: new Date(), mime_type: 'image/png', description, browser_id: browserContext?.browser_id, browser_type: browserContext?.browser_type, session_id: browserContext?.session_id }); Logger.info(`Screenshot saved to database with ID: ${id} (no URL)`); // Return ID-based URI for unknown URLs resourceUri = getScreenshotUri(id); } return { id, resourceUri }; },
- src/index.ts:87-92 (registration)Top-level call to registerBrowserTools which internally registers the capture-screenshot tool along with other browser tools.registerBrowserTools( server, contextManager, lastHMREvents, screenshotHelpers );