build_run_mac_proj
Build and run macOS applications from Xcode project files in a single command, specifying scheme and configuration options.
Instructions
Builds and runs a macOS app from a project file in one step.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectPath | Yes | Path to the .xcodeproj file (Required) | |
| scheme | Yes | The scheme to use (Required) | |
| configuration | No | Build configuration (Debug, Release, etc.) | |
| derivedDataPath | No | Path where build products and other derived data will go | |
| extraArgs | No | Additional xcodebuild arguments | |
| preferXcodebuild | No | If true, prefers xcodebuild over the experimental incremental build system, useful for when incremental build system fails. |
Implementation Reference
- src/tools/build_macos.ts:137-216 (handler)Core handler function for the 'build_run_mac_proj' tool. Builds the macOS project using xcodebuild, extracts the app path from build settings, and launches the app using the 'open' command.async function _handleMacOSBuildAndRunLogic(params: { workspacePath?: string; projectPath?: string; scheme: string; configuration: string; derivedDataPath?: string; arch?: string; extraArgs?: string[]; preferXcodebuild?: boolean; }): Promise<ToolResponse> { log('info', 'Handling macOS build & run logic...'); const _warningMessages: { type: 'text'; text: string }[] = []; const _warningRegex = /\[warning\]: (.*)/g; try { // First, build the app const buildResult = await _handleMacOSBuildLogic(params); // 1. Check if the build itself failed if (buildResult.isError) { return buildResult; // Return build failure directly } const buildWarningMessages = buildResult.content?.filter((c) => c.type === 'text') ?? []; // 2. Build succeeded, now get the app path using the helper const appPathResult = await _getAppPathFromBuildSettings(params); // 3. Check if getting the app path failed if (!appPathResult.success) { log('error', 'Build succeeded, but failed to get app path to launch.'); const response = createTextResponse( `✅ Build succeeded, but failed to get app path to launch: ${appPathResult.error}`, false, // Build succeeded, so not a full error ); if (response.content) { response.content.unshift(...buildWarningMessages); } return response; } const appPath = appPathResult.appPath; // We know this is a valid string now log('info', `App path determined as: ${appPath}`); // 4. Launch the app using the verified path // Launch the app try { await promisify(exec)(`open "${appPath}"`); log('info', `✅ macOS app launched successfully: ${appPath}`); const successResponse: ToolResponse = { content: [ ...buildWarningMessages, { type: 'text', text: `✅ macOS build and run succeeded for scheme ${params.scheme}. App launched: ${appPath}`, }, ], }; return successResponse; } catch (launchError) { const errorMessage = launchError instanceof Error ? launchError.message : String(launchError); log('error', `Build succeeded, but failed to launch app ${appPath}: ${errorMessage}`); const errorResponse = createTextResponse( `✅ Build succeeded, but failed to launch app ${appPath}. Error: ${errorMessage}`, false, // Build succeeded ); if (errorResponse.content) { errorResponse.content.unshift(...buildWarningMessages); } return errorResponse; } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); log('error', `Error during macOS build & run logic: ${errorMessage}`); const errorResponse = createTextResponse( `Error during macOS build and run: ${errorMessage}`, true, ); return errorResponse; } }
- src/tools/build_macos.ts:321-352 (registration)Direct registration of the 'build_run_mac_proj' tool, defining its name, description, input schema, and handler function.// Register macOS build and run project tool export function registerMacOSBuildAndRunProjectTool(server: McpServer): void { type ProjectParams = { projectPath: string; scheme: string; configuration?: string; derivedDataPath?: string; arch?: string; extraArgs?: string[]; preferXcodebuild?: boolean; }; registerTool<ProjectParams>( server, 'build_run_mac_proj', 'Builds and runs a macOS app from a project file in one step.', { projectPath: projectPathSchema, scheme: schemeSchema, configuration: configurationSchema, derivedDataPath: derivedDataPathSchema, extraArgs: extraArgsSchema, preferXcodebuild: preferXcodebuildSchema, }, async (params) => _handleMacOSBuildAndRunLogic({ ...params, configuration: params.configuration ?? 'Debug', preferXcodebuild: params.preferXcodebuild ?? false, }), ); }
- src/tools/build_macos.ts:47-71 (helper)Private helper that executes the xcodebuild 'build' action for macOS targets.async function _handleMacOSBuildLogic(params: { workspacePath?: string; projectPath?: string; scheme: string; configuration: string; derivedDataPath?: string; arch?: string; extraArgs?: string[]; preferXcodebuild?: boolean; }): Promise<ToolResponse> { log('info', `Starting macOS build for scheme ${params.scheme} (internal)`); return executeXcodeBuildCommand( { ...params, }, { platform: XcodePlatform.macOS, arch: params.arch, logPrefix: 'macOS Build', }, params.preferXcodebuild, 'build', ); }
- src/tools/build_macos.ts:73-132 (helper)Private helper that runs 'xcodebuild -showBuildSettings' to parse and return the built app's path.async function _getAppPathFromBuildSettings(params: { workspacePath?: string; projectPath?: string; scheme: string; configuration: string; derivedDataPath?: string; arch?: string; extraArgs?: string[]; }): Promise<{ success: boolean; appPath?: string; error?: string }> { try { // Create the command array for xcodebuild const command = ['xcodebuild', '-showBuildSettings']; // Add the workspace or project if (params.workspacePath) { command.push('-workspace', params.workspacePath); } else if (params.projectPath) { command.push('-project', params.projectPath); } // Add the scheme and configuration command.push('-scheme', params.scheme); command.push('-configuration', params.configuration); // Add derived data path if provided if (params.derivedDataPath) { command.push('-derivedDataPath', params.derivedDataPath); } // Add extra args if provided if (params.extraArgs && params.extraArgs.length > 0) { command.push(...params.extraArgs); } // Execute the command directly const result = await executeCommand(command, 'Get Build Settings for Launch'); if (!result.success) { return { success: false, error: result.error || 'Failed to get build settings', }; } // Parse the output to extract the app path const buildSettingsOutput = result.output; const builtProductsDirMatch = buildSettingsOutput.match(/BUILT_PRODUCTS_DIR = (.+)$/m); const fullProductNameMatch = buildSettingsOutput.match(/FULL_PRODUCT_NAME = (.+)$/m); if (!builtProductsDirMatch || !fullProductNameMatch) { return { success: false, error: 'Could not extract app path from build settings' }; } const appPath = `${builtProductsDirMatch[1].trim()}/${fullProductNameMatch[1].trim()}`; return { success: true, appPath }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { success: false, error: errorMessage }; } }
- src/utils/register-tools.ts:209-213 (registration)Invocation of the tool's registration function in the central tool registry array, enabling it conditionally via environment variable.{ register: registerMacOSBuildAndRunProjectTool, groups: [ToolGroup.MACOS_WORKFLOW, ToolGroup.APP_DEPLOYMENT], envVar: 'XCODEBUILDMCP_TOOL_MACOS_BUILD_AND_RUN_PROJECT', },
- src/tools/build_macos.ts:337-344 (schema)Zod-based input schema definition for the 'build_run_mac_proj' tool parameters.{ projectPath: projectPathSchema, scheme: schemeSchema, configuration: configurationSchema, derivedDataPath: derivedDataPathSchema, extraArgs: extraArgsSchema, preferXcodebuild: preferXcodebuildSchema, },