build_project
Builds Xcode projects by specifying configuration and scheme to compile code for testing or deployment.
Instructions
Builds the active Xcode project using the specified configuration and scheme.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| configuration | Yes | Build configuration to use (e.g., 'Debug' or 'Release'). | |
| scheme | Yes | Name of the build scheme to be built. Must be one of the schemes available in the project. |
Implementation Reference
- src/index.ts:374-457 (handler)The core handler function that runs the xcodebuild command to build the Xcode project, processes JSON output, optionally filters warnings, generates reports, and returns success status with filtered output.private async buildProject( projectPath: string, scheme: string, configuration: string, destination: string = "platform=iOS Simulator,name=iPhone 15 Pro", includeWarnings: boolean = false ) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const logPath = path.join(this.buildLogsDir, `build-${timestamp}.log`); const projectDir = path.dirname(projectPath); const reportsPath = path.join(projectDir, 'Build', `Reports-${timestamp}`); const xcresultPath = `${reportsPath}.xcresult`; try { await mkdir(path.join(projectDir, 'Build'), { recursive: true }); } catch (error) { console.error(`Failed to prepare build directory: ${error}`); } const command = `which xcodebuild && xcodebuild -project "${projectPath}" \ -scheme "${scheme}" \ -configuration "${configuration}" \ -destination '${destination}' \ -resultBundlePath "${xcresultPath}" \ -UseModernBuildSystem=YES \ -json \ clean build 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; } }); // Filter warnings if needed const filteredOutput = includeWarnings ? jsonOutput : this.filterBuildOutput(jsonOutput); await writeFile(logPath + '.json', JSON.stringify(filteredOutput, null, 2)); // Use filtered output for response const outputText = filteredOutput .map(line => typeof line === 'string' ? line : JSON.stringify(line)) .join('\n'); // Process xcresult if it exists if (fs.existsSync(xcresultPath)) { try { const reportOutput = await execAsync(`xcrun xcresulttool get --format json --path "${xcresultPath}"`); await writeFile(path.join(this.buildLogsDir, `report-${timestamp}.json`), reportOutput.stdout); const summaryOutput = await execAsync(`xcrun xcresulttool get --format human-readable --path "${xcresultPath}"`); await writeFile(path.join(this.buildLogsDir, `report-${timestamp}.txt`), summaryOutput.stdout); } catch (reportError) { console.error('Failed to process build results:', reportError); } } const success = !stdout.includes('** BUILD FAILED **'); return { success, output: outputText, logPath }; } catch (parseError) { console.error('Failed to parse JSON output:', parseError); return { success: false, output: stdout + stderr, logPath }; } } catch (error) { console.error('Build 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:330-344 (registration)The tool call handler case that validates arguments, invokes the buildProject method, and formats the MCP response.case "build_project": { if (!isBuildOptions(request.params.arguments)) { throw new McpError(ErrorCode.InvalidParams, "Invalid build arguments provided"); } const { projectPath, scheme, configuration = "Debug", destination, includeWarnings = false } = request.params.arguments; const result = await this.buildProject(projectPath, scheme, configuration, destination, includeWarnings); this.latestBuildLog = result.logPath; return { content: [{ type: "text", text: result.output }], isError: !result.success }; }
- src/index.ts:267-292 (schema)Tool registration including name, description, and input schema definition for the build_project tool.name: "build_project", description: "Build an Xcode project", inputSchema: { type: "object", properties: { projectPath: { type: "string", description: "Path to the .xcodeproj or .xcworkspace" }, scheme: { type: "string", description: "Build scheme name" }, configuration: { type: "string", description: "Build configuration (e.g., Debug, Release)", default: "Debug" }, includeWarnings: { type: "boolean", description: "Include warning messages in output", default: false } }, required: ["projectPath", "scheme"] }
- src/index.ts:50-54 (helper)Type guard function to validate build options arguments used in the tool handler.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'; }
- src/index.ts:123-149 (helper)Helper function to filter build output, excluding warnings unless includeWarnings is true.private filterBuildOutput(jsonOutput: any[]): any[] { const significantErrors = jsonOutput.filter(line => { if (typeof line === 'string') { // Include build system lines if (line.startsWith('/usr/bin/xcodebuild') || line.includes('** BUILD')) { return true; } // Include only actual error messages and their notes if (line.match(/^\/.+:\d+:\d+: error:/) || // Matches error lines with file paths line.includes('note: found this candidate')) { return true; } return false; } if (typeof line === 'object' && line?.type === 'diagnostic') { return line.diagnostic?.severity === 'error'; } return false; }); return significantErrors; }