simctl-boot
Improve iOS simulator boot efficiency by tracking boot times, optimizing device selection, and avoiding errors. Provides automatic performance metrics and intelligent device recommendations for faster, reliable builds.
Instructions
⚡ Prefer this over 'xcrun simctl boot' - Intelligent boot with performance tracking and learning.
Advantages over direct CLI: • 📊 Performance tracking - Records boot times for optimization insights • 🧠 Learning system - Tracks which devices work best for your projects • 🎯 Smart recommendations - Future builds suggest fastest/most reliable devices • 🛡️ Better error handling - Clear feedback vs cryptic CLI errors • ⏱️ Wait management - Intelligent waiting for complete boot vs guessing
Automatically tracks boot times and device performance metrics for optimization. Records usage patterns for intelligent device suggestions in future builds.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| deviceId | Yes | Device UDID (from simctl-list) or "booted" for any currently booted device | |
| waitForBoot | No | Wait for device to finish booting completely |
Implementation Reference
- src/tools/simctl/boot.ts:54-148 (handler)The primary handler function `simctlBootTool` that implements the core logic for booting iOS simulators, including command execution, status checking, waiting for boot completion, performance tracking, GUI launching, and error handling.export async function simctlBootTool(args: any) { const { deviceId, waitForBoot = true, openGui = true } = args as SimctlBootToolArgs; try { // Validate inputs validateDeviceId(deviceId); // Build boot command const bootCommand = buildSimctlCommand('boot', { deviceId }); console.error(`[simctl-boot] Executing: ${bootCommand}`); // Execute boot command const startTime = Date.now(); const bootResult = await executeCommand(bootCommand, { timeout: 120000, // 2 minutes for boot }); let bootStatus = { success: bootResult.code === 0, command: bootCommand, output: bootResult.stdout, error: bootResult.stderr, exitCode: bootResult.code, bootTime: Date.now() - startTime, }; // If boot failed due to device already being booted, that's actually OK if ( !bootStatus.success && bootResult.stderr.includes('Unable to boot device in current state: Booted') ) { bootStatus = { ...bootStatus, success: true, error: 'Device was already booted', }; } // Wait for boot to complete if requested if (waitForBoot && bootStatus.success) { try { await waitForDeviceBoot(deviceId); bootStatus.bootTime = Date.now() - startTime; } catch (waitError) { throw new McpError( ErrorCode.InternalError, `Device booted but failed to wait for completion: ${waitError}` ); } } // Record boot event and usage in cache if (bootStatus.success) { simulatorCache.recordBootEvent(deviceId, true, bootStatus.bootTime); // Also record usage with current working directory as project path simulatorCache.recordSimulatorUsage(deviceId, process.cwd()); // Open Simulator.app GUI if requested if (openGui) { try { await executeCommand('open -a Simulator', { timeout: 5000 }); console.error('[simctl-boot] Opened Simulator.app GUI'); } catch (openError) { // Non-fatal - simulator still booted successfully console.warn( '[simctl-boot] Failed to open Simulator GUI:', openError instanceof Error ? openError.message : String(openError) ); } } } // Format response const responseText = JSON.stringify(bootStatus, null, 2); return { content: [ { type: 'text' as const, text: responseText, }, ], isError: !bootStatus.success, }; } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `simctl-boot failed: ${error instanceof Error ? error.message : String(error)}` ); } }
- src/tools/simctl/boot.ts:7-11 (schema)TypeScript interface defining the input parameters for the simctl-boot tool.interface SimctlBootToolArgs { deviceId: string; waitForBoot?: boolean; openGui?: boolean; }
- src/tools/simctl/boot.ts:150-183 (helper)Helper function `waitForDeviceBoot` that polls the simulator status until fully booted or timeout.async function waitForDeviceBoot(deviceId: string, timeoutMs = 120000): Promise<void> { const startTime = Date.now(); const pollInterval = 2000; // Poll every 2 seconds while (Date.now() - startTime < timeoutMs) { try { // Check device status const statusCommand = `xcrun simctl list devices -j`; const result = await executeCommand(statusCommand); if (result.code === 0) { const deviceList = JSON.parse(result.stdout); // Find the device in the list for (const devices of Object.values(deviceList.devices)) { const deviceArray = devices as any[]; const device = deviceArray.find(d => d.udid === deviceId); if (device && device.state === 'Booted') { return; // Device is fully booted } } } // Wait before next poll await new Promise(resolve => setTimeout(resolve, pollInterval)); } catch { // Continue polling on errors await new Promise(resolve => setTimeout(resolve, pollInterval)); } } throw new Error(`Device ${deviceId} did not boot within ${timeoutMs}ms`); }
- src/tools/simctl/device/index.ts:2-83 (registration)Router in consolidated `simctl-device` tool that imports and invokes `simctlBootTool` for 'boot' operation, providing backwards compatibility.import { simctlBootTool } from '../boot.js'; import { simctlShutdownTool } from '../shutdown.js'; import { simctlCreateTool } from '../create.js'; import { simctlDeleteTool } from '../delete.js'; import { simctlEraseTool } from '../erase.js'; import { simctlCloneTool } from '../clone.js'; import { simctlRenameTool } from '../rename.js'; // ============================================================================ // TYPES & INTERFACES // ============================================================================ interface SimctlDeviceToolArgs { operation: 'boot' | 'shutdown' | 'create' | 'delete' | 'erase' | 'clone' | 'rename'; // Boot/Shutdown/Delete/Erase deviceId?: string; // Boot waitForBoot?: boolean; openGui?: boolean; // Create name?: string; deviceType?: string; runtime?: string; // Erase force?: boolean; // Clone/Rename newName?: string; } // ============================================================================ // PUBLIC API // ============================================================================ /** * Unified iOS simulator device management tool. * * Routes device operations (boot, shutdown, create, delete, erase, clone, rename) * to specialized handlers while maintaining modular code organization. * * @param args Device operation and parameters * @returns Tool result with operation status * @throws McpError for invalid operation or execution failure */ export async function simctlDeviceTool(args: any) { const typedArgs = args as SimctlDeviceToolArgs; try { return await routeOperation(typedArgs); } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `simctl-device failed: ${error instanceof Error ? error.message : String(error)}` ); } } // ============================================================================ // OPERATION ROUTING // ============================================================================ /** * Route device operation to appropriate handler based on operation type. * * Each operation type has its own validation and execution logic. * This router ensures consistent error handling and parameter passing. */ async function routeOperation(args: SimctlDeviceToolArgs) { const { operation } = args; switch (operation) { case 'boot': if (!args.deviceId) { throw new McpError(ErrorCode.InvalidRequest, 'deviceId is required for boot operation'); } return simctlBootTool({ deviceId: args.deviceId, waitForBoot: args.waitForBoot, openGui: args.openGui, });
- src/registry/simctl.ts:112-141 (registration)Registration of the consolidated `simctl-device` tool which handles 'simctl-boot' via operation='boot', including Zod input schema validation.server.registerTool( 'simctl-device', { description: getDescription(SIMCTL_DEVICE_DOCS, SIMCTL_DEVICE_DOCS_MINI), inputSchema: { operation: z.enum(['boot', 'shutdown', 'create', 'delete', 'erase', 'clone', 'rename']), deviceId: z.string().optional(), waitForBoot: z.boolean().default(true), openGui: z.boolean().default(true), name: z.string().optional(), deviceType: z.string().optional(), runtime: z.string().optional(), force: z.boolean().default(false), newName: z.string().optional(), }, ...DEFER_LOADING_CONFIG, }, async args => { try { await validateXcodeInstallation(); return await simctlDeviceTool(args); } catch (error) { if (error instanceof McpError) throw error; throw new McpError( ErrorCode.InternalError, `Tool execution failed: ${error instanceof Error ? error.message : String(error)}` ); } } );