Skip to main content
Glama

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
NameRequiredDescriptionDefault
udidYesSimulator UDID
pathYesAbsolute path to save screenshot

Implementation Reference

  • The main handler function for the ios_take_screenshot tool. It validates inputs using Zod schema, performs security checks on the output path, executes the 'xcrun simctl io screenshot' command, verifies the screenshot file was created, and returns structured success data including file size.
    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, }, }; }
  • JSON Schema definition for the tool's input parameters as required by the MCP protocol: udid (required string) and path (required string).
    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'] },
  • Registration of the ios_take_screenshot tool within the createIOSTools factory function, adding it to the tools Map with name, description, inputSchema, and 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, }, }; } });
  • Internal Zod schema used by the handler for runtime input validation.
    const IosSimulatorScreenshotSchema = z.object({ udid: z.string().min(1), path: z.string().min(1), });

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/cristianoaredes/mcp-mobile-server'

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