Skip to main content
Glama
conorluddy

XC-MCP: XCode CLI wrapper

by conorluddy

simctl-get-details

Retrieve filtered simulator details from cached simctl-list data by specifying cache ID, detail type, device, runtime, or max devices. Optimizes Xcode CLI usage within MCP limits.

Instructions

Get detailed simulator information from cached simctl-list results with progressive disclosure

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
cacheIdYesCache ID from previous simctl-list call
detailTypeYesType of details to retrieve
deviceTypeNoFilter by device type (iPhone, iPad, etc.)
maxDevicesNoMaximum number of devices to return
runtimeNoFilter by runtime version

Implementation Reference

  • Primary handler function that processes arguments, validates cache, parses simulator data, dispatches to formatters based on detailType, and returns formatted JSON response.
    export async function simctlGetDetailsTool(args: any) {
      const {
        cacheId,
        detailType,
        deviceType,
        runtime,
        maxDevices = 20,
      } = args as SimctlGetDetailsArgs;
    
      try {
        const cached = responseCache.get(cacheId);
        if (!cached) {
          throw new McpError(
            ErrorCode.InvalidParams,
            `Cache ID '${cacheId}' not found or expired. Use recent simctl-list result.`
          );
        }
    
        if (cached.tool !== 'simctl-list') {
          throw new McpError(
            ErrorCode.InvalidParams,
            `Cache ID '${cacheId}' is not from simctl-list tool.`
          );
        }
    
        const fullList: CachedSimulatorList = JSON.parse(cached.fullOutput);
    
        let responseData: any;
    
        switch (detailType) {
          case 'full-list':
            responseData = formatFullList(fullList, { deviceType, runtime, maxDevices });
            break;
          case 'devices-only':
            responseData = formatDevicesOnly(fullList, { deviceType, runtime, maxDevices });
            break;
          case 'runtimes-only':
            responseData = formatRuntimesOnly(fullList);
            break;
          case 'available-only':
            responseData = formatAvailableOnly(fullList, { deviceType, runtime, maxDevices });
            break;
          default:
            throw new McpError(ErrorCode.InvalidParams, `Unknown detailType: ${detailType}`);
        }
    
        return {
          content: [
            {
              type: 'text' as const,
              text: JSON.stringify(responseData, null, 2),
            },
          ],
        };
      } catch (error) {
        if (error instanceof McpError) {
          throw error;
        }
        throw new McpError(
          ErrorCode.InternalError,
          `simctl-get-details failed: ${error instanceof Error ? error.message : String(error)}`
        );
      }
    }
  • Registers the 'simctl-get-details' tool with the MCP server in registerSimctlTools function, including schema, description, and error-handling wrapper around the handler.
    server.registerTool(
      'simctl-get-details',
      {
        description: getDescription(SIMCTL_GET_DETAILS_DOCS, SIMCTL_GET_DETAILS_DOCS_MINI),
        inputSchema: {
          cacheId: z.string(),
          detailType: z.enum(['full-list', 'devices-only', 'runtimes-only', 'available-only']),
          deviceType: z.string().optional(),
          runtime: z.string().optional(),
          maxDevices: z.number().default(20),
        },
        ...DEFER_LOADING_CONFIG,
      },
      async args => {
        try {
          await validateXcodeInstallation();
          return await simctlGetDetailsTool(args);
        } catch (error) {
          if (error instanceof McpError) throw error;
          throw new McpError(
            ErrorCode.InternalError,
            `Tool execution failed: ${error instanceof Error ? error.message : String(error)}`
          );
        }
      }
    );
  • Zod input schema defining validation for tool parameters: required cacheId and detailType, optional filters.
    inputSchema: {
      cacheId: z.string(),
      detailType: z.enum(['full-list', 'devices-only', 'runtimes-only', 'available-only']),
      deviceType: z.string().optional(),
      runtime: z.string().optional(),
      maxDevices: z.number().default(20),
    },
    ...DEFER_LOADING_CONFIG,
  • TypeScript interface for tool input arguments used in type casting within handler.
    interface SimctlGetDetailsArgs {
      cacheId: string;
      detailType: 'full-list' | 'devices-only' | 'runtimes-only' | 'available-only';
      deviceType?: string;
      runtime?: string;
      maxDevices?: number;
    }
  • Core helper function that applies deviceType and runtime filters to the full simulator list data.
    function applyFilters(
      fullList: CachedSimulatorList,
      filters: { deviceType?: string; runtime?: string; maxDevices?: number }
    ): CachedSimulatorList {
      const filtered: CachedSimulatorList = {
        devices: {},
        runtimes: fullList.runtimes,
        devicetypes: fullList.devicetypes,
        lastUpdated: fullList.lastUpdated,
        preferredByProject: fullList.preferredByProject,
      };
    
      // Filter device types if specified
      if (filters.deviceType) {
        filtered.devicetypes = fullList.devicetypes.filter(dt =>
          dt.name.toLowerCase().includes(filters.deviceType!.toLowerCase())
        );
      }
    
      // Filter runtimes if specified
      if (filters.runtime) {
        filtered.runtimes = fullList.runtimes.filter(
          rt =>
            rt.name.toLowerCase().includes(filters.runtime!.toLowerCase()) ||
            rt.version.includes(filters.runtime!)
        );
      }
    
      // Filter devices
      for (const [runtimeKey, devices] of Object.entries(fullList.devices)) {
        // Skip runtime if it doesn't match filter
        if (filters.runtime && !runtimeKey.toLowerCase().includes(filters.runtime.toLowerCase())) {
          continue;
        }
    
        const filteredDevices = devices.filter(device => {
          // Filter by device type
          if (
            filters.deviceType &&
            !device.name.toLowerCase().includes(filters.deviceType.toLowerCase())
          ) {
            return false;
          }
    
          return true;
        });
    
        if (filteredDevices.length > 0) {
          filtered.devices[runtimeKey] = filteredDevices;
        }
      }
    
      return filtered;
    }

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