--- name: axiom-xcode-mcp-tools description: Xcode MCP workflow patterns — BuildFix loop, TestFix loop, preview verification, window targeting, tool gotchas license: MIT --- # Xcode MCP Tool Workflows **Core principle**: Xcode MCP gives you programmatic IDE access. Use workflow loops, not isolated tool calls. ## Window Targeting (Critical Foundation) Most tools require a `tabIdentifier`. **Always call `XcodeListWindows` first.** ``` 1. XcodeListWindows → list of (tabIdentifier, workspacePath) pairs 2. Match workspacePath to your project 3. Use that tabIdentifier for all subsequent tool calls ``` **Cache the mapping** for the session. Only re-fetch if: - A tool call fails with an invalid tab identifier - You opened/closed Xcode windows - You switched projects **If `XcodeListWindows` returns empty**: Xcode has no project open. Ask the user to open their project. ## Workflow: BuildFix Loop Iteratively build, diagnose, and fix until the project compiles. ``` 1. BuildProject(tabIdentifier) 2. Check buildResult — if success, done 3. GetBuildLog(tabIdentifier) → parse errors 4. XcodeListNavigatorIssues(tabIdentifier) → canonical diagnostics 5. XcodeUpdate(file, fix) for each diagnostic 6. Go to step 1 (max 5 iterations) 7. If same error persists after 3 attempts → fall back to axiom-xcode-debugging ``` **Why `XcodeListNavigatorIssues` over build log parsing**: The Issue Navigator provides structured, deduplicated diagnostics. Build logs contain raw compiler output with noise. **When to fall back to `axiom-xcode-debugging`**: When the error is environmental (zombie processes, stale Derived Data, simulator issues) rather than code-level. MCP tools operate on code; environment issues need CLI diagnostics. ## Workflow: TestFix Loop Fast iteration on failing tests. ``` 1. GetTestList(tabIdentifier) → discover available tests 2. RunSomeTests(tabIdentifier, [specific failing tests]) for fast iteration 3. Parse failures → identify code to fix 4. XcodeUpdate(file, fix) to patch code 5. Go to step 2 (max 5 iterations per test) 6. RunAllTests(tabIdentifier) as final verification ``` **Why `RunSomeTests` first**: Running a single test takes seconds. Running all tests takes minutes. Iterate on the failing test, then verify the full suite once it passes. **Parsing test results**: Look for `testResult` field in the response. Failed tests include failure messages with file paths and line numbers. ## Workflow: PreviewVerify Render SwiftUI previews and verify UI changes visually. ``` 1. RenderPreview(tabIdentifier, sourceFilePath, previewDefinitionIndexInFile: 0) → image artifact 2. Review the rendered image for correctness 3. If making changes: XcodeUpdate → RenderPreview again 4. Compare before/after for regressions ``` **Use cases**: Verifying layout changes, checking dark mode appearance, confirming Liquid Glass effects render correctly. ## Workflow: IssueTriage Use Xcode's Issue Navigator as the canonical diagnostics source. ``` 1. XcodeListNavigatorIssues(tabIdentifier) → all current issues 2. For specific files: XcodeRefreshCodeIssuesInFile(tabIdentifier, file) 3. Prioritize: errors > warnings > notes 4. Fix errors first, rebuild, re-check ``` **Why this over grep-for-errors**: The Issue Navigator tracks live diagnostics including type-check errors, missing imports, and constraint issues that only Xcode's compiler frontend surfaces. ## Workflow: DocumentationSearch Query Apple's documentation corpus through MCP. ``` 1. DocumentationSearch(query) → documentation results 2. Cross-reference with axiom-apple-docs for bundled Xcode guides ``` **Note**: `DocumentationSearch` searches Apple's online documentation and WWDC transcripts. For the 20 for-LLM guides bundled inside Xcode, use `axiom-apple-docs` instead. ## File Operations via MCP ### Reading and Writing | Operation | Tool | Notes | |-----------|------|-------| | Read file contents | `XcodeRead` | Sees Xcode's project view (generated files, resolved packages) | | Create new file | `XcodeWrite` | Creates file — auto-adds to project structure | | Edit existing file | `XcodeUpdate` | str_replace-style patches — safer than full rewrites | | Search for files | `XcodeGlob` | Pattern matching within the project | | Search file contents | `XcodeGrep` | Content search with line numbers | | List directory | `XcodeLS` | Directory listing | | Create directory | `XcodeMakeDir` | Creates directories | ### Destructive Operations (Require Confirmation) | Operation | Tool | Risk | |-----------|------|------| | Delete file/directory | `XcodeRM` | Moves to Trash by default (`deleteFiles: true`) — confirm with user | | Move/rename file | `XcodeMV` | May break imports and references | **Always confirm destructive operations with the user** before calling `XcodeRM` or `XcodeMV`. ### When to Use MCP File Tools vs Standard Tools | Scenario | Use MCP | Use Standard (Read/Write/Grep) | |----------|---------|-------------------------------| | Files in the Xcode project view | Yes — includes generated/resolved files | May miss generated files | | Files outside the project | No | Yes — standard tools work everywhere | | Need build context (diagnostics after edit) | Yes — edit + rebuild in one workflow | No build integration | | Simple file read/edit | Either works | Slightly faster (no MCP overhead) | ## Code Snippets ### Execute Swift Code ``` ExecuteSnippet(tabIdentifier, codeSnippet: "print(MyModel.self)", sourceFilePath: "Sources/MyModel.swift") ``` Runs code in the context of a specific Swift file — has access to that file's `fileprivate` declarations. Not a generic REPL. No `language` parameter (Swift only). ## Gotchas and Anti-Patterns ### Tab Identifier Staleness Tab identifiers become invalid when: - Xcode window is closed and reopened - Project is closed and reopened - Xcode is restarted **Fix**: Re-call `XcodeListWindows` to get fresh identifiers. ### XcodeWrite vs XcodeUpdate - `XcodeWrite` — **creates** a new file. Fails if file exists (in some clients). - `XcodeUpdate` — **patches** an existing file with `oldString`/`newString` replacement. One replacement per call (use `replaceAll: true` for all occurrences). **Common mistake**: Using `XcodeWrite` to edit an existing file overwrites its entire contents. Use `XcodeUpdate` for edits. ### Schema Compliance Xcode's mcpbridge has a known MCP spec violation: it populates `content` but omits `structuredContent` when tools declare `outputSchema`. This breaks strict MCP clients (Cursor, some Zed configurations). **Workaround**: Use [XcodeMCPWrapper](https://github.com/SoundBlaster/XcodeMCPWrapper) as a proxy for strict clients. ### Build After File Changes After `XcodeUpdate`, the project may need a build to surface new diagnostics. Don't assume edits are correct without rebuilding. ## Anti-Rationalization | Thought | Reality | |---------|---------| | "I'll just use xcodebuild" | MCP gives IDE state + navigator diagnostics + previews that CLI doesn't | | "Read tool works fine for Xcode files" | `XcodeRead` sees Xcode's project view including generated files and resolved packages | | "Skip tab identifier, I only have one project" | Most tools fail silently without `tabIdentifier` — always call `XcodeListWindows` first | | "Run all tests every time" | `RunSomeTests` for iteration, `RunAllTests` for verification — saves minutes per cycle | | "I'll parse the build log for errors" | `XcodeListNavigatorIssues` provides structured, deduplicated diagnostics | | "XcodeWrite to update a file" | `XcodeUpdate` for edits. `XcodeWrite` creates/overwrites. Wrong tool = data loss. | | "One tool call is enough" | Workflows (BuildFix, TestFix) use loops. Isolated calls miss the iteration pattern. | ## Resources **Skills**: axiom-xcode-mcp-setup, axiom-xcode-mcp-ref, axiom-xcode-debugging