Headless Xcode: From Prompt to Simulator with MCP
Headless Xcode: From Prompt to Simulator with MCP<br>August 13, 2026•14 min read•Loading views<br>XcodeMCPAIClaudeSwiftUI
Xcode's MCP server lets a coding agent create files, build, render previews,<br>and drive the simulator. Until now, those tools disappeared when you quit<br>Xcode.
Xcode 27 beta 5 adds xcrun mcp-server, which exposes the same tools without<br>opening the Xcode UI. Combined with Apple's exportable agent skills, it lets an<br>external agent create a project, build it, render previews, and verify<br>interactions in the simulator. I'll use Claude Code to do exactly that with a<br>small reading list app.
ℹ️Everything here was run on Xcode 27.0 beta 5 (build 27A5237l) with Claude<br>Code as the MCP client. You need that Xcode build, Claude Code, and an<br>administrator account to enable the service. This is beta software and the<br>CLI surface may change.
Quit Xcode. We're getting started.
Starting the server without the Xcode UI
Headless mode is off until you turn it on, and every command that changes<br>permissions needs sudo:
$ sudo xcrun mcp-server enable<br>mcp-server: enabled (unsafeAlwaysAllowAllAgents: false)<br>$ xcrun mcp-server start
enable flips the switch; start launches the service and is a no-op if it is<br>already up. unsafeAlwaysAllowAllAgents is the one thing enable lets you<br>change, and false — the default — means every agent gets approved<br>individually. More on that later.
xcrun mcp-server status reports where things stand:
$ xcrun mcp-server status<br>Permission: enabled<br>mcp-server: running<br>Open workspaces: none
Wiring the project: MCP server and Apple's skills
Two things have to be in place before an agent is any use here, and both belong<br>in the project repo rather than in your machine's global config: the server<br>registration, which is how the agent reaches Xcode at all, and Apple's skills,<br>which are how it knows what to do once it gets there.
Registering the MCP server in the repo
The MCP server itself is a stdio bridge. Pinning DEVELOPER_DIR in the<br>registration keeps the beta scoped to the agent and leaves the stable Xcode<br>selected for day-to-day work:
$ claude mcp add --scope project \<br>-e DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer \<br>xcode -- xcrun mcpbridge
Everything after -- is the command the bridge runs, so the flags belong to<br>claude rather than to xcrun. --scope project writes a .mcp.json at the<br>repository root. The registration travels with the repository, but every<br>developer still approves it locally. The resulting file is small enough to<br>hand-edit later:
.mcp.json{<br>"mcpServers": {<br>"xcode": {<br>"type": "stdio",<br>"command": "xcrun",<br>"args": ["mcpbridge"],<br>"env": {<br>"DEVELOPER_DIR": "/Applications/Xcode-beta.app/Contents/Developer"
Point DEVELOPER_DIR at wherever the beta actually lives. You can omit the<br>variable entirely to use the Xcode selected by xcode-select. When set,<br>DEVELOPER_DIR takes precedence without changing the selection for other<br>terminals.
Exporting Apple's skills into the repo
Tools are verbs: build this, render that. Skills tell the agent when to use<br>them and how Apple expects SwiftUI code to be structured. One command copies<br>Apple's skills next to .mcp.json:
$ xcrun agent skills export --output-dir ~/Developer/ReadingListExample/.claude/skills<br>Launching Xcode...<br>Exported 10 skills to /Users/artemnovichkov/Developer/ReadingListExample/.claude/skills<br>✓ device-interaction<br>✓ swiftui-specialist<br>✓ swiftui-whats-new-27
Xcode launches and shows its window while exporting the skills — its only<br>on-screen appearance in this entire headless workflow. The skills live inside<br>Xcode rather than the CLI, which is why the command prints Launching Xcode....<br>Existing skills are skipped rather than overwritten, so pass<br>--replace-existing when you re-export after an update.
⚠️Pass --output-dir an absolute path. The export is performed by Xcode<br>over XPC (Apple's system for communication between processes), not by your<br>shell, so a relative path may resolve outside your project and fail.
Each skill is a plain SKILL.md with name and description frontmatter,<br>most with a references/ directory of deeper material and occasionally a<br>scripts/ directory:
.claude<br>skills<br>swiftui-specialist<br>SKILL.md<br>references<br>dataflow.md<br>foreach.md<br>structure.md
device-interaction<br>SKILL.md
Putting them under .claude/skills/ is what makes Claude Code discover them<br>automatically, and discovery is relative to the directory the agent was started<br>in — so the agent has to be started in the project, the same place the server<br>registration lives.
Understanding the two permission gates
After you start an agent, its first request to the MCP server waits while the<br>headless service authorizes two things independently.
The first gate is the agent itself. This prompt appears:
The prompt comes from the headless service, not from Claude Code. The grant is<br>keyed to the code signature rather than the app name, which is why the dialog<br>says agents from Anthropic PBC....