#
tokens: 49278/50000 133/337 files (page 1/14)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 14. Use http://codebase.md/cameroncooke/xcodebuildmcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .axe-version
├── .claude
│   └── agents
│       └── xcodebuild-mcp-qa-tester.md
├── .cursor
│   ├── BUGBOT.md
│   └── environment.json
├── .cursorrules
├── .github
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   └── feature_request.yml
│   └── workflows
│       ├── ci.yml
│       ├── claude-code-review.yml
│       ├── claude-dispatch.yml
│       ├── claude.yml
│       ├── droid-code-review.yml
│       ├── README.md
│       ├── release.yml
│       └── sentry.yml
├── .gitignore
├── .prettierignore
├── .prettierrc.js
├── .vscode
│   ├── extensions.json
│   ├── launch.json
│   ├── mcp.json
│   ├── settings.json
│   └── tasks.json
├── AGENTS.md
├── banner.png
├── build-plugins
│   ├── plugin-discovery.js
│   ├── plugin-discovery.ts
│   └── tsconfig.json
├── CHANGELOG.md
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── docs
│   ├── ARCHITECTURE.md
│   ├── CODE_QUALITY.md
│   ├── CONTRIBUTING.md
│   ├── ESLINT_TYPE_SAFETY.md
│   ├── MANUAL_TESTING.md
│   ├── NODEJS_2025.md
│   ├── PLUGIN_DEVELOPMENT.md
│   ├── RELEASE_PROCESS.md
│   ├── RELOADEROO_FOR_XCODEBUILDMCP.md
│   ├── RELOADEROO_XCODEBUILDMCP_PRIMER.md
│   ├── RELOADEROO.md
│   ├── session_management_plan.md
│   ├── session-aware-migration-todo.md
│   ├── TEST_RUNNER_ENV_IMPLEMENTATION_PLAN.md
│   ├── TESTING.md
│   └── TOOLS.md
├── eslint.config.js
├── example_projects
│   ├── .vscode
│   │   └── launch.json
│   ├── iOS
│   │   ├── .cursor
│   │   │   └── rules
│   │   │       └── errors.mdc
│   │   ├── .vscode
│   │   │   └── settings.json
│   │   ├── Makefile
│   │   ├── MCPTest
│   │   │   ├── Assets.xcassets
│   │   │   │   ├── AccentColor.colorset
│   │   │   │   │   └── Contents.json
│   │   │   │   ├── AppIcon.appiconset
│   │   │   │   │   └── Contents.json
│   │   │   │   └── Contents.json
│   │   │   ├── ContentView.swift
│   │   │   ├── MCPTestApp.swift
│   │   │   └── Preview Content
│   │   │       └── Preview Assets.xcassets
│   │   │           └── Contents.json
│   │   ├── MCPTest.xcodeproj
│   │   │   ├── project.pbxproj
│   │   │   └── xcshareddata
│   │   │       └── xcschemes
│   │   │           └── MCPTest.xcscheme
│   │   └── MCPTestUITests
│   │       └── MCPTestUITests.swift
│   ├── iOS_Calculator
│   │   ├── CalculatorApp
│   │   │   ├── Assets.xcassets
│   │   │   │   ├── AccentColor.colorset
│   │   │   │   │   └── Contents.json
│   │   │   │   ├── AppIcon.appiconset
│   │   │   │   │   └── Contents.json
│   │   │   │   └── Contents.json
│   │   │   ├── CalculatorApp.swift
│   │   │   └── CalculatorApp.xctestplan
│   │   ├── CalculatorApp.xcodeproj
│   │   │   ├── project.pbxproj
│   │   │   └── xcshareddata
│   │   │       └── xcschemes
│   │   │           └── CalculatorApp.xcscheme
│   │   ├── CalculatorApp.xcworkspace
│   │   │   └── contents.xcworkspacedata
│   │   ├── CalculatorAppPackage
│   │   │   ├── .gitignore
│   │   │   ├── Package.swift
│   │   │   ├── Sources
│   │   │   │   └── CalculatorAppFeature
│   │   │   │       ├── BackgroundEffect.swift
│   │   │   │       ├── CalculatorButton.swift
│   │   │   │       ├── CalculatorDisplay.swift
│   │   │   │       ├── CalculatorInputHandler.swift
│   │   │   │       ├── CalculatorService.swift
│   │   │   │       └── ContentView.swift
│   │   │   └── Tests
│   │   │       └── CalculatorAppFeatureTests
│   │   │           └── CalculatorServiceTests.swift
│   │   ├── CalculatorAppTests
│   │   │   └── CalculatorAppTests.swift
│   │   └── Config
│   │       ├── Debug.xcconfig
│   │       ├── Release.xcconfig
│   │       ├── Shared.xcconfig
│   │       └── Tests.xcconfig
│   ├── macOS
│   │   ├── MCPTest
│   │   │   ├── Assets.xcassets
│   │   │   │   ├── AccentColor.colorset
│   │   │   │   │   └── Contents.json
│   │   │   │   ├── AppIcon.appiconset
│   │   │   │   │   └── Contents.json
│   │   │   │   └── Contents.json
│   │   │   ├── ContentView.swift
│   │   │   ├── MCPTest.entitlements
│   │   │   ├── MCPTestApp.swift
│   │   │   └── Preview Content
│   │   │       └── Preview Assets.xcassets
│   │   │           └── Contents.json
│   │   └── MCPTest.xcodeproj
│   │       ├── project.pbxproj
│   │       └── xcshareddata
│   │           └── xcschemes
│   │               └── MCPTest.xcscheme
│   └── spm
│       ├── .gitignore
│       ├── Package.resolved
│       ├── Package.swift
│       ├── Sources
│       │   ├── long-server
│       │   │   └── main.swift
│       │   ├── quick-task
│       │   │   └── main.swift
│       │   ├── spm
│       │   │   └── main.swift
│       │   └── TestLib
│       │       └── TaskManager.swift
│       └── Tests
│           └── TestLibTests
│               └── SimpleTests.swift
├── LICENSE
├── mcp-install-dark.png
├── package-lock.json
├── package.json
├── README.md
├── scripts
│   ├── analysis
│   │   └── tools-analysis.ts
│   ├── bundle-axe.sh
│   ├── check-code-patterns.js
│   ├── release.sh
│   ├── tools-cli.ts
│   └── update-tools-docs.ts
├── server.json
├── smithery.yaml
├── src
│   ├── core
│   │   ├── __tests__
│   │   │   └── resources.test.ts
│   │   ├── dynamic-tools.ts
│   │   ├── plugin-registry.ts
│   │   ├── plugin-types.ts
│   │   └── resources.ts
│   ├── doctor-cli.ts
│   ├── index.ts
│   ├── mcp
│   │   ├── resources
│   │   │   ├── __tests__
│   │   │   │   ├── devices.test.ts
│   │   │   │   ├── doctor.test.ts
│   │   │   │   └── simulators.test.ts
│   │   │   ├── devices.ts
│   │   │   ├── doctor.ts
│   │   │   └── simulators.ts
│   │   └── tools
│   │       ├── device
│   │       │   ├── __tests__
│   │       │   │   ├── build_device.test.ts
│   │       │   │   ├── get_device_app_path.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── install_app_device.test.ts
│   │       │   │   ├── launch_app_device.test.ts
│   │       │   │   ├── list_devices.test.ts
│   │       │   │   ├── re-exports.test.ts
│   │       │   │   ├── stop_app_device.test.ts
│   │       │   │   └── test_device.test.ts
│   │       │   ├── build_device.ts
│   │       │   ├── clean.ts
│   │       │   ├── discover_projs.ts
│   │       │   ├── get_app_bundle_id.ts
│   │       │   ├── get_device_app_path.ts
│   │       │   ├── index.ts
│   │       │   ├── install_app_device.ts
│   │       │   ├── launch_app_device.ts
│   │       │   ├── list_devices.ts
│   │       │   ├── list_schemes.ts
│   │       │   ├── show_build_settings.ts
│   │       │   ├── start_device_log_cap.ts
│   │       │   ├── stop_app_device.ts
│   │       │   ├── stop_device_log_cap.ts
│   │       │   └── test_device.ts
│   │       ├── discovery
│   │       │   ├── __tests__
│   │       │   │   └── discover_tools.test.ts
│   │       │   ├── discover_tools.ts
│   │       │   └── index.ts
│   │       ├── doctor
│   │       │   ├── __tests__
│   │       │   │   ├── doctor.test.ts
│   │       │   │   └── index.test.ts
│   │       │   ├── doctor.ts
│   │       │   ├── index.ts
│   │       │   └── lib
│   │       │       └── doctor.deps.ts
│   │       ├── logging
│   │       │   ├── __tests__
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── start_device_log_cap.test.ts
│   │       │   │   ├── start_sim_log_cap.test.ts
│   │       │   │   ├── stop_device_log_cap.test.ts
│   │       │   │   └── stop_sim_log_cap.test.ts
│   │       │   ├── index.ts
│   │       │   ├── start_device_log_cap.ts
│   │       │   ├── start_sim_log_cap.ts
│   │       │   ├── stop_device_log_cap.ts
│   │       │   └── stop_sim_log_cap.ts
│   │       ├── macos
│   │       │   ├── __tests__
│   │       │   │   ├── build_macos.test.ts
│   │       │   │   ├── build_run_macos.test.ts
│   │       │   │   ├── get_mac_app_path.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── launch_mac_app.test.ts
│   │       │   │   ├── re-exports.test.ts
│   │       │   │   ├── stop_mac_app.test.ts
│   │       │   │   └── test_macos.test.ts
│   │       │   ├── build_macos.ts
│   │       │   ├── build_run_macos.ts
│   │       │   ├── clean.ts
│   │       │   ├── discover_projs.ts
│   │       │   ├── get_mac_app_path.ts
│   │       │   ├── get_mac_bundle_id.ts
│   │       │   ├── index.ts
│   │       │   ├── launch_mac_app.ts
│   │       │   ├── list_schemes.ts
│   │       │   ├── show_build_settings.ts
│   │       │   ├── stop_mac_app.ts
│   │       │   └── test_macos.ts
│   │       ├── project-discovery
│   │       │   ├── __tests__
│   │       │   │   ├── discover_projs.test.ts
│   │       │   │   ├── get_app_bundle_id.test.ts
│   │       │   │   ├── get_mac_bundle_id.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── list_schemes.test.ts
│   │       │   │   └── show_build_settings.test.ts
│   │       │   ├── discover_projs.ts
│   │       │   ├── get_app_bundle_id.ts
│   │       │   ├── get_mac_bundle_id.ts
│   │       │   ├── index.ts
│   │       │   ├── list_schemes.ts
│   │       │   └── show_build_settings.ts
│   │       ├── project-scaffolding
│   │       │   ├── __tests__
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── scaffold_ios_project.test.ts
│   │       │   │   └── scaffold_macos_project.test.ts
│   │       │   ├── index.ts
│   │       │   ├── scaffold_ios_project.ts
│   │       │   └── scaffold_macos_project.ts
│   │       ├── session-management
│   │       │   ├── __tests__
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── session_clear_defaults.test.ts
│   │       │   │   ├── session_set_defaults.test.ts
│   │       │   │   └── session_show_defaults.test.ts
│   │       │   ├── index.ts
│   │       │   ├── session_clear_defaults.ts
│   │       │   ├── session_set_defaults.ts
│   │       │   └── session_show_defaults.ts
│   │       ├── simulator
│   │       │   ├── __tests__
│   │       │   │   ├── boot_sim.test.ts
│   │       │   │   ├── build_run_sim.test.ts
│   │       │   │   ├── build_sim.test.ts
│   │       │   │   ├── get_sim_app_path.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── install_app_sim.test.ts
│   │       │   │   ├── launch_app_logs_sim.test.ts
│   │       │   │   ├── launch_app_sim.test.ts
│   │       │   │   ├── list_sims.test.ts
│   │       │   │   ├── open_sim.test.ts
│   │       │   │   ├── record_sim_video.test.ts
│   │       │   │   ├── screenshot.test.ts
│   │       │   │   ├── stop_app_sim.test.ts
│   │       │   │   └── test_sim.test.ts
│   │       │   ├── boot_sim.ts
│   │       │   ├── build_run_sim.ts
│   │       │   ├── build_sim.ts
│   │       │   ├── clean.ts
│   │       │   ├── describe_ui.ts
│   │       │   ├── discover_projs.ts
│   │       │   ├── get_app_bundle_id.ts
│   │       │   ├── get_sim_app_path.ts
│   │       │   ├── index.ts
│   │       │   ├── install_app_sim.ts
│   │       │   ├── launch_app_logs_sim.ts
│   │       │   ├── launch_app_sim.ts
│   │       │   ├── list_schemes.ts
│   │       │   ├── list_sims.ts
│   │       │   ├── open_sim.ts
│   │       │   ├── record_sim_video.ts
│   │       │   ├── screenshot.ts
│   │       │   ├── show_build_settings.ts
│   │       │   ├── stop_app_sim.ts
│   │       │   └── test_sim.ts
│   │       ├── simulator-management
│   │       │   ├── __tests__
│   │       │   │   ├── erase_sims.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── reset_sim_location.test.ts
│   │       │   │   ├── set_sim_appearance.test.ts
│   │       │   │   ├── set_sim_location.test.ts
│   │       │   │   └── sim_statusbar.test.ts
│   │       │   ├── boot_sim.ts
│   │       │   ├── erase_sims.ts
│   │       │   ├── index.ts
│   │       │   ├── list_sims.ts
│   │       │   ├── open_sim.ts
│   │       │   ├── reset_sim_location.ts
│   │       │   ├── set_sim_appearance.ts
│   │       │   ├── set_sim_location.ts
│   │       │   └── sim_statusbar.ts
│   │       ├── swift-package
│   │       │   ├── __tests__
│   │       │   │   ├── active-processes.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── swift_package_build.test.ts
│   │       │   │   ├── swift_package_clean.test.ts
│   │       │   │   ├── swift_package_list.test.ts
│   │       │   │   ├── swift_package_run.test.ts
│   │       │   │   ├── swift_package_stop.test.ts
│   │       │   │   └── swift_package_test.test.ts
│   │       │   ├── active-processes.ts
│   │       │   ├── index.ts
│   │       │   ├── swift_package_build.ts
│   │       │   ├── swift_package_clean.ts
│   │       │   ├── swift_package_list.ts
│   │       │   ├── swift_package_run.ts
│   │       │   ├── swift_package_stop.ts
│   │       │   └── swift_package_test.ts
│   │       ├── ui-testing
│   │       │   ├── __tests__
│   │       │   │   ├── button.test.ts
│   │       │   │   ├── describe_ui.test.ts
│   │       │   │   ├── gesture.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── key_press.test.ts
│   │       │   │   ├── key_sequence.test.ts
│   │       │   │   ├── long_press.test.ts
│   │       │   │   ├── screenshot.test.ts
│   │       │   │   ├── swipe.test.ts
│   │       │   │   ├── tap.test.ts
│   │       │   │   ├── touch.test.ts
│   │       │   │   └── type_text.test.ts
│   │       │   ├── button.ts
│   │       │   ├── describe_ui.ts
│   │       │   ├── gesture.ts
│   │       │   ├── index.ts
│   │       │   ├── key_press.ts
│   │       │   ├── key_sequence.ts
│   │       │   ├── long_press.ts
│   │       │   ├── screenshot.ts
│   │       │   ├── swipe.ts
│   │       │   ├── tap.ts
│   │       │   ├── touch.ts
│   │       │   └── type_text.ts
│   │       └── utilities
│   │           ├── __tests__
│   │           │   ├── clean.test.ts
│   │           │   └── index.test.ts
│   │           ├── clean.ts
│   │           └── index.ts
│   ├── server
│   │   └── server.ts
│   ├── test-utils
│   │   └── mock-executors.ts
│   ├── types
│   │   └── common.ts
│   └── utils
│       ├── __tests__
│       │   ├── build-utils.test.ts
│       │   ├── environment.test.ts
│       │   ├── session-aware-tool-factory.test.ts
│       │   ├── session-store.test.ts
│       │   ├── simulator-utils.test.ts
│       │   ├── test-runner-env-integration.test.ts
│       │   └── typed-tool-factory.test.ts
│       ├── axe
│       │   └── index.ts
│       ├── axe-helpers.ts
│       ├── build
│       │   └── index.ts
│       ├── build-utils.ts
│       ├── capabilities.ts
│       ├── command.ts
│       ├── CommandExecutor.ts
│       ├── environment.ts
│       ├── errors.ts
│       ├── execution
│       │   └── index.ts
│       ├── FileSystemExecutor.ts
│       ├── log_capture.ts
│       ├── log-capture
│       │   └── index.ts
│       ├── logger.ts
│       ├── logging
│       │   └── index.ts
│       ├── plugin-registry
│       │   └── index.ts
│       ├── responses
│       │   └── index.ts
│       ├── schema-helpers.ts
│       ├── sentry.ts
│       ├── session-store.ts
│       ├── simulator-utils.ts
│       ├── template
│       │   └── index.ts
│       ├── template-manager.ts
│       ├── test
│       │   └── index.ts
│       ├── test-common.ts
│       ├── tool-registry.ts
│       ├── typed-tool-factory.ts
│       ├── validation
│       │   └── index.ts
│       ├── validation.ts
│       ├── version
│       │   └── index.ts
│       ├── video_capture.ts
│       ├── video-capture
│       │   └── index.ts
│       ├── xcode.ts
│       ├── xcodemake
│       │   └── index.ts
│       └── xcodemake.ts
├── tsconfig.json
├── tsconfig.test.json
├── tsup.config.ts
└── vitest.config.ts
```

# Files

--------------------------------------------------------------------------------
/.axe-version:
--------------------------------------------------------------------------------

```
1 | 1.1.1
2 | 
```

--------------------------------------------------------------------------------
/.cursorrules:
--------------------------------------------------------------------------------

```
1 | AGENTS.md
```

--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------

```
1 | node_modules
2 | build
3 | dist
4 | coverage
5 | *.json
6 | *.md
7 | 
```

--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------

```javascript
1 | export default {
2 |   semi: true,
3 |   trailingComma: 'all',
4 |   singleQuote: true,
5 |   printWidth: 100,
6 |   tabWidth: 2,
7 |   endOfLine: 'auto',
8 | };
9 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS_Calculator/CalculatorAppPackage/.gitignore:
--------------------------------------------------------------------------------

```
1 | .DS_Store
2 | /.build
3 | /Packages
4 | xcuserdata/
5 | DerivedData/
6 | .swiftpm/configuration/registries.json
7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8 | .netrc
9 | 
```

--------------------------------------------------------------------------------
/example_projects/spm/.gitignore:
--------------------------------------------------------------------------------

```
1 | .DS_Store
2 | /.build
3 | /Packages
4 | xcuserdata/
5 | DerivedData/
6 | .swiftpm/configuration/registries.json
7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8 | .netrc
9 | 
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
  1 | # Dependencies
  2 | node_modules/
  3 | npm-debug.log*
  4 | yarn-debug.log*
  5 | yarn-error.log*
  6 | 
  7 | # TypeScript build output
  8 | dist/
  9 | /build/
 10 | *.tsbuildinfo
 11 | 
 12 | # Auto-generated files
 13 | src/version.ts
 14 | src/core/generated-plugins.ts
 15 | src/core/generated-resources.ts
 16 | 
 17 | # IDE and editor files
 18 | .idea/
 19 | .vscode/*
 20 | !.vscode/mcp.json
 21 | !.vscode/launch.json
 22 | !.vscode/settings.json
 23 | !.vscode/tasks.json
 24 | !.vscode/extensions.json
 25 | *.swp
 26 | *.swo
 27 | .DS_Store
 28 | .env
 29 | .env.local
 30 | .env.*.local
 31 | 
 32 | # Logs
 33 | logs/
 34 | *.log
 35 | 
 36 | # Test coverage
 37 | coverage/
 38 | 
 39 | # macOS specific
 40 | .DS_Store
 41 | .AppleDouble
 42 | .LSOverride
 43 | Icon
 44 | ._*
 45 | .DocumentRevisions-V100
 46 | .fseventsd
 47 | .Spotlight-V100
 48 | .TemporaryItems
 49 | .Trashes
 50 | .VolumeIcon.icns
 51 | .com.apple.timemachine.donotpresent
 52 | 
 53 | # Xcode
 54 | *.xcodeproj/*
 55 | !*.xcodeproj/project.pbxproj
 56 | !*.xcodeproj/xcshareddata/
 57 | !*.xcworkspace/contents.xcworkspacedata
 58 | **/xcshareddata/WorkspaceSettings.xcsettings
 59 | *.xcuserstate
 60 | project.xcworkspace/
 61 | xcuserdata/
 62 | 
 63 | # Debug files
 64 | .nyc_output/
 65 | *.map
 66 | 
 67 | # Optional npm cache directory
 68 | .npm
 69 | 
 70 | # Optional eslint cache
 71 | .eslintcache
 72 | 
 73 | # Optional REPL history
 74 | .node_repl_history
 75 | 
 76 | # Output of 'npm pack'
 77 | *.tgz
 78 | 
 79 | # Yarn Integrity file
 80 | .yarn-integrity
 81 | 
 82 | # dotenv environment variable files
 83 | .env
 84 | .env.test
 85 | .env.production
 86 | 
 87 | # parcel-bundler cache
 88 | .cache
 89 | .parcel-cache
 90 | 
 91 | # Windsurf
 92 | .windsurfrules
 93 | 
 94 | # Sentry Config File
 95 | .sentryclirc
 96 | 
 97 | # Claude Config File
 98 | **/.claude/settings.local.json
 99 | 
100 | # incremental builds
101 | Makefile
102 | buildServer.json
103 | 
104 | # Bundled AXe artifacts (generated during build)
105 | bundled/
106 | 
107 | /.mcpregistry_github_token
108 | /.mcpregistry_registry_token
109 | /key.pem
110 | .mcpli
111 | .factory
112 | 
```

--------------------------------------------------------------------------------
/.github/workflows/README.md:
--------------------------------------------------------------------------------

```markdown
1 | # Test workflow trigger
2 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | <img src="banner.png" alt="XcodeBuild MCP" width="600"/>
  2 | 
  3 | A Model Context Protocol (MCP) server that provides Xcode-related tools for integration with AI assistants and other MCP clients.
  4 | 
  5 | [![CI](https://github.com/cameroncooke/XcodeBuildMCP/actions/workflows/ci.yml/badge.svg)](https://github.com/cameroncooke/XcodeBuildMCP/actions/workflows/ci.yml)
  6 | [![npm version](https://badge.fury.io/js/xcodebuildmcp.svg)](https://badge.fury.io/js/xcodebuildmcp) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Node.js](https://img.shields.io/badge/node->=18.x-brightgreen.svg)](https://nodejs.org/) [![Xcode 16](https://img.shields.io/badge/Xcode-16-blue.svg)](https://developer.apple.com/xcode/) [![macOS](https://img.shields.io/badge/platform-macOS-lightgrey.svg)](https://www.apple.com/macos/) [![MCP](https://img.shields.io/badge/MCP-Compatible-green.svg)](https://modelcontextprotocol.io/) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/cameroncooke/XcodeBuildMCP)
  7 | 
  8 | ## Table of contents
  9 | 
 10 | - [Overview](#overview)
 11 | - [Why?](#why)
 12 | - [Features](#features)
 13 |   - [Xcode project management](#xcode-project-management)
 14 |   - [Swift Package Manager](#swift-package-manager)
 15 |   - [Simulator management](#simulator-management)
 16 |   - [Device management](#device-management)
 17 |   - [App utilities](#app-utilities)
 18 |   - [MCP Resources](#mcp-resources)
 19 | - [Getting started](#getting-started)
 20 |   - [Prerequisites](#prerequisites)
 21 |   - [Configure your MCP client](#configure-your-mcp-client)
 22 |     - [One click install](#one-click-install)
 23 |     - [General installation](#general-installation)
 24 |     - [Specific client installation instructions](#specific-client-installation-instructions)
 25 |       - [OpenAI Codex CLI](#openai-codex-cli)
 26 |       - [Claude Code CLI](#claude-code-cli)
 27 |       - [Smithery](#smithery)
 28 |     - [MCP Compatibility](#mcp-compatibility)
 29 | - [Incremental build support](#incremental-build-support)
 30 | - [Dynamic Tools](#dynamic-tools)
 31 |   - [What is Dynamic Tools?](#what-is-dynamic-tools)
 32 |   - [How to Enable Dynamic Tools](#how-to-enable-dynamic-tools)
 33 |   - [Usage Example](#usage-example)
 34 |   - [Client Compatibility](#client-compatibility)
 35 |   - [Selective Workflow Loading (Static Mode)](#selective-workflow-loading-static-mode)
 36 | - [Code Signing for Device Deployment](#code-signing-for-device-deployment)
 37 | - [Troubleshooting](#troubleshooting)
 38 |   - [Doctor Tool](#doctor-tool)
 39 | - [Privacy](#privacy)
 40 |   - [What is sent to Sentry?](#what-is-sent-to-sentry)
 41 |   - [Opting Out of Sentry](#opting-out-of-sentry)
 42 | - [Demos](#demos)
 43 |   - [Autonomously fixing build errors in Cursor](#autonomously-fixing-build-errors-in-cursor)
 44 |   - [Utilising the new UI automation and screen capture features](#utilising-the-new-ui-automation-and-screen-capture-features)
 45 |   - [Building and running iOS app in Claude Desktop](#building-and-running-ios-app-in-claude-desktop)
 46 | - [Contributing](#contributing)
 47 | - [Licence](#licence)
 48 | 
 49 | ## Overview
 50 | 
 51 | XcodeBuildMCP is a Model Context Protocol (MCP) server that exposes Xcode operations as tools and resources for AI assistants and other MCP clients. Built with a modern plugin architecture, it provides a comprehensive set of self-contained tools organized into workflow-based directories, plus MCP resources for efficient data access, enabling programmatic interaction with Xcode projects, simulators, devices, and Swift packages through a standardized interface.
 52 | 
 53 | ![xcodebuildmcp2](https://github.com/user-attachments/assets/8961d5db-f7ed-4e60-bbb8-48bfd0bc1353)
 54 | <caption>Using Cursor to build, install, and launch an app on the iOS simulator while capturing logs at run-time.</caption>
 55 | 
 56 | ## Why?
 57 | 
 58 | The XcodeBuild MCP tool exists primarily to streamline and standardise interaction between AI agents and Xcode projects. By providing dedicated tools for common Xcode operations, it removes reliance on manual or potentially incorrect command-line invocations.
 59 | 
 60 | This ensures a reliable and efficient development process, allowing agents to seamlessly leverage Xcode's capabilities while reducing the risk of configuration errors.
 61 | 
 62 | Critically, this MCP enables AI agents to independently validate code changes by building projects, inspecting errors, and iterating autonomously. In contrast to user-driven tools like Sweetpad, XcodeBuild MCP empowers agents to automate these workflows effectively.
 63 | 
 64 | ## Features
 65 | 
 66 | The XcodeBuildMCP server provides the following tool capabilities:
 67 | 
 68 | ### Xcode project management
 69 | - **Discover Projects**: Xcode projects and workspaces discovery
 70 | - **Build Operations**: Platform-specific build tools for macOS, iOS simulator, and iOS device targets
 71 | - **Project Information**: Tools to list schemes and show build settings for Xcode projects and workspaces
 72 | - **Clean Operations**: Clean build products using xcodebuild's native clean action
 73 | - **Incremental build support**: Lightning fast builds using incremental build support (experimental, opt-in required)
 74 | - **Project Scaffolding**: Create new iOS and macOS projects from modern templates with workspace + SPM package architecture, customizable bundle identifiers, deployment targets, and device families
 75 | 
 76 | ### Swift Package Manager
 77 | - **Build Packages**: Build Swift packages with configuration and architecture options
 78 | - **Run Tests**: Execute Swift package test suites with filtering and parallel execution
 79 | - **Run Executables**: Execute package binaries with timeout handling and background execution support
 80 | - **Process Management**: List and stop long-running executables started with Swift Package tools
 81 | - **Clean Artifacts**: Remove build artifacts and derived data for fresh builds
 82 | 
 83 | ### Simulator management
 84 | - **Simulator Control**: List, boot, and open simulators
 85 | - **App Lifecycle**: Complete app management - install, launch, and stop apps on simulators
 86 | - **Log Capture**: Capture run-time logs from a simulator
 87 | - **UI Automation**: Interact with simulator UI elements
 88 | - **Screenshot**: Capture screenshots from a simulator
 89 | - **Video Capture**: Start/stop simulator video capture to MP4 (AXe v1.1.0+)
 90 | 
 91 | ### Device management
 92 | - **Device Discovery**: List connected physical Apple devices over USB or Wi-Fi
 93 | - **App Lifecycle**: Complete app management - build, install, launch, and stop apps on physical devices
 94 | - **Testing**: Run test suites on physical devices with detailed results and cross-platform support
 95 | - **Log Capture**: Capture console output from apps running on physical Apple devices
 96 | - **Wireless Connectivity**: Support for devices connected over Wi-Fi networks
 97 | 
 98 | ### App utilities
 99 | - **Bundle ID Extraction**: Extract bundle identifiers from app bundles across all Apple platforms
100 | - **App Lifecycle Management**: Complete app lifecycle control across all platforms
101 |   - Launch apps on simulators, physical devices, and macOS
102 |   - Stop running apps with process ID or bundle ID management
103 |   - Process monitoring and control for comprehensive app management
104 | 
105 | ### MCP Resources
106 | 
107 | For clients that support MCP resources XcodeBuildMCP provides efficient URI-based data access:
108 | 
109 | - **Simulators Resource** (`xcodebuildmcp://simulators`): Direct access to available iOS simulators with UUIDs and states
110 | - **Devices Resource** (`xcodebuildmcp://devices`): Direct access to connected physical Apple devices with UDIDs and states
111 | - **Doctor Resource** (`xcodebuildmcp://doctor`): Direct access to environment information such as Xcode version, macOS version, and Node.js version
112 | 
113 | ## Getting started
114 | 
115 | ### Prerequisites
116 | 
117 | - macOS 14.5 or later
118 | - Xcode 16.x or later
119 | - Node 18.x or later
120 | 
121 | > Video capture requires the bundled AXe binary (v1.1.0+). Run `npm run bundle:axe` once locally before using `record_sim_video`. This is not required for unit tests.
122 | 
123 | Configure your MCP client
124 | 
125 | #### One click install
126 | 
127 | For a quick install, you can use the following links:
128 | 
129 | [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=XcodeBuildMCP&config=eyJ0eXBlIjoic3RkaW8iLCJjb21tYW5kIjoibnB4IC15IHhjb2RlYnVpbGRtY3BAbGF0ZXN0IiwiZW52Ijp7IklOQ1JFTUVOVEFMX0JVSUxEU19FTkFCTEVEIjoiZmFsc2UiLCJYQ09ERUJVSUxETUNQX1NFTlRSWV9ESVNBQkxFRCI6ImZhbHNlIn19)
130 | 
131 | [<img src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Server&color=0098FF" alt="Install in VS Code">](https://insiders.vscode.dev/redirect/mcp/install?name=XcodeBuildMCP&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22xcodebuildmcp%40latest%22%5D%7D)
132 | 
133 | [<img alt="Install in VS Code Insiders" src="https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Server&color=24bfa5">](https://insiders.vscode.dev/redirect/mcp/install?name=XcodeBuildMCP&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22xcodebuildmcp%40latest%22%5D%7D&quality=insiders)
134 | 
135 | #### General installation
136 | 
137 | Most MCP clients (Cursor, VS Code, Windsurf, Claude Desktop etc) have standardised on the following JSON configuration format, just add the the following to your client's JSON configuration's `mcpServers` object:
138 | 
139 | ```json
140 | "XcodeBuildMCP": {
141 |   "command": "npx",
142 |   "args": [
143 |     "-y",
144 |     "xcodebuildmcp@latest"
145 |   ]
146 | }
147 | ```
148 | 
149 | #### Specific client installation instructions
150 | 
151 | ##### OpenAI Codex CLI
152 | 
153 | Codex uses a toml configuration file to configure MCP servers. To configure XcodeBuildMCP with [OpenAI's Codex CLI](https://github.com/openai/codex), add the following configuration to your Codex CLI config file:
154 | 
155 | ```toml
156 | [mcp_servers.XcodeBuildMCP]
157 | command = "npx"
158 | args = ["-y", "xcodebuildmcp@latest"]
159 | env = { "INCREMENTAL_BUILDS_ENABLED" = "false", "XCODEBUILDMCP_SENTRY_DISABLED" = "false" }
160 | ```
161 | 
162 | For more information see [OpenAI Codex MCP Server Configuration](https://github.com/openai/codex/blob/main/codex-rs/config.md#mcp_servers) documentation.
163 | 
164 | ##### Claude Code CLI
165 | 
166 | To use XcodeBuildMCP with [Claude Code](https://code.anthropic.com), you can add it via the command line:
167 | 
168 | ```bash
169 | # Add XcodeBuildMCP server to Claude Code
170 | claude mcp add XcodeBuildMCP npx xcodebuildmcp@latest
171 | 
172 | # Or with environment variables
173 | claude mcp add XcodeBuildMCP npx xcodebuildmcp@latest -e INCREMENTAL_BUILDS_ENABLED=false -e XCODEBUILDMCP_SENTRY_DISABLED=false
174 | ```
175 | 
176 | ##### Smithery
177 | 
178 | To install XcodeBuildMCP Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@cameroncooke/XcodeBuildMCP):
179 | 
180 | ```bash
181 | npx -y @smithery/cli install @cameroncooke/XcodeBuildMCP --client claude
182 | ```
183 | 
184 | > [!IMPORTANT]
185 | > Please note that XcodeBuildMCP will request xcodebuild to skip macro validation. This is to avoid errors when building projects that use Swift Macros.
186 | 
187 | #### MCP Compatibility
188 | 
189 | XcodeBuildMCP supports both MCP tools, resources and sampling. At time of writing the following editors have varying levels of MCP feature support:
190 | 
191 | | Editor | Tools | Resources | Samplng |
192 | |--------|-------|-----------|---------|
193 | | **VS Code** | ✅ | ✅ | ✅ |
194 | | **Cursor** | ✅ | ❌ | ❌ |
195 | | **Windsurf** | ✅ | ❌ | ❌ |
196 | | **Claude Code** | ✅ | ✅ | ❌ |
197 | | **Claude Desktop** | ✅ | ✅ | ❌ |
198 | 
199 | ## Incremental build support
200 | 
201 | XcodeBuildMCP includes experimental support for incremental builds. This feature is disabled by default and can be enabled by setting the `INCREMENTAL_BUILDS_ENABLED` environment variable to `true`:
202 | 
203 | To enable incremental builds, set the `INCREMENTAL_BUILDS_ENABLED` environment variable to `true`:
204 | 
205 | Example MCP configuration:
206 | ```json
207 | "XcodeBuildMCP": {
208 |   ...
209 |   "env": {
210 |     "INCREMENTAL_BUILDS_ENABLED": "true"
211 |   }
212 | }
213 | ```
214 | 
215 | > [!IMPORTANT]
216 | > Please note that incremental builds support is currently highly experimental and your mileage may vary. Please report any issues you encounter to the [issue tracker](https://github.com/cameroncooke/XcodeBuildMCP/issues).
217 | 
218 | ## Dynamic Tools
219 | 
220 | XcodeBuildMCP supports dynamic tool loading to optimize context window usage in AI assistants. This feature is particularly useful for managing the extensive toolset that XcodeBuildMCP provides.
221 | 
222 | ### What is Dynamic Tools?
223 | 
224 | By default, XcodeBuildMCP loads all available tools at startup (Static Mode), which provides immediate access to the complete toolset but uses a larger context window. Dynamic Tools mode solves this by:
225 | 
226 | 1. **Starting minimal**: Only essential tools like `discover_tools` and `discover_projs` are available initially
227 | 2. **AI-powered discovery**: When an AI agent identifies XcodeBuildMCP can help with development tasks, it automatically uses the `discover_tools` tool
228 | 3. **Intelligent loading**: The server uses an LLM call to identify the most relevant workflow group and dynamically loads only those tools
229 | 4. **Context efficiency**: Reduces the initial context footprint from the entire list of tools to just 2 discovery tools while maintaining full functionality
230 | 
231 | ### How to Enable Dynamic Tools
232 | 
233 | To enable dynamic tools, set the `XCODEBUILDMCP_DYNAMIC_TOOLS` environment variable to `true`:
234 | 
235 | Example MCP client configuration:
236 | ```json
237 | "XcodeBuildMCP": {
238 |   ...
239 |   "env": {
240 |     "XCODEBUILDMCP_DYNAMIC_TOOLS": "true"
241 |   }
242 | }
243 | ```
244 | 
245 | ### Usage Example
246 | 
247 | Once enabled, AI agents automatically discover and load relevant tools based on context. For example, when you mention working on an iOS app or the agent detects iOS development tasks in your workspace, it will automatically use the `discover_tools` tool to load the appropriate simulator and project tools needed for your workflow.
248 | 
249 | ### Client Compatibility
250 | 
251 | Dynamic Tools requires MCP clients that support **MCP Sampling** for the AI-powered tool discovery to function:
252 | 
253 | | Editor | Dynamic Tools Support |
254 | |--------|----------------------|
255 | | **VS Code** | ✅ |
256 | | **Cursor** | ❌ (No MCP Sampling) |
257 | | **Windsurf** | ❌ (No MCP Sampling) |
258 | | **Claude Code** | ❌ (No MCP Sampling) |
259 | | **Claude Desktop** | ❌ (No MCP Sampling) |
260 | 
261 | > [!NOTE]
262 | > For clients that don't support MCP Sampling, XcodeBuildMCP will automatically fall back to Static Mode, loading all tools at startup regardless of the `XCODEBUILDMCP_DYNAMIC_TOOLS` setting.
263 | 
264 | ### Selective Workflow Loading (Static Mode)
265 | 
266 | For clients that don't support MCP Sampling but still want to reduce context window usage, you can selectively load only specific workflows using the `XCODEBUILDMCP_ENABLED_WORKFLOWS` environment variable:
267 | 
268 | ```json
269 | "XcodeBuildMCP": {
270 |   ...
271 |   "env": {
272 |     "XCODEBUILDMCP_ENABLED_WORKFLOWS": "simulator,device,project-discovery"
273 |   }
274 | }
275 | ```
276 | 
277 | **Available Workflows:**
278 | - `device` (14 tools) - iOS Device Development
279 | - `simulator` (18 tools) - iOS Simulator Development
280 | - `simulator-management` (8 tools) - Simulator Management
281 | - `swift-package` (6 tools) - Swift Package Manager
282 | - `project-discovery` (5 tools) - Project Discovery
283 | - `macos` (11 tools) - macOS Development
284 | - `ui-testing` (11 tools) - UI Testing & Automation
285 | - `logging` (4 tools) - Log Capture & Management
286 | - `project-scaffolding` (2 tools) - Project Scaffolding
287 | - `utilities` (1 tool) - Project Utilities
288 | - `doctor` (1 tool) - System Doctor
289 | - `discovery` (1 tool) - Dynamic Tool Discovery
290 | 
291 | > [!NOTE]
292 | > The `XCODEBUILDMCP_ENABLED_WORKFLOWS` setting only works in Static Mode. If `XCODEBUILDMCP_DYNAMIC_TOOLS=true` is set, the selective workflow setting will be ignored.
293 | 
294 | ## Code Signing for Device Deployment
295 | 
296 | For device deployment features to work, code signing must be properly configured in Xcode **before** using XcodeBuildMCP device tools:
297 | 
298 | 1. Open your project in Xcode
299 | 2. Select your project target
300 | 3. Go to "Signing & Capabilities" tab
301 | 4. Configure "Automatically manage signing" and select your development team
302 | 5. Ensure a valid provisioning profile is selected
303 | 
304 | > **Note**: XcodeBuildMCP cannot configure code signing automatically. This initial setup must be done once in Xcode, after which the MCP device tools can build, install, and test apps on physical devices.
305 | 
306 | ## Troubleshooting
307 | 
308 | If you encounter issues with XcodeBuildMCP, the doctor tool can help identify the problem by providing detailed information about your environment and dependencies.
309 | 
310 | ### Doctor Tool
311 | 
312 | The doctor tool is a standalone utility that checks your system configuration and reports on the status of all dependencies required by XcodeBuildMCP. It's particularly useful when reporting issues.
313 | 
314 | ```bash
315 | # Run the doctor tool using npx
316 | npx --package xcodebuildmcp@latest xcodebuildmcp-doctor
317 | ```
318 | 
319 | The doctor tool will output comprehensive information about:
320 | 
321 | - System and Node.js environment
322 | - Xcode installation and configuration
323 | - Required dependencies (xcodebuild, AXe, etc.)
324 | - Environment variables affecting XcodeBuildMCP
325 | - Feature availability status
326 | 
327 | When reporting issues on GitHub, please include the full output from the doctor tool to help with troubleshooting.
328 | 
329 | ## Privacy
330 | 
331 | This project uses [Sentry](https://sentry.io/) for error monitoring and diagnostics. Sentry helps us track issues, crashes, and unexpected errors to improve the reliability and stability of XcodeBuildMCP.
332 | 
333 | ### What is sent to Sentry?
334 | - Only error-level logs and diagnostic information are sent to Sentry by default.
335 | - Error logs may include details such as error messages, stack traces, and (in some cases) file paths or project names. You can review the sources in this repository to see exactly what is logged.
336 | 
337 | ### Opting Out of Sentry
338 | - If you do not wish to send error logs to Sentry, you can opt out by setting the environment variable `XCODEBUILDMCP_SENTRY_DISABLED=true`.
339 | 
340 | Example MCP client configuration:
341 | ```json
342 | "XcodeBuildMCP": {
343 |   ...
344 |   "env": {
345 |     "XCODEBUILDMCP_SENTRY_DISABLED": "true"
346 |   }
347 | }
348 | ```
349 | 
350 | ## Demos
351 | 
352 | ### Autonomously fixing build errors in Cursor
353 | ![xcodebuildmcp3](https://github.com/user-attachments/assets/173e6450-8743-4379-a76c-de2dd2b678a3)
354 | 
355 | ### Utilising the new UI automation and screen capture features
356 | 
357 | ![xcodebuildmcp4](https://github.com/user-attachments/assets/17300a18-f47a-428a-aad3-dc094859c1b2)
358 | 
359 | ### Building and running iOS app in Claude Desktop
360 | https://github.com/user-attachments/assets/e3c08d75-8be6-4857-b4d0-9350b26ef086
361 | 
362 | ## Contributing
363 | 
364 | [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org/) [![Node.js](https://img.shields.io/badge/node->=18.x-brightgreen.svg)](https://nodejs.org/)
365 | 
366 | Contributions are welcome! Here's how you can help improve XcodeBuildMCP.
367 | 
368 | See our documentation for development:
369 | - [CONTRIBUTING](docs/CONTRIBUTING.md) - Contribution guidelines and development setup
370 | - [CODE_QUALITY](docs/CODE_QUALITY.md) - Code quality standards, linting, and architectural rules
371 | - [TESTING](docs/TESTING.md) - Testing principles and patterns
372 | - [ARCHITECTURE](docs/ARCHITECTURE.md) - System architecture and design principles
373 | 
374 | ## Licence
375 | 
376 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
377 | 
```

--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
1 | AGENTS.md
```

--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Contributor Covenant Code of Conduct
  2 | 
  3 | ## Our Pledge
  4 | 
  5 | We as members, contributors, and leaders pledge to make participation in our
  6 | community a harassment-free experience for everyone, regardless of age, body
  7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
  8 | identity and expression, level of experience, education, socio-economic status,
  9 | nationality, personal appearance, race, religion, or sexual identity
 10 | and orientation.
 11 | 
 12 | We pledge to act and interact in ways that contribute to an open, welcoming,
 13 | diverse, inclusive, and healthy community.
 14 | 
 15 | ## Our Standards
 16 | 
 17 | Examples of behavior that contributes to a positive environment for our
 18 | community include:
 19 | 
 20 | * Demonstrating empathy and kindness toward other people
 21 | * Being respectful of differing opinions, viewpoints, and experiences
 22 | * Giving and gracefully accepting constructive feedback
 23 | * Accepting responsibility and apologizing to those affected by our mistakes,
 24 |   and learning from the experience
 25 | * Focusing on what is best not just for us as individuals, but for the
 26 |   overall community
 27 | 
 28 | Examples of unacceptable behavior include:
 29 | 
 30 | * The use of sexualized language or imagery, and sexual attention or
 31 |   advances of any kind
 32 | * Trolling, insulting or derogatory comments, and personal or political attacks
 33 | * Public or private harassment
 34 | * Publishing others' private information, such as a physical or email
 35 |   address, without their explicit permission
 36 | * Other conduct which could reasonably be considered inappropriate in a
 37 |   professional setting
 38 | 
 39 | ## Enforcement Responsibilities
 40 | 
 41 | Community leaders are responsible for clarifying and enforcing our standards of
 42 | acceptable behavior and will take appropriate and fair corrective action in
 43 | response to any behavior that they deem inappropriate, threatening, offensive,
 44 | or harmful.
 45 | 
 46 | Community leaders have the right and responsibility to remove, edit, or reject
 47 | comments, commits, code, wiki edits, issues, and other contributions that are
 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
 49 | decisions when appropriate.
 50 | 
 51 | ## Scope
 52 | 
 53 | This Code of Conduct applies within all community spaces, and also applies when
 54 | an individual is officially representing the community in public spaces.
 55 | Examples of representing our community include using an official e-mail address,
 56 | posting via an official social media account, or acting as an appointed
 57 | representative at an online or offline event.
 58 | 
 59 | ## Enforcement
 60 | 
 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
 62 | reported to the community leaders responsible for enforcement at
 63 | [email protected].
 64 | All complaints will be reviewed and investigated promptly and fairly.
 65 | 
 66 | All community leaders are obligated to respect the privacy and security of the
 67 | reporter of any incident.
 68 | 
 69 | ## Enforcement Guidelines
 70 | 
 71 | Community leaders will follow these Community Impact Guidelines in determining
 72 | the consequences for any action they deem in violation of this Code of Conduct:
 73 | 
 74 | ### 1. Correction
 75 | 
 76 | **Community Impact**: Use of inappropriate language or other behavior deemed
 77 | unprofessional or unwelcome in the community.
 78 | 
 79 | **Consequence**: A private, written warning from community leaders, providing
 80 | clarity around the nature of the violation and an explanation of why the
 81 | behavior was inappropriate. A public apology may be requested.
 82 | 
 83 | ### 2. Warning
 84 | 
 85 | **Community Impact**: A violation through a single incident or series
 86 | of actions.
 87 | 
 88 | **Consequence**: A warning with consequences for continued behavior. No
 89 | interaction with the people involved, including unsolicited interaction with
 90 | those enforcing the Code of Conduct, for a specified period of time. This
 91 | includes avoiding interactions in community spaces as well as external channels
 92 | like social media. Violating these terms may lead to a temporary or
 93 | permanent ban.
 94 | 
 95 | ### 3. Temporary Ban
 96 | 
 97 | **Community Impact**: A serious violation of community standards, including
 98 | sustained inappropriate behavior.
 99 | 
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 | 
106 | ### 4. Permanent Ban
107 | 
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior,  harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 | 
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 | 
115 | ## Attribution
116 | 
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 | 
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 | 
124 | [homepage]: https://www.contributor-covenant.org
125 | 
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 | 
```

--------------------------------------------------------------------------------
/AGENTS.md:
--------------------------------------------------------------------------------

```markdown
  1 | This file provides guidance to AI assisants (Claude Code, Cursor etc) when working with code in this repository.
  2 | 
  3 | ## Project Overview
  4 | 
  5 | XcodeBuildMCP is a Model Context Protocol (MCP) server providing standardized tools for AI assistants to interact with Xcode projects, iOS simulators, devices, and Apple development workflows. It's a TypeScript/Node.js project that runs as a stdio-based MCP server.
  6 | 
  7 | ## Common Commands
  8 | 
  9 | ### Build & Development
 10 | ```bash
 11 | npm run build         # Compile TypeScript with tsup, generates version info
 12 | npm run dev           # Watch mode development
 13 | npm run bundle:axe    # Bundle axe CLI tool for simulator automation (needed when using local MCP server)
 14 | npm run test          # Run complete Vitest test suite
 15 | npm run test:watch    # Watch mode testing
 16 | npm run lint          # ESLint code checking
 17 | npm run lint:fix       # ESLint code checking and fixing
 18 | npm run format:check  # Prettier code checking
 19 | npm run format        # Prettier code formatting
 20 | npm run typecheck     # TypeScript type checking
 21 | npm run inspect       # Run interactive MCP protocol inspector
 22 | npm run doctor        # Doctor CLI
 23 | ```
 24 | 
 25 | ### Development with Reloaderoo
 26 | 
 27 | **Reloaderoo** (v1.1.2+) provides CLI-based testing and hot-reload capabilities for XcodeBuildMCP without requiring MCP client configuration.
 28 | 
 29 | #### Quick Start
 30 | 
 31 | **CLI Mode (Testing & Development):**
 32 | ```bash
 33 | # List all tools
 34 | npx reloaderoo inspect list-tools -- node build/index.js
 35 | 
 36 | # Call any tool
 37 | npx reloaderoo inspect call-tool list_devices --params '{}' -- node build/index.js
 38 | 
 39 | # Get server information
 40 | npx reloaderoo inspect server-info -- node build/index.js
 41 | 
 42 | # List and read resources
 43 | npx reloaderoo inspect list-resources -- node build/index.js
 44 | npx reloaderoo inspect read-resource "xcodebuildmcp://devices" -- node build/index.js
 45 | ```
 46 | 
 47 | **Proxy Mode (MCP Client Integration):**
 48 | ```bash
 49 | # Start persistent server for MCP clients
 50 | npx reloaderoo proxy -- node build/index.js
 51 | 
 52 | # With debug logging
 53 | npx reloaderoo proxy --log-level debug -- node build/index.js
 54 | 
 55 | # Then ask AI: "Please restart the MCP server to load my changes"
 56 | ```
 57 | 
 58 | #### All CLI Inspect Commands
 59 | 
 60 | Reloaderoo provides 8 inspect subcommands for comprehensive MCP server testing:
 61 | 
 62 | ```bash
 63 | # Server capabilities and information
 64 | npx reloaderoo inspect server-info -- node build/index.js
 65 | 
 66 | # Tool management
 67 | npx reloaderoo inspect list-tools -- node build/index.js
 68 | npx reloaderoo inspect call-tool <tool_name> --params '<json>' -- node build/index.js
 69 | 
 70 | # Resource access
 71 | npx reloaderoo inspect list-resources -- node build/index.js
 72 | npx reloaderoo inspect read-resource "<uri>" -- node build/index.js
 73 | 
 74 | # Prompt management
 75 | npx reloaderoo inspect list-prompts -- node build/index.js
 76 | npx reloaderoo inspect get-prompt <name> --args '<json>' -- node build/index.js
 77 | 
 78 | # Connectivity testing
 79 | npx reloaderoo inspect ping -- node build/index.js
 80 | ```
 81 | 
 82 | #### Advanced Options
 83 | 
 84 | ```bash
 85 | # Custom working directory
 86 | npx reloaderoo inspect list-tools --working-dir /custom/path -- node build/index.js
 87 | 
 88 | # Timeout configuration
 89 | npx reloaderoo inspect call-tool slow_tool --timeout 60000 --params '{}' -- node build/index.js
 90 | 
 91 | # Use timeout configuration if needed
 92 | npx reloaderoo inspect server-info --timeout 60000 -- node build/index.js
 93 | 
 94 | # Debug logging (use proxy mode for detailed logging)
 95 | npx reloaderoo proxy --log-level debug -- node build/index.js
 96 | ```
 97 | 
 98 | #### Key Benefits
 99 | 
100 | - ✅ **No MCP Client Setup**: Direct CLI access to all 84+ tools
101 | - ✅ **Raw JSON Output**: Perfect for AI agents and programmatic use
102 | - ✅ **Hot-Reload Support**: `restart_server` tool for MCP client development
103 | - ✅ **Claude Code Compatible**: Automatic content block consolidation
104 | - ✅ **8 Inspect Commands**: Complete MCP protocol testing capabilities
105 | - ✅ **Universal Compatibility**: Works on any system via npx
106 | 
107 | For complete documentation, examples, and troubleshooting, see @docs/RELOADEROO.md
108 | 
109 | ## Architecture Overview
110 | 
111 | ### Plugin-Based MCP architecture
112 | 
113 | XcodeBuildMCP uses the concept of configuration by convention for MCP exposing and running MCP capabilities like tools and resources. This means to add a new tool or resource, you simply create a new file in the appropriate directory and it will be automatically loaded and exposed to MCP clients.
114 | 
115 | #### Tools
116 | 
117 | Tools are the core of the MCP server and are the primary way to interact with the server. They are organized into directories by their functionality and are automatically loaded and exposed to MCP clients.
118 | 
119 | For more information see @docs/PLUGIN_DEVELOPMENT.md
120 | 
121 | #### Resources
122 | 
123 | Resources are the secondary way to interact with the server. They are used to provide data to tools and are organized into directories by their functionality and are automatically loaded and exposed to MCP clients.
124 | 
125 | For more information see @docs/PLUGIN_DEVELOPMENT.md
126 | 
127 | ### Operating Modes
128 | 
129 | XcodeBuildMCP has two modes to manage its extensive toolset, controlled by the `XCODEBUILDMCP_DYNAMIC_TOOLS` environment variable.
130 | 
131 | #### Static Mode (Default)
132 | - **Environment**: `XCODEBUILDMCP_DYNAMIC_TOOLS=false` or unset.
133 | - **Behavior**: All tools are loaded at startup. This provides immediate access to the full toolset but uses a larger context window.
134 | 
135 | #### Dynamic Mode (AI-Powered)
136 | - **Environment**: `XCODEBUILDMCP_DYNAMIC_TOOLS=true`.
137 | - **Behavior**: Only the `discover_tools` tool is available initially. You can use this tool by providing a natural language task description. The server then uses an LLM call (via MCP Sampling) to identify the most relevant workflow group and dynamically loads only those tools. This conserves context window space.
138 | 
139 | #### Claude Code Compatibility Workaround
140 | - **Detection**: Automatic detection when running under Claude Code.
141 | - **Purpose**: Workaround for Claude Code's MCP specification violation where it only displays the first content block in tool responses.
142 | - **Behavior**: When Claude Code is detected, multiple content blocks are automatically consolidated into a single text response, separated by `---` dividers. This ensures all information (including test results and stderr warnings) is visible to Claude Code users.
143 | 
144 | ### Core Architecture Layers
145 | 1. **MCP Transport**: stdio protocol communication
146 | 2. **Plugin Discovery**: Automatic tool AND resource registration system  
147 | 3. **MCP Resources**: URI-based data access (e.g., `xcodebuildmcp://simulators`)
148 | 4. **Tool Implementation**: Self-contained workflow modules
149 | 5. **Shared Utilities**: Command execution, build management, validation
150 | 6. **Types**: Shared interfaces and Zod schemas
151 | 
152 | For more information see @docs/ARCHITECTURE.md
153 | 
154 | ## Testing
155 | 
156 | The project enforces a strict **Dependency Injection (DI)** testing philosophy.
157 | 
158 | - **NO Vitest Mocking**: The use of `vi.mock()`, `vi.fn()`, `vi.spyOn()`, etc., is **completely banned**.
159 | - **Executors**: All external interactions (like running commands or accessing the file system) are handled through injectable "executors".
160 |     - `CommandExecutor`: For running shell commands.
161 |     - `FileSystemExecutor`: For file system operations.
162 | - **Testing Logic**: Tests import the core `...Logic` function from a tool file and pass in a mock executor (`createMockExecutor` or `createMockFileSystemExecutor`) to simulate different outcomes.
163 | 
164 | This approach ensures that tests are robust, easy to maintain, and verify the actual integration between components without being tightly coupled to implementation details.
165 | 
166 | For complete guidelines, refer to @docs/TESTING.md.
167 | 
168 | ## TypeScript Import Standards
169 | 
170 | This project uses **TypeScript file extensions** (`.ts`) for all relative imports to ensure compatibility with native TypeScript runtimes.
171 | 
172 | ### Import Rules
173 | 
174 | - ✅ **Use `.ts` extensions**: `import { tool } from './tool.ts'`
175 | - ✅ **Use `.ts` for re-exports**: `export { default } from '../shared/tool.ts'`
176 | - ✅ **External packages use `.js`**: `import { McpServer } from '@camsoft/mcp-sdk/server/mcp.js'`
177 | - ❌ **Never use `.js` for internal files**: `import { tool } from './tool.js'` ← ESLint error
178 | 
179 | ### Benefits
180 | 
181 | 1. **Future-proof**: Compatible with native TypeScript runtimes (Bun, Deno, Node.js --loader)
182 | 2. **IDE Experience**: Direct navigation to source TypeScript files
183 | 3. **Consistency**: Import path matches the actual file you're editing
184 | 4. **Modern Standard**: Aligns with TypeScript 4.7+ `allowImportingTsExtensions`
185 | 
186 | ### ESLint Enforcement
187 | 
188 | The project automatically enforces this standard:
189 | 
190 | ```bash
191 | npm run lint  # Will catch .js imports for internal files
192 | ```
193 | 
194 | This ensures all new code follows the `.ts` import pattern and maintains compatibility with both current and future TypeScript execution environments.
195 | 
196 | ## Release Process
197 | 
198 | Follow standardized development workflow with feature branches, structured pull requests, and linear commit history. **Never push to main directly or force push without permission.**
199 | 
200 | For complete guidelines, refer to @docs/RELEASE_PROCESS.md
201 | 
202 | ## Useful external resources
203 | 
204 | ### Model Context Protocol
205 | 
206 | https://modelcontextprotocol.io/llms-full.txt
207 | 
208 | ### MCP Specification
209 | 
210 | https://modelcontextprotocol.io/specification
211 | 
212 | ### MCP Inspector
213 | 
214 | https://github.com/modelcontextprotocol/inspector
215 | 
216 | ### MCP Client SDKs
217 | 
218 | https://github.com/modelcontextprotocol/typescript-sdk
```

--------------------------------------------------------------------------------
/docs/CONTRIBUTING.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Contributing
  2 | 
  3 | Contributions are welcome! Here's how you can help improve XcodeBuildMCP.
  4 | 
  5 | ## Local development setup
  6 | 
  7 | ### Prerequisites
  8 | 
  9 | In addition to the prerequisites mentioned in the [Getting started](README.md/#getting-started) section of the README, you will also need:
 10 | 
 11 | - Node.js (v18 or later)
 12 | - npm
 13 | 
 14 | #### Optional: Enabling UI Automation
 15 | 
 16 | When running locally, you'll need to install AXe for UI automation:
 17 | 
 18 | ```bash
 19 | # Install axe (required for UI automation)
 20 | brew tap cameroncooke/axe
 21 | brew install axe
 22 | ```
 23 | 
 24 | ### Installation
 25 | 
 26 | 1. Clone the repository
 27 | 2. Install dependencies:
 28 |    ```
 29 |    npm install
 30 |    ```
 31 | 3. Build the project:
 32 |    ```
 33 |    npm run build
 34 |    ```
 35 | 4. Start the server:
 36 |    ```
 37 |    node build/index.js
 38 |    ```
 39 | 
 40 | ### Configure your MCP client
 41 | 
 42 | Most MCP clients (Cursor, VS Code, Windsurf, Claude Desktop etc) have standardised on the following JSON configuration format, just add the the following to your client's JSON configuration's `mcpServers` object:
 43 | 
 44 | ```json
 45 | {
 46 |   "mcpServers": {
 47 |     "XcodeBuildMCP": {
 48 |       "command": "node",
 49 |       "args": [
 50 |         "/path_to/XcodeBuildMCP/build/index.js"
 51 |       ]
 52 |     }
 53 |   }
 54 | }
 55 | ```
 56 | 
 57 | ### Developing using VS Code
 58 | 
 59 | VS Code is especially good for developing XcodeBuildMCP as it has a built-in way to view MCP client/server logs as well as the ability to configure MCP servers at a project level. It probably has the most comprehensive support for MCP development.
 60 | 
 61 | To make your development workflow in VS Code more efficient:
 62 | 
 63 | 1.  **Start the MCP Server**: Open the `.vscode/mcp.json` file. You can start the `xcodebuildmcp-dev` server either by clicking the `Start` CodeLens that appears above the server definition, or by opening the Command Palette (`Cmd+Shift+P` or `Ctrl+Shift+P`), running `Mcp: List Servers`, selecting `xcodebuildmcp-dev`, and starting the server.
 64 | 2.  **Launch the Debugger**: Press `F5` to attach the Node.js debugger.
 65 | 
 66 | Once these steps are completed, you can utilize the tools from the MCP server you are developing within this repository in agent mode.
 67 | For more details on how to work with MCP servers in VS Code see: https://code.visualstudio.com/docs/copilot/chat/mcp-servers
 68 | 
 69 | ### Debugging
 70 | 
 71 | #### MCP Inspector (Basic Debugging)
 72 | 
 73 | You can use MCP Inspector for basic debugging via:
 74 | 
 75 | ```bash
 76 | npm run inspect
 77 | ```
 78 | 
 79 | or if you prefer the explicit command:
 80 | 
 81 | ```bash
 82 | npx @modelcontextprotocol/inspector node build/index.js
 83 | ```
 84 | 
 85 | #### Reloaderoo (Advanced Debugging) - **RECOMMENDED**
 86 | 
 87 | For development and debugging, we strongly recommend using **Reloaderoo**, which provides hot-reloading capabilities and advanced debugging features for MCP servers.
 88 | 
 89 | Reloaderoo operates in two modes:
 90 | 
 91 | ##### 1. Proxy Mode (Hot-Reloading)
 92 | Provides transparent hot-reloading without disconnecting your MCP client:
 93 | 
 94 | ```bash
 95 | # Install reloaderoo globally
 96 | npm install -g reloaderoo
 97 | 
 98 | # Start XcodeBuildMCP through reloaderoo proxy
 99 | reloaderoo -- node build/index.js
100 | ```
101 | 
102 | **Benefits**:
103 | - 🔄 Hot-reload server without restarting client
104 | - 🛠️ Automatic `restart_server` tool added to toolset
105 | - 🌊 Transparent MCP protocol forwarding
106 | - 📡 Full protocol support (tools, resources, prompts)
107 | 
108 | **MCP Client Configuration for Proxy Mode**:
109 | ```json
110 | "XcodeBuildMCP": {
111 |   "command": "reloaderoo",
112 |   "args": ["--", "node", "/path/to/XcodeBuildMCP/build/index.js"],
113 |   "env": {
114 |     "XCODEBUILDMCP_DYNAMIC_TOOLS": "true",
115 |     "XCODEBUILDMCP_DEBUG": "true"
116 |   }
117 | }
118 | ```
119 | 
120 | ##### 2. Inspection Mode (Raw MCP Debugging)
121 | Exposes debug tools for making raw MCP protocol calls and inspecting server responses:
122 | 
123 | ```bash
124 | # Start reloaderoo in inspection mode
125 | reloaderoo inspect mcp -- node build/index.js
126 | ```
127 | 
128 | **Available Debug Tools**:
129 | - `list_tools` - List all server tools
130 | - `call_tool` - Execute any server tool with parameters
131 | - `list_resources` - List all server resources
132 | - `read_resource` - Read any server resource
133 | - `list_prompts` - List all server prompts
134 | - `get_prompt` - Get any server prompt
135 | - `get_server_info` - Get comprehensive server information
136 | - `ping` - Test server connectivity
137 | 
138 | **MCP Client Configuration for Inspection Mode**:
139 | ```json
140 | "XcodeBuildMCP": {
141 |   "command": "node",
142 |   "args": [
143 |     "/path/to/reloaderoo/dist/bin/reloaderoo.js",
144 |     "inspect", "mcp",
145 |     "--working-dir", "/path/to/XcodeBuildMCP",
146 |     "--",
147 |     "node", "/path/to/XcodeBuildMCP/build/index.js"
148 |   ],
149 |   "env": {
150 |     "XCODEBUILDMCP_DYNAMIC_TOOLS": "true",
151 |     "XCODEBUILDMCP_DEBUG": "true"
152 |   }
153 | }
154 | ```
155 | 
156 | #### Operating Mode Testing
157 | 
158 | Test both static and dynamic modes during development:
159 | 
160 | ```bash
161 | # Test static mode (all tools loaded immediately)
162 | XCODEBUILDMCP_DYNAMIC_TOOLS=false reloaderoo inspect mcp -- node build/index.js
163 | 
164 | # Test dynamic mode (only discover_tools initially available)
165 | XCODEBUILDMCP_DYNAMIC_TOOLS=true reloaderoo inspect mcp -- node build/index.js
166 | ```
167 | 
168 | **Key Differences to Test**:
169 | - **Static Mode**: 50+ tools available immediately via `list_tools`
170 | - **Dynamic Mode**: Only 2 tools (`discover_tools` and `discover_projs`) available initially
171 | - **Dynamic Discovery**: After calling `discover_tools`, additional workflow tools become available
172 | 
173 | #### Using XcodeBuildMCP doctor tool
174 | 
175 | Running the XcodeBuildMCP server with the environmental variable `XCODEBUILDMCP_DEBUG=true` will expose a new doctor MCP tool called `doctor` which your agent can call to get information about the server's environment, available tools, and configuration status.
176 | 
177 | > [!NOTE]
178 | > You can also call the doctor tool directly using the following command but be advised that the output may vary from that of the MCP tool call due to environmental differences:
179 | > ```bash
180 | > npm run doctor
181 | > ```
182 | 
183 | #### Development Workflow with Reloaderoo
184 | 
185 | 1. **Start Development Session**:
186 |    ```bash
187 |    # Terminal 1: Start in hot-reload mode
188 |    reloaderoo -- node build/index.js
189 | 
190 |    # Terminal 2: Start build watcher
191 |    npm run build:watch
192 |    ```
193 | 
194 | 2. **Make Changes**: Edit source code in `src/`
195 | 
196 | 3. **Test Changes**: Ask your AI client to restart the server:
197 |    ```
198 |    "Please restart the MCP server to load my changes"
199 |    ```
200 |    The AI will automatically call the `restart_server` tool provided by reloaderoo.
201 | 
202 | 4. **Verify Changes**: New functionality immediately available without reconnecting client
203 | 
204 | ## Architecture and Code Standards
205 | 
206 | Before making changes, please familiarize yourself with:
207 | - [ARCHITECTURE.md](ARCHITECTURE.md) - Comprehensive architectural overview
208 | - [CLAUDE.md](CLAUDE.md) - AI assistant guidelines and testing principles
209 | - [TOOLS.md](TOOLS.md) - Complete tool documentation
210 | - [TOOL_OPTIONS.md](TOOL_OPTIONS.md) - Tool configuration options
211 | 
212 | ### Code Quality Requirements
213 | 
214 | 1. **Follow existing code patterns and structure**
215 | 2. **Use TypeScript strictly** - no `any` types, proper typing throughout
216 | 3. **Add proper error handling and logging** - all failures must set `isError: true`
217 | 4. **Update documentation for new features**
218 | 5. **Test with example projects before submitting**
219 | 
220 | ### Testing Standards
221 | 
222 | All contributions must adhere to the testing standards outlined in the [**XcodeBuildMCP Plugin Testing Guidelines (docs/TESTING.md)**](docs/TESTING.md). This is the canonical source of truth for all testing practices.
223 | 
224 | **Key Principles (Summary):**
225 | - **No Vitest Mocking**: All forms of `vi.mock`, `vi.fn`, `vi.spyOn`, etc., are strictly forbidden.
226 | - **Dependency Injection**: All external dependencies (command execution, file system access) must be injected into tool logic functions using the `CommandExecutor` and `FileSystemExecutor` patterns.
227 | - **Test Production Code**: Tests must import and execute the actual tool logic, not mock implementations.
228 | - **Comprehensive Coverage**: Tests must cover input validation, command generation, and output processing.
229 | 
230 | Please read [docs/TESTING.md](docs/TESTING.md) in its entirety before writing tests.
231 | 
232 | ### Pre-Commit Checklist
233 | 
234 | **MANDATORY**: Run these commands before any commit and ensure they all pass:
235 | 
236 | ```bash
237 | # 1. Run linting (must pass with 0 errors)
238 | npm run lint
239 | 
240 | # 2. Run formatting (must format all files)
241 | npm run format
242 | 
243 | # 3. Run build (must compile successfully)
244 | npm run build
245 | 
246 | # 4. Run tests (all tests must pass)
247 | npm test
248 | ```
249 | 
250 | **NO EXCEPTIONS**: Code that fails any of these commands cannot be committed.
251 | 
252 | ## Making changes
253 | 
254 | 1. Fork the repository and create a new branch
255 | 2. Follow the TypeScript best practices and existing code style
256 | 3. Add proper parameter validation and error handling
257 | 
258 | ## Plugin Development
259 | 
260 | For comprehensive instructions on creating new tools and workflow groups, see our dedicated [Plugin Development Guide](docs/PLUGIN_DEVELOPMENT.md).
261 | 
262 | The plugin development guide covers:
263 | - Auto-discovery system architecture
264 | - Tool creation with dependency injection patterns
265 | - Workflow group organization
266 | - Testing guidelines and patterns
267 | - Integration with dynamic tool discovery
268 | 
269 | ### Quick Plugin Development Checklist
270 | 
271 | 1. Choose appropriate workflow directory in `src/mcp/tools/`
272 | 2. Follow naming conventions: `{action}_{target}_{specifier}_{projectType}`
273 | 3. Use dependency injection pattern with separate logic functions
274 | 4. Create comprehensive tests using `createMockExecutor()`
275 | 5. Add workflow metadata if creating new workflow group
276 | 
277 | See [PLUGIN_DEVELOPMENT.md](docs/PLUGIN_DEVELOPMENT.md) for complete details.
278 | 
279 | ### Working with Project Templates
280 | 
281 | XcodeBuildMCP uses external template repositories for the iOS and macOS project scaffolding features. These templates are maintained separately to allow independent versioning and updates.
282 | 
283 | #### Template Repositories
284 | 
285 | - **iOS Template**: [XcodeBuildMCP-iOS-Template](https://github.com/cameroncooke/XcodeBuildMCP-iOS-Template)
286 | - **macOS Template**: [XcodeBuildMCP-macOS-Template](https://github.com/cameroncooke/XcodeBuildMCP-macOS-Template)
287 | 
288 | #### Local Template Development
289 | 
290 | When developing or testing changes to the templates:
291 | 
292 | 1. Clone the template repository you want to work on:
293 |    ```bash
294 |    git clone https://github.com/cameroncooke/XcodeBuildMCP-iOS-Template.git
295 |    git clone https://github.com/cameroncooke/XcodeBuildMCP-macOS-Template.git
296 |    ```
297 | 
298 | 2. Set the appropriate environment variable to use your local template:
299 |    ```bash
300 |    # For iOS template development
301 |    export XCODEBUILDMCP_IOS_TEMPLATE_PATH=/path/to/XcodeBuildMCP-iOS-Template
302 | 
303 |    # For macOS template development
304 |    export XCODEBUILDMCP_MACOS_TEMPLATE_PATH=/path/to/XcodeBuildMCP-macOS-Template
305 |    ```
306 | 
307 | 3. When using MCP clients, add these environment variables to your MCP configuration:
308 | ```json
309 | "XcodeBuildMCP": {
310 |   "command": "node",
311 |   "args": ["/path_to/XcodeBuildMCP/build/index.js"],
312 |   "env": {
313 |     "XCODEBUILDMCP_IOS_TEMPLATE_PATH": "/path/to/XcodeBuildMCP-iOS-Template",
314 |     "XCODEBUILDMCP_MACOS_TEMPLATE_PATH": "/path/to/XcodeBuildMCP-macOS-Template"
315 |   }
316 | }
317 | ```
318 | 
319 | 4. The scaffold tools will use your local templates instead of downloading from GitHub releases.
320 | 
321 | #### Template Versioning
322 | 
323 | - Templates are versioned independently from XcodeBuildMCP
324 | - The default template version is specified in `package.json` under `templateVersion`
325 | - You can override the template version with `XCODEBUILD_MCP_TEMPLATE_VERSION` environment variable
326 | - To update the default template version:
327 |   1. Update `templateVersion` in `package.json`
328 |   2. Run `npm run build` to regenerate version.ts
329 |   3. Create a new XcodeBuildMCP release
330 | 
331 | #### Testing Template Changes
332 | 
333 | 1. Make changes to your local template
334 | 2. Test scaffolding with your changes using the local override
335 | 3. Verify the scaffolded project builds and runs correctly
336 | 4. Once satisfied, create a PR in the template repository
337 | 5. After merging, create a new release in the template repository using the release script
338 | 
339 | ## Testing
340 | 
341 | 1. Build the project with `npm run build`
342 | 2. Test your changes with MCP Inspector
343 | 3. Verify tools work correctly with different MCP clients
344 | 
345 | ## Submitting
346 | 
347 | 1. Run `npm run lint` to check for linting issues (use `npm run lint:fix` to auto-fix)
348 | 2. Run `npm run format:check` to verify formatting (use `npm run format` to fix)
349 | 3. Update documentation if you've added or modified features
350 | 4. Add your changes to the CHANGELOG.md file
351 | 5. Push your changes and create a pull request with a clear description
352 | 6. Link any related issues
353 | 
354 | For major changes or new features, please open an issue first to discuss your proposed changes.
355 | 
356 | ## Code of Conduct
357 | 
358 | Please follow our [Code of Conduct](CODE_OF_CONDUCT.md) and community guidelines.
359 | 
```

--------------------------------------------------------------------------------
/src/utils/capabilities.ts:
--------------------------------------------------------------------------------

```typescript
1 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS/.vscode/settings.json:
--------------------------------------------------------------------------------

```json
1 | {}
```

--------------------------------------------------------------------------------
/example_projects/spm/Sources/spm/main.swift:
--------------------------------------------------------------------------------

```swift
1 | print("Hello, world!")
2 | 
```

--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------

```yaml
1 | blank_issues_enabled: false
```

--------------------------------------------------------------------------------
/.cursor/environment.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "agentCanUpdateSnapshot": true
3 | }
```

--------------------------------------------------------------------------------
/src/utils/version/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export { version } from '../../version.ts';
2 | 
```

--------------------------------------------------------------------------------
/src/utils/test/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export { handleTestLogic } from '../test-common.ts';
2 | 
```

--------------------------------------------------------------------------------
/src/utils/template/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export { TemplateManager } from '../template-manager.ts';
2 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS_Calculator/CalculatorApp/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "info" : {
3 |     "author" : "xcode",
4 |     "version" : 1
5 |   }
6 | }
7 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS/MCPTest/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "info" : {
3 |     "author" : "xcode",
4 |     "version" : 1
5 |   }
6 | }
7 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS/MCPTest/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "info" : {
3 |     "author" : "xcode",
4 |     "version" : 1
5 |   }
6 | }
7 | 
```

--------------------------------------------------------------------------------
/example_projects/macOS/MCPTest/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "info" : {
3 |     "author" : "xcode",
4 |     "version" : 1
5 |   }
6 | }
7 | 
```

--------------------------------------------------------------------------------
/example_projects/macOS/MCPTest/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "info" : {
3 |     "author" : "xcode",
4 |     "version" : 1
5 |   }
6 | }
7 | 
```

--------------------------------------------------------------------------------
/src/utils/log-capture/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export { startLogCapture, stopLogCapture } from '../log_capture.ts';
2 | 
```

--------------------------------------------------------------------------------
/src/utils/xcodemake/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export { isXcodemakeEnabled, isXcodemakeAvailable, doesMakefileExist } from '../xcodemake.ts';
2 | 
```

--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------

```yaml
1 | # These are supported funding model platforms
2 | github: cameroncooke
3 | buy_me_a_coffee: cameroncooke
4 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator-management/boot_sim.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from simulator to avoid duplication
2 | export { default } from '../simulator/boot_sim.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator-management/open_sim.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from simulator to avoid duplication
2 | export { default } from '../simulator/open_sim.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator-management/list_sims.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from simulator to avoid duplication
2 | export { default } from '../simulator/list_sims.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator/screenshot.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from ui-testing to avoid duplication
2 | export { default } from '../ui-testing/screenshot.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator/describe_ui.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from ui-testing to avoid duplication
2 | export { default } from '../ui-testing/describe_ui.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/device/stop_device_log_cap.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from logging to complete workflow
2 | export { default } from '../logging/stop_device_log_cap.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/macos/clean.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export unified clean tool for macos-project workflow
2 | export { default } from '../utilities/clean.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/device/clean.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export unified clean tool for device-project workflow
2 | export { default } from '../utilities/clean.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/device/start_device_log_cap.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from logging to complete workflow
2 | export { default } from '../logging/start_device_log_cap.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator/clean.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export unified clean tool for simulator-project workflow
2 | export { default } from '../utilities/clean.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/utils/video-capture/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export {
2 |   startSimulatorVideoCapture,
3 |   stopSimulatorVideoCapture,
4 |   type AxeHelpers,
5 | } from '../video_capture.ts';
6 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS_Calculator/CalculatorApp/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "colors" : [
 3 |     {
 4 |       "idiom" : "universal"
 5 |     }
 6 |   ],
 7 |   "info" : {
 8 |     "author" : "xcode",
 9 |     "version" : 1
10 |   }
11 | }
12 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS/MCPTest/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "colors" : [
 3 |     {
 4 |       "idiom" : "universal"
 5 |     }
 6 |   ],
 7 |   "info" : {
 8 |     "author" : "xcode",
 9 |     "version" : 1
10 |   }
11 | }
12 | 
```

--------------------------------------------------------------------------------
/example_projects/macOS/MCPTest/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "colors" : [
 3 |     {
 4 |       "idiom" : "universal"
 5 |     }
 6 |   ],
 7 |   "info" : {
 8 |     "author" : "xcode",
 9 |     "version" : 1
10 |   }
11 | }
12 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/device/discover_projs.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from project-discovery to complete workflow
2 | export { default } from '../project-discovery/discover_projs.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/macos/discover_projs.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from project-discovery to complete workflow
2 | export { default } from '../project-discovery/discover_projs.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator/discover_projs.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from project-discovery to complete workflow
2 | export { default } from '../project-discovery/discover_projs.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/macos/show_build_settings.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export unified tool for macos-project workflow
2 | export { default } from '../project-discovery/show_build_settings.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/device/show_build_settings.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export unified tool for device-project workflow
2 | export { default } from '../project-discovery/show_build_settings.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/device/get_app_bundle_id.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from project-discovery to complete workflow
2 | export { default } from '../project-discovery/get_app_bundle_id.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/macos/get_mac_bundle_id.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from project-discovery to complete workflow
2 | export { default } from '../project-discovery/get_mac_bundle_id.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator/get_app_bundle_id.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export from project-discovery to complete workflow
2 | export { default } from '../project-discovery/get_app_bundle_id.ts';
3 | 
```

--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "recommendations": [
 3 |     "dbaeumer.vscode-eslint"
 4 |   ],
 5 |   "unwantedRecommendations": [
 6 |     "esbenp.prettier-vscode"
 7 |   ]
 8 | }
 9 | 
10 | 
11 | 
12 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator/show_build_settings.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export unified tool for simulator-project workflow
2 | export { default } from '../project-discovery/show_build_settings.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/macos/list_schemes.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export unified list_schemes tool for macos-project workflow
2 | export { default } from '../project-discovery/list_schemes.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/device/list_schemes.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export unified list_schemes tool for device-project workflow
2 | export { default } from '../project-discovery/list_schemes.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator/list_schemes.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Re-export unified list_schemes tool for simulator-project workflow
2 | export { default } from '../project-discovery/list_schemes.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/utils/plugin-registry/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export { loadWorkflowGroups, loadPlugins } from '../../core/plugin-registry.ts';
2 | export { getEnabledWorkflows } from '../../core/dynamic-tools.ts';
3 | 
```

--------------------------------------------------------------------------------
/src/utils/logging/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | /**
2 |  * Focused logging facade.
3 |  * Prefer importing from 'utils/logging/index.js' instead of the legacy utils barrel.
4 |  */
5 | export { log } from '../logger.ts';
6 | 
```

--------------------------------------------------------------------------------
/src/utils/axe/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export {
2 |   createAxeNotAvailableResponse,
3 |   getAxePath,
4 |   getBundledAxeEnvironment,
5 |   areAxeToolsAvailable,
6 |   isAxeAtLeastVersion,
7 | } from '../axe-helpers.ts';
8 | 
```

--------------------------------------------------------------------------------
/src/utils/validation/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | /**
2 |  * Focused validation facade.
3 |  * Prefer importing from 'utils/validation/index.js' instead of the legacy utils barrel.
4 |  */
5 | export * from '../validation.ts';
6 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS_Calculator/CalculatorApp/CalculatorApp.swift:
--------------------------------------------------------------------------------

```swift
 1 | import SwiftUI
 2 | import CalculatorAppFeature
 3 | 
 4 | @main
 5 | struct CalculatorApp: App {
 6 |     var body: some Scene {
 7 |         WindowGroup {
 8 |             ContentView()
 9 |         }
10 |     }
11 | }
12 | 
13 | #Preview {
14 |     ContentView()
15 | }
16 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS/MCPTest/MCPTestApp.swift:
--------------------------------------------------------------------------------

```swift
 1 | //
 2 | //  MCPTestApp.swift
 3 | //  MCPTest
 4 | //
 5 | //  Created by Cameron on 16/02/2025.
 6 | //
 7 | 
 8 | import SwiftUI
 9 | 
10 | @main
11 | struct MCPTestApp: App {
12 |     var body: some Scene {
13 |         WindowGroup {
14 |             ContentView()
15 |         }
16 |     }
17 | }
18 | 
```

--------------------------------------------------------------------------------
/example_projects/macOS/MCPTest/MCPTestApp.swift:
--------------------------------------------------------------------------------

```swift
 1 | //
 2 | //  MCPTestApp.swift
 3 | //  MCPTest
 4 | //
 5 | //  Created by Cameron on 16/02/2025.
 6 | //
 7 | 
 8 | import SwiftUI
 9 | 
10 | @main
11 | struct MCPTestApp: App {
12 |     var body: some Scene {
13 |         WindowGroup {
14 |             ContentView()
15 |         }
16 |     }
17 | }
18 | 
```

--------------------------------------------------------------------------------
/tsconfig.test.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "extends": "./tsconfig.json",
 3 |   "compilerOptions": {
 4 |     "types": ["vitest/globals", "node"],
 5 |     "allowJs": true,
 6 |     "noEmit": true
 7 |   },
 8 |   "include": ["src/**/*.test.ts", "tests-vitest/**/*"],
 9 |   "exclude": ["node_modules", "dist"]
10 | }
```

--------------------------------------------------------------------------------
/build-plugins/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "extends": "../tsconfig.json",
 3 |   "compilerOptions": {
 4 |     "module": "ESNext",
 5 |     "target": "ES2022",
 6 |     "outDir": "../build-plugins-dist",
 7 |     "rootDir": ".",
 8 |     "allowSyntheticDefaultImports": true,
 9 |     "esModuleInterop": true
10 |   },
11 |   "include": ["**/*.ts"],
12 |   "exclude": ["node_modules", "dist"]
13 | }
```

--------------------------------------------------------------------------------
/src/mcp/tools/doctor/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export const workflow = {
 2 |   name: 'System Doctor',
 3 |   description:
 4 |     'Debug tools and system doctor for troubleshooting XcodeBuildMCP server, development environment, and tool availability.',
 5 |   platforms: ['system'],
 6 |   capabilities: [
 7 |     'doctor',
 8 |     'server-diagnostics',
 9 |     'troubleshooting',
10 |     'system-analysis',
11 |     'environment-validation',
12 |   ],
13 | };
14 | 
```

--------------------------------------------------------------------------------
/src/utils/responses/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Focused responses facade.
 3 |  * Prefer importing from 'utils/responses/index.js' instead of the legacy utils barrel.
 4 |  */
 5 | export { createTextResponse } from '../validation.ts';
 6 | export {
 7 |   createErrorResponse,
 8 |   DependencyError,
 9 |   AxeError,
10 |   SystemError,
11 |   ValidationError,
12 | } from '../errors.ts';
13 | 
14 | // Types
15 | export type { ToolResponse } from '../../types/common.ts';
16 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/macos/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export const workflow = {
 2 |   name: 'macOS Development',
 3 |   description:
 4 |     'Complete macOS development workflow for both .xcodeproj and .xcworkspace files. Build, test, deploy, and manage macOS applications.',
 5 |   platforms: ['macOS'],
 6 |   targets: ['native'],
 7 |   projectTypes: ['project', 'workspace'],
 8 |   capabilities: ['build', 'test', 'deploy', 'debug', 'app-management'],
 9 | };
10 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/project-discovery/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export const workflow = {
2 |   name: 'Project Discovery',
3 |   description:
4 |     'Discover and examine Xcode projects, workspaces, and Swift packages. Analyze project structure, schemes, build settings, and bundle information.',
5 |   platforms: ['iOS', 'macOS', 'watchOS', 'tvOS', 'visionOS'],
6 |   capabilities: ['project-analysis', 'scheme-discovery', 'build-settings', 'bundle-inspection'],
7 | };
8 | 
```

--------------------------------------------------------------------------------
/example_projects/macOS/MCPTest/ContentView.swift:
--------------------------------------------------------------------------------

```swift
 1 | //
 2 | //  ContentView.swift
 3 | //  MCPTest
 4 | //
 5 | //  Created by Cameron on 16/02/2025.
 6 | //
 7 | 
 8 | import SwiftUI
 9 | 
10 | struct ContentView: View {
11 |     var body: some View {
12 |         VStack {
13 |             Image(systemName: "globe")
14 |                 .imageScale(.large)
15 |                 .foregroundStyle(.tint)
16 |             Text("Hello, world!")
17 |         }
18 |         .padding()
19 |     }
20 | }
21 | 
22 | #Preview {
23 |     ContentView()
24 | }
25 | 
26 | 
```

--------------------------------------------------------------------------------
/src/utils/execution/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Focused execution facade.
 3 |  * Prefer importing from 'utils/execution/index.js' instead of the legacy utils barrel.
 4 |  */
 5 | export { getDefaultCommandExecutor, getDefaultFileSystemExecutor } from '../command.ts';
 6 | 
 7 | // Types
 8 | export type { CommandExecutor, CommandResponse, CommandExecOptions } from '../CommandExecutor.ts';
 9 | export type { FileSystemExecutor } from '../FileSystemExecutor.ts';
10 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/logging/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export const workflow = {
2 |   name: 'Log Capture & Management',
3 |   description:
4 |     'Log capture and management tools for iOS simulators and physical devices. Start, stop, and analyze application and system logs during development and testing.',
5 |   platforms: ['iOS', 'watchOS', 'tvOS', 'visionOS'],
6 |   targets: ['simulator', 'device'],
7 |   capabilities: ['log-capture', 'log-analysis', 'debugging', 'monitoring'],
8 | };
9 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export const workflow = {
 2 |   name: 'iOS Simulator Development',
 3 |   description:
 4 |     'Complete iOS development workflow for both .xcodeproj and .xcworkspace files targeting simulators. Build, test, deploy, and interact with iOS apps on simulators.',
 5 |   platforms: ['iOS'],
 6 |   targets: ['simulator'],
 7 |   projectTypes: ['project', 'workspace'],
 8 |   capabilities: ['build', 'test', 'deploy', 'debug', 'ui-automation'],
 9 | };
10 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/utilities/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export const workflow = {
 2 |   name: 'Project Utilities',
 3 |   description:
 4 |     'Essential project maintenance utilities for cleaning and managing existing projects. Provides clean operations for both .xcodeproj and .xcworkspace files.',
 5 |   platforms: ['iOS', 'macOS'],
 6 |   targets: ['simulator', 'device', 'mac'],
 7 |   projectTypes: ['project', 'workspace'],
 8 |   capabilities: ['project-cleaning', 'project-maintenance'],
 9 | };
10 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/ui-testing/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export const workflow = {
 2 |   name: 'UI Testing & Automation',
 3 |   description:
 4 |     'UI automation and accessibility testing tools for iOS simulators. Perform gestures, interactions, screenshots, and UI analysis for automated testing workflows.',
 5 |   platforms: ['iOS'],
 6 |   targets: ['simulator'],
 7 |   capabilities: [
 8 |     'ui-automation',
 9 |     'gesture-simulation',
10 |     'screenshot-capture',
11 |     'accessibility-testing',
12 |     'ui-analysis',
13 |   ],
14 | };
15 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/session-management/session_show_defaults.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { sessionStore } from '../../../utils/session-store.ts';
 2 | import type { ToolResponse } from '../../../types/common.ts';
 3 | 
 4 | export default {
 5 |   name: 'session-show-defaults',
 6 |   description: 'Show current session defaults.',
 7 |   schema: {},
 8 |   handler: async (): Promise<ToolResponse> => {
 9 |     const current = sessionStore.getAll();
10 |     return { content: [{ type: 'text', text: JSON.stringify(current, null, 2) }], isError: false };
11 |   },
12 | };
13 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/swift-package/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export const workflow = {
 2 |   name: 'Swift Package Manager',
 3 |   description:
 4 |     'Swift Package Manager operations for building, testing, running, and managing Swift packages and dependencies. Complete SPM workflow support.',
 5 |   platforms: ['iOS', 'macOS', 'watchOS', 'tvOS', 'visionOS', 'Linux'],
 6 |   targets: ['package'],
 7 |   projectTypes: ['swift-package'],
 8 |   capabilities: ['build', 'test', 'run', 'clean', 'dependency-management', 'package-management'],
 9 | };
10 | 
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # Smithery configuration file: https://smithery.ai/docs/build/project-config
 2 | 
 3 | startCommand:
 4 |   type: stdio
 5 |   configSchema:
 6 |     # JSON Schema defining the configuration options for the MCP.
 7 |     type: object
 8 |     description: Configuration for XcodeBuildMCP (no options needed)
 9 |   commandFunction:
10 |     # A JS function that produces the CLI command based on the given config to start the MCP on stdio.
11 |     |-
12 |     (config) => ({ command: 'xcodebuildmcp', args: [], env: {} })
13 |   exampleConfig: {}
14 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/session-management/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | export const workflow = {
2 |   name: 'session-management',
3 |   description:
4 |     'Manage session defaults for projectPath/workspacePath, scheme, configuration, simulatorName/simulatorId, deviceId, useLatestOS and arch. These defaults are required by many tools and must be set before attempting to call tools that would depend on these values.',
5 |   platforms: ['iOS', 'macOS', 'tvOS', 'watchOS', 'visionOS'],
6 |   targets: ['simulator', 'device'],
7 |   capabilities: ['configuration', 'state-management'],
8 | };
9 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/device/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export const workflow = {
 2 |   name: 'iOS Device Development',
 3 |   description:
 4 |     'Complete iOS development workflow for both .xcodeproj and .xcworkspace files targeting physical devices (iPhone, iPad, Apple Watch, Apple TV, Apple Vision Pro). Build, test, deploy, and debug apps on real hardware.',
 5 |   platforms: ['iOS', 'watchOS', 'tvOS', 'visionOS'],
 6 |   targets: ['device'],
 7 |   projectTypes: ['project', 'workspace'],
 8 |   capabilities: ['build', 'test', 'deploy', 'debug', 'log-capture', 'device-management'],
 9 | };
10 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/discovery/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Discovery Workflow
 3 |  *
 4 |  * Dynamic tool discovery and workflow recommendation system
 5 |  */
 6 | 
 7 | export const workflow = {
 8 |   name: 'Dynamic Tool Discovery',
 9 |   description:
10 |     'Intelligent discovery and recommendation of appropriate development workflows based on project structure and requirements',
11 |   platforms: ['iOS', 'macOS', 'watchOS', 'tvOS', 'visionOS'],
12 |   targets: ['simulator', 'device'],
13 |   projectTypes: ['project', 'workspace', 'package'],
14 |   capabilities: ['discovery', 'recommendation', 'workflow-analysis'],
15 | };
16 | 
```

--------------------------------------------------------------------------------
/src/utils/CommandExecutor.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { ChildProcess } from 'child_process';
 2 | 
 3 | export interface CommandExecOptions {
 4 |   env?: Record<string, string>;
 5 |   cwd?: string;
 6 | }
 7 | 
 8 | /**
 9 |  * Command executor function type for dependency injection
10 |  */
11 | export type CommandExecutor = (
12 |   command: string[],
13 |   logPrefix?: string,
14 |   useShell?: boolean,
15 |   opts?: CommandExecOptions,
16 |   detached?: boolean,
17 | ) => Promise<CommandResponse>;
18 | /**
19 |  * Command execution response interface
20 |  */
21 | 
22 | export interface CommandResponse {
23 |   success: boolean;
24 |   output: string;
25 |   error?: string;
26 |   process: ChildProcess;
27 |   exitCode?: number;
28 | }
29 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS_Calculator/CalculatorApp/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "images" : [
 3 |     {
 4 |       "idiom" : "universal",
 5 |       "platform" : "ios",
 6 |       "size" : "1024x1024"
 7 |     },
 8 |     {
 9 |       "appearances" : [
10 |         {
11 |           "appearance" : "luminosity",
12 |           "value" : "dark"
13 |         }
14 |       ],
15 |       "idiom" : "universal",
16 |       "platform" : "ios",
17 |       "size" : "1024x1024"
18 |     },
19 |     {
20 |       "appearances" : [
21 |         {
22 |           "appearance" : "luminosity",
23 |           "value" : "tinted"
24 |         }
25 |       ],
26 |       "idiom" : "universal",
27 |       "platform" : "ios",
28 |       "size" : "1024x1024"
29 |     }
30 |   ],
31 |   "info" : {
32 |     "author" : "xcode",
33 |     "version" : 1
34 |   }
35 | }
36 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS/MCPTest/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "images" : [
 3 |     {
 4 |       "idiom" : "universal",
 5 |       "platform" : "ios",
 6 |       "size" : "1024x1024"
 7 |     },
 8 |     {
 9 |       "appearances" : [
10 |         {
11 |           "appearance" : "luminosity",
12 |           "value" : "dark"
13 |         }
14 |       ],
15 |       "idiom" : "universal",
16 |       "platform" : "ios",
17 |       "size" : "1024x1024"
18 |     },
19 |     {
20 |       "appearances" : [
21 |         {
22 |           "appearance" : "luminosity",
23 |           "value" : "tinted"
24 |         }
25 |       ],
26 |       "idiom" : "universal",
27 |       "platform" : "ios",
28 |       "size" : "1024x1024"
29 |     }
30 |   ],
31 |   "info" : {
32 |     "author" : "xcode",
33 |     "version" : 1
34 |   }
35 | }
36 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/project-scaffolding/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Project Scaffolding workflow
 3 |  *
 4 |  * Provides tools for creating new iOS and macOS projects from templates.
 5 |  * These tools are used at project inception to bootstrap new applications
 6 |  * with best practices and standard configurations.
 7 |  */
 8 | 
 9 | export const workflow = {
10 |   name: 'Project Scaffolding',
11 |   description:
12 |     'Tools for creating new iOS and macOS projects from templates. Bootstrap new applications with best practices, standard configurations, and modern project structures.',
13 |   platforms: ['iOS', 'macOS'],
14 |   targets: ['simulator', 'device', 'mac'],
15 |   projectTypes: ['project'],
16 |   capabilities: ['project-creation', 'template-generation', 'project-initialization'],
17 | };
18 | 
```

--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: CI
 2 | 
 3 | on:
 4 |   push:
 5 |     branches: [ main ]
 6 |   pull_request:
 7 |     branches: [ main ]
 8 | 
 9 | jobs:
10 |   build-and-test:
11 |     runs-on: ubuntu-latest
12 | 
13 |     strategy:
14 |       matrix:
15 |         node-version: [24.x]
16 | 
17 |     steps:
18 |     - uses: actions/checkout@v3
19 | 
20 |     - name: Use Node.js ${{ matrix.node-version }}
21 |       uses: actions/setup-node@v3
22 |       with:
23 |         node-version: ${{ matrix.node-version }}
24 |         cache: 'npm'
25 | 
26 |     - name: Install dependencies
27 |       run: npm ci
28 | 
29 |     - name: Build
30 |       run: npm run build
31 | 
32 |     - name: Lint
33 |       run: npm run lint
34 | 
35 |     - name: Check formatting
36 |       run: npm run format:check
37 | 
38 |     - name: Type check
39 |       run: npm run typecheck
40 | 
41 |     - name: Run tests
42 |       run: npm test
43 | 
44 |     - run: npx pkg-pr-new publish
45 | 
```

--------------------------------------------------------------------------------
/src/utils/FileSystemExecutor.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * File system executor interface for dependency injection
 3 |  */
 4 | 
 5 | export interface FileSystemExecutor {
 6 |   mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;
 7 |   readFile(path: string, encoding?: BufferEncoding): Promise<string>;
 8 |   writeFile(path: string, content: string, encoding?: BufferEncoding): Promise<void>;
 9 |   cp(source: string, destination: string, options?: { recursive?: boolean }): Promise<void>;
10 |   readdir(path: string, options?: { withFileTypes?: boolean }): Promise<unknown[]>;
11 |   rm(path: string, options?: { recursive?: boolean; force?: boolean }): Promise<void>;
12 |   existsSync(path: string): boolean;
13 |   stat(path: string): Promise<{ isDirectory(): boolean }>;
14 |   mkdtemp(prefix: string): Promise<string>;
15 |   tmpdir(): string;
16 | }
17 | 
```

--------------------------------------------------------------------------------
/src/utils/schema-helpers.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Schema Helper Utilities
 3 |  *
 4 |  * Shared utility functions for schema validation and preprocessing.
 5 |  */
 6 | 
 7 | /**
 8 |  * Convert empty strings to undefined in an object (shallow transformation)
 9 |  * Used for preprocessing Zod schemas with optional fields
10 |  *
11 |  * @param value - The value to process
12 |  * @returns The processed value with empty strings converted to undefined
13 |  */
14 | export function nullifyEmptyStrings(value: unknown): unknown {
15 |   if (value && typeof value === 'object' && !Array.isArray(value)) {
16 |     const copy: Record<string, unknown> = { ...(value as Record<string, unknown>) };
17 |     for (const key of Object.keys(copy)) {
18 |       const v = copy[key];
19 |       if (typeof v === 'string' && v.trim() === '') copy[key] = undefined;
20 |     }
21 |     return copy;
22 |   }
23 |   return value;
24 | }
25 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "Node16",
 5 |     "moduleResolution": "Node16",
 6 |     "outDir": "./build",
 7 |     "rootDir": "./src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true,
12 |     "sourceMap": true,
13 |     "inlineSources": true,
14 | 
15 |     // Set `sourceRoot` to  "/" to strip the build path prefix
16 |     // from generated source code references.
17 |     // This improves issue grouping in Sentry.
18 |     "sourceRoot": "/",
19 |     "allowImportingTsExtensions": true,
20 |     "noEmit": true
21 |   },
22 |   "include": ["src/**/*"],
23 |   "exclude": [
24 |     "node_modules",
25 |     "**/*.test.ts",
26 |     "tests-vitest/**/*",
27 |     "plugins/**/*",
28 |     "src/core/generated-plugins.ts",
29 |     "src/core/generated-resources.ts"
30 |   ]
31 | }
32 | 
```

--------------------------------------------------------------------------------
/src/core/plugin-types.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { ToolResponse } from '../types/common.ts';
 3 | 
 4 | export interface PluginMeta {
 5 |   readonly name: string; // Verb used by MCP
 6 |   readonly schema: Record<string, z.ZodTypeAny>; // Zod validation schema (object schema)
 7 |   readonly description?: string; // One-liner shown in help
 8 |   handler(params: Record<string, unknown>): Promise<ToolResponse>;
 9 | }
10 | 
11 | export interface WorkflowMeta {
12 |   readonly name: string;
13 |   readonly description: string;
14 |   readonly platforms?: string[];
15 |   readonly targets?: string[];
16 |   readonly projectTypes?: string[];
17 |   readonly capabilities?: string[];
18 | }
19 | 
20 | export interface WorkflowGroup {
21 |   readonly workflow: WorkflowMeta;
22 |   readonly tools: PluginMeta[];
23 |   readonly directoryName: string;
24 | }
25 | 
26 | export const defineTool = (meta: PluginMeta): PluginMeta => meta;
27 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator-management/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Simulator Management workflow
 3 |  *
 4 |  * Provides tools for working with simulators like booting and opening simulators, launching apps,
 5 |  * listing sims, stopping apps, erasing simulator content and settings, and setting sim environment
 6 |  * options like location, network, statusbar and appearance.
 7 |  */
 8 | 
 9 | export const workflow = {
10 |   name: 'Simulator Management',
11 |   description:
12 |     'Tools for managing simulators from booting, opening simulators, listing simulators, stopping simulators, erasing simulator content and settings, and setting simulator environment options like location, network, statusbar and appearance.',
13 |   platforms: ['iOS'],
14 |   targets: ['simulator'],
15 |   projectTypes: ['project', 'workspace'],
16 |   capabilities: ['boot', 'open', 'list', 'appearance', 'location', 'network', 'statusbar', 'erase'],
17 | };
18 | 
```

--------------------------------------------------------------------------------
/example_projects/macOS/MCPTest/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "images" : [
 3 |     {
 4 |       "idiom" : "mac",
 5 |       "scale" : "1x",
 6 |       "size" : "16x16"
 7 |     },
 8 |     {
 9 |       "idiom" : "mac",
10 |       "scale" : "2x",
11 |       "size" : "16x16"
12 |     },
13 |     {
14 |       "idiom" : "mac",
15 |       "scale" : "1x",
16 |       "size" : "32x32"
17 |     },
18 |     {
19 |       "idiom" : "mac",
20 |       "scale" : "2x",
21 |       "size" : "32x32"
22 |     },
23 |     {
24 |       "idiom" : "mac",
25 |       "scale" : "1x",
26 |       "size" : "128x128"
27 |     },
28 |     {
29 |       "idiom" : "mac",
30 |       "scale" : "2x",
31 |       "size" : "128x128"
32 |     },
33 |     {
34 |       "idiom" : "mac",
35 |       "scale" : "1x",
36 |       "size" : "256x256"
37 |     },
38 |     {
39 |       "idiom" : "mac",
40 |       "scale" : "2x",
41 |       "size" : "256x256"
42 |     },
43 |     {
44 |       "idiom" : "mac",
45 |       "scale" : "1x",
46 |       "size" : "512x512"
47 |     },
48 |     {
49 |       "idiom" : "mac",
50 |       "scale" : "2x",
51 |       "size" : "512x512"
52 |     }
53 |   ],
54 |   "info" : {
55 |     "author" : "xcode",
56 |     "version" : 1
57 |   }
58 | }
59 | 
```

--------------------------------------------------------------------------------
/tsup.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { defineConfig } from 'tsup';
 2 | import { chmodSync, existsSync } from 'fs';
 3 | import { createPluginDiscoveryPlugin } from './build-plugins/plugin-discovery.js';
 4 | 
 5 | export default defineConfig({
 6 |   entry: {
 7 |     index: 'src/index.ts',
 8 |     'doctor-cli': 'src/doctor-cli.ts',
 9 |   },
10 |   format: ['esm'],
11 |   target: 'node18',
12 |   platform: 'node',
13 |   outDir: 'build',
14 |   clean: true,
15 |   sourcemap: true, // Enable source maps for debugging
16 |   dts: {
17 |     entry: {
18 |       index: 'src/index.ts',
19 |     },
20 |   },
21 |   splitting: false,
22 |   shims: false,
23 |   treeshake: true,
24 |   minify: false,
25 |   esbuildPlugins: [createPluginDiscoveryPlugin()],
26 |   onSuccess: async () => {
27 |     console.log('✅ Build complete!');
28 | 
29 |     // Set executable permissions for built files
30 |     if (existsSync('build/index.js')) {
31 |       chmodSync('build/index.js', '755');
32 |     }
33 |     if (existsSync('build/doctor-cli.js')) {
34 |       chmodSync('build/doctor-cli.js', '755');
35 |     }
36 |   },
37 | });
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | # Generated by https://smithery.ai. See: https://smithery.ai/docs/build/project-config
 2 | # Use a small base image with Node.js LTS
 3 | FROM node:lts-alpine AS build
 4 | 
 5 | # Install dependencies needed for building
 6 | RUN apk add --no-cache python3 g++ make git
 7 | 
 8 | # Create app directory
 9 | WORKDIR /usr/src/app
10 | 
11 | # Copy package manifests
12 | COPY package.json package-lock.json tsconfig.json eslint.config.js ./
13 | 
14 | # Copy source
15 | COPY src ./src
16 | 
17 | # Install dependencies ignoring any prepare scripts, then build
18 | RUN npm ci --ignore-scripts
19 | RUN npm run prebuild && npm run build
20 | 
21 | # Stage for runtime
22 | FROM node:lts-alpine
23 | WORKDIR /usr/src/app
24 | 
25 | # Install minimal runtime dependencies
26 | # No build tools needed, install production deps
27 | COPY package.json package-lock.json ./
28 | RUN npm ci --omit=dev --ignore-scripts
29 | 
30 | # Copy built files
31 | COPY --from=build /usr/src/app/build ./build
32 | 
33 | # Symlink binary
34 | RUN npm link
35 | 
36 | # Default command
37 | ENTRYPOINT ["xcodebuildmcp"]
38 | CMD []
39 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/swift-package/active-processes.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Shared process state management for Swift Package tools
 3 |  * This module provides a centralized way to manage active processes
 4 |  * between swift_package_run and swift_package_stop tools
 5 |  */
 6 | 
 7 | export interface ProcessInfo {
 8 |   process: {
 9 |     kill: (signal?: string) => void;
10 |     on: (event: string, callback: () => void) => void;
11 |     pid?: number;
12 |   };
13 |   startedAt: Date;
14 | }
15 | 
16 | // Global map to track active processes
17 | export const activeProcesses = new Map<number, ProcessInfo>();
18 | 
19 | // Helper functions for process management
20 | export const getProcess = (pid: number): ProcessInfo | undefined => {
21 |   return activeProcesses.get(pid);
22 | };
23 | 
24 | export const addProcess = (pid: number, processInfo: ProcessInfo): void => {
25 |   activeProcesses.set(pid, processInfo);
26 | };
27 | 
28 | export const removeProcess = (pid: number): boolean => {
29 |   return activeProcesses.delete(pid);
30 | };
31 | 
32 | export const clearAllProcesses = (): void => {
33 |   activeProcesses.clear();
34 | };
35 | 
```

--------------------------------------------------------------------------------
/.github/workflows/sentry.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Sentry Release
 2 | on:
 3 |   push:
 4 |     tags:
 5 |       - 'v*'
 6 | 
 7 | jobs:
 8 |   release:
 9 |     runs-on: ubuntu-latest
10 |     steps:
11 |       - uses: actions/checkout@v4
12 |         with:
13 |           fetch-depth: 0
14 |       - name: Install dependencies
15 |         run: npm ci
16 | 
17 |       - name: Build project
18 |         run: npm run build
19 | 
20 |       - name: Run tests
21 |         run: npm test
22 | 
23 |       - name: Extract version from build/version.js
24 |         id: get_version
25 |         run: echo "MCP_VERSION=$(grep -oE "'[0-9]+\.[0-9]+\.[0-9]+'" build/version.js | tr -d "'")" >> $GITHUB_OUTPUT
26 | 
27 |       - name: Create Sentry release
28 |         uses: getsentry/action-release@v3
29 |         env:
30 |           SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
31 |           SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
32 |           SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
33 |         with:
34 |           environment: production
35 |           sourcemaps: "./build"
36 |           version: ${{ steps.get_version.outputs.MCP_VERSION }}
```

--------------------------------------------------------------------------------
/example_projects/iOS_Calculator/CalculatorAppPackage/Package.swift:
--------------------------------------------------------------------------------

```swift
 1 | // swift-tools-version: 5.10
 2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
 3 | 
 4 | import PackageDescription
 5 | 
 6 | let package = Package(
 7 |     name: "CalculatorAppFeature",
 8 |     platforms: [.iOS(.v17)],
 9 |     products: [
10 |         // Products define the executables and libraries a package produces, making them visible to other packages.
11 |         .library(
12 |             name: "CalculatorAppFeature",
13 |             targets: ["CalculatorAppFeature"]
14 |         ),
15 |     ],
16 |     targets: [
17 |         // Targets are the basic building blocks of a package, defining a module or a test suite.
18 |         // Targets can depend on other targets in this package and products from dependencies.
19 |         .target(
20 |             name: "CalculatorAppFeature"
21 |         ),
22 |         .testTarget(
23 |             name: "CalculatorAppFeatureTests",
24 |             dependencies: [
25 |                 "CalculatorAppFeature"
26 |             ]
27 |         ),
28 |     ]
29 | )
30 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS_Calculator/CalculatorAppPackage/Sources/CalculatorAppFeature/BackgroundEffect.swift:
--------------------------------------------------------------------------------

```swift
 1 | import SwiftUI
 2 | 
 3 | // MARK: - Background State Management
 4 | enum BackgroundState {
 5 |     case normal, calculated, error
 6 |     
 7 |     var colors: [Color] {
 8 |         switch self {
 9 |         case .normal:
10 |             return [Color.blue.opacity(0.8), Color.purple.opacity(0.8), Color.indigo.opacity(0.9)]
11 |         case .calculated:
12 |             return [Color.green.opacity(0.7), Color.mint.opacity(0.8), Color.teal.opacity(0.9)]
13 |         case .error:
14 |             return [Color.red.opacity(0.7), Color.pink.opacity(0.8), Color.orange.opacity(0.9)]
15 |         }
16 |     }
17 | }
18 | 
19 | // MARK: - Animated Background Component
20 | struct AnimatedBackground: View {
21 |     let backgroundGradient: BackgroundState
22 |     
23 |     var body: some View {
24 |         AngularGradient(
25 |             colors: backgroundGradient.colors,
26 |             center: .topLeading,
27 |             angle: .degrees(45)
28 |         )
29 |         .ignoresSafeArea()
30 |         .animation(.easeInOut(duration: 0.8), value: backgroundGradient)
31 |     }
32 | }
```

--------------------------------------------------------------------------------
/example_projects/spm/Tests/TestLibTests/SimpleTests.swift:
--------------------------------------------------------------------------------

```swift
 1 | import Testing
 2 | 
 3 | @Test("Basic truth assertions")
 4 | func basicTruthTest() {
 5 |     #expect(true == true)
 6 |     #expect(false == false)
 7 |     #expect(true != false)
 8 | }
 9 | 
10 | @Test("Basic math operations")
11 | func basicMathTest() {
12 |     #expect(2 + 2 == 4)
13 |     #expect(5 - 3 == 2)
14 |     #expect(3 * 4 == 12)
15 |     #expect(10 / 2 == 5)
16 | }
17 | 
18 | @Test("String operations")
19 | func stringTest() {
20 |     let greeting = "Hello"
21 |     let world = "World"
22 |     #expect(greeting + " " + world == "Hello World")
23 |     #expect(greeting.count == 5)
24 |     #expect(world.isEmpty == false)
25 | }
26 | 
27 | @Test("Array operations")
28 | func arrayTest() {
29 |     let numbers = [1, 2, 3, 4, 5]
30 |     #expect(numbers.count == 5)
31 |     #expect(numbers.first == 1)
32 |     #expect(numbers.last == 5)
33 |     #expect(numbers.contains(3) == true)
34 | }
35 | 
36 | @Test("Optional handling")
37 | func optionalTest() {
38 |     let someValue: Int? = 42
39 |     let nilValue: Int? = nil
40 |     
41 |     #expect(someValue != nil)
42 |     #expect(nilValue == nil)
43 |     #expect(someValue! == 42)
44 | }
45 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS_Calculator/CalculatorAppPackage/Sources/CalculatorAppFeature/CalculatorInputHandler.swift:
--------------------------------------------------------------------------------

```swift
 1 | import Foundation
 2 | 
 3 | // MARK: - Input Handling
 4 | /// Handles input parsing and routing to the calculator service
 5 | struct CalculatorInputHandler {
 6 |     private let service: CalculatorService
 7 |     
 8 |     init(service: CalculatorService) {
 9 |         self.service = service
10 |     }
11 |     
12 |     func handleInput(_ input: String) {
13 |         switch input {
14 |         case "C":
15 |             service.clear()
16 |         case "±":
17 |             service.toggleSign()
18 |         case "%":
19 |             service.percentage()
20 |         case "+", "-", "×", "÷":
21 |             if let operation = CalculatorService.Operation(rawValue: input) {
22 |                 service.setOperation(operation)
23 |             }
24 |         case "=":
25 |             service.calculate()
26 |         case ".":
27 |             service.inputDecimal()
28 |         case "0"..."9":
29 |             service.inputNumber(input)
30 |         default:
31 |             break // Ignore unknown inputs
32 |         }
33 |     }
34 |     
35 |     func deleteLastDigit() {
36 |         service.deleteLastDigit()
37 |     }
38 | }
39 | 
```

--------------------------------------------------------------------------------
/example_projects/spm/Sources/quick-task/main.swift:
--------------------------------------------------------------------------------

```swift
 1 | import Foundation
 2 | import TestLib
 3 | import ArgumentParser
 4 | 
 5 | @main
 6 | struct QuickTask: AsyncParsableCommand {
 7 |     static let configuration = CommandConfiguration(
 8 |         commandName: "quick-task",
 9 |         abstract: "A quick task that finishes within 5 seconds",
10 |         version: "1.0.0"
11 |     )
12 |     
13 |     @Option(name: .shortAndLong, help: "Number of seconds to work (default: 3)")
14 |     var duration: Int = 3
15 |     
16 |     @Flag(name: .shortAndLong, help: "Enable verbose output")
17 |     var verbose: Bool = false
18 |     
19 |     @Option(name: .shortAndLong, help: "Task name to display")
20 |     var taskName: String = "DefaultTask"
21 |     
22 |     func run() async throws {
23 |         let taskManager = TaskManager()
24 |         
25 |         if verbose {
26 |             print("🚀 Starting quick task: \(taskName)")
27 |             print("⏱️  Duration: \(duration) seconds")
28 |         }
29 |         
30 |         await taskManager.executeQuickTask(name: taskName, duration: duration, verbose: verbose)
31 |         
32 |         if verbose {
33 |             print("✅ Quick task completed successfully!")
34 |         }
35 |     }
36 | }
```

--------------------------------------------------------------------------------
/example_projects/spm/Package.swift:
--------------------------------------------------------------------------------

```swift
 1 | // swift-tools-version: 6.1
 2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
 3 | 
 4 | import PackageDescription
 5 | 
 6 | let package = Package(
 7 |     name: "spm",
 8 |     platforms: [
 9 |         .macOS(.v15),
10 |     ],
11 |     dependencies: [
12 |         .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.5.1"),
13 |     ],
14 |     targets: [
15 |         .executableTarget(
16 |             name: "spm"
17 |         ),
18 |         .executableTarget(
19 |             name: "quick-task",
20 |             dependencies: [
21 |                 "TestLib",
22 |                 .product(name: "ArgumentParser", package: "swift-argument-parser"),
23 |             ]
24 |         ),
25 |         .executableTarget(
26 |             name: "long-server",
27 |             dependencies: [
28 |                 "TestLib", 
29 |                 .product(name: "ArgumentParser", package: "swift-argument-parser"),
30 |             ]
31 |         ),
32 |         .target(
33 |             name: "TestLib"
34 |         ),
35 |         .testTarget(
36 |             name: "TestLibTests",
37 |             dependencies: ["TestLib"]
38 |         ),
39 |     ]
40 | )
41 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS/MCPTest/ContentView.swift:
--------------------------------------------------------------------------------

```swift
 1 | //
 2 | //  ContentView.swift
 3 | //  MCPTest
 4 | //
 5 | //  Created by Cameron on 16/02/2025.
 6 | //
 7 | 
 8 | import SwiftUI
 9 | import OSLog
10 | 
11 | struct ContentView: View {
12 |     @State private var text: String = ""
13 | 
14 |     var body: some View {
15 |         VStack {
16 |             Image(systemName: "globe")
17 |                 .imageScale(.large)
18 |                 .foregroundStyle(.tint)
19 |             TextField("Enter text", text: $text)
20 |                 .textFieldStyle(RoundedBorderTextFieldStyle())
21 |                 .padding(.horizontal)
22 |             Text(text)
23 | 
24 |             Button("Log something") {
25 |                 let message = ProcessInfo.processInfo.environment.map { "\($0.key): \($0.value)" }.joined(separator: "\n")
26 |                 Logger.myApp.debug("Environment: \(message)")                
27 |                 debugPrint("Button was pressed.")
28 | 
29 |                 text = "You just pressed the button!"
30 |             }
31 |         }
32 |         .padding()
33 |     }
34 | }
35 | 
36 | #Preview {
37 |     ContentView()
38 | }
39 | 
40 | // OS Log Extension
41 | extension Logger {
42 |     static let myApp = Logger(
43 |         subsystem: "com.cameroncooke.MCPTest", 
44 |         category: "default"
45 |     )
46 | }
47 |     
48 | 
```

--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { defineConfig } from 'vitest/config';
 2 | 
 3 | export default defineConfig({
 4 |   test: {
 5 |     environment: 'node',
 6 |     globals: true,
 7 |     include: [
 8 |       'src/**/__tests__/**/*.test.ts'  // Only __tests__ directories
 9 |     ],
10 |     exclude: [
11 |       'node_modules/**',
12 |       'build/**',
13 |       'coverage/**',
14 |       'bundled/**',
15 |       'example_projects/**',
16 |       '.git/**',
17 |       '**/*.d.ts',
18 |       '**/temp_*',
19 |       '**/full-output.txt',
20 |       '**/experiments/**',
21 |       '**/__pycache__/**',
22 |       '**/dist/**'
23 |     ],
24 |     pool: 'threads',
25 |     poolOptions: {
26 |       threads: {
27 |         maxThreads: 4
28 |       }
29 |     },
30 |     env: {
31 |       NODE_OPTIONS: '--max-old-space-size=4096'
32 |     },
33 |     testTimeout: 30000,
34 |     hookTimeout: 10000,
35 |     teardownTimeout: 5000,
36 |     coverage: {
37 |       provider: 'v8',
38 |       reporter: ['text', 'json', 'html'],
39 |       exclude: [
40 |         'node_modules/**',
41 |         'build/**',
42 |         'tests/**',
43 |         'example_projects/**',
44 |         '**/*.config.*',
45 |         '**/*.d.ts'
46 |       ]
47 |     }
48 |   },
49 |   resolve: {
50 |     alias: {
51 |       // Handle .js imports in TypeScript files
52 |       '^(\\.{1,2}/.*)\\.js$': '$1'
53 |     }
54 |   }
55 | });
```

--------------------------------------------------------------------------------
/src/mcp/tools/session-management/session_clear_defaults.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { sessionStore } from '../../../utils/session-store.ts';
 3 | import { createTypedTool } from '../../../utils/typed-tool-factory.ts';
 4 | import { getDefaultCommandExecutor } from '../../../utils/execution/index.ts';
 5 | import type { ToolResponse } from '../../../types/common.ts';
 6 | 
 7 | const keys = [
 8 |   'projectPath',
 9 |   'workspacePath',
10 |   'scheme',
11 |   'configuration',
12 |   'simulatorName',
13 |   'simulatorId',
14 |   'deviceId',
15 |   'useLatestOS',
16 |   'arch',
17 | ] as const;
18 | 
19 | const schemaObj = z.object({
20 |   keys: z.array(z.enum(keys)).optional(),
21 |   all: z.boolean().optional(),
22 | });
23 | 
24 | type Params = z.infer<typeof schemaObj>;
25 | 
26 | export async function sessionClearDefaultsLogic(params: Params): Promise<ToolResponse> {
27 |   if (params.all || !params.keys) sessionStore.clear();
28 |   else sessionStore.clear(params.keys);
29 |   return { content: [{ type: 'text', text: 'Session defaults cleared' }], isError: false };
30 | }
31 | 
32 | export default {
33 |   name: 'session-clear-defaults',
34 |   description: 'Clear selected or all session defaults.',
35 |   schema: schemaObj.shape,
36 |   handler: createTypedTool(schemaObj, sessionClearDefaultsLogic, getDefaultCommandExecutor),
37 | };
38 | 
```

--------------------------------------------------------------------------------
/.vscode/mcp.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |     "servers": {
 3 |       "XcodeBuildMCP": {
 4 |         "type": "stdio",
 5 |         "command": "npx",
 6 |         "args": [
 7 |           "-y",
 8 |           "xcodebuildmcp@latest"
 9 |         ],
10 |         "env": {
11 |           "XCODEBUILDMCP_DEBUG": "true",
12 |           "XCODEBUILDMCP_DYNAMIC_TOOLS": "true",
13 |           "INCREMENTAL_BUILDS_ENABLED": "false",
14 |           "XCODEBUILDMCP_IOS_TEMPLATE_PATH": "/Volumes/Developer/XcodeBuildMCP-iOS-Template",
15 |           "XCODEBUILDMCP_MACOS_TEMPLATE_PATH": "/Volumes/Developer/XcodeBuildMCP-macOS-Template"
16 |         }
17 |       },      
18 |       "XcodeBuildMCP-Dev": {
19 |         "type": "stdio",
20 |         "command": "node",
21 |         "args": [
22 |           "--inspect-brk=9999",
23 |           "--trace-warnings",
24 |           "/Users/cameroncooke/Developer/XcodeBuildMCP/build/index.js"
25 |         ],
26 |         "env": {
27 |           "XCODEBUILDMCP_DEBUG": "true",
28 |           "XCODEBUILDMCP_DYNAMIC_TOOLS": "true",
29 |           "INCREMENTAL_BUILDS_ENABLED": "false",
30 |           "XCODEBUILDMCP_IOS_TEMPLATE_PATH": "/Volumes/Developer/XcodeBuildMCP-iOS-Template",
31 |           "XCODEBUILDMCP_MACOS_TEMPLATE_PATH": "/Volumes/Developer/XcodeBuildMCP-macOS-Template"
32 |         }
33 |       },
34 |     }
35 | }
```

--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Feature Request
 2 | description: Suggest a new feature for XcodeBuildMCP
 3 | title: "[Feature]: "
 4 | labels: ["enhancement"]
 5 | body:
 6 |   - type: markdown
 7 |     attributes:
 8 |       value: |
 9 |         Thanks for suggesting a new feature for XcodeBuildMCP!
10 |         
11 |   - type: textarea
12 |     id: feature-description
13 |     attributes:
14 |       label: Feature Description
15 |       description: Describe the new capability you'd like to add to XcodeBuildMCP
16 |       placeholder: I would like the AI assistant to be able to...
17 |     validations:
18 |       required: true
19 |       
20 |   - type: textarea
21 |     id: use-cases
22 |     attributes:
23 |       label: Use Cases
24 |       description: Describe specific scenarios where this feature would be useful
25 |       placeholder: |
26 |         - Building and testing iOS apps with custom schemes
27 |         - Managing multiple simulator configurations
28 |         - Automating complex Xcode workflows
29 |     validations:
30 |       required: false
31 |       
32 |   - type: textarea
33 |     id: example-interactions
34 |     attributes:
35 |       label: Example Interactions
36 |       description: Provide examples of how you envision using this feature
37 |       placeholder: |
38 |         You: [Example request to the AI]
39 |         AI: [Desired response/action]
40 |     validations:
41 |       required: false
42 | 
```

--------------------------------------------------------------------------------
/src/utils/session-store.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { log } from './logger.ts';
 2 | 
 3 | export type SessionDefaults = {
 4 |   projectPath?: string;
 5 |   workspacePath?: string;
 6 |   scheme?: string;
 7 |   configuration?: string;
 8 |   simulatorName?: string;
 9 |   simulatorId?: string;
10 |   deviceId?: string;
11 |   useLatestOS?: boolean;
12 |   arch?: 'arm64' | 'x86_64';
13 | };
14 | 
15 | class SessionStore {
16 |   private defaults: SessionDefaults = {};
17 | 
18 |   setDefaults(partial: Partial<SessionDefaults>): void {
19 |     this.defaults = { ...this.defaults, ...partial };
20 |     log('info', `[Session] Defaults updated: ${Object.keys(partial).join(', ')}`);
21 |   }
22 | 
23 |   clear(keys?: (keyof SessionDefaults)[]): void {
24 |     if (keys == null) {
25 |       this.defaults = {};
26 |       log('info', '[Session] All defaults cleared');
27 |       return;
28 |     }
29 |     if (keys.length === 0) {
30 |       // No-op when an empty array is provided (e.g., empty UI selection)
31 |       log('info', '[Session] No keys provided to clear; no changes made');
32 |       return;
33 |     }
34 |     for (const k of keys) delete this.defaults[k];
35 |     log('info', `[Session] Defaults cleared: ${keys.join(', ')}`);
36 |   }
37 | 
38 |   get<K extends keyof SessionDefaults>(key: K): SessionDefaults[K] {
39 |     return this.defaults[key];
40 |   }
41 | 
42 |   getAll(): SessionDefaults {
43 |     return { ...this.defaults };
44 |   }
45 | }
46 | 
47 | export const sessionStore = new SessionStore();
48 | 
```

--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "eslint.useFlatConfig": true,
 3 |   "eslint.validate": [
 4 |     "javascript",
 5 |     "typescript"
 6 |   ],
 7 |   "eslint.runtime": "/opt/homebrew/bin/node",
 8 |   "eslint.format.enable": true,
 9 |   "eslint.nodePath": "${workspaceFolder}/node_modules",
10 |   "eslint.workingDirectories": [
11 |     {
12 |       "directory": "${workspaceFolder}",
13 |       "changeProcessCWD": true
14 |     }
15 |   ],
16 |   "typescript.tsdk": "node_modules/typescript/lib",
17 |   "typescript.enablePromptUseWorkspaceTsdk": true,
18 |   "typescript.tsserver.maxTsServerMemory": 4096,
19 |   "javascript.validate.enable": false,
20 |   "typescript.validate.enable": false,
21 |   "editor.codeActionsOnSave": {
22 |     "source.fixAll.eslint": "explicit"
23 |   },
24 |   "editor.defaultFormatter": "vscode.typescript-language-features",
25 |   "[typescript]": {
26 |     "editor.defaultFormatter": "vscode.typescript-language-features"
27 |   },
28 |   "[javascript]": {
29 |     "editor.defaultFormatter": "vscode.typescript-language-features"
30 |   },
31 |   "terminal.integrated.shellIntegration.decorationsEnabled": "never",
32 |   "vitest.nodeExecutable": "/opt/homebrew/bin/node",
33 |   "[json]": {
34 |     "editor.defaultFormatter": "vscode.json-language-features"
35 |   },
36 |   "[jsonc]": {
37 |     "editor.defaultFormatter": "vscode.json-language-features"
38 |   },
39 |   "chat.mcp.serverSampling": {
40 |     "XcodeBuildMCP/.vscode/mcp.json: XcodeBuildMCP-Dev": {
41 |       "allowedDuringChat": true
42 |     }
43 |   },
44 | }
```

--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "version": "0.2.0",
 3 |   "configurations": [
 4 |     {
 5 |       "type": "node",
 6 |       "request": "attach",
 7 |       "name": "Wait for MCP Server to Start",
 8 |       "port": 9999,
 9 |       "address": "localhost",
10 |       "restart": true,
11 |       "skipFiles": [
12 |         "<node_internals>/**"
13 |       ],
14 |       "sourceMaps": true,
15 |       "outFiles": [
16 |         "${workspaceFolder}/build/**/*.js"
17 |       ],
18 |       "cwd": "${workspaceFolder}",
19 |       "sourceMapPathOverrides": {
20 |         "/*": "${workspaceFolder}/src/*"
21 |       },
22 |       "timeout": 60000,
23 |       "localRoot": "${workspaceFolder}",
24 |       "remoteRoot": "${workspaceFolder}"
25 |     },
26 |     {
27 |       "type": "node",
28 |       "request": "launch",
29 |       "name": "Launch MCP Server Dev",
30 |       "program": "${workspaceFolder}/build/index.js",
31 |       "cwd": "${workspaceFolder}",
32 |       "runtimeArgs": [
33 |         "--inspect=9999"
34 |       ],
35 |       "env": {
36 |         "XCODEBUILDMCP_DEBUG": "true",
37 |         "XCODEBUILDMCP_DYNAMIC_TOOLS": "true",
38 |         "INCREMENTAL_BUILDS_ENABLED": "false",
39 |         "XCODEBUILDMCP_IOS_TEMPLATE_PATH": "/Volumes/Developer/XcodeBuildMCP-iOS-Template",
40 |         "XCODEBUILDMCP_MACOS_TEMPLATE_PATH": "/Volumes/Developer/XcodeBuildMCP-macOS-Template"
41 |       },
42 |       "sourceMaps": true,
43 |       "outFiles": [
44 |         "${workspaceFolder}/build/**/*.js"
45 |       ],
46 |       "skipFiles": [
47 |         "<node_internals>/**"
48 |       ],
49 |       "sourceMapPathOverrides": {
50 |         "/*": "${workspaceFolder}/src/*"
51 |       }
52 |     }
53 |   ]
54 | }
55 | 
```

--------------------------------------------------------------------------------
/.github/workflows/claude-dispatch.yml:
--------------------------------------------------------------------------------

```yaml
 1 | # IMPORTANT: Do not move this file in your repo! Make sure it's located at .github/workflows/claude-dispatch.yml
 2 | name: Claude Code Dispatch
 3 | 
 4 | # IMPORTANT: Do not modify this `on` section!
 5 | on:
 6 |   repository_dispatch:
 7 |     types: [claude-dispatch]
 8 | 
 9 | jobs:
10 |   claude-dispatch:
11 |     runs-on: ubuntu-latest
12 |     permissions:
13 |       contents: write
14 |       pull-requests: write 
15 |       issues: write
16 |       id-token: write
17 |     steps:
18 |       - name: Checkout repository
19 |         uses: actions/checkout@v4
20 |         with:
21 |           fetch-depth: 1
22 | 
23 |       # - name: Preliminary Setup
24 |         # run: |
25 |           # echo "Setting up environment..."
26 |           # Add any preliminary setup commands here to setup Claude's dev environment
27 |           # e.g., npm install, etc.
28 | 
29 |       - name: Run Claude Code
30 |         id: claude
31 |         uses: anthropics/claude-code-action@eap
32 |         with:
33 |           mode: 'remote-agent'
34 |           
35 |           # Optional: Specify an API key, otherwise we'll use your Claude account automatically
36 |           # anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
37 | 
38 |           # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
39 |           # model: "claude-opus-4-20250514"
40 | 
41 |           # Optional: Allow Claude to run specific commands
42 |           # allowed_tools: |
43 |             # Bash(npm run lint)
44 |             # Bash(npm run test)
45 |             # Bash(npm run build)
46 | 
47 |           # Optional: Custom environment variables for Claude
48 |           # claude_env: |
49 |           #   NODE_ENV: test
```

--------------------------------------------------------------------------------
/src/mcp/tools/session-management/__tests__/session_show_defaults.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect, beforeEach, afterEach } from 'vitest';
 2 | import { sessionStore } from '../../../../utils/session-store.ts';
 3 | import plugin from '../session_show_defaults.ts';
 4 | 
 5 | describe('session-show-defaults tool', () => {
 6 |   beforeEach(() => {
 7 |     sessionStore.clear();
 8 |   });
 9 | 
10 |   afterEach(() => {
11 |     sessionStore.clear();
12 |   });
13 | 
14 |   describe('Export Field Validation (Literal)', () => {
15 |     it('should have correct name', () => {
16 |       expect(plugin.name).toBe('session-show-defaults');
17 |     });
18 | 
19 |     it('should have correct description', () => {
20 |       expect(plugin.description).toBe('Show current session defaults.');
21 |     });
22 | 
23 |     it('should have handler function', () => {
24 |       expect(typeof plugin.handler).toBe('function');
25 |     });
26 | 
27 |     it('should have empty schema', () => {
28 |       expect(plugin.schema).toEqual({});
29 |     });
30 |   });
31 | 
32 |   describe('Handler Behavior', () => {
33 |     it('should return empty defaults when none set', async () => {
34 |       const result = await plugin.handler({});
35 |       expect(result.isError).toBe(false);
36 |       const parsed = JSON.parse(result.content[0].text);
37 |       expect(parsed).toEqual({});
38 |     });
39 | 
40 |     it('should return current defaults when set', async () => {
41 |       sessionStore.setDefaults({ scheme: 'MyScheme', simulatorId: 'SIM-123' });
42 |       const result = await plugin.handler({});
43 |       expect(result.isError).toBe(false);
44 |       const parsed = JSON.parse(result.content[0].text);
45 |       expect(parsed.scheme).toBe('MyScheme');
46 |       expect(parsed.simulatorId).toBe('SIM-123');
47 |     });
48 |   });
49 | });
50 | 
```

--------------------------------------------------------------------------------
/src/utils/__tests__/session-store.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect, beforeEach } from 'vitest';
 2 | import { sessionStore } from '../session-store.ts';
 3 | 
 4 | describe('SessionStore', () => {
 5 |   beforeEach(() => {
 6 |     sessionStore.clear();
 7 |   });
 8 | 
 9 |   it('should set and get defaults', () => {
10 |     sessionStore.setDefaults({ scheme: 'App', useLatestOS: true });
11 |     expect(sessionStore.get('scheme')).toBe('App');
12 |     expect(sessionStore.get('useLatestOS')).toBe(true);
13 |   });
14 | 
15 |   it('should merge defaults on set', () => {
16 |     sessionStore.setDefaults({ scheme: 'App' });
17 |     sessionStore.setDefaults({ simulatorName: 'iPhone 16' });
18 |     const all = sessionStore.getAll();
19 |     expect(all.scheme).toBe('App');
20 |     expect(all.simulatorName).toBe('iPhone 16');
21 |   });
22 | 
23 |   it('should clear specific keys', () => {
24 |     sessionStore.setDefaults({ scheme: 'App', simulatorId: 'SIM-1', deviceId: 'DEV-1' });
25 |     sessionStore.clear(['simulatorId']);
26 |     const all = sessionStore.getAll();
27 |     expect(all.scheme).toBe('App');
28 |     expect(all.simulatorId).toBeUndefined();
29 |     expect(all.deviceId).toBe('DEV-1');
30 |   });
31 | 
32 |   it('should clear all when no keys provided', () => {
33 |     sessionStore.setDefaults({ scheme: 'App', simulatorId: 'SIM-1' });
34 |     sessionStore.clear();
35 |     const all = sessionStore.getAll();
36 |     expect(Object.keys(all).length).toBe(0);
37 |   });
38 | 
39 |   it('should be a no-op when empty keys array provided', () => {
40 |     sessionStore.setDefaults({ scheme: 'App', simulatorId: 'SIM-1' });
41 |     sessionStore.clear([]);
42 |     const all = sessionStore.getAll();
43 |     expect(all.scheme).toBe('App');
44 |     expect(all.simulatorId).toBe('SIM-1');
45 |   });
46 | });
47 | 
```

--------------------------------------------------------------------------------
/example_projects/spm/Sources/long-server/main.swift:
--------------------------------------------------------------------------------

```swift
 1 | import Foundation
 2 | import TestLib
 3 | import ArgumentParser
 4 | 
 5 | @main
 6 | struct LongServer: AsyncParsableCommand {
 7 |     static let configuration = CommandConfiguration(
 8 |         commandName: "long-server",
 9 |         abstract: "A long-running server that runs indefinitely until stopped"
10 |     )
11 |     
12 |     @Option(name: .shortAndLong, help: "Port to listen on (default: 8080)")
13 |     var port: Int = 8080
14 |     
15 |     @Flag(name: .shortAndLong, help: "Enable verbose logging")
16 |     var verbose: Bool = false
17 |     
18 |     @Option(name: .shortAndLong, help: "Auto-shutdown after N seconds (0 = run forever)")
19 |     var autoShutdown: Int = 0
20 |     
21 |     func run() async throws {
22 |         let taskManager = TaskManager()
23 |         
24 |         if verbose {
25 |             print("🚀 Starting long-running server...")
26 |             print("🌐 Port: \(port)")
27 |             if autoShutdown > 0 {
28 |                 print("⏰ Auto-shutdown: \(autoShutdown) seconds")
29 |             } else {
30 |                 print("♾️  Running indefinitely (use SIGTERM to stop)")
31 |             }
32 |         }
33 |         
34 |         // Set up signal handling for graceful shutdown
35 |         let signalSource = DispatchSource.makeSignalSource(signal: SIGTERM, queue: .main)
36 |         signalSource.setEventHandler {
37 |             if verbose {
38 |                 print("\n🛑 Received SIGTERM, shutting down gracefully...")
39 |             }
40 |             taskManager.stopServer()
41 |         }
42 |         signalSource.resume()
43 |         signal(SIGTERM, SIG_IGN)
44 |         
45 |         await taskManager.startLongRunningServer(
46 |             port: port, 
47 |             verbose: verbose, 
48 |             autoShutdown: autoShutdown
49 |         )
50 |     }
51 | }
```

--------------------------------------------------------------------------------
/example_projects/iOS_Calculator/CalculatorAppPackage/Sources/CalculatorAppFeature/CalculatorDisplay.swift:
--------------------------------------------------------------------------------

```swift
 1 | import SwiftUI
 2 | 
 3 | // MARK: - Calculator Display Component
 4 | struct CalculatorDisplay: View {
 5 |     let expressionDisplay: String
 6 |     let display: String
 7 |     var onDeleteLastDigit: (() -> Void)? = nil
 8 |     
 9 |     var body: some View {
10 |         VStack(alignment: .trailing, spacing: 8) {
11 |             // Expression display (smaller, secondary)
12 |             Text(expressionDisplay)
13 |                 .font(.title2)
14 |                 .foregroundColor(.white.opacity(0.7))
15 |                 .frame(maxWidth: .infinity, alignment: .trailing)
16 |                 .lineLimit(1)
17 |                 .minimumScaleFactor(0.5)
18 |             
19 |             // Main result display
20 |             Text(display)
21 |                 .font(.system(size: 56, weight: .light, design: .rounded))
22 |                 .foregroundColor(.white)
23 |                 .frame(maxWidth: .infinity, alignment: .trailing)
24 |                 .lineLimit(1)
25 |                 .minimumScaleFactor(0.3)
26 |                 .gesture(DragGesture(minimumDistance: 20, coordinateSpace: .local)
27 |                     .onEnded { value in
28 |                         if value.translation.width < -20 || value.translation.width > 20 {
29 |                             onDeleteLastDigit?()
30 |                         }
31 |                     }
32 |                 )
33 |         }
34 |         .padding(.horizontal, 24)
35 |         .padding(.bottom, 30)
36 |         .frame(height: 140)
37 |     }
38 | }
39 | 
40 | struct CalculatorDisplay_Previews: PreviewProvider {
41 |     static var previews: some View {
42 |         CalculatorDisplay(expressionDisplay: "12 + 7", display: "19", onDeleteLastDigit: nil)
43 |             .background(Color.black)
44 |             .previewLayout(.sizeThatFits)
45 |     }
46 | }
47 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/logging/stop_sim_log_cap.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Logging Plugin: Stop Simulator Log Capture
 3 |  *
 4 |  * Stops an active simulator log capture session and returns the captured logs.
 5 |  */
 6 | 
 7 | import { z } from 'zod';
 8 | import { stopLogCapture as _stopLogCapture } from '../../../utils/log-capture/index.ts';
 9 | import { ToolResponse, createTextContent } from '../../../types/common.ts';
10 | import { createTypedTool } from '../../../utils/typed-tool-factory.ts';
11 | import { getDefaultCommandExecutor } from '../../../utils/command.ts';
12 | 
13 | // Define schema as ZodObject
14 | const stopSimLogCapSchema = z.object({
15 |   logSessionId: z.string().describe('The session ID returned by start_sim_log_cap.'),
16 | });
17 | 
18 | // Use z.infer for type safety
19 | type StopSimLogCapParams = z.infer<typeof stopSimLogCapSchema>;
20 | 
21 | /**
22 |  * Business logic for stopping simulator log capture session
23 |  */
24 | export async function stop_sim_log_capLogic(params: StopSimLogCapParams): Promise<ToolResponse> {
25 |   const { logContent, error } = await _stopLogCapture(params.logSessionId);
26 |   if (error) {
27 |     return {
28 |       content: [
29 |         createTextContent(`Error stopping log capture session ${params.logSessionId}: ${error}`),
30 |       ],
31 |       isError: true,
32 |     };
33 |   }
34 |   return {
35 |     content: [
36 |       createTextContent(
37 |         `Log capture session ${params.logSessionId} stopped successfully. Log content follows:\n\n${logContent}`,
38 |       ),
39 |     ],
40 |   };
41 | }
42 | 
43 | export default {
44 |   name: 'stop_sim_log_cap',
45 |   description: 'Stops an active simulator log capture session and returns the captured logs.',
46 |   schema: stopSimLogCapSchema.shape, // MCP SDK compatibility
47 |   handler: createTypedTool(stopSimLogCapSchema, stop_sim_log_capLogic, getDefaultCommandExecutor),
48 | };
49 | 
```

--------------------------------------------------------------------------------
/src/doctor-cli.ts:
--------------------------------------------------------------------------------

```typescript
 1 | #!/usr/bin/env node
 2 | 
 3 | /**
 4 |  * XcodeBuildMCP Doctor CLI
 5 |  *
 6 |  * This standalone script runs the doctor tool and outputs the results
 7 |  * to the console. It's designed to be run directly via npx or mise.
 8 |  */
 9 | 
10 | import { version } from './version.ts';
11 | import { doctorLogic } from './mcp/tools/doctor/doctor.ts';
12 | import { getDefaultCommandExecutor } from './utils/execution/index.ts';
13 | 
14 | async function runDoctor(): Promise<void> {
15 |   try {
16 |     // Using console.error to avoid linting issues as it's allowed by the project's linting rules
17 |     console.error(`Running XcodeBuildMCP Doctor (v${version})...`);
18 |     console.error('Collecting system information and checking dependencies...\n');
19 | 
20 |     // Run the doctor tool logic directly with CLI flag enabled
21 |     const executor = getDefaultCommandExecutor();
22 |     const result = await doctorLogic({}, executor, true); // showAsciiLogo = true for CLI
23 | 
24 |     // Output the doctor information
25 |     if (result.content && result.content.length > 0) {
26 |       const textContent = result.content.find((item) => item.type === 'text');
27 |       if (textContent && textContent.type === 'text') {
28 |         // eslint-disable-next-line no-console
29 |         console.log(textContent.text);
30 |       } else {
31 |         console.error('Error: Unexpected doctor result format');
32 |       }
33 |     } else {
34 |       console.error('Error: No doctor information returned');
35 |     }
36 | 
37 |     console.error('\nDoctor run complete. Please include this output when reporting issues.');
38 |   } catch (error) {
39 |     console.error('Error running doctor:', error);
40 |     process.exit(1);
41 |   }
42 | }
43 | 
44 | // Run the doctor
45 | runDoctor().catch((error) => {
46 |   console.error('Unhandled exception:', error);
47 |   process.exit(1);
48 | });
49 | 
```

--------------------------------------------------------------------------------
/example_projects/iOS/MCPTestUITests/MCPTestUITests.swift:
--------------------------------------------------------------------------------

```swift
 1 | import XCTest
 2 | 
 3 | /// Reproduction tests for TEST_RUNNER_ environment variable passthrough.
 4 | /// GitHub Issue: https://github.com/cameroncooke/XcodeBuildMCP/issues/101
 5 | ///
 6 | /// Expected behavior:
 7 | /// - When invoking xcodebuild test with TEST_RUNNER_USE_DEV_MODE=YES,
 8 | ///   the test runner environment should contain USE_DEV_MODE=YES
 9 | ///   (the TEST_RUNNER_ prefix is stripped by xcodebuild).
10 | ///
11 | /// Current behavior (before implementation in Node layer):
12 | /// - Running via XcodeBuildMCP test tools does not yet pass TEST_RUNNER_
13 | ///   variables through, so this test will fail and serve as a repro.
14 | final class MCPTestUITests: XCTestCase {
15 | 
16 |     override func setUpWithError() throws {
17 |         continueAfterFailure = false
18 |     }
19 | 
20 |     /// Verifies that USE_DEV_MODE=YES is present in the test runner environment.
21 |     /// This proves TEST_RUNNER_USE_DEV_MODE=YES was passed to xcodebuild.
22 |     func testEnvironmentVariablePassthrough() throws {
23 |         let env = ProcessInfo.processInfo.environment
24 |         let value = env["USE_DEV_MODE"] ?? "<nil>"
25 |         XCTAssertEqual(
26 |             value,
27 |             "YES",
28 |             "Expected USE_DEV_MODE=YES via TEST_RUNNER_USE_DEV_MODE. Actual: \(value)"
29 |         )
30 |     }
31 | 
32 |     /// Example of how a project might use the env var to alter behavior in dev mode.
33 |     /// This does not change test runner configuration; it simply demonstrates conditional logic.
34 |     func testDevModeBehaviorPlaceholder() throws {
35 |         let isDevMode = ProcessInfo.processInfo.environment["USE_DEV_MODE"] == "YES"
36 |         if isDevMode {
37 |             XCTSkip("Dev mode: skipping heavy or duplicated UI configuration runs")
38 |         }
39 |         XCTAssertTrue(true)
40 |     }
41 | }
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator-management/__tests__/index.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Tests for simulator-management workflow metadata
 3 |  */
 4 | import { describe, it, expect } from 'vitest';
 5 | import { workflow } from '../index.ts';
 6 | 
 7 | describe('simulator-management workflow metadata', () => {
 8 |   describe('Workflow Structure', () => {
 9 |     it('should export workflow object with required properties', () => {
10 |       expect(workflow).toHaveProperty('name');
11 |       expect(workflow).toHaveProperty('description');
12 |       expect(workflow).toHaveProperty('platforms');
13 |       expect(workflow).toHaveProperty('targets');
14 |       expect(workflow).toHaveProperty('projectTypes');
15 |       expect(workflow).toHaveProperty('capabilities');
16 |     });
17 | 
18 |     it('should have correct workflow name', () => {
19 |       expect(workflow.name).toBe('Simulator Management');
20 |     });
21 | 
22 |     it('should have correct description', () => {
23 |       expect(workflow.description).toBe(
24 |         'Tools for managing simulators from booting, opening simulators, listing simulators, stopping simulators, erasing simulator content and settings, and setting simulator environment options like location, network, statusbar and appearance.',
25 |       );
26 |     });
27 | 
28 |     it('should have correct platforms array', () => {
29 |       expect(workflow.platforms).toEqual(['iOS']);
30 |     });
31 | 
32 |     it('should have correct targets array', () => {
33 |       expect(workflow.targets).toEqual(['simulator']);
34 |     });
35 | 
36 |     it('should have correct projectTypes array', () => {
37 |       expect(workflow.projectTypes).toEqual(['project', 'workspace']);
38 |     });
39 | 
40 |     it('should have correct capabilities array', () => {
41 |       expect(workflow.capabilities).toEqual([
42 |         'boot',
43 |         'open',
44 |         'list',
45 |         'appearance',
46 |         'location',
47 |         'network',
48 |         'statusbar',
49 |         'erase',
50 |       ]);
51 |     });
52 |   });
53 | });
54 | 
```

--------------------------------------------------------------------------------
/src/server/server.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Server Configuration - MCP Server setup and lifecycle management
 3 |  *
 4 |  * This module handles the creation, configuration, and lifecycle management of the
 5 |  * Model Context Protocol (MCP) server. It provides the foundation for all tool
 6 |  * registrations and server capabilities.
 7 |  *
 8 |  * Responsibilities:
 9 |  * - Creating and configuring the MCP server instance
10 |  * - Setting up server capabilities and options
11 |  * - Managing server lifecycle (start/stop)
12 |  * - Handling transport configuration (stdio)
13 |  */
14 | 
15 | import { McpServer } from '@camsoft/mcp-sdk/server/mcp.js';
16 | import { StdioServerTransport } from '@camsoft/mcp-sdk/server/stdio.js';
17 | import { log } from '../utils/logger.ts';
18 | import { version } from '../version.ts';
19 | import * as Sentry from '@sentry/node';
20 | 
21 | /**
22 |  * Create and configure the MCP server
23 |  * @returns Configured MCP server instance
24 |  */
25 | export function createServer(): McpServer {
26 |   // Create server instance
27 |   const baseServer = new McpServer(
28 |     {
29 |       name: 'xcodebuildmcp',
30 |       version,
31 |     },
32 |     {
33 |       capabilities: {
34 |         tools: {
35 |           listChanged: true,
36 |         },
37 |         resources: {
38 |           subscribe: true,
39 |           listChanged: true,
40 |         },
41 |         logging: {},
42 |       },
43 |     },
44 |   );
45 | 
46 |   // Wrap server with Sentry for MCP instrumentation
47 |   const server = Sentry.wrapMcpServerWithSentry(baseServer);
48 | 
49 |   // Log server initialization
50 |   log('info', `Server initialized with Sentry MCP instrumentation (version ${version})`);
51 | 
52 |   return server;
53 | }
54 | 
55 | /**
56 |  * Start the MCP server with stdio transport
57 |  * @param server The MCP server instance to start
58 |  */
59 | export async function startServer(server: McpServer): Promise<void> {
60 |   const transport = new StdioServerTransport();
61 |   await server.connect(transport);
62 |   log('info', 'XcodeBuildMCP Server running on stdio');
63 | }
64 | 
```

--------------------------------------------------------------------------------
/src/mcp/resources/devices.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Devices Resource Plugin
 3 |  *
 4 |  * Provides access to connected Apple devices through MCP resource system.
 5 |  * This resource reuses the existing list_devices tool logic to maintain consistency.
 6 |  */
 7 | 
 8 | import { log } from '../../utils/logging/index.ts';
 9 | import type { CommandExecutor } from '../../utils/execution/index.ts';
10 | import { getDefaultCommandExecutor } from '../../utils/execution/index.ts';
11 | import { list_devicesLogic } from '../tools/device/list_devices.ts';
12 | 
13 | // Testable resource logic separated from MCP handler
14 | export async function devicesResourceLogic(
15 |   executor: CommandExecutor = getDefaultCommandExecutor(),
16 | ): Promise<{ contents: Array<{ text: string }> }> {
17 |   try {
18 |     log('info', 'Processing devices resource request');
19 |     const result = await list_devicesLogic({}, executor);
20 | 
21 |     if (result.isError) {
22 |       const errorText = result.content[0]?.text;
23 |       throw new Error(typeof errorText === 'string' ? errorText : 'Failed to retrieve device data');
24 |     }
25 | 
26 |     return {
27 |       contents: [
28 |         {
29 |           text:
30 |             typeof result.content[0]?.text === 'string'
31 |               ? result.content[0].text
32 |               : 'No device data available',
33 |         },
34 |       ],
35 |     };
36 |   } catch (error) {
37 |     const errorMessage = error instanceof Error ? error.message : String(error);
38 |     log('error', `Error in devices resource handler: ${errorMessage}`);
39 | 
40 |     return {
41 |       contents: [
42 |         {
43 |           text: `Error retrieving device data: ${errorMessage}`,
44 |         },
45 |       ],
46 |     };
47 |   }
48 | }
49 | 
50 | export default {
51 |   uri: 'xcodebuildmcp://devices',
52 |   name: 'devices',
53 |   description: 'Connected physical Apple devices with their UUIDs, names, and connection status',
54 |   mimeType: 'text/plain',
55 |   async handler(): Promise<{ contents: Array<{ text: string }> }> {
56 |     return devicesResourceLogic();
57 |   },
58 | };
59 | 
```

--------------------------------------------------------------------------------
/src/mcp/resources/simulators.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Simulator Resource Plugin
 3 |  *
 4 |  * Provides access to available iOS simulators through MCP resource system.
 5 |  * This resource reuses the existing list_sims tool logic to maintain consistency.
 6 |  */
 7 | 
 8 | import { log } from '../../utils/logging/index.ts';
 9 | import { getDefaultCommandExecutor } from '../../utils/execution/index.ts';
10 | import type { CommandExecutor } from '../../utils/execution/index.ts';
11 | import { list_simsLogic } from '../tools/simulator/list_sims.ts';
12 | 
13 | // Testable resource logic separated from MCP handler
14 | export async function simulatorsResourceLogic(
15 |   executor: CommandExecutor = getDefaultCommandExecutor(),
16 | ): Promise<{ contents: Array<{ text: string }> }> {
17 |   try {
18 |     log('info', 'Processing simulators resource request');
19 |     const result = await list_simsLogic({}, executor);
20 | 
21 |     if (result.isError) {
22 |       const errorText = result.content[0]?.text;
23 |       throw new Error(
24 |         typeof errorText === 'string' ? errorText : 'Failed to retrieve simulator data',
25 |       );
26 |     }
27 | 
28 |     return {
29 |       contents: [
30 |         {
31 |           text:
32 |             typeof result.content[0]?.text === 'string'
33 |               ? result.content[0].text
34 |               : 'No simulator data available',
35 |         },
36 |       ],
37 |     };
38 |   } catch (error) {
39 |     const errorMessage = error instanceof Error ? error.message : String(error);
40 |     log('error', `Error in simulators resource handler: ${errorMessage}`);
41 | 
42 |     return {
43 |       contents: [
44 |         {
45 |           text: `Error retrieving simulator data: ${errorMessage}`,
46 |         },
47 |       ],
48 |     };
49 |   }
50 | }
51 | 
52 | export default {
53 |   uri: 'xcodebuildmcp://simulators',
54 |   name: 'simulators',
55 |   description: 'Available iOS simulators with their UUIDs and states',
56 |   mimeType: 'text/plain',
57 |   async handler(): Promise<{ contents: Array<{ text: string }> }> {
58 |     return simulatorsResourceLogic();
59 |   },
60 | };
61 | 
```

--------------------------------------------------------------------------------
/src/mcp/resources/doctor.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Doctor Resource Plugin
 3 |  *
 4 |  * Provides access to development environment doctor information through MCP resource system.
 5 |  * This resource reuses the existing doctor tool logic to maintain consistency.
 6 |  */
 7 | 
 8 | import { log } from '../../utils/logging/index.ts';
 9 | import { getDefaultCommandExecutor, CommandExecutor } from '../../utils/execution/index.ts';
10 | import { doctorLogic } from '../tools/doctor/doctor.ts';
11 | 
12 | // Testable resource logic separated from MCP handler
13 | export async function doctorResourceLogic(
14 |   executor: CommandExecutor = getDefaultCommandExecutor(),
15 | ): Promise<{ contents: Array<{ text: string }> }> {
16 |   try {
17 |     log('info', 'Processing doctor resource request');
18 |     const result = await doctorLogic({}, executor);
19 | 
20 |     if (result.isError) {
21 |       const textItem = result.content.find((i) => i.type === 'text') as
22 |         | { type: 'text'; text: string }
23 |         | undefined;
24 |       const errorText = textItem?.text;
25 |       const errorMessage =
26 |         typeof errorText === 'string' ? errorText : 'Failed to retrieve doctor data';
27 |       log('error', `Error in doctor resource handler: ${errorMessage}`);
28 |       return {
29 |         contents: [
30 |           {
31 |             text: `Error retrieving doctor data: ${errorMessage}`,
32 |           },
33 |         ],
34 |       };
35 |     }
36 | 
37 |     const okTextItem = result.content.find((i) => i.type === 'text') as
38 |       | { type: 'text'; text: string }
39 |       | undefined;
40 |     return {
41 |       contents: [
42 |         {
43 |           text: okTextItem?.text ?? 'No doctor data available',
44 |         },
45 |       ],
46 |     };
47 |   } catch (error) {
48 |     const errorMessage = error instanceof Error ? error.message : String(error);
49 |     log('error', `Error in doctor resource handler: ${errorMessage}`);
50 | 
51 |     return {
52 |       contents: [
53 |         {
54 |           text: `Error retrieving doctor data: ${errorMessage}`,
55 |         },
56 |       ],
57 |     };
58 |   }
59 | }
60 | 
61 | export default {
62 |   uri: 'xcodebuildmcp://doctor',
63 |   name: 'doctor',
64 |   description:
65 |     'Comprehensive development environment diagnostic information and configuration status',
66 |   mimeType: 'text/plain',
67 |   async handler(): Promise<{ contents: Array<{ text: string }> }> {
68 |     return doctorResourceLogic();
69 |   },
70 | };
71 | 
```

--------------------------------------------------------------------------------
/server.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-16/server.schema.json",
 3 |   "name": "com.xcodebuildmcp/XcodeBuildMCP",
 4 |   "description": "XcodeBuildMCP provides tools for Xcode project management, simulator management, and app utilities.",
 5 |   "status": "active",
 6 |   "repository": {
 7 |     "url": "https://github.com/cameroncooke/XcodeBuildMCP",
 8 |     "source": "github",
 9 |     "id": "945551361"
10 |   },
11 |   "version": "1.14.1",
12 |   "packages": [
13 |     {
14 |       "registryType": "npm",
15 |       "registryBaseUrl": "https://registry.npmjs.org",
16 |       "identifier": "xcodebuildmcp",
17 |       "version": "1.14.1",
18 |       "transport": {
19 |         "type": "stdio"
20 |       },
21 |       "runtimeHint": "npx",
22 |       "environmentVariables": [
23 |         {
24 |           "name": "INCREMENTAL_BUILDS_ENABLED",
25 |           "description": "Enable experimental xcodemake incremental builds (true/false or 1/0).",
26 |           "format": "boolean",
27 |           "default": "false",
28 |           "choices": [
29 |             "true",
30 |             "false",
31 |             "1",
32 |             "0"
33 |           ]
34 |         },
35 |         {
36 |           "name": "XCODEBUILDMCP_DYNAMIC_TOOLS",
37 |           "description": "Enable AI-powered dynamic tool discovery to load only relevant workflows.",
38 |           "format": "boolean",
39 |           "default": "false",
40 |           "choices": [
41 |             "true",
42 |             "false"
43 |           ]
44 |         },
45 |         {
46 |           "name": "XCODEBUILDMCP_ENABLED_WORKFLOWS",
47 |           "description": "Comma-separated list of workflows to load in Static Mode (e.g., 'simulator,device,project-discovery').",
48 |           "format": "string",
49 |           "default": ""
50 |         },
51 |         {
52 |           "name": "XCODEBUILDMCP_SENTRY_DISABLED",
53 |           "description": "Disable Sentry error reporting (preferred flag).",
54 |           "format": "boolean",
55 |           "default": "false",
56 |           "choices": [
57 |             "true",
58 |             "false"
59 |           ]
60 |         },
61 |         {
62 |           "name": "XCODEBUILDMCP_DEBUG",
63 |           "description": "Enable verbose debug logging from the server.",
64 |           "format": "boolean",
65 |           "default": "false",
66 |           "choices": [
67 |             "true",
68 |             "false"
69 |           ]
70 |         }
71 |       ]
72 |     }
73 |   ]
74 | }
75 | 
```

--------------------------------------------------------------------------------
/example_projects/.vscode/launch.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |     "configurations": [
 3 |         {
 4 |             "type": "swift",
 5 |             "request": "launch",
 6 |             "args": [],
 7 |             "cwd": "${workspaceFolder:example_projects}/spm",
 8 |             "name": "Debug spm (spm)",
 9 |             "program": "${workspaceFolder:example_projects}/spm/.build/debug/spm",
10 |             "preLaunchTask": "swift: Build Debug spm (spm)"
11 |         },
12 |         {
13 |             "type": "swift",
14 |             "request": "launch",
15 |             "args": [],
16 |             "cwd": "${workspaceFolder:example_projects}/spm",
17 |             "name": "Release spm (spm)",
18 |             "program": "${workspaceFolder:example_projects}/spm/.build/release/spm",
19 |             "preLaunchTask": "swift: Build Release spm (spm)"
20 |         },
21 |         {
22 |             "type": "swift",
23 |             "request": "launch",
24 |             "args": [],
25 |             "cwd": "${workspaceFolder:example_projects}/spm",
26 |             "name": "Debug quick-task (spm)",
27 |             "program": "${workspaceFolder:example_projects}/spm/.build/debug/quick-task",
28 |             "preLaunchTask": "swift: Build Debug quick-task (spm)"
29 |         },
30 |         {
31 |             "type": "swift",
32 |             "request": "launch",
33 |             "args": [],
34 |             "cwd": "${workspaceFolder:example_projects}/spm",
35 |             "name": "Release quick-task (spm)",
36 |             "program": "${workspaceFolder:example_projects}/spm/.build/release/quick-task",
37 |             "preLaunchTask": "swift: Build Release quick-task (spm)"
38 |         },
39 |         {
40 |             "type": "swift",
41 |             "request": "launch",
42 |             "args": [],
43 |             "cwd": "${workspaceFolder:example_projects}/spm",
44 |             "name": "Debug long-server (spm)",
45 |             "program": "${workspaceFolder:example_projects}/spm/.build/debug/long-server",
46 |             "preLaunchTask": "swift: Build Debug long-server (spm)"
47 |         },
48 |         {
49 |             "type": "swift",
50 |             "request": "launch",
51 |             "args": [],
52 |             "cwd": "${workspaceFolder:example_projects}/spm",
53 |             "name": "Release long-server (spm)",
54 |             "program": "${workspaceFolder:example_projects}/spm/.build/release/long-server",
55 |             "preLaunchTask": "swift: Build Release long-server (spm)"
56 |         }
57 |     ]
58 | }
```

--------------------------------------------------------------------------------
/src/mcp/tools/swift-package/swift_package_clean.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import path from 'node:path';
 3 | import type { CommandExecutor } from '../../../utils/execution/index.ts';
 4 | import { getDefaultCommandExecutor } from '../../../utils/execution/index.ts';
 5 | import { createErrorResponse } from '../../../utils/responses/index.ts';
 6 | import { log } from '../../../utils/logging/index.ts';
 7 | import { ToolResponse } from '../../../types/common.ts';
 8 | import { createTypedTool } from '../../../utils/typed-tool-factory.ts';
 9 | 
10 | // Define schema as ZodObject
11 | const swiftPackageCleanSchema = z.object({
12 |   packagePath: z.string().describe('Path to the Swift package root (Required)'),
13 | });
14 | 
15 | // Use z.infer for type safety
16 | type SwiftPackageCleanParams = z.infer<typeof swiftPackageCleanSchema>;
17 | 
18 | export async function swift_package_cleanLogic(
19 |   params: SwiftPackageCleanParams,
20 |   executor: CommandExecutor,
21 | ): Promise<ToolResponse> {
22 |   const resolvedPath = path.resolve(params.packagePath);
23 |   const swiftArgs = ['package', '--package-path', resolvedPath, 'clean'];
24 | 
25 |   log('info', `Running swift ${swiftArgs.join(' ')}`);
26 |   try {
27 |     const result = await executor(['swift', ...swiftArgs], 'Swift Package Clean', true, undefined);
28 |     if (!result.success) {
29 |       const errorMessage = result.error ?? result.output ?? 'Unknown error';
30 |       return createErrorResponse('Swift package clean failed', errorMessage);
31 |     }
32 | 
33 |     return {
34 |       content: [
35 |         { type: 'text', text: '✅ Swift package cleaned successfully.' },
36 |         {
37 |           type: 'text',
38 |           text: '💡 Build artifacts and derived data removed. Ready for fresh build.',
39 |         },
40 |         { type: 'text', text: result.output || '(clean completed silently)' },
41 |       ],
42 |       isError: false,
43 |     };
44 |   } catch (error) {
45 |     const message = error instanceof Error ? error.message : String(error);
46 |     log('error', `Swift package clean failed: ${message}`);
47 |     return createErrorResponse('Failed to execute swift package clean', message);
48 |   }
49 | }
50 | 
51 | export default {
52 |   name: 'swift_package_clean',
53 |   description: 'Cleans Swift Package build artifacts and derived data',
54 |   schema: swiftPackageCleanSchema.shape, // MCP SDK compatibility
55 |   handler: createTypedTool(
56 |     swiftPackageCleanSchema,
57 |     swift_package_cleanLogic,
58 |     getDefaultCommandExecutor,
59 |   ),
60 | };
61 | 
```

--------------------------------------------------------------------------------
/example_projects/spm/Sources/TestLib/TaskManager.swift:
--------------------------------------------------------------------------------

```swift
 1 | import Foundation
 2 | 
 3 | public class TaskManager {
 4 |     private var isServerRunning = false
 5 |     
 6 |     public init() {}
 7 |     
 8 |     public func executeQuickTask(name: String, duration: Int, verbose: Bool) async {
 9 |         if verbose {
10 |             print("📝 Task '\(name)' started at \(Date())")
11 |         }
12 |         
13 |         // Simulate work with periodic output using Swift Concurrency
14 |         for i in 1...duration {
15 |             if verbose {
16 |                 print("⚙️  Working... step \(i)/\(duration)")
17 |             }
18 |             try? await Task.sleep(for: .seconds(1))
19 |         }
20 |         
21 |         if verbose {
22 |             print("🎉 Task '\(name)' completed at \(Date())")
23 |         } else {
24 |             print("Task '\(name)' completed in \(duration)s")
25 |         }
26 |     }
27 |     
28 |     public func startLongRunningServer(port: Int, verbose: Bool, autoShutdown: Int) async {
29 |         if verbose {
30 |             print("🔧 Initializing server on port \(port)...")
31 |         }
32 |         
33 |         var secondsRunning = 0
34 |         let startTime = Date()
35 |         isServerRunning = true
36 |         
37 |         // Simulate server startup
38 |         try? await Task.sleep(for: .milliseconds(500))
39 |         print("✅ Server running on port \(port)")
40 |         
41 |         // Main server loop using Swift Concurrency
42 |         while isServerRunning {
43 |             try? await Task.sleep(for: .seconds(1))
44 |             secondsRunning += 1
45 |             
46 |             if verbose && secondsRunning % 5 == 0 {
47 |                 print("📊 Server heartbeat: \(secondsRunning)s uptime")
48 |             }
49 |             
50 |             // Handle auto-shutdown
51 |             if autoShutdown > 0 && secondsRunning >= autoShutdown {
52 |                 if verbose {
53 |                     print("⏰ Auto-shutdown triggered after \(autoShutdown)s")
54 |                 }
55 |                 break
56 |             }
57 |         }
58 |         
59 |         let uptime = Date().timeIntervalSince(startTime)
60 |         print("🛑 Server stopped after \(String(format: "%.1f", uptime))s uptime")
61 |         isServerRunning = false
62 |     }
63 |     
64 |     public func stopServer() {
65 |         isServerRunning = false
66 |     }
67 |     
68 |     public func calculateSum(_ a: Int, _ b: Int) -> Int {
69 |         return a + b
70 |     }
71 |     
72 |     public func validateInput(_ input: String) -> Bool {
73 |         return !input.isEmpty && input.count <= 100
74 |     }
75 | }
```

--------------------------------------------------------------------------------
/src/mcp/tools/session-management/__tests__/index.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Tests for session-management workflow metadata
 3 |  */
 4 | import { describe, it, expect } from 'vitest';
 5 | import { workflow } from '../index.ts';
 6 | 
 7 | describe('session-management workflow metadata', () => {
 8 |   describe('Workflow Structure', () => {
 9 |     it('should export workflow object with required properties', () => {
10 |       expect(workflow).toHaveProperty('name');
11 |       expect(workflow).toHaveProperty('description');
12 |       expect(workflow).toHaveProperty('platforms');
13 |       expect(workflow).toHaveProperty('targets');
14 |       expect(workflow).toHaveProperty('capabilities');
15 |     });
16 | 
17 |     it('should have correct workflow name', () => {
18 |       expect(workflow.name).toBe('session-management');
19 |     });
20 | 
21 |     it('should have correct description', () => {
22 |       expect(workflow.description).toBe(
23 |         'Manage session defaults for projectPath/workspacePath, scheme, configuration, simulatorName/simulatorId, deviceId, useLatestOS and arch. These defaults are required by many tools and must be set before attempting to call tools that would depend on these values.',
24 |       );
25 |     });
26 | 
27 |     it('should have correct platforms array', () => {
28 |       expect(workflow.platforms).toEqual(['iOS', 'macOS', 'tvOS', 'watchOS', 'visionOS']);
29 |     });
30 | 
31 |     it('should have correct targets array', () => {
32 |       expect(workflow.targets).toEqual(['simulator', 'device']);
33 |     });
34 | 
35 |     it('should have correct capabilities array', () => {
36 |       expect(workflow.capabilities).toEqual(['configuration', 'state-management']);
37 |     });
38 |   });
39 | 
40 |   describe('Workflow Validation', () => {
41 |     it('should have valid string properties', () => {
42 |       expect(typeof workflow.name).toBe('string');
43 |       expect(typeof workflow.description).toBe('string');
44 |       expect(workflow.name.length).toBeGreaterThan(0);
45 |       expect(workflow.description.length).toBeGreaterThan(0);
46 |     });
47 | 
48 |     it('should have valid array properties', () => {
49 |       expect(Array.isArray(workflow.platforms)).toBe(true);
50 |       expect(Array.isArray(workflow.targets)).toBe(true);
51 |       expect(Array.isArray(workflow.capabilities)).toBe(true);
52 | 
53 |       expect(workflow.platforms.length).toBeGreaterThan(0);
54 |       expect(workflow.targets.length).toBeGreaterThan(0);
55 |       expect(workflow.capabilities.length).toBeGreaterThan(0);
56 |     });
57 |   });
58 | });
59 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/logging/start_sim_log_cap.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Logging Plugin: Start Simulator Log Capture
 3 |  *
 4 |  * Starts capturing logs from a specified simulator.
 5 |  */
 6 | 
 7 | import { z } from 'zod';
 8 | import { startLogCapture } from '../../../utils/log-capture/index.ts';
 9 | import { CommandExecutor, getDefaultCommandExecutor } from '../../../utils/command.ts';
10 | import { ToolResponse, createTextContent } from '../../../types/common.ts';
11 | import { createTypedTool } from '../../../utils/typed-tool-factory.ts';
12 | 
13 | // Define schema as ZodObject
14 | const startSimLogCapSchema = z.object({
15 |   simulatorUuid: z
16 |     .string()
17 |     .describe('UUID of the simulator to capture logs from (obtained from list_simulators).'),
18 |   bundleId: z.string().describe('Bundle identifier of the app to capture logs for.'),
19 |   captureConsole: z
20 |     .boolean()
21 |     .optional()
22 |     .describe('Whether to capture console output (requires app relaunch).'),
23 | });
24 | 
25 | // Use z.infer for type safety
26 | type StartSimLogCapParams = z.infer<typeof startSimLogCapSchema>;
27 | 
28 | export async function start_sim_log_capLogic(
29 |   params: StartSimLogCapParams,
30 |   _executor: CommandExecutor = getDefaultCommandExecutor(),
31 |   logCaptureFunction: typeof startLogCapture = startLogCapture,
32 | ): Promise<ToolResponse> {
33 |   const paramsWithDefaults = {
34 |     ...params,
35 |     captureConsole: params.captureConsole ?? false,
36 |   };
37 |   const { sessionId, error } = await logCaptureFunction(paramsWithDefaults, _executor);
38 |   if (error) {
39 |     return {
40 |       content: [createTextContent(`Error starting log capture: ${error}`)],
41 |       isError: true,
42 |     };
43 |   }
44 |   return {
45 |     content: [
46 |       createTextContent(
47 |         `Log capture started successfully. Session ID: ${sessionId}.\n\n${paramsWithDefaults.captureConsole ? 'Note: Your app was relaunched to capture console output.' : 'Note: Only structured logs are being captured.'}\n\nNext Steps:\n1.  Interact with your simulator and app.\n2.  Use 'stop_sim_log_cap' with session ID '${sessionId}' to stop capture and retrieve logs.`,
48 |       ),
49 |     ],
50 |   };
51 | }
52 | 
53 | export default {
54 |   name: 'start_sim_log_cap',
55 |   description:
56 |     'Starts capturing logs from a specified simulator. Returns a session ID. By default, captures only structured logs.',
57 |   schema: startSimLogCapSchema.shape, // MCP SDK compatibility
58 |   handler: createTypedTool(startSimLogCapSchema, start_sim_log_capLogic, getDefaultCommandExecutor),
59 | };
60 | 
```

--------------------------------------------------------------------------------
/.github/workflows/claude.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Claude Code
 2 | 
 3 | on:
 4 |   issue_comment:
 5 |     types: [created]
 6 |   pull_request_review_comment:
 7 |     types: [created]
 8 |   issues:
 9 |     types: [opened, assigned]
10 |   pull_request_review:
11 |     types: [submitted]
12 | 
13 | jobs:
14 |   claude:
15 |     if: |
16 |       (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
17 |       (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
18 |       (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
19 |       (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
20 |     runs-on: ubuntu-latest
21 |     permissions:
22 |       contents: write
23 |       pull-requests: write
24 |       issues: write
25 |       id-token: write
26 |       actions: read # Required for Claude to read CI results on PRs
27 |     steps:
28 |       - name: Checkout repository
29 |         uses: actions/checkout@v4
30 |         with:
31 |           fetch-depth: 1
32 | 
33 |       - name: Run Claude Code
34 |         id: claude
35 |         uses: anthropics/claude-code-action@beta
36 |         with:
37 |           claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
38 | 
39 |           # This is an optional setting that allows Claude to read CI results on PRs
40 |           additional_permissions: |
41 |             actions: read
42 |           
43 |           # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
44 |           # model: "claude-opus-4-20250514"
45 |           
46 |           # Optional: Customize the trigger phrase (default: @claude)
47 |           # trigger_phrase: "/claude"
48 |           
49 |           # Optional: Trigger when specific user is assigned to an issue
50 |           assignee_trigger: "claude-bot"
51 |           
52 |           # Optional: Allow Claude to run specific commands
53 |           allowed_tools: "Bash(npm install),Bash(npm run build:*),Bash(npm run test:*),Bash(npm run lint:*),Bash(npm run format:*),Bash(npm run doctor)"
54 |           
55 |           # Optional: Add custom instructions for Claude to customize its behavior for your project
56 |           # custom_instructions: |
57 |           #   Follow our coding standards
58 |           #   Ensure all new code has tests
59 |           #   Use TypeScript for new files
60 |           
61 |           # Optional: Custom environment variables for Claude
62 |           # claude_env: |
63 |           #   NODE_ENV: test
64 | 
65 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/session-management/session_set_defaults.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { sessionStore, type SessionDefaults } from '../../../utils/session-store.ts';
 3 | import { createTypedTool } from '../../../utils/typed-tool-factory.ts';
 4 | import { getDefaultCommandExecutor } from '../../../utils/execution/index.ts';
 5 | import type { ToolResponse } from '../../../types/common.ts';
 6 | 
 7 | const baseSchema = z.object({
 8 |   projectPath: z.string().optional(),
 9 |   workspacePath: z.string().optional(),
10 |   scheme: z.string().optional(),
11 |   configuration: z.string().optional(),
12 |   simulatorName: z.string().optional(),
13 |   simulatorId: z.string().optional(),
14 |   deviceId: z.string().optional(),
15 |   useLatestOS: z.boolean().optional(),
16 |   arch: z.enum(['arm64', 'x86_64']).optional(),
17 | });
18 | 
19 | const schemaObj = baseSchema
20 |   .refine((v) => !(v.projectPath && v.workspacePath), {
21 |     message: 'projectPath and workspacePath are mutually exclusive',
22 |     path: ['projectPath'],
23 |   })
24 |   .refine((v) => !(v.simulatorId && v.simulatorName), {
25 |     message: 'simulatorId and simulatorName are mutually exclusive',
26 |     path: ['simulatorId'],
27 |   });
28 | 
29 | type Params = z.infer<typeof schemaObj>;
30 | 
31 | export async function sessionSetDefaultsLogic(params: Params): Promise<ToolResponse> {
32 |   // Clear mutually exclusive counterparts before merging new defaults
33 |   const toClear = new Set<keyof SessionDefaults>();
34 |   if (Object.prototype.hasOwnProperty.call(params, 'projectPath')) toClear.add('workspacePath');
35 |   if (Object.prototype.hasOwnProperty.call(params, 'workspacePath')) toClear.add('projectPath');
36 |   if (Object.prototype.hasOwnProperty.call(params, 'simulatorId')) toClear.add('simulatorName');
37 |   if (Object.prototype.hasOwnProperty.call(params, 'simulatorName')) toClear.add('simulatorId');
38 | 
39 |   if (toClear.size > 0) {
40 |     sessionStore.clear(Array.from(toClear));
41 |   }
42 | 
43 |   sessionStore.setDefaults(params as Partial<SessionDefaults>);
44 |   const current = sessionStore.getAll();
45 |   return {
46 |     content: [{ type: 'text', text: `Defaults updated:\n${JSON.stringify(current, null, 2)}` }],
47 |     isError: false,
48 |   };
49 | }
50 | 
51 | export default {
52 |   name: 'session-set-defaults',
53 |   description:
54 |     'Set the session defaults needed by many tools. Most tools require one or more session defaults to be set before they can be used. Agents should set the relevant defaults at the beginning of a session.',
55 |   schema: baseSchema.shape,
56 |   handler: createTypedTool(schemaObj, sessionSetDefaultsLogic, getDefaultCommandExecutor),
57 | };
58 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator/boot_sim.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { ToolResponse } from '../../../types/common.ts';
 3 | import { log } from '../../../utils/logging/index.ts';
 4 | import { getDefaultCommandExecutor } from '../../../utils/execution/index.ts';
 5 | import type { CommandExecutor } from '../../../utils/execution/index.ts';
 6 | import { createSessionAwareTool } from '../../../utils/typed-tool-factory.ts';
 7 | 
 8 | const bootSimSchemaObject = z.object({
 9 |   simulatorId: z.string().describe('UUID of the simulator to boot'),
10 | });
11 | 
12 | // Use z.infer for type safety
13 | type BootSimParams = z.infer<typeof bootSimSchemaObject>;
14 | 
15 | const publicSchemaObject = bootSimSchemaObject.omit({
16 |   simulatorId: true,
17 | } as const);
18 | 
19 | export async function boot_simLogic(
20 |   params: BootSimParams,
21 |   executor: CommandExecutor,
22 | ): Promise<ToolResponse> {
23 |   log('info', `Starting xcrun simctl boot request for simulator ${params.simulatorId}`);
24 | 
25 |   try {
26 |     const command = ['xcrun', 'simctl', 'boot', params.simulatorId];
27 |     const result = await executor(command, 'Boot Simulator', true);
28 | 
29 |     if (!result.success) {
30 |       return {
31 |         content: [
32 |           {
33 |             type: 'text',
34 |             text: `Boot simulator operation failed: ${result.error}`,
35 |           },
36 |         ],
37 |       };
38 |     }
39 | 
40 |     return {
41 |       content: [
42 |         {
43 |           type: 'text',
44 |           text: `✅ Simulator booted successfully. To make it visible, use: open_sim()
45 | 
46 | Next steps:
47 | 1. Open the Simulator app (makes it visible): open_sim()
48 | 2. Install an app: install_app_sim({ simulatorId: "${params.simulatorId}", appPath: "PATH_TO_YOUR_APP" })
49 | 3. Launch an app: launch_app_sim({ simulatorId: "${params.simulatorId}", bundleId: "YOUR_APP_BUNDLE_ID" })`,
50 |         },
51 |       ],
52 |     };
53 |   } catch (error) {
54 |     const errorMessage = error instanceof Error ? error.message : String(error);
55 |     log('error', `Error during boot simulator operation: ${errorMessage}`);
56 |     return {
57 |       content: [
58 |         {
59 |           type: 'text',
60 |           text: `Boot simulator operation failed: ${errorMessage}`,
61 |         },
62 |       ],
63 |     };
64 |   }
65 | }
66 | 
67 | export default {
68 |   name: 'boot_sim',
69 |   description: 'Boots an iOS simulator.',
70 |   schema: publicSchemaObject.shape,
71 |   handler: createSessionAwareTool<BootSimParams>({
72 |     internalSchema: bootSimSchemaObject,
73 |     logicFunction: boot_simLogic,
74 |     getExecutor: getDefaultCommandExecutor,
75 |     requirements: [{ allOf: ['simulatorId'], message: 'simulatorId is required' }],
76 |   }),
77 | };
78 | 
```

--------------------------------------------------------------------------------
/src/mcp/tools/simulator/open_sim.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from 'zod';
 2 | import { ToolResponse } from '../../../types/common.ts';
 3 | import { log } from '../../../utils/logging/index.ts';
 4 | import type { CommandExecutor } from '../../../utils/execution/index.ts';
 5 | import { getDefaultCommandExecutor } from '../../../utils/execution/index.ts';
 6 | import { createTypedTool } from '../../../utils/typed-tool-factory.ts';
 7 | 
 8 | // Define schema as ZodObject
 9 | const openSimSchema = z.object({});
10 | 
11 | // Use z.infer for type safety
12 | type OpenSimParams = z.infer<typeof openSimSchema>;
13 | 
14 | export async function open_simLogic(
15 |   params: OpenSimParams,
16 |   executor: CommandExecutor,
17 | ): Promise<ToolResponse> {
18 |   log('info', 'Starting open simulator request');
19 | 
20 |   try {
21 |     const command = ['open', '-a', 'Simulator'];
22 |     const result = await executor(command, 'Open Simulator', true);
23 | 
24 |     if (!result.success) {
25 |       return {
26 |         content: [
27 |           {
28 |             type: 'text',
29 |             text: `Open simulator operation failed: ${result.error}`,
30 |           },
31 |         ],
32 |       };
33 |     }
34 | 
35 |     return {
36 |       content: [
37 |         {
38 |           type: 'text',
39 |           text: `Simulator app opened successfully`,
40 |         },
41 |         {
42 |           type: 'text',
43 |           text: `Next Steps:
44 | 1. Boot a simulator if needed: boot_sim({ simulatorUuid: 'UUID_FROM_LIST_SIMULATORS' })
45 | 2. Launch your app and interact with it
46 | 3. Log capture options:
47 |    - Option 1: Capture structured logs only (app continues running):
48 |      start_sim_log_cap({ simulatorUuid: 'UUID', bundleId: 'YOUR_APP_BUNDLE_ID' })
49 |    - Option 2: Capture both console and structured logs (app will restart):
50 |      start_sim_log_cap({ simulatorUuid: 'UUID', bundleId: 'YOUR_APP_BUNDLE_ID', captureConsole: true })
51 |    - Option 3: Launch app with logs in one step:
52 |      launch_app_logs_sim({ simulatorUuid: 'UUID', bundleId: 'YOUR_APP_BUNDLE_ID' })`,
53 |         },
54 |       ],
55 |     };
56 |   } catch (error) {
57 |     const errorMessage = error instanceof Error ? error.message : String(error);
58 |     log('error', `Error during open simulator operation: ${errorMessage}`);
59 |     return {
60 |       content: [
61 |         {
62 |           type: 'text',
63 |           text: `Open simulator operation failed: ${errorMessage}`,
64 |         },
65 |       ],
66 |     };
67 |   }
68 | }
69 | 
70 | export default {
71 |   name: 'open_sim',
72 |   description: 'Opens the iOS Simulator app.',
73 |   schema: openSimSchema.shape, // MCP SDK compatibility
74 |   handler: createTypedTool(openSimSchema, open_simLogic, getDefaultCommandExecutor),
75 | };
76 | 
```
Page 1/14FirstPrevNextLast