This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
XC-MCP is a Model Context Protocol (MCP) server that provides intelligent access to Xcode command-line tools with advanced caching and progressive disclosure features. It wraps xcodebuild, simctl, and idb commands to solve token overflow issues while maintaining full functionality.
70 discrete tools, MCP-spec-modernized, with deferred loading (~1k tokens at startup).
Evolution:
| Version | Tools | Architecture |
|---|---|---|
| Pre-RTFM (v1.2.1) | 51 | Individual tools (~7,850 tokens) |
| V1.3.2 (RTFM) | 51 | Individual + RTFM (~3,000 tokens) |
| V2.0.0 | 28 | Operation-enum routers + accessibility-first |
| V3.0.0 | 30 | Deferred loading + workflows (~1k startup) |
| V4.0.0 (Current) | 70 | Discrete tools + MCP spec (annotations / outputSchema / resources) + skill feature parity |
V4.0 modernizes the MCP layer and reaches feature parity with the ios-simulator-skill:
- SDK:
@modelcontextprotocol/sdk@^1.29, protocol2025-06-18. Zod v4. - Routers dissolved → discrete tools: the v2 operation-enum routers are gone. Annotations and
outputSchemaare per-tool, so each operation is now its own tool (deferred loading already covers the token cost). See the Migration Guide below. - Tool annotations: every tool declares
title+readOnlyHint/destructiveHint/idempotentHint/openWorldHintso clients can gate destructive ops (delete/erase/uninstall/clear). - Structured output: high-value tools (xcodebuild-build/-test, accessibility-audit, localization-audit, xcode-model-inspect, visual-diff) declare
outputSchemaand return validatedstructuredContent. - Resources: large cached output is exposed via the
resourcescapability atxcmcp://response/{cacheId}; build/test/list/ui-describe emitresource_linkblocks (cache IDs retained for back-compat). - listChanged capability declared for deferred/dynamic tool loading.
- Deferred loading retained (
XC_MCP_DEFER_LOADING);rtfmprovides progressive docs; old router names still fuzzy-match inrtfm.
Tool Categories (V4.0):
build: xcodebuild-version/-list/-build/-clean/-test/-get-details/-showsdks/-inspect-scheme/-validate-capabilitiessimulator: simctl-list/-get-details/-health-check/-suggest + lifecycle: simctl-boot/-shutdown/-create/-delete/-erase/-clone/-renameapp: simctl-install/-uninstall/-launch/-terminate/-get-app-container/-container/-openurlidb: idb-ui-describe/-find-element/-tap/-input/-gesture, accessibility-quality-check, accessibility-audit, idb-targets, idb-list-apps, idb-install/-uninstall/-launch/-terminateio: simctl-io, screenshotdevicestate: simctl-appearance, simctl-locationanalysis: localization-audit, xcode-model-inspect, visual-diffdiagnostics: hang-start/-stop/-get-details/-list (HangBuster)cache: cache-get-stats/-get-config/-set-config/-clearworkflow: workflow-tap-element/-fresh-install/-build-and-run, test-record-step, test-record-reportsystem: rtfm, persistence-enable/-disable/-status, simctl-push/-addmedia/-pbcopy/-privacy/-status-bar/-stream-logs
The v2/v3 operation-enum routers were removed. Call the discrete tool directly:
OLD (router) NEW (discrete tool)
─────────────────────────────────────────────────────────────────
simctl-device({operation:"boot", ...}) → simctl-boot({...})
simctl-device({operation:"shutdown", ...}) → simctl-shutdown({...})
simctl-device({operation:"create", ...}) → simctl-create({...})
simctl-device({operation:"delete", ...}) → simctl-delete({...})
simctl-device({operation:"erase", ...}) → simctl-erase({...})
simctl-device({operation:"clone", ...}) → simctl-clone({...})
simctl-device({operation:"rename", ...}) → simctl-rename({...})
simctl-app({operation:"install", ...}) → simctl-install({...})
simctl-app({operation:"uninstall", ...}) → simctl-uninstall({...})
simctl-app({operation:"launch", ...}) → simctl-launch({...})
simctl-app({operation:"terminate", ...}) → simctl-terminate({...})
idb-app({operation:"install", ...}) → idb-install({...})
idb-app({operation:"uninstall", ...}) → idb-uninstall({...})
idb-app({operation:"launch", ...}) → idb-launch({...})
idb-app({operation:"terminate", ...}) → idb-terminate({...})
cache({operation:"get-stats"}) → cache-get-stats({...})
cache({operation:"get-config"}) → cache-get-config({...})
cache({operation:"set-config", ...}) → cache-set-config({...})
cache({operation:"clear", ...}) → cache-clear({...})
persistence({operation:"enable", ...}) → persistence-enable({...})
persistence({operation:"disable", ...}) → persistence-disable({...})
persistence({operation:"status"}) → persistence-status({...})
Operation-specific parameters are unchanged; just drop the operation field and use the matching tool name. rtfm({ toolName: "simctl-device" }) still fuzzy-suggests the discrete tools.
New in V4 (feature parity with ios-simulator-skill):
simctl-appearance(theme/Dynamic Type/locale+RTL),simctl-location(GPS/city/GPX/waypoints)simctl-container(app sandbox ls/cat/userdefaults/coredata-path)- enhanced
simctl-stream-logs(severity filter + dedup + statistics) accessibility-audit(WCAG-tier audit),localization-audit(.xcstrings),xcode-model-inspect(Core Data/SwiftData),visual-diff(PNG pixel diff)- HangBuster:
hang-start/hang-stop/hang-get-details/hang-list(main-thread hang capture + clustering) test-record-step/test-record-report(test recording + markdown report)
- npm run build - Compile TypeScript to JavaScript in
dist/ - npm run dev - Development mode with TypeScript watch compilation
- npm start - Start the MCP server from compiled JavaScript
- npm run clean - Remove
dist/build artifacts
- npm run lint - Run ESLint on TypeScript source files
- npm run lint:fix - Auto-fix ESLint issues where possible
- npm run format - Format code with Prettier
- npm run format:check - Check code formatting without making changes
- npm test - Run Jest test suite with ESM support
- npm run test -- --watch - Run tests in watch mode during development
- npm run test -- --coverage - Run tests with coverage report (80% threshold required)
- npm run test -- tests/tests/utils/ - Run specific test directory
- npm run test -- --testNamePattern="cache" - Run tests matching pattern
- npm run precommit - Run lint-staged (triggered automatically by Husky)
- npm run prepare - Set up Husky git hooks
- Lint-staged automatically runs prettier and eslint on staged TypeScript files
- node dist/index.js - Run the MCP server directly after building
- Use stdio transport for MCP client testing
- Validate Xcode installation is available before server operations
- src/index.ts - Main MCP server with tool registration and request routing
- src/tools/ - Tool implementations organized by command category:
xcodebuild/- Build, test, clean, list, version tools with intelligent defaultssimctl/- Simulator management with progressive disclosurecache/- Cache management and statistics tools
- src/state/ - Intelligent caching system:
simulator-cache.ts- Simulator state with usage tracking and performance metricsproject-cache.ts- Project configuration memory and build historybuild-settings-cache.ts- Xcode build settings with auto-discovery of bundle IDs, deployment targets, and capabilities
- src/utils/ - Shared utilities for command execution and validation
- src/types/ - TypeScript definitions for Xcode data structures
- Progressive Disclosure: Returns concise summaries by default, full details on demand via cache IDs
- Intelligent Caching: 4-layer cache system (simulator, project, build settings, response) with smart invalidation
- Performance Tracking: Boot times, build metrics, and usage patterns for optimization
- Smart Defaults: Learns from successful builds and suggests optimal configurations
- SimulatorCache: 1-hour default retention, tracks device usage and boot performance
- ProjectCache: Remembers successful build configurations per project
- BuildSettingsCache: 1-hour default retention, auto-discovers bundle IDs, deployment targets, device families, and app capabilities from project build settings
- ResponseCache: 30-minute retention for progressive disclosure of large outputs
- All caches support configurable timeouts and selective clearing
Tools return structured responses with:
- Success indicators and error handling
- Cache IDs for progressive disclosure when outputs exceed token limits
- Smart recommendations based on usage history
- Performance metrics for optimization insights
- xcodebuild-build: Returns
buildIdfor progressive access to full logs viaxcodebuild-get-details - xcodebuild-test: Returns
testIdfor progressive access to full test logs viaxcodebuild-get-details - simctl-list: Returns
cacheIdfor progressive access to full device data viasimctl-get-details - simctl-device: Consolidated router with 7 operations (boot, shutdown, create, delete, erase, clone, rename)
- simctl-app: Consolidated router with 4 operations (install, uninstall, launch, terminate)
- cache: Consolidated router with 4 operations (get-stats, get-config, set-config, clear)
- Progressive Disclosure: Large outputs (10k+ tokens) automatically cached to prevent MCP token overflow
Core Philosophy: XC-MCP promotes accessibility-first automation to encourage inclusive app development while enabling faster, cheaper AI interaction.
Workflow Pattern:
-
Assess Quality:
accessibility-quality-check({ screenContext: "LoginScreen" })- Returns:
rich(>3 tappable) |moderate(2-3) |minimal(≤1) - Cost: ~30 tokens, ~80ms
- Returns:
-
Decision Branch:
- IF
richormoderate: Useidb-ui-find-element+idb-ui-tap(semantic approach) - IF
minimal: Fall back toscreenshot(visual approach last resort)
- IF
-
Semantic Element Search:
idb-ui-find-element({ query: "login" })- Returns: Tap-ready coordinates (centerX, centerY) with frame boundaries
- Cost: ~40 tokens, ~120ms
- 3-4x faster and cheaper than screenshot analysis
Performance Comparison:
| Approach | Tokens | Latency | When to Use |
|---|---|---|---|
| Accessibility Tree | ~50 | ~120ms | Rich UIs (>3 tappable elements) |
| Screenshot Analysis | ~170 | ~2000ms | Minimal UIs (≤1 tappable element) |
| Efficiency Gain | 3.4x cheaper | 16x faster | When accessibility sufficient |
Why This Matters:
- Encourages developers to build accessible UIs benefiting all users
- Enables precise semantic targeting vs visual pattern matching
- Reduces token cost and execution time significantly
- Promotes inclusive app development practices
Major Changes from V1.3.2:
- Tool consolidation: 51 → 28 tools (21 tools → 6 routers with operation enums)
- Token reduction: 3,000 → 1,980 tokens (40% additional savings beyond RTFM)
- Accessibility-first: 3 new tools for semantic UI automation workflow
- Operation enums:
simctl-device({ operation: "boot" })instead ofsimctl-boot
Tool Consolidation Mapping:
Old (V1.3.2) → New (V2.0.0)
─────────────────────────────────────────────────────────
simctl-boot → simctl-device({ operation: "boot" })
simctl-shutdown → simctl-device({ operation: "shutdown" })
simctl-create → simctl-device({ operation: "create" })
simctl-delete → simctl-device({ operation: "delete" })
simctl-erase → simctl-device({ operation: "erase" })
simctl-clone → simctl-device({ operation: "clone" })
simctl-rename → simctl-device({ operation: "rename" })
simctl-install → simctl-app({ operation: "install" })
simctl-uninstall → simctl-app({ operation: "uninstall" })
simctl-launch → simctl-app({ operation: "launch" })
simctl-terminate → simctl-app({ operation: "terminate" })
idb-install → idb-app({ operation: "install" })
idb-uninstall → idb-app({ operation: "uninstall" })
idb-launch → idb-app({ operation: "launch" })
idb-terminate → idb-app({ operation: "terminate" })
cache-get-stats → cache({ operation: "get-stats" })
cache-get-config → cache({ operation: "get-config" })
cache-set-config → cache({ operation: "set-config" })
cache-clear → cache({ operation: "clear" })
persistence-enable → persistence({ operation: "enable" })
persistence-disable → persistence({ operation: "disable" })
persistence-status → persistence({ operation: "status" })
New Tools in V2.0:
idb-ui-find-element: Semantic element search by label/identifieraccessibility-quality-check: Rapid UI richness assessment- Enhanced
idb-ui-describe: Optimized accessibility tree queries with progressive disclosure
Removed Tools (Niche Use Cases):
xcodebuild-showsdks: Usexcodebuild-versioninsteadsimctl-suggest: Usesimctl-listquick-access recommendationssimctl-addmedia,simctl-privacy,simctl-pbcopy,simctl-status-bar: Commented out to reduce schema bloatlist-cached-responses: Integrated into main cache tools
For Claude Code (V2.0):
- Use
rtfm()to discover tools progressively - Prefer
accessibility-quality-checkbefore screenshots - Use
idb-ui-find-elementfor semantic element search - Progressive disclosure via cache IDs (buildId, testId, cacheId, uiTreeId)
Major Changes from V2.0:
- Deferred loading: Only
tool-searchandrtfmvisible at startup (~1k tokens vs ~18.7k) - Tool count: 28 → 30 tools (added 2 workflow tools)
- Dynamic discovery: Agents discover tools on-demand via
tool-search - Auto-enabling: Discovered tools automatically added to agent context
- Startup optimization: 94% reduction in initial context overhead
- Full feature parity: All V2.0 features preserved with dynamic loading
New Tools in V3.0:
tool-search: Dynamic tool discovery by name, description, category, or capabilityworkflow-tap-element: High-level semantic tap workflow combining accessibility assessment and element interactionworkflow-fresh-install: Clean slate installation workflow for testing
Tool Search Usage:
// Discover build tools
tool-search({ query: "build", category: "build" })
// Find simulator tools
tool-search({ query: "boot" })
// List all tools in a category
tool-search({ category: "idb" })Workflow Tools:
workflow-tap-element: Combinesaccessibility-quality-check+idb-ui-find-element+idb-ui-tapinto single high-level operationworkflow-fresh-install: Combines device cleanup, fresh install, and app launch into single operation
For Claude Code (V3.0):
- Start with
tool-searchto discover relevant tools - Use
rtfm()for detailed documentation once tools are discovered workflow-tap-elementfor accessibility-first UI interactionworkflow-fresh-installfor test environment setup- Progressive disclosure via cache IDs (buildId, testId, cacheId, uiTreeId)
Environment Variables:
XC_MCP_DEFER_LOADING=false- Disables deferred loading and loads all tools like V2.x (default: true)
- ESLint Configuration: TypeScript-specific rules with Prettier integration
- Formatting: 100-character line width, 2-space indentation, single quotes
- Language Target: ES2020+ with Node.js ESM modules (
"type": "module") - Coverage Requirements: 60% minimum across branches, functions, lines, statements (current: 60.28%)
- Pre-commit Validation: Husky + lint-staged ensures code quality before commits
- Unused Variables: Prefix with underscore (
_unused) to satisfy linting
- All tools validate Xcode installation before execution
- Proper async/await patterns with comprehensive error catching
- MCP-compliant error responses with appropriate error codes
- Cache validity checks based on file modification times
- Configurable cache timeouts via tool parameters
- Graceful degradation when caches are invalid or missing
- Large command outputs (>token limits) automatically cached with unique IDs
- Summary responses provide key information upfront
- Detail retrieval tools allow drilling down into cached full outputs
- Smart filtering and pagination for large datasets
- Jest with ESM Support: Uses
ts-jestpreset with ES module transformation - Test Structure: Tests in
tests/__tests__/mirrorsrc/structure - Coverage Thresholds: 80% minimum across all metrics (enforced in CI)
- Mock Integration: Custom MCP SDK mocks for testing tool responses
- Test Categories: State management, utility functions, command execution, and validation
- All Tests:
npm test(includes TypeScript compilation validation) - Specific Tests:
npm test tests/__tests__/state/(test specific modules) - Coverage Report:
npm test -- --coverage(generates HTML + LCOV reports) - Watch Mode:
npm test -- --watch(re-run tests on file changes) - Pattern Matching:
npm test -- --testNamePattern="cache"(test specific functionality)
- TypeScript Compilation: Must compile without errors
- ESLint Validation: No errors (warnings acceptable, max 50 on staged files)
- Prettier Formatting: Automatically applied to staged files
- Test Suite: All tests must pass before commits
- Git Hooks: Husky enforces pre-commit validation automatically
- macOS Required: Xcode command-line tools must be installed
- Xcode Validation: Tools validate installation before execution
- Compatibility: Xcode 15+ and iOS simulators
- Node.js: Version 18+ required for ESM support
- Uses
@modelcontextprotocol/sdkfor MCP protocol compliance - Stdio transport for Claude Desktop integration
- Tool schema definitions with comprehensive parameter validation
{
"mcpServers": {
"xc-mcp": {
"command": "node",
"args": ["/path/to/xc-mcp/dist/index.js"]
}
}
}- Main Server:
src/index.ts- Tool registration, request routing, and MCP protocol handling - Tool Modules: Organized by command category in
src/tools/with consistent return patterns - Shared State: Global caches in
src/state/for cross-tool intelligence - Validation Layer:
src/utils/validation.tsvalidates Xcode installation before tool execution - Command Execution:
src/utils/command.tshandles secure subprocess execution with proper error handling
- Project Discovery:
xcodebuild-list,xcodebuild-showsdks,xcodebuild-version - Build Operations:
xcodebuild-build,xcodebuild-clean,xcodebuild-get-details - Test Operations:
xcodebuild-test(with support for test plans, filtering, and test-without-building) - Simulator Discovery:
simctl-list,simctl-get-details,simctl-suggest - Simulator Lifecycle:
simctl-create,simctl-delete,simctl-erase,simctl-clone,simctl-rename,simctl-health-check - Simulator Control:
simctl-boot,simctl-shutdown - App Management:
simctl-install,simctl-uninstall,simctl-get-app-container - App Control:
simctl-launch,simctl-terminate,simctl-openurl - I/O & Media:
simctl-io(screenshots/videos),simctl-addmedia(photo library) - Advanced Testing:
simctl-privacy(permissions),simctl-push(notifications),simctl-pbcopy(clipboard),simctl-status-bar(status bar override) - Cache Management:
cache-get-stats,cache-set-config,cache-get-config,cache-clear,list-cached-responses - Documentation:
rtfm(Read The Manual - progressive disclosure documentation for all 51 tools)
XC-MCP implements context engineering patterns specifically optimized for LLM/AI agent usage. These patterns enable agents to reason effectively about simulator state and testing workflows.
Screenshots can be named semantically to help agents understand screen context:
- Parameters:
appName,screenName,state - Generated filename:
{appName}_{screenName}_{state}_{date}.png - Example:
MyApp_LoginScreen_Empty_2025-01-23.png - Agent benefit: Agents can reason about which screen was captured and track state progression
Push notifications include structured test tracking:
- Parameters:
testName,expectedBehavior - Response includes:
deliveryInfo(sent/sentAt) andtestContext(testName, expectedBehavior, actualBehavior, passed) - Agent benefit: Agents can verify push delivery and validate app behavior matches expectations
Permission changes are tracked with audit context:
- Parameters:
scenario,step - Response includes:
auditEntrywith timestamp, action, service, success, and test context - Agent benefit: Agents can track permission state changes across test scenarios and verify permissions at each step
All tools follow these LLM optimization principles:
- Semantic Metadata: Include descriptive parameters that help agents reason about operations (e.g., appName, screenName, state)
- Structured Context: Responses include context objects (semanticMetadata, deliveryInfo, auditEntry, testContext) for agent reasoning
- Progressive Disclosure: Large outputs use cache IDs; summaries provide upfront value
- Verification Guidance: Responses suggest next steps for agents to verify outcomes (e.g., "Take screenshot to confirm visual delivery")
- Consistent Naming: Tool parameters and response fields follow consistent patterns for agent predictability
See docs/LLM_OPTIMIZATION.md for comprehensive patterns including:
- Session logging with artifact indexing for workflow reconstruction
- Video recording with scene markers and metadata
- Test result summaries with structured comparison
- Media library with semantic indexing
- Status bar before/after snapshots
- Operation chaining with explicit dependencies