In my last post, I explored the GitHub MCP to work with GitHub workflows directly from AI-powered editors for iOS development.

The dream is a single IDE for all things AI + iOS development, right?
That includes Xcode builds, simulators, and everything in between that comes with it, ideally without constantly hopping between my editor and Xcode itself.
I got to know about XcodeBuildMCP by Cameron Cooke last month but recently explored it enough to write about it.
Its promise? To bridge the gap between your AI assistant and the Xcode build system and iOS simulators and devices.
Just like with the GitHub MCP, my goal is to see how this MCP can help me with the common iOS development tasks like building, cleaning, running on simulators, getting bundle IDs – directly within VS Code, Cursor, and Windsurf.
Let's dive in and see if we can ditch some of that context switching!
This is the first part on exploring XcodeBuildMCP. Stay tuned for the second and third one!
A Quick MCP Refresher
Model Context Protocol (MCP), developed by Anthropic, is an open standard dictating how AI models communicate with external tools and data sources. Instead of custom integrations for every AI and every tool, MCP provides a common language.
This means that tools like XcodeBuildMCP can be built once and theoretically plugged into any MCP-compatible client (like VS Code with Copilot Agent Mode, Cursor, Windsurf, Claude Desktop, etc.).
Less reinventing the wheel, more interoperability. You can refresh your memory on the details:
Introducing XcodeBuildMCP
XcodeBuildMCP is an open-source MCP server wrapped around common xcodebuild
and simctl
commands into tools that you or the agent can understand and execute.
According to Cameron, the primary goal is to standardize how AI agents interact with Xcode projects, removing dependency on flaky or incorrect manual command-line steps. Also, it autonomously validate code changes by building projects, inspecting errors, and iterating!
It exposes a suite of tools covering:
- Xcode Project Management:
- Discovering projects/workspaces (
discover_projects
), - building for various platforms (
macos_build
,ios_simulator_build
,ios_device_build
), - cleaning build artifacts (
clean_workspace
,clean_project
), and - querying project info (
list_schemes
,show_build_settings
).
- Discovering projects/workspaces (
- Simulator Management:
- Listing available simulators (
list_simulators
), - booting them (
boot_simulator
), - opening the Simulator app (
open_simulator
), installing apps (install_app_in_simulator
), - launching apps (
launch_app_in_simulator
), - capturing runtime logs (
start_simulator_log_capture
,stop_and_get_simulator_log
), and - even experimental UI automation via idb (tap, swipe, screenshot - more on this later).
- Listing available simulators (
- App Utilities: Extracting bundle IDs (
get_macos_bundle_id
,get_ios_bundle_id
) and launching macOS apps (launch_macos_app
).
Imagine asking your AI assistant:
- Discover the Xcode projects and workspaces in this directory
- List the schemes for the
Polarixy.xcworkspace
- Build
Polarixy
app foriPhone 16 Pro
simulator using the Debug configuration - Clean the
Polarixy
project - List available simulators
- Install
Polarixy
on the current booted simulator - Launch
Polarixy
on the simulator and capture its logs
All without touching Xcode.
Getting Started: Setting Up Your Environment
Compared to the Docker hassle for the GitHub MCP, XcodeBuildMCP uses mise (a polyglot dev tool manager) for a smoother setup.
mise: A command-line tool version manager. If you do not have it, install it (Make sure mise is accessible in your PATH):
# macOS (Homebrew)
brew install mise
# Other methods: https://mise.jdx.dev/getting-started.html
Configuring Your Editor (MCP Client)
You need to tell your editor (Cursor, Windsurf, etc.) how to find and run the XcodeBuildMCP server using mise. This involves adding a JSON configuration block.
Note: The exact version npm:xcodebuildmcp@1.3.0 might change; check the XcodeBuildMCP repository for the latest version.
Cursor
Create or edit the ~/.cursor/mcp.json
file (for global access) or .cursor/mcp.json
(for project-specific access). Add the XcodeBuildMCP server entry:
{
"mcpServers": {
"XcodeBuildMCP": { // This is the name your AI will use to refer to the agent
"command": "mise",
"args": [
"x", // mise execute command
"npm:xcodebuildmcp@1.3.0", // Specify the package and version
"--", // Separator for arguments passed to the underlying command
"xcodebuildmcp" // The binary name inside the package
]
// No 'env' needed here as mise handles the environment
}
// ... other MCP servers like 'github' might be here
}
}
Windsurf (Codeium)
Edit the ~/.codeium/windsurf/mcp_config.json
file. The structure is identical to the Cursor example:
{
"mcpServers": {
"XcodeBuildMCP": {
"command": "mise",
"args": [
"x",
"npm:xcodebuildmcp@1.3.0",
"--",
"xcodebuildmcp"
]
}
// ... other MCP servers
}
}
VS Code (with Copilot Agent Mode):
Edit the file ~/User/settings.json
under the Application support of VS Code. Note that it is different from the other two IDEs:
{
"mcp": {
"servers": {
"XcodeBuildMCP": {
"command": "mise",
"args": [
"x",
"npm:xcodebuildmcp@1.3.0",
"--",
"xcodebuildmcp"
]
}
}
}
}
XcodeBuildMCP in Action
Alright, setup done! Let's try a typical iOS development workflow. I will use Cursor with Gemini 2.5 Pro for this example, but the prompts and tool interactions should be similar elsewhere.
Goal: Discover the project, build it for a simulator, find the built app, install it, and launch it.
Discovering the Project
I start by asking Cursor Discover the Xcode projects and workspaces in the current directory
and Cursor confirms it will use the discover_projects
tool.
Okay, I can help with that. I will scan the current workspace directory to find Xcode project and workspace files.
Called MCP tool `discover_projects`
Parameters:
{
"scanPath": ".",
"workspaceRoot": "/Users/rudrankriyam/Downloads/Genie"
}
Result:
Discovery finished. Found 1 projects and 6 workspaces.
Projects (relative to workspace root):
- genie-app/genie.xcodeproj
Workspaces (relative to workspace root):
- genie-app/LLMPackage/.swiftpm/xcode/package.xcworkspace
- genie-app/NetworkPackage/.swiftpm/xcode/package.xcworkspace
...
Then it gives me the list of the projects in the conversation asking me if I want to list the schemes or build a specific target.
Listing Schemes
Now I want to see the schemes for the iOS project. List schemes
and Cursor uses the list_schemes_project
tool.
Okay, I will list the schemes available in the genie-app/genie.xcodeproj project file.
Called MCP tool `list_schemes_project`
Parameters:
{
"projectPath": "/Users/rudrankriyam/Downloads/Genie/genie-app/genie.xcodeproj"
}
Result:
✅ Available schemes:
Genie
LLMPackage
NetworkPackage
SuggestionsPackage
WebSearchPackage
...
Next Steps:
1. Build the app: macos_build_project({ projectPath: "/Users/rudrankriyam/Downloads/Genie/genie-app/genie.xcodeproj", scheme: "ArchetypeProfilerPackage" })
or for iOS: ios_simulator_build_by_name_project({ projectPath: "/Users/rudrankriyam/Downloads/Genie/genie-app/genie.xcodeproj", scheme: "LLMPackage", simulatorName: "iPhone 16" })
2. Show build settings: show_build_settings_project({ projectPath: "/Users/rudrankriyam/Downloads/Genie/genie-app/genie.xcodeproj", scheme: "LLMPackage" })
It provides me with the schemes and the next steps on building the app as well.
Building for Simulator
Let's build the main app scheme for a specific simulator: build the main scheme on iphone 16
and Cursor started with the ios_simulator_build_by_name_project
tool;
Okay, I will build the Genie scheme from the genie-app/genie.xcodeproj project for the "iPhone 16" simulator.
Called MCP tool `ios_simulator_build_by_name_project`
Parameters:
{
"projectPath": "/Users/rudrankriyam/Downloads/Genie/genie-app/genie.xcodeproj",
"simulatorName": "iPhone 16",
"scheme": "Genie"
}
Result:
⚠️ Warning: 2025-04-29 23:22:11.820
... (many more)
✅ iOS Simulator Build build succeeded for scheme Genie.
ArchetypeProfilerPackage
Genie
LLMPackage
NetworkPackage
SkeletonUI
SkeletonUISnapshotTests
SkeletonUIUnitTests
SuggestionsPackage
WebSearchPackage
Next Steps:
1. Get App Path: get_simulator_app_path_by_name_project({ simulatorName: 'iPhone 16', scheme: 'Genie' })
2. Get Bundle ID: get_ios_bundle_id({ appPath: 'APP_PATH_FROM_STEP_1' })
3. Choose one of the following options:
- Option 1: Launch app normally:
launch_app_in_simulator({ simulatorUuid: 'SIMULATOR_UUID', bundleId: 'APP_BUNDLE_ID' })
- Option 2: Launch app with logs (captures both console and structured logs):
launch_app_with_logs_in_simulator({ simulatorUuid: 'SIMULATOR_UUID', bundleId:'APP_BUNDLE_ID' })
- Option 3: Launch app normally, then capture structured logs only:
launch_app_in_simulator({ simulatorUuid: 'SIMULATOR_UUID', bundleId: 'APP_BUNDLE_ID' })
start_simulator_log_capture({ simulatorUuid: 'SIMULATOR_UUID', bundleId:'APP_BUNDLE_ID' })
- Option 4: Launch app normally, then capture all logs (will restart app):
launch_app_in_simulator({ simulatorUuid: 'SIMULATOR_UUID', bundleId: 'APP_BUNDLE_ID' })
start_simulator_log_capture({ simulatorUuid: 'SIMULATOR_UUID', bundleId:'APP_BUNDLE_ID', captureConsole: true })
When done capturing logs, use: stop_and_get_simulator_log({ logSessionId: 'SESSION_ID' })
Cursor then tells me that I have some Swift 6 language mode warnings that I am too lazy to fix. But with this tool, I can add it in my Cursor rule to look for Swift 6 warnings and errors and fix it autonomously!
Running the App
Finally, I want to run the app on simulator and Cursor called many tools to get it running, although Gemini 2.5 Pro is pretty quick with its inference.
Okay, I will start the process to run the app on the simulator.
First, I need to get the path to the built application bundle for the "iPhone 16" simulator.
Called MCP tool `get_simulator_app_path_by_name_project`
Parameters:
{
"projectPath": "/Users/rudrankriyam/Downloads/Genie/genie-app/genie.xcodeproj",
"scheme": "Genie",
"platform": "iOS Simulator",
"simulatorName": "iPhone 16"
}
Result:
✅ App path retrieved successfully: /Users/rudrankriyam/Library/Developer/Xcode/DerivedData/genie-dfkfabirxzvfmogjceldrduvcvhl/Build/Products/Debug-iphonesimulator/Genie.app
Great, the app path is: /Users/rudrankriyam/Library/Developer/Xcode/DerivedData/genie-dfkfabirxzvfmogjceldrduvcvhl/Build/Products/Debug-iphonesimulator/Genie.app
Next, I'll get the bundle identifier from this app path.
Called MCP tool `get_ios_bundle_id`
Parameters:
{
"appPath": "/Users/rudrankriyam/Library/Developer/Xcode/DerivedData/genie-dfkfabirxzvfmogjceldrduvcvhl/Build/Products/Debug-iphonesimulator/Genie.app"
}
Result:
Bundle ID for iOS app: com.redacted
Next Steps:
- Launch in simulator: launch_app_in_simulator({ simulatorUuid: "YOUR_SIMULATOR_UUID", bundleId: "com.redacted" })
The bundle ID is com.redacted.
Now, I need to find the UUID for the "iPhone 16" simulator. I'll list the available simulators.
Called MCP tool `list_simulators`
Parameters:
{
"enabled": true
}
Result:
Available iOS Simulators:
com.apple.CoreSimulator.SimRuntime.iOS-18-4:
- iPhone 16 Pro (736153B4-B59D-4C65-9773-3204FB95EEAA)
- iPhone 16e (1589758E-D3B1-47EA-9CC4-E50EBB1F4A6C)
com.apple.CoreSimulator.SimRuntime.xrOS-2-3:
- Apple Vision Pro (C4CD195E-2497-4352-A71F-3C1ED9EDF612)
com.apple.CoreSimulator.SimRuntime.iOS-18-3:
- iPhone 16 Pro Max (E69E0918-6907-43F2-A8EE-FFCC6F0E8043)
- iPhone 16 (90B3F0B8-18E3-48E2-82C2-15C57C72F720)
Next Steps:
1. Boot a simulator: boot_simulator({ simulatorUuid: 'UUID_FROM_ABOVE' })
2. Open the simulator UI: open_simulator({})
3. Build for simulator: ios_simulator_build_by_id({ scheme: 'YOUR_SCHEME', simulatorId: 'UUID_FROM_ABOVE' })
4. Get app path: get_app_path_by_id({ scheme: 'YOUR_SCHEME', simulatorId: 'UUID_FROM_ABOVE' })
Found it! The UUID for the "iPhone 16" simulator (with iOS 18.4) is 7C197C2A-328F-4B14-9372-FE2C25E61AE5.
Now I'll boot this simulator.
Called MCP tool `boot_simulator`
Parameters:
{
"simulatorUuid": "7C197C2A-328F-4B14-9372-FE2C25E61AE5"
}
Result:
Simulator booted successfully. Next steps:
...removed for brevity.
The simulator is booting up. Next, I will install the app (Genie.app) onto this simulator.
Called MCP tool `install_app_in_simulator`
Parameters:
{
"simulatorUuid": "7C197C2A-328F-4B14-9372-FE2C25E61AE5",
"appPath": "/Users/rudrankriyam/Library/Developer/Xcode/DerivedData/genie-dfkfabirxzvfmogjceldrduvcvhl/Build/Products/Debug-iphonesimulator/Genie.app"
}
Result:
App launched successfully in simulator 7C197C2A-328F-4B14-9372-FE2C25E61AE5
Finally, I will launch the app (com.redacted) in the simulator.
Called MCP tool `launch_app_in_simulator`
Parameters:
{
"simulatorUuid": "7C197C2A-328F-4B14-9372-FE2C25E61AE5",
"bundleId": "com.redacted"
}
Result:
App launched successfully in simulator 7C197C2A-328F-4B14-9372-FE2C25E61AE5
Next Steps:
1. You can now interact with the app in the simulator.
2. Log capture options:
- Option 1: Capture structured logs only (app continues running):
start_simulator_log_capture({ simulatorUuid: "7C197C2A-328F-4B14-9372-FE2C25E61AE5", bundleId: "com.redacted" })
- Option 2: Capture both console and structured logs (app will restart):
start_simulator_log_capture({ simulatorUuid: "7C197C2A-328F-4B14-9372-FE2C25E61AE5", bundleId: "com.redacted", captureConsole: true })
- Option 3: Restart with logs in one step:
launch_app_with_logs_in_simulator({ simulatorUuid: "7C197C2A-328F-4B14-9372-FE2C25E61AE5", bundleId: "com.redacted" })
3. When done with any option, use: stop_and_get_simulator_log({ logSessionId: 'SESSION_ID' })
The Genie app should now be running on the "iPhone 16" simulator! You can interact with it directly in the Simulator app window.
Let me know if you want to capture logs or perform any other actions.
Success! We went from discovering the project to launching the app on a simulator, all by chat commands within the editor (no Xcode!), powered by XcodeBuildMCP.
Moving Forward
This exploration was smoother than the GitHub one, largely thanks to simplified the server setup. Still, a few things to keep in mind:
- Just like with GitHub MCP, vague prompts will not cut it.
- The models (and the tools) generally understand the sequence needed (build before install, install before launch), but sometimes you might need to guide it explicitly step-by-step.
- Imagine building with XcodeBuildMCP, and if successful, using GitHub MCP to commit the changes or create a PR!
I just created a PR before writing this blog post and loved this automated workflow where it checks for the errors before committing the changes.
Again, MCPs are not magic but well structured wrappers around different tools and APIs, made accessible via the open standard.
The quality of the AI model you use in your editor (Cursor, Windsurf, etc.) will also still significantly impact how smoothly these interactions go.
Happy MCPing!