xcode_open_project
Open and manage Xcode projects or workspaces via the XcodeMCP server to automate build processes and log parsing for errors and warnings.
Instructions
Open an Xcode project or workspace
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| xcodeproj | Yes | Path to the .xcodeproj file (or .xcworkspace if available) - supports both absolute (/path/to/project.xcodeproj) and relative (MyApp.xcodeproj) paths |
Input Schema (JSON Schema)
{
"properties": {
"xcodeproj": {
"description": "Path to the .xcodeproj file (or .xcworkspace if available) - supports both absolute (/path/to/project.xcodeproj) and relative (MyApp.xcodeproj) paths",
"type": "string"
}
},
"required": [
"xcodeproj"
],
"type": "object"
}
Implementation Reference
- src/tools/ProjectTools.ts:129-167 (handler)The core handler function that implements xcode_open_project. Validates the project path, prefers .xcworkspace over .xcodeproj if both exist, ensures Xcode is launched if not running, and uses JXA scripting to open the project via Application('Xcode').open(path).public static async openProject(projectPath: string): Promise<McpResult> { const validationError = PathValidator.validateProjectPath(projectPath); if (validationError) return validationError; // Check for workspace preference: if we're opening a .xcodeproj file, // check if there's a corresponding .xcworkspace file in the same directory let actualPath = projectPath; if (projectPath.endsWith('.xcodeproj')) { const { existsSync } = await import('fs'); const workspacePath = projectPath.replace(/\.xcodeproj$/, '.xcworkspace'); if (existsSync(workspacePath)) { actualPath = workspacePath; } } // Ensure Xcode is running before trying to open project const xcodeError = await this.ensureXcodeIsRunning(); if (xcodeError) return xcodeError; const script = ` const app = Application('Xcode'); app.open(${JSON.stringify(actualPath)}); 'Project opened successfully'; `; try { const result = await JXAExecutor.execute(script); // If we automatically chose a workspace over a project, indicate this in the response if (actualPath !== projectPath && actualPath.endsWith('.xcworkspace')) { return { content: [{ type: 'text', text: `Opened workspace instead of project: ${result}` }] }; } return { content: [{ type: 'text', text: result }] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [{ type: 'text', text: `Failed to open project: ${errorMessage}` }] }; } }
- src/shared/toolDefinitions.ts:18-32 (schema)Defines the tool name, description, and input schema (parameters: xcodeproj path, with optional default based on configuration). Used by both MCP server and CLI.name: 'xcode_open_project', description: 'Open an Xcode project or workspace', inputSchema: { type: 'object', properties: { xcodeproj: { type: 'string', description: preferredXcodeproj ? `Absolute path to the .xcodeproj file (or .xcworkspace if available) - defaults to ${preferredXcodeproj}` : 'Absolute path to the .xcodeproj file (or .xcworkspace if available) - e.g., /path/to/project.xcodeproj', }, }, required: preferredXcodeproj ? [] : ['xcodeproj'], }, },
- src/XcodeServer.ts:362-380 (registration)Tool registration and dispatching in the main MCP server CallToolRequestSchema handler. Validates parameters, calls ProjectTools.openProject, and updates currentProjectPath on success. Identical logic duplicated in callToolDirect method.case 'xcode_open_project': if (!args.xcodeproj) { throw new McpError( ErrorCode.InvalidParams, this.preferredXcodeproj ? `Missing required parameter: xcodeproj (no preferred value was applied)\n\n💡 Expected: absolute path to .xcodeproj or .xcworkspace file` : `Missing required parameter: xcodeproj\n\n💡 Expected: absolute path to .xcodeproj or .xcworkspace file` ); } const result = await ProjectTools.openProject(args.xcodeproj as string); if (result && 'content' in result && result.content?.[0] && 'text' in result.content[0]) { const textContent = result.content[0]; if (textContent.type === 'text' && typeof textContent.text === 'string') { if (!textContent.text.includes('Error') && !textContent.text.includes('does not exist')) { this.currentProjectPath = args.xcodeproj as string; } } } return result;