Skip to content

Instantly share code, notes, and snippets.

@everyplace
Last active March 16, 2026 01:39
Show Gist options
  • Select an option

  • Save everyplace/0a1e2637261325ea1d47447f4085bf37 to your computer and use it in GitHub Desktop.

Select an option

Save everyplace/0a1e2637261325ea1d47447f4085bf37 to your computer and use it in GitHub Desktop.
Configure Xcode 26.3 with agent support to use the iOS-simulator mcp server

Disable Xcode's agent permissions checks

Note

This addresses the concern of "how to get Xcode's agent support to reach outside of itself without asking for permission" but does not address the reverse of "how to get a terminal agent to talk to Xcode without prompting."

This is basically the equivalent of running something like claude --dangerously-skip-permissions, so... probably this is a bad idea.

defaults write com.apple.dt.Xcode IDEChatAgenticChatSkipPermissions -bool YES

When you set this flag, after you initiate a session with Claude Agent in Xcode, if you go to terminal and run ps -ax | grep danger you will see the claude agent process has --dangerously-skip-permissions passed directly to it from Xcode.

How This Was Discovered

By running strings and nm on the IDEIntelligenceAgents.framework and IDEIntelligenceChat.framework binaries inside Xcode 26.3.0 RC:

/Applications/Xcode-26.3.0-Release.Candidate.app/Contents/PlugIns/IDEIntelligenceAgents.framework/
/Applications/Xcode-26.3.0-Release.Candidate.app/Contents/PlugIns/IDEIntelligenceChat.framework/

How Xcode Launches the Claude Agent

From ps -ax output, the full invocation looks like:

claude -p --output-format=stream-json --input-format=stream-json --verbose \
  --mcp-config /tmp/mcp-config-<UUID>.json \
  --permission-prompt-tool stdio \
  --settings {"env":{"ANTHROPIC_MODEL":"opus",...}} \
  --allowedTools <comma-separated list of mcp__xcode-tools__* tools> \
  --dangerously-skip-permissions   # only present when IDEChatAgenticChatSkipPermissions=YES

Key details:

  • The temp MCP config (/tmp/mcp-config-<UUID>.json) only includes xcode-tools (Xcode's built-in MCP server via xcrun mcpbridge). Third-party MCP servers (e.g., ios-simulator) are loaded by Claude Code from .claude.json, not from Xcode's temp config.
  • The --allowedTools list only includes mcp__xcode-tools__* tools. Third-party MCP tools are not included regardless of what's in .claude.json.
  • With --dangerously-skip-permissions, all tools bypass approval regardless of the --allowedTools list.
  • The agent binary is at ~/Library/Developer/Xcode/CodingAssistant/Agents/Versions/26.3/claude.
  • Xcode validates the code signature on the binary at launch. You can swap it with another signed Mach-O binary (e.g., a newer Claude Code build), but replacing it with a shell script wrapper fails with: "The code signing identity for the agent did not match expectations."

The .claude.json allowedTools Array

The allowedTools array in project entries within ~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/.claude.json is read by Claude Code but is not used by Xcode's --allowedTools CLI flag. It has no effect on which tools require approval. The only thing that controls tool approval is IDEChatAgenticChatSkipPermissions.

External Agent Connection (Unsolved)

Note

For the reverse, IDEAllowUnauthenticatedAgents is the "Allow external coding agents" checkbox in Xcode Settings. It controls whether external agents can connect to Xcode's MCP server at all -- setting it to NO disables the MCP server entirely. But setting it to YES still shows a per-launch approval dialog.

IDEChatInternalAllowUntrustedAgentsWithoutUserInteraction is the key that should bypass the external agent approval dialog, but it appears to only work in Apple-internal Xcode builds. Setting it to YES has no effect in release/RC builds.

No known bypass exists for the per-launch "The agent 'claude-code' wants to use Xcode's tools" dialog in shipping Xcode as of 26.3.0 RC.

All Known IDEChat Defaults

Found via strings on the IDEIntelligenceChat.framework binary:

Default Type Effect
IDEChatAgenticChatSkipPermissions bool Passes --dangerously-skip-permissions to internal agent
IDEAllowUnauthenticatedAgents bool Master toggle for external agent MCP access (UI setting)
IDEChatInternalAllowUntrustedAgentsWithoutUserInteraction bool Apple-internal only, no effect in release builds
IDEChatSkipPermissionsForTools bool/? Per-tool skip (may need tool names, not bool)
IDEChatSkipPermissionsForTrustedTools bool/? Skip for "trusted" tools (unclear what qualifies)
IDEChatOverrideAllEnabledMCPTools ? Possibly overrides entire tool list
IDEChatAgentAllowsInternetAccessTools bool Controls web access tools
IDEChatHiddenMCPTools ? Hides specific MCP tools
IDEChatAddEnabledMCPTools ? Possibly adds tools to enabled list
IDEChatRemoveEnabledMCPTools ? Possibly removes tools from enabled list
IDEChatClaudeAgentModelConfigurationAlias string Model selection (e.g., "opus")
IDEChatOverrideAgenticHomeDirectory string Override home dir for agent
IDEChatAgenticChatClaudeStreaming bool Controls streaming mode
IDEChatAllowAgents bool General agent toggle
IDEChatAutoApplyEnabled bool Auto-apply code changes
IDEChatSendTelemetryOverride ? Override telemetry settings

Getting ios-simulator-mcp Working with Xcode 26.3

How to get the ios-simulator-mcp MCP server working with Xcode 26.3's Claude integration.

The Problem

Xcode 26.3 includes Claude integration via MCP (Model Context Protocol). The ios-simulator-mcp server is configured to run via npx, but Xcode's environment doesn't inherit the user's shell PATH, causing two failures:

  1. npx not found (when using nvm-managed Node)
  2. node not found (even after finding npx, because the spawned process can't find node)
  3. idb not found (for accessibility-based UI tools like ui_describe_all)

Configuration Location

Xcode stores Claude/MCP configuration at:

~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/.claude.json

Debug logs are at:

~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/debug/latest

Solution

Step 1: Install Node via Homebrew

nvm-managed Node uses shell functions that aren't available in Xcode's environment. Install Node via Homebrew for a stable, PATH-accessible binary:

/opt/homebrew/bin/brew install node

This provides /opt/homebrew/bin/npx and /opt/homebrew/bin/node which are real binaries (symlinks to the Cellar), not shell functions.

Step 2: Update MCP Server Configuration

Edit ~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/.claude.json and update the ios-simulator entry for each project:

Before:

"ios-simulator": {
  "command": "npx",
  "args": ["-y", "ios-simulator-mcp"],
  "transport": "stdio"
}

After:

"ios-simulator": {
  "command": "/opt/homebrew/bin/npx",
  "args": ["-y", "ios-simulator-mcp"],
  "transport": "stdio",
  "env": {
    "PATH": "~/.local/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"
  }
}

Three things changed:

  • Full path to npx instead of just npx
  • Added env.PATH so the spawned process can find node (the MCP package uses #!/usr/bin/env node)
  • Included ~/.local/bin in PATH for idb (Facebook's iOS Development Bridge, installed via pipx)

Step 3: Restart Xcode

Close and reopen Xcode (or at minimum, close and reopen the Claude chat panel) for the configuration changes to take effect.

Verification

Check the debug log after restart:

grep "ios-simulator" ~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/debug/latest

Successful connection looks like:

MCP server "ios-simulator": Starting connection with timeout of 30000ms
MCP server "ios-simulator": Successfully connected to undefined server in 3546ms
MCP server "ios-simulator": Connection established with capabilities: {"hasTools":true,...,"serverVersion":{"name":"ios-simulator","version":"1.5.2"}}

Failed connections show errors like:

  • Executable not found in $PATH: "npx" - need full path to npx
  • env: node: No such file or directory - need to add PATH to env

Tool-specific errors (after successful connection):

  • spawn idb ENOENT - need to add ~/.local/bin to PATH for idb (only affects accessibility tools like ui_describe_all, screenshot still works)

Why Not Use nvm?

nvm works by defining shell functions (nvm, node, npm, npx) in your shell profile. These functions lazy-load the actual binaries. Xcode doesn't source your shell profile, so these functions don't exist in its environment.

Options I considered:

  • Hardcode nvm version path (e.g., ~/.nvm/versions/node/v22.20.0/bin/npx) - breaks when you update Node
  • Wrapper script that sources nvm - works but annoying to maintain
  • Homebrew Node - this is what I went with since it auto-updates with brew upgrade

Notes

  • First connection after restart takes 3-5 seconds while npx downloads/caches the package. After that it's fast.
  • Homebrew's Node is separate from nvm. You can use both - nvm for development, Homebrew for system tools like this.
  • Run brew upgrade node occasionally to keep it current.

Related Files

  • Config: ~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/.claude.json
  • Debug logs: ~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/debug/
  • Skills directory: ~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/skills/
  • Claude agent binary: ~/Library/Developer/Xcode/CodingAssistant/Agents/Versions/26.3/claude
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment