screenshot
Capture screenshots on the sl-test MCP server for visual verification tasks. Ensure accurate UI testing without relying on screenshots for coordinate determination.
Instructions
Captures screenshot for visual verification. For UI coordinates, use describe_ui instead (don't determine coordinates from screenshots).
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| simulatorUuid | Yes |
Implementation Reference
- src/tools/screenshot.ts:32-106 (handler)Handler function that takes simulatorUuid, runs xcrun simctl io screenshot command, base64 encodes the PNG image, and returns it in the tool response content as image/png.async (params): Promise<ToolResponse> => { const toolName = 'screenshot'; const simUuidValidation = validateRequiredParam('simulatorUuid', params.simulatorUuid); if (!simUuidValidation.isValid) return simUuidValidation.errorResponse!; const { simulatorUuid } = params; const tempDir = os.tmpdir(); const screenshotFilename = `screenshot_${uuidv4()}.png`; const screenshotPath = path.join(tempDir, screenshotFilename); // Use xcrun simctl to take screenshot const commandArgs = ['xcrun', 'simctl', 'io', simulatorUuid, 'screenshot', screenshotPath]; log( 'info', `${LOG_PREFIX}/${toolName}: Starting capture to ${screenshotPath} on ${simulatorUuid}`, ); try { // Execute the screenshot command const result = await executeCommand(commandArgs, `${LOG_PREFIX}: screenshot`, false); if (!result.success) { throw new SystemError(`Failed to capture screenshot: ${result.error || result.output}`); } log('info', `${LOG_PREFIX}/${toolName}: Success for ${simulatorUuid}`); try { // Read the image file into memory const imageBuffer = await fs.readFile(screenshotPath); // Encode the image as a Base64 string const base64Image = imageBuffer.toString('base64'); log('info', `${LOG_PREFIX}/${toolName}: Successfully encoded image as Base64`); // Clean up the temporary file await fs.unlink(screenshotPath).catch((err) => { log('warning', `${LOG_PREFIX}/${toolName}: Failed to delete temporary file: ${err}`); }); // Return the image directly in the tool response return { content: [ { type: 'image', data: base64Image, mimeType: 'image/png', }, ], }; } catch (fileError) { log('error', `${LOG_PREFIX}/${toolName}: Failed to process image file: ${fileError}`); return createErrorResponse( `Screenshot captured but failed to process image file: ${fileError instanceof Error ? fileError.message : String(fileError)}`, undefined, 'FileProcessingError', ); } } catch (_error) { log('error', `${LOG_PREFIX}/${toolName}: Failed - ${_error}`); if (_error instanceof SystemError) { return createErrorResponse( `System error executing screenshot: ${_error.message}`, _error.originalError?.stack, _error.name, ); } return createErrorResponse( `An unexpected error occurred: ${_error instanceof Error ? _error.message : String(_error)}`, undefined, 'UnexpectedError', ); } },
- src/tools/screenshot.ts:29-31 (schema)Input schema using Zod: requires simulatorUuid as a valid UUID string.{ simulatorUuid: z.string().uuid('Invalid Simulator UUID format'), },
- src/tools/screenshot.ts:25-108 (registration)Local registration of the 'screenshot' tool with McpServer using server.tool(), including name, description, input schema, and handler.export function registerScreenshotTool(server: McpServer): void { server.tool( 'screenshot', "Captures screenshot for visual verification. For UI coordinates, use describe_ui instead (don't determine coordinates from screenshots).", { simulatorUuid: z.string().uuid('Invalid Simulator UUID format'), }, async (params): Promise<ToolResponse> => { const toolName = 'screenshot'; const simUuidValidation = validateRequiredParam('simulatorUuid', params.simulatorUuid); if (!simUuidValidation.isValid) return simUuidValidation.errorResponse!; const { simulatorUuid } = params; const tempDir = os.tmpdir(); const screenshotFilename = `screenshot_${uuidv4()}.png`; const screenshotPath = path.join(tempDir, screenshotFilename); // Use xcrun simctl to take screenshot const commandArgs = ['xcrun', 'simctl', 'io', simulatorUuid, 'screenshot', screenshotPath]; log( 'info', `${LOG_PREFIX}/${toolName}: Starting capture to ${screenshotPath} on ${simulatorUuid}`, ); try { // Execute the screenshot command const result = await executeCommand(commandArgs, `${LOG_PREFIX}: screenshot`, false); if (!result.success) { throw new SystemError(`Failed to capture screenshot: ${result.error || result.output}`); } log('info', `${LOG_PREFIX}/${toolName}: Success for ${simulatorUuid}`); try { // Read the image file into memory const imageBuffer = await fs.readFile(screenshotPath); // Encode the image as a Base64 string const base64Image = imageBuffer.toString('base64'); log('info', `${LOG_PREFIX}/${toolName}: Successfully encoded image as Base64`); // Clean up the temporary file await fs.unlink(screenshotPath).catch((err) => { log('warning', `${LOG_PREFIX}/${toolName}: Failed to delete temporary file: ${err}`); }); // Return the image directly in the tool response return { content: [ { type: 'image', data: base64Image, mimeType: 'image/png', }, ], }; } catch (fileError) { log('error', `${LOG_PREFIX}/${toolName}: Failed to process image file: ${fileError}`); return createErrorResponse( `Screenshot captured but failed to process image file: ${fileError instanceof Error ? fileError.message : String(fileError)}`, undefined, 'FileProcessingError', ); } } catch (_error) { log('error', `${LOG_PREFIX}/${toolName}: Failed - ${_error}`); if (_error instanceof SystemError) { return createErrorResponse( `System error executing screenshot: ${_error.message}`, _error.originalError?.stack, _error.name, ); } return createErrorResponse( `An unexpected error occurred: ${_error instanceof Error ? _error.message : String(_error)}`, undefined, 'UnexpectedError', ); } }, ); }
- src/utils/register-tools.ts:421-424 (registration)Central tool registration configuration in registerTools(), which calls the module's registerScreenshotTool if enabled via env var.register: registerScreenshotTool, groups: [ToolGroup.IOS_SIMULATOR_WORKFLOW, ToolGroup.UI_TESTING], envVar: 'XCODEBUILDMCP_TOOL_SCREENSHOT', },