Skip to main content
Glama

MCP Xcode

by Stefan-Nitu
SimulatorLocatorAdapter.ts3.64 kB
import { ISimulatorLocator, SimulatorInfo } from '../../../application/ports/SimulatorPorts.js'; import { ICommandExecutor } from '../../../application/ports/CommandPorts.js'; import { SimulatorState } from '../domain/SimulatorState.js'; /** * Locates simulators using xcrun simctl */ export class SimulatorLocatorAdapter implements ISimulatorLocator { constructor(private executor: ICommandExecutor) {} async findSimulator(idOrName: string): Promise<SimulatorInfo | null> { const result = await this.executor.execute('xcrun simctl list devices --json'); const data = JSON.parse(result.stdout); const allMatches: Array<{ device: any; runtime: string; }> = []; for (const [runtime, deviceList] of Object.entries(data.devices)) { for (const device of deviceList as any[]) { if ((device.udid === idOrName || device.name === idOrName) && device.isAvailable) { allMatches.push({ device, runtime }); } } } if (allMatches.length === 0) { return null; } // Sort by: booted first, then newer runtime allMatches.sort((a, b) => { // Booted devices first if (a.device.state === SimulatorState.Booted && b.device.state !== SimulatorState.Booted) return -1; if (b.device.state === SimulatorState.Booted && a.device.state !== SimulatorState.Booted) return 1; // Then by runtime version (newer first) return this.compareRuntimeVersions(b.runtime, a.runtime); }); const selected = allMatches[0]; return { id: selected.device.udid, name: selected.device.name, state: SimulatorState.parse(selected.device.state), platform: this.extractPlatform(selected.runtime), runtime: selected.runtime }; } async findBootedSimulator(): Promise<SimulatorInfo | null> { const result = await this.executor.execute('xcrun simctl list devices --json'); const data = JSON.parse(result.stdout); const bootedDevices: SimulatorInfo[] = []; for (const [runtime, deviceList] of Object.entries(data.devices)) { for (const device of deviceList as any[]) { if (device.state === SimulatorState.Booted && device.isAvailable) { bootedDevices.push({ id: device.udid, name: device.name, state: SimulatorState.Booted, platform: this.extractPlatform(runtime), runtime: runtime }); } } } if (bootedDevices.length === 0) { return null; } if (bootedDevices.length > 1) { throw new Error(`Multiple booted simulators found (${bootedDevices.length}). Please specify a simulator ID.`); } return bootedDevices[0]; } private extractPlatform(runtime: string): string { const runtimeLower = runtime.toLowerCase(); if (runtimeLower.includes('ios')) return 'iOS'; if (runtimeLower.includes('tvos')) return 'tvOS'; if (runtimeLower.includes('watchos')) return 'watchOS'; if (runtimeLower.includes('xros') || runtimeLower.includes('visionos')) return 'visionOS'; return 'iOS'; } private compareRuntimeVersions(runtimeA: string, runtimeB: string): number { const extractVersion = (runtime: string): number[] => { const match = runtime.match(/(\d+)-(\d+)/); if (!match) return [0, 0]; return [parseInt(match[1]), parseInt(match[2])]; }; const [majorA, minorA] = extractVersion(runtimeA); const [majorB, minorB] = extractVersion(runtimeB); if (majorA !== majorB) return majorA - majorB; return minorA - minorB; } }

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/Stefan-Nitu/mcp-xcode'

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