ios_take_screenshot
Capture screenshots from iOS simulators by specifying device UDID and save path for development testing and debugging workflows.
Instructions
Take a screenshot of an iOS simulator
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| udid | Yes | Simulator UDID | |
| path | Yes | Absolute path to save screenshot |
Implementation Reference
- src/tools/ios.ts:540-607 (handler)Handler function that validates inputs, performs security and path checks, executes xcrun simctl to take screenshot, verifies file creation, and returns structured result.handler: async (args: any) => { checkMacOS(); const validation = IosSimulatorScreenshotSchema.safeParse(args); if (!validation.success) { throw new Error(`Invalid request: ${validation.error.message}`); } const { udid, path: screenshotPath } = validation.data; // Validate UDID format if (!validateUDID(udid)) { throw new Error(`Invalid simulator UDID format. UDID must be in format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX: ${udid}`); } // Validate screenshot path - must be absolute and not contain dangerous patterns if (!path.isAbsolute(screenshotPath)) { throw new Error(`Screenshot path must be absolute. Path must start with /: ${screenshotPath}`); } // Security check - prevent path traversal and access to sensitive directories const normalizedPath = path.normalize(screenshotPath); const dangerousPaths = ['/etc', '/usr', '/System', '/private', '/var']; if (dangerousPaths.some(dangerous => normalizedPath.startsWith(dangerous))) { throw new Error(`Access to this path is not allowed. Path access denied for security reasons: ${normalizedPath}`); } // Ensure file has image extension const allowedExtensions = ['.png', '.jpg', '.jpeg']; const extension = path.extname(screenshotPath).toLowerCase(); if (!allowedExtensions.includes(extension)) { throw new Error(`Screenshot file must have image extension. Allowed extensions: ${allowedExtensions.join(', ')}. Got: ${extension}`); } // Create directory if it doesn't exist const directory = path.dirname(screenshotPath); try { await fs.mkdir(directory, { recursive: true }); } catch (mkdirError) { throw new Error(`Failed to create screenshot directory: ${mkdirError}`); } const result = await processExecutor.execute('xcrun', ['simctl', 'io', udid, 'screenshot', screenshotPath]); if (result.exitCode !== 0) { throw new Error(`Failed to capture screenshot: ${result.stderr}`); } // Verify screenshot was created let fileStats; try { fileStats = await fs.stat(screenshotPath); } catch { throw new Error(`Screenshot file was not created. Expected file: ${screenshotPath}`); } return { success: true, data: { udid, screenshotPath, fileSize: fileStats.size, status: 'captured', message: 'Screenshot captured successfully', output: result.stdout, }, }; }
- src/tools/ios.ts:70-79 (schema)Zod schema used for input validation in the handler, defining udid and path parameters.* Zod validation schema for ios_simulator_screenshot tool. * * @type {z.ZodObject} * @property {string} udid - Simulator UDID * @property {string} path - Output file path for screenshot */ const IosSimulatorScreenshotSchema = z.object({ udid: z.string().min(1), path: z.string().min(1), });
- src/tools/ios.ts:529-608 (registration)Registration of the tool in the createIOSTools function, including name, description, inputSchema (JSON schema for MCP), and reference to handler.tools.set('ios_take_screenshot', { name: 'ios_take_screenshot', description: 'Take a screenshot of an iOS simulator', inputSchema: { type: 'object', properties: { udid: { type: 'string', minLength: 1, description: 'Simulator UDID' }, path: { type: 'string', minLength: 1, description: 'Absolute path to save screenshot' } }, required: ['udid', 'path'] }, handler: async (args: any) => { checkMacOS(); const validation = IosSimulatorScreenshotSchema.safeParse(args); if (!validation.success) { throw new Error(`Invalid request: ${validation.error.message}`); } const { udid, path: screenshotPath } = validation.data; // Validate UDID format if (!validateUDID(udid)) { throw new Error(`Invalid simulator UDID format. UDID must be in format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX: ${udid}`); } // Validate screenshot path - must be absolute and not contain dangerous patterns if (!path.isAbsolute(screenshotPath)) { throw new Error(`Screenshot path must be absolute. Path must start with /: ${screenshotPath}`); } // Security check - prevent path traversal and access to sensitive directories const normalizedPath = path.normalize(screenshotPath); const dangerousPaths = ['/etc', '/usr', '/System', '/private', '/var']; if (dangerousPaths.some(dangerous => normalizedPath.startsWith(dangerous))) { throw new Error(`Access to this path is not allowed. Path access denied for security reasons: ${normalizedPath}`); } // Ensure file has image extension const allowedExtensions = ['.png', '.jpg', '.jpeg']; const extension = path.extname(screenshotPath).toLowerCase(); if (!allowedExtensions.includes(extension)) { throw new Error(`Screenshot file must have image extension. Allowed extensions: ${allowedExtensions.join(', ')}. Got: ${extension}`); } // Create directory if it doesn't exist const directory = path.dirname(screenshotPath); try { await fs.mkdir(directory, { recursive: true }); } catch (mkdirError) { throw new Error(`Failed to create screenshot directory: ${mkdirError}`); } const result = await processExecutor.execute('xcrun', ['simctl', 'io', udid, 'screenshot', screenshotPath]); if (result.exitCode !== 0) { throw new Error(`Failed to capture screenshot: ${result.stderr}`); } // Verify screenshot was created let fileStats; try { fileStats = await fs.stat(screenshotPath); } catch { throw new Error(`Screenshot file was not created. Expected file: ${screenshotPath}`); } return { success: true, data: { udid, screenshotPath, fileSize: fileStats.size, status: 'captured', message: 'Screenshot captured successfully', output: result.stdout, }, }; } });
- src/tools/ios.ts:159-162 (helper)Helper function to validate UDID format, used in the handler.const validateUDID = (udid: string): boolean => { const uuidPattern = /^[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}$/i; return uuidPattern.test(udid); };
- src/tools/ios.ts:140-144 (helper)Helper function to ensure running on macOS, called at start of handler.const checkMacOS = (): void => { if (process.platform !== 'darwin') { throw new Error(`iOS development tools only work on macOS. Current platform: ${process.platform}`); } };