Xcode IDE and Xcode MCP support + Insane refactor of tool/workflow management, discovery and run-time visibility#202
Merged
cameroncooke merged 24 commits intomainfrom Feb 6, 2026
Merged
Conversation
…of truth - Add YAML manifest system for tools and workflows in manifests/ directory - Implement manifest loader with schema validation (Zod) - Add visibility system with predicates for runtime filtering - Remove legacy codegen (generate-tools-manifest.ts, generate-loaders.ts) - Remove legacy index.ts workflow exports and re-export tool files - Add PredicateContext for runtime-aware tool filtering - Support hideWhenXcodeAgentMode predicate for Xcode IDE conflicts - Fix CLI next steps to use canonical names from manifests - Default MCP server to info log level - Remove fallback in next-steps-renderer (require cliTool from enrichment) - Update entry points from index.js to cli.js in docs and configs
- Add annotationsSchema with title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint - Add annotations field to toolManifestEntrySchema - Update tool-catalog to prefer manifest annotations with module fallback
Migrate all tools from default export objects to named schema handler exports. Add annotations metadata to YAML manifests as single source of truth for tool metadata. Introduce predicates (runningUnderXcodeAgent, requiresXcodeTools) for conditional tool visibility. Remove mandatory workflow selection concept and simplify workflow resolution logic.
Add simulator-resolver.ts utility that resolves simulator names to UDIDs via simctl. Refactor session_set_defaults to auto-resolve simulatorName to simulatorId when only a name is provided. Update bootstrap-runtime to auto-resolve simulator names from config defaults at startup. Expand exclusivePairs handling across tools that accept both simulatorId and simulatorName.
Sync session defaults (scheme, simulator, bundle ID) from Xcode's UserInterfaceState.xcuserstate file, both at startup and via FSEvents file watching for real-time updates. - Parse xcuserstate binary plists via bplist-parser to extract active scheme and run destination from NSKeyedArchiver object graph - Watch xcuserstate for changes using chokidar with debouncing and change detection to filter out UI-only writes - Resolve simulator name and bundle ID asynchronously (non-blocking) to avoid delaying session default updates - Add disableXcodeAutoSync config option: when true, disables file watcher and exposes manual sync_xcode_defaults tool instead - Add xcode-ide-state MCP resource for reading current IDE selection - Fix mutually exclusive session defaults (simulatorId preferred over simulatorName when both come from session defaults) - Use project/workspace path from config for monorepo disambiguation
Build CLI workflow groups from manifest-exposed CLI workflows instead of all manifest workflows. This removes empty workflow placeholders like xcode-ide when no CLI commands are available. Clarify xcode-ide help output to state bridge tools are MCP-only and point users to MCP server usage plus Xcode MCP Tools prerequisites. Co-Authored-By: Claude <noreply@anthropic.com>
Route xcode-ide status/sync/disconnect through a shared tool handler facade that uses the manager when a server instance exists and a standalone bridge client otherwise. This removes repeated branching logic across handlers and keeps CLI/debug bridge commands usable without requiring server bootstrap state. Co-Authored-By: Claude <noreply@anthropic.com>
commit: |
Contributor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
Remove legacy daemon routing knobs and CLI daemon flags so routing is driven by tool statefulness plus the explicit xcode-ide special case. Add idle shutdown with an activity lease registry so long-running tools signal lifecycle activity without hardcoded daemon imports. Clean manifest files by removing values that match schema defaults and regenerate generated tool documentation. Co-Authored-By: Claude <noreply@anthropic.com>
Limit parent-directory fallback discovery for xcuserstate to a configured search root instead of traversing to filesystem root. Pass the resolved workspace root from server bootstrap so Xcode IDE sync and watcher startup only search within the active workspace context. Add regression coverage for nested cwd discovery and boundary enforcement. Co-Authored-By: Claude <noreply@anthropic.com>
…atching - Deduplicate tools in buildToolCatalogFromManifest when the same tool appears in multiple workflows, preventing ambiguous resolution via kebab-case MCP name lookup and non-deterministic Map overwrites - Fix screenshot window title matching to use the actual Simulator title separator (en-dash/hyphen) instead of bare space, preventing false-positives like "iPhone 15" matching "iPhone 15 Pro" - Remove dead tool-visibility.ts superseded by the predicate system
…pping - Add explicit cli: names to 6 swift-package manifests - Remove getBaseToolName() from output.ts and register-tool-commands.ts - Remove global CLI name uniqueness check from loadManifest
Add cli: names to all 70 tool manifests using human-friendly names scoped by workflow namespace. Simple names (build, test, list) where unique within a workflow; platform-qualified names (start-device-log-capture, get-macos-bundle-id) only where tools coexist in the same workflow and would otherwise clash. Move tool catalog deduplication from the builder to the index maps in createToolCatalog so shared tools still appear in every workflow they belong to (for CLI grouping) while preventing ambiguous resolution in the lookup indices.
…t catalog lookup CLI tool subcommands like `simulator list` were resolving to the wrong handler because multiple workflows share the same CLI name (e.g. "list", "build", "test"). The flat byCliName map meant last-inserted won. Instead of re-resolving by name, pass the ToolDefinition directly from the workflow-scoped yargs handler via a new invokeDirect() method. For daemon wire communication, use mcpName (unique within the catalog) instead of the ambiguous cliName. Also skip the bridge availability check (xcrun --find mcpbridge) in CLI mode since xcode-ide has availability.cli: false, avoiding an unwanted Xcode authorization prompt.
The docs incorrectly stated the predicate depends on both runningUnderXcode AND xcodeToolsActive. In reality it only checks runningUnderXcode — Xcode's coding agent always provides native equivalents, independent of the Xcode Tools bridge (which is for external agents connecting to Xcode's MCP server).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
Medium Risk
Touches core tool discovery/visibility and CLI/daemon routing semantics, which can affect which tools are registered and how stateful operations execute; however, much of the diff is documentation/config updates and removal of obsolete build-time generators.
Overview
Adds an optional
xcode-ideworkflow that proxies Xcode 26+ IDE MCP tools viaxcrun mcpbridge, with new dynamicxcode_tools_*tool registration and a dedicated doc (docs/XCODE_IDE_MCPBRIDGE.md).Refactors tool/workflow discovery and visibility toward YAML manifests (new
docs/dev/MANIFEST_FORMAT.md) and updates generated tool docs to reflect new workflows/tools (tool counts, re-org of groups, and newsync_xcode_defaults).Simplifies CLI execution/routing: updates docs/config to describe stateless tools running directly while stateful tools auto-route through a per-workspace daemon with a 10-minute idle shutdown (configurable via
XCODEBUILDMCP_DAEMON_IDLE_TIMEOUT_MS), and removes the old build-time plugin-discovery generator code. Also standardizes dev/test commands and VS Code configs to launch MCP viabuild/cli.js mcpand updates rp-cli CLI command templates to require explicit-w <window_id>routing + longer timeouts.Written by Cursor Bugbot for commit 13807c9. This will update automatically on new commits. Configure here.