Skip to main content
Glama

run_tests

Execute tests for the active Xcode project to verify code functionality and identify issues. Optionally specify a test plan to run specific test suites.

Instructions

Executes tests for the active Xcode project.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
testPlanNoOptional name of the test plan to run.

Implementation Reference

  • Main handler implementing the run_tests tool logic: runs xcodebuild tests with filtering options, captures and processes output, generates logs, test reports, and code coverage.
    private async runTests( projectPath: string, scheme: string, configuration: string = "Debug", testIdentifier?: string, skipTests?: string[], destination: string = "platform=iOS Simulator,name=iPhone 15 Pro" ): Promise<{ success: boolean; output: string; logPath: string }> { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const logPath = path.join(this.buildLogsDir, `test-${timestamp}.log`); const projectDir = path.dirname(projectPath); const reportsPath = path.join(projectDir, 'TestReports', `Reports-${timestamp}`); const xcresultPath = `${reportsPath}.xcresult`; try { await mkdir(path.join(projectDir, 'TestReports'), { recursive: true }); } catch (error) { console.error(`Failed to prepare test reports directory: ${error}`); } let testFlags = 'test'; if (testIdentifier) { testFlags += ` -only-testing:${testIdentifier}`; } if (skipTests?.length) { testFlags += ` ${skipTests.map(test => `-skip-testing:${test}`).join(' ')}`; } const command = `which xcodebuild && xcodebuild -project "${projectPath}" \ -scheme "${scheme}" \ -configuration "${configuration}" \ -destination '${destination}' \ -resultBundlePath "${xcresultPath}" \ -enableCodeCoverage YES \ -UseModernBuildSystem=YES \ -json \ clean ${testFlags} 2>&1 | tee ${logPath}`; try { const { stdout, stderr } = await execAsync(command, { maxBuffer: 100 * 1024 * 1024 }); try { const jsonOutput = stdout.split('\n') .filter(line => line.trim()) .map(line => { try { return JSON.parse(line); } catch (e) { return line; } }); await writeFile(logPath + '.json', JSON.stringify(jsonOutput, null, 2)); } catch (parseError) { console.error('Failed to parse JSON output:', parseError); } // Process test results using xcresulttool if (fs.existsSync(xcresultPath)) { try { // Get test summary const summaryCmd = `xcrun xcresulttool get --format json --path "${xcresultPath}"`; const { stdout: summaryOutput } = await execAsync(summaryCmd); await writeFile(path.join(this.buildLogsDir, `test-summary-${timestamp}.json`), summaryOutput); // Get code coverage if available const coverageOutput = await execAsync(`xcrun xccov view --report "${xcresultPath}"`); await writeFile(path.join(this.buildLogsDir, `coverage-${timestamp}.txt`), coverageOutput.stdout); } catch (resultsError) { console.error('Failed to process test results:', resultsError); } } const success = !stdout.includes('** TEST FAILED **') && !stdout.includes('** BUILD FAILED **'); return { success, output: stdout + stderr, logPath }; } catch (error) { console.error('Test error:', error); if (error instanceof Error) { const execError = error as { stderr?: string }; const errorOutput = error.message + (execError.stderr ? `\n${execError.stderr}` : ''); await writeFile(logPath, errorOutput); return { success: false, output: errorOutput, logPath }; } throw error; } }
  • src/index.ts:295-325 (registration)
    Registers the "run_tests" tool in the MCP ListToolsRequestSchema handler, defining its name, description, and JSON input schema.
    name: "run_tests", description: "Run Xcode project tests with optional filtering", inputSchema: { type: "object", properties: { projectPath: { type: "string", description: "Path to the .xcodeproj or .xcworkspace" }, scheme: { type: "string", description: "Test scheme name" }, testIdentifier: { type: "string", description: "Optional specific test to run (e.g., 'MyTests/testExample')" }, skipTests: { type: "array", items: { type: "string" }, description: "Optional array of test identifiers to skip" }, configuration: { type: "string", description: "Build configuration (e.g., Debug, Release)", default: "Debug" } }, required: ["projectPath", "scheme"] } }]
  • TypeScript interface and type guard for validating run_tests tool input arguments.
    interface TestArguments { projectPath: string; scheme: string; testIdentifier?: string; skipTests?: string[]; configuration?: string; destination?: string; } interface BuildOptions extends BuildArguments { includeWarnings?: boolean; } interface TestOptions extends TestArguments { includeWarnings?: boolean; } // Add these type guard functions function isBuildOptions(args: unknown): args is BuildOptions { if (!isBuildArguments(args)) return false; const a = args as Partial<BuildOptions>; return a.includeWarnings === undefined || typeof a.includeWarnings === 'boolean'; } function isTestOptions(args: unknown): args is TestOptions { if (!isTestArguments(args)) return false; const a = args as Partial<TestOptions>; return a.includeWarnings === undefined || typeof a.includeWarnings === 'boolean'; } function isTestArguments(args: unknown): args is TestArguments { if (typeof args !== 'object' || args === null) return false; const a = args as Partial<TestArguments>; return ( typeof a.projectPath === 'string' && typeof a.scheme === 'string' && (a.testIdentifier === undefined || typeof a.testIdentifier === 'string') && (a.skipTests === undefined || (Array.isArray(a.skipTests) && a.skipTests.every(t => typeof t === 'string'))) && (a.configuration === undefined || typeof a.configuration === 'string') && (a.destination === undefined || typeof a.destination === 'string') ); }
  • MCP CallToolRequestSchema dispatch case for "run_tests": validates arguments and invokes the runTests handler.
    case "run_tests": { if (!isTestArguments(request.params.arguments)) { throw new McpError(ErrorCode.InvalidParams, "Invalid test arguments provided"); } const result = await this.runTests( request.params.arguments.projectPath, request.params.arguments.scheme, request.params.arguments.configuration, request.params.arguments.testIdentifier, request.params.arguments.skipTests, request.params.arguments.destination ); this.latestBuildLog = result.logPath; return { content: [{ type: "text", text: result.output }], isError: !result.success }; }

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/PolarVista/Xcode-mcp-server'

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