Skip to main content
Glama

XC-MCP: XCode CLI wrapper

by conorluddy
boot.ts8.19 kB
import { validateDeviceId } from '../../utils/validation.js'; import { executeCommand, buildSimctlCommand } from '../../utils/command.js'; // Removed unused import import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'; import { simulatorCache } from '../../state/simulator-cache.js'; interface SimctlBootToolArgs { deviceId: string; waitForBoot?: boolean; openGui?: boolean; } /** * Boot iOS simulator device with intelligent performance tracking and learning * * **What it does:** * Boots an iOS simulator device and optionally waits for complete boot. Tracks performance * metrics and learns from successful configurations for future recommendations. * * **Why you'd use it:** * - 📊 Performance tracking - Records boot times for optimization insights * - 🧠 Learning system - Remembers which devices are fastest * - 🎯 Smart recommendations - Future boots suggest fastest devices * - 🛡️ Better error handling - Clear feedback vs cryptic xcrun errors * - ⏱️ Wait management - Intelligent waiting vs guessing when boot is done * * **Parameters:** * - `deviceId` (string): Device UDID from simctl-list, "booted" for current, or "all" * - `waitForBoot` (boolean, default: true): Wait for device to finish booting completely * - `openGui` (boolean, default: true): Open Simulator.app GUI (visual feedback) * * **Returns:** * Boot status with device info, boot time metrics, and next step guidance * * **Example:** * ```typescript * // Boot with defaults (wait + GUI) * await simctlBootTool({ deviceId: 'ABC-123-DEF' }) * * // Quick boot without GUI * await simctlBootTool({ deviceId: 'ABC-123-DEF', waitForBoot: false, openGui: false }) * ``` * * **Device Support:** * - Simulators: Full support ✅ * - Physical devices: N/A * * **Full documentation:** See simctl/boot.md for detailed parameters and examples * * @param args Boot configuration (requires deviceId) * @returns Boot result with status, metrics, and guidance * @throws McpError for invalid device ID or boot failure */ 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)}` ); } } 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`); } export const SIMCTL_BOOT_DOCS = ` # simctl-boot ⚡ **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. ## Parameters ### Required - \`deviceId\` (string): Device UDID (from simctl-list) or "booted" for any currently booted device ### Optional - \`waitForBoot\` (boolean, default: true): Wait for device to finish booting completely - \`openGui\` (boolean, default: true): Open Simulator.app GUI automatically ## Returns Success response includes: - Boot status (success/failure) - Device information - Boot time in milliseconds - Performance metrics - Guidance for next steps ## Examples ### Boot a specific device \`\`\`json { "deviceId": "ABC123DEF-GHIJ-KLMN-OPQR-STUVWXYZ1234", "waitForBoot": true } \`\`\` ### Boot any available device quickly \`\`\`json { "deviceId": "booted", "waitForBoot": false, "openGui": false } \`\`\` ## Related Tools - \`simctl-list\` - Discover available simulators and their UDIDs - \`simctl-suggest\` - Get intelligent device recommendations based on history - \`simctl-shutdown\` - Shut down booted devices - \`simctl-health-check\` - Verify simulator environment health ## Device Support - **Simulators:** Full support ✅ - **Physical Devices:** Not applicable (devices don't have simctl boot) ## Notes - Handles "already booted" case gracefully (treats as success) - Tracks boot performance for future optimization recommendations - First boot of a device type may take longer than subsequent boots - Opening GUI with \`openGui: true\` provides visual feedback but increases boot time slightly `;

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/conorluddy/xc-mcp'

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