xcode-mcp-server 1.3.7__tar.gz → 1.3.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/PKG-INFO +1 -1
  2. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/TODO.md +2 -1
  3. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/dev.sh +0 -4
  4. xcode_mcp_server-1.3.9/fools-errand.md +80 -0
  5. xcode_mcp_server-1.3.9/test_projects/fromXcode/iosEmptySwiftUIApp/iosEmptySwiftUIApp.xcodeproj/project.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  6. {xcode_mcp_server-1.3.7/test_projects/templates/BrokenApp/BrokenApp.xcodeproj → xcode_mcp_server-1.3.9/test_projects/fromXcode/iosEmptySwiftUIApp/iosEmptySwiftUIApp.xcodeproj}/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist +1 -1
  7. xcode_mcp_server-1.3.9/test_projects/fromXcode/macosEmptyCommandLineApp/macosEmptyCommandLineApp.xcodeproj/project.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  8. xcode_mcp_server-1.3.9/test_projects/fromXcode/macosEmptyCommandLineApp/macosEmptyCommandLineApp.xcodeproj/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  9. xcode_mcp_server-1.3.9/test_projects/fromXcode/macosEmptySwiftUIApp/macosEmptySwiftUIApp.xcodeproj/project.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  10. xcode_mcp_server-1.3.9/test_projects/fromXcode/macosEmptySwiftUIApp/macosEmptySwiftUIApp.xcodeproj/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  11. xcode_mcp_server-1.3.9/test_projects/templates/BrokenApp/BrokenApp.xcodeproj/project.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  12. xcode_mcp_server-1.3.9/test_projects/templates/BrokenApp/BrokenApp.xcodeproj/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  13. xcode_mcp_server-1.3.9/test_projects/templates/ConsoleApp/ConsoleApp.xcodeproj/project.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  14. xcode_mcp_server-1.3.9/test_projects/templates/ConsoleApp/ConsoleApp.xcodeproj/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  15. xcode_mcp_server-1.3.9/test_projects/templates/SimpleApp/SimpleApp.xcodeproj/project.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  16. xcode_mcp_server-1.3.9/test_projects/templates/SimpleApp/SimpleApp.xcodeproj/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  17. xcode_mcp_server-1.3.9/test_projects/templates/SwiftUITestApp/SwiftUITestApp.xcodeproj/project.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  18. xcode_mcp_server-1.3.9/test_projects/templates/SwiftUITestApp/SwiftUITestApp.xcodeproj/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  19. xcode_mcp_server-1.3.9/test_projects/templates/iOSTestApp/iOSTestApp.xcodeproj/project.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  20. xcode_mcp_server-1.3.9/test_projects/templates/iOSTestApp/iOSTestApp.xcodeproj/xcuserdata/andrew.xcuserdatad/xcschemes/xcschememanagement.plist +19 -0
  21. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/tests/test_basic.py +24 -15
  22. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/tests/test_runner.py +10 -17
  23. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/__init__.py +1 -1
  24. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/security.py +65 -0
  25. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/__init__.py +4 -0
  26. xcode_mcp_server-1.3.9/xcode_mcp_server/tools/create_project.py +100 -0
  27. xcode_mcp_server-1.3.9/xcode_mcp_server/tools/get_active_run_destination.py +199 -0
  28. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/get_xcode_projects.py +16 -0
  29. xcode_mcp_server-1.3.9/xcode_mcp_server/tools/list_run_destinations.py +155 -0
  30. xcode_mcp_server-1.3.9/xcode_mcp_server/tools/set_run_destination.py +103 -0
  31. xcode_mcp_server-1.3.9/xcode_mcp_server/utils/decode_active_destination.swift +104 -0
  32. xcode_mcp_server-1.3.9/xcode_mcp_server/utils/project_templates.py +658 -0
  33. xcode_mcp_server-1.3.7/test_projects/templates/BrokenApp/BrokenApp.xcodeproj/project.xcworkspace/xcuserdata/andrew.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  34. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/.github/workflows/claude-code.yml +0 -0
  35. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/.github/workflows/claude-self-review.yml +0 -0
  36. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/.gitignore +0 -0
  37. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/CLAUDE.md +0 -0
  38. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/LICENSE +0 -0
  39. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/README.md +0 -0
  40. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/_venv-setup.sh +0 -0
  41. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/deploy-beta.sh +0 -0
  42. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/deploy.sh +0 -0
  43. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/info.sh +0 -0
  44. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/pyproject.toml +0 -0
  45. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/requirements.txt +0 -0
  46. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/run_local_for_claude.sh +0 -0
  47. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/scripts/cleanup_tests.sh +0 -0
  48. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/scripts/create_projects.py +0 -0
  49. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/scripts/create_real_projects.py +0 -0
  50. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/scripts/create_spm_projects.sh +0 -0
  51. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/scripts/create_xcode_projects.sh +0 -0
  52. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/scripts/run_all_tests.sh +0 -0
  53. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/scripts/setup_test_projects.sh +0 -0
  54. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/scripts/setup_tests.sh +0 -0
  55. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/iosEmptySwiftUIApp/iosEmptySwiftUIApp/Assets.xcassets/AccentColor.colorset/Contents.json +0 -0
  56. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/iosEmptySwiftUIApp/iosEmptySwiftUIApp/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
  57. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/iosEmptySwiftUIApp/iosEmptySwiftUIApp/Assets.xcassets/Contents.json +0 -0
  58. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/iosEmptySwiftUIApp/iosEmptySwiftUIApp/ContentView.swift +0 -0
  59. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/iosEmptySwiftUIApp/iosEmptySwiftUIApp/iosEmptySwiftUIAppApp.swift +0 -0
  60. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/iosEmptySwiftUIApp/iosEmptySwiftUIApp.xcodeproj/project.pbxproj +0 -0
  61. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/iosEmptySwiftUIApp/iosEmptySwiftUIApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -0
  62. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/macosEmptyCommandLineApp/macosEmptyCommandLineApp/main.swift +0 -0
  63. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/macosEmptyCommandLineApp/macosEmptyCommandLineApp.xcodeproj/project.pbxproj +0 -0
  64. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/macosEmptyCommandLineApp/macosEmptyCommandLineApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -0
  65. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/macosEmptySwiftUIApp/macosEmptySwiftUIApp/Assets.xcassets/AccentColor.colorset/Contents.json +0 -0
  66. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/macosEmptySwiftUIApp/macosEmptySwiftUIApp/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
  67. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/macosEmptySwiftUIApp/macosEmptySwiftUIApp/Assets.xcassets/Contents.json +0 -0
  68. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/macosEmptySwiftUIApp/macosEmptySwiftUIApp/ContentView.swift +0 -0
  69. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/macosEmptySwiftUIApp/macosEmptySwiftUIApp/macosEmptySwiftUIAppApp.swift +0 -0
  70. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/macosEmptySwiftUIApp/macosEmptySwiftUIApp.xcodeproj/project.pbxproj +0 -0
  71. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/fromXcode/macosEmptySwiftUIApp/macosEmptySwiftUIApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -0
  72. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/BrokenApp/BrokenApp/main.swift +0 -0
  73. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/BrokenApp/BrokenApp.xcodeproj/project.pbxproj +0 -0
  74. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/BrokenApp/BrokenApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -0
  75. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/ConsoleApp/ConsoleApp/main.swift +0 -0
  76. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/ConsoleApp/ConsoleApp.xcodeproj/project.pbxproj +0 -0
  77. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/ConsoleApp/ConsoleApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -0
  78. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/SimpleApp/SimpleApp/main.swift +0 -0
  79. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/SimpleApp/SimpleApp.xcodeproj/project.pbxproj +0 -0
  80. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/SimpleApp/SimpleApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -0
  81. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/SwiftUITestApp/SwiftUITestApp/Assets.xcassets/AccentColor.colorset/Contents.json +0 -0
  82. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/SwiftUITestApp/SwiftUITestApp/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
  83. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/SwiftUITestApp/SwiftUITestApp/Assets.xcassets/Contents.json +0 -0
  84. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/SwiftUITestApp/SwiftUITestApp/ContentView.swift +0 -0
  85. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/SwiftUITestApp/SwiftUITestApp/macosEmptySwiftUIAppApp.swift +0 -0
  86. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/SwiftUITestApp/SwiftUITestApp.xcodeproj/project.pbxproj +0 -0
  87. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/SwiftUITestApp/SwiftUITestApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -0
  88. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/iOSTestApp/iOSTestApp/Assets.xcassets/AccentColor.colorset/Contents.json +0 -0
  89. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/iOSTestApp/iOSTestApp/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
  90. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/iOSTestApp/iOSTestApp/Assets.xcassets/Contents.json +0 -0
  91. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/iOSTestApp/iOSTestApp/ContentView.swift +0 -0
  92. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/iOSTestApp/iOSTestApp/iosEmptySwiftUIAppApp.swift +0 -0
  93. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/iOSTestApp/iOSTestApp.xcodeproj/project.pbxproj +0 -0
  94. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/test_projects/templates/iOSTestApp/iOSTestApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -0
  95. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/tests/debug_build.py +0 -0
  96. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/tests/debug_test.py +0 -0
  97. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/tests/test_build.py +0 -0
  98. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/tests/test_fixed.py +0 -0
  99. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/tests/test_minimal.py +0 -0
  100. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/__main__.py +0 -0
  101. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/cli.py +0 -0
  102. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/config_manager.py +0 -0
  103. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/config_ui.py +0 -0
  104. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/exceptions.py +0 -0
  105. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/server.py +0 -0
  106. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/build_project.py +0 -0
  107. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/clean_project.py +0 -0
  108. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/debug_list_notification_history.py +0 -0
  109. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/get_build_errors.py +0 -0
  110. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/get_build_results.py +0 -0
  111. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/get_directory_listing.py +0 -0
  112. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/get_directory_tree.py +0 -0
  113. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/get_latest_test_results.py +0 -0
  114. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/get_project_schemes.py +0 -0
  115. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/get_runtime_output.py +0 -0
  116. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/list_booted_simulators.py +0 -0
  117. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/list_mac_app_windows.py +0 -0
  118. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/list_project_tests.py +0 -0
  119. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/list_running_mac_apps.py +0 -0
  120. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/run_project_tests.py +0 -0
  121. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/run_project_unmonitored.py +0 -0
  122. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/run_project_until_terminated.py +0 -0
  123. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/run_project_with_user_interaction.py +0 -0
  124. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/stop_project.py +0 -0
  125. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/take_app_screenshot.py +0 -0
  126. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/take_simulator_screenshot.py +0 -0
  127. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/take_window_screenshot.py +0 -0
  128. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/take_xcode_screenshot.py +0 -0
  129. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/tools/version.py +0 -0
  130. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/utils/__init__.py +0 -0
  131. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/utils/applescript.py +0 -0
  132. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/utils/build_log_parser.py +0 -0
  133. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/utils/decode_xcode_recents.swift +0 -0
  134. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/utils/screenshot.py +0 -0
  135. {xcode_mcp_server-1.3.7 → xcode_mcp_server-1.3.9}/xcode_mcp_server/utils/xcresult.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xcode-mcp-server
3
- Version: 1.3.7
3
+ Version: 1.3.9
4
4
  Summary: Drew's MCP server for Xcode integration
5
5
  Project-URL: Homepage, https://github.com/drewster99/xcode-mcp-server
6
6
  Project-URL: Repository, https://github.com/drewster99/xcode-mcp-server
@@ -192,4 +192,5 @@ xcrun xcresulttool get --path <xcresult> --format json
192
192
  - `ALLOWED_FOLDERS` environment variable or CLI args
193
193
  - All paths validated: absolute, exist, directory, no '..'
194
194
  - Default to `$HOME` if not specified
195
- - Every tool validates project path against allowed folders
195
+ - Every tool validates project path against allowed folders
196
+
@@ -59,11 +59,7 @@ echo ""
59
59
  echo ""
60
60
  echo "If you need to test with Claude, do this:"
61
61
  echo " claude mcp remove xcode-mcp-server"
62
- echo " claude mcp add --transport stdio --scope user xcode-mcp-server -- python3 -m `pwd`/xcode_mcp_server"
63
- echo ""
64
- echo " or maybe..."
65
62
  echo " claude mcp add --transport stdio --scope user xcode-mcp-server `pwd`/run_local_for_claude.sh"
66
- echo " claude mcp add --transport stdio --scope user xcode-mcp-server -- /opt/homebrew/Caskroom/miniconda/base/envs/xcode-mcp-dev/bin/python -m `pwd`/xcode_mcp_server"
67
63
  echo ""
68
64
 
69
65
  # Run the MCP inspector
@@ -0,0 +1,80 @@
1
+ ---
2
+ How Xcode Instantiates Projects Internally
3
+
4
+ The process is handled by private framework classes in IDEFoundation.framework:
5
+
6
+ 1. IDETemplateKind — knows the different kinds of templates (projectTemplateKind,
7
+ fileTemplateKind, targetTemplateKind, playgroundTemplateKind)
8
+ 2. IDETemplate — loads TemplateInfo.plist, resolves the Ancestors inheritance chain, and
9
+ merges all options/definitions/nodes
10
+ 3. IDETemplateFactory — the workhorse: instantiateTemplateForContext:options:whenDone:
11
+ takes a template + user's option choices and creates the project on disk
12
+ 4. IDETemplateMacroEngine (Swift class) — performs variable substitution on filenames and
13
+ file contents:
14
+ - ___PACKAGENAME___ → project name
15
+ - ___PACKAGENAME:identifier___ → sanitized for Swift identifiers
16
+ - ___PACKAGENAME:rfc1034Identifier___ → for bundle IDs
17
+ - ___FULLUSERNAME___ → from system contacts
18
+ - ___ORGANIZATIONNAME___ → from Xcode preferences
19
+ - ___DATE___, ___YEAR___ → current date
20
+ - ___FILEHEADER___ → assembled copyright header
21
+ 5. The factory generates the .xcodeproj/project.pbxproj file programmatically (not from a
22
+ template pbxproj), wiring up targets, build configurations, build settings, and file
23
+ references based on what TemplateInfo.plist declared.
24
+
25
+ Can you do this from the command line?
26
+
27
+ Short answer: No. There is no public CLI for it.
28
+
29
+ - xcodebuild — has no project creation capability at all. It only operates on existing
30
+ projects.
31
+ - xcrun — no tool for this exists in the toolchain.
32
+ - IDETemplateCommandLineVerb exists in the framework (suggesting Apple has or had an
33
+ internal verb for it), but it's not exposed. Similarly,
34
+ IDETemplateTester.createSingleProjectFromTemplate:withOptionValues:atPath:completion: is
35
+ clearly used for internal testing but not public.
36
+
37
+ Your realistic options for automating "new App project"
38
+
39
+ 1. swift package init --type executable — creates a Swift Package, not an .xcodeproj.
40
+ Works great for CLI tools/libraries but not for iOS/macOS GUI apps with asset catalogs,
41
+ entitlements, etc.
42
+ 2. Keep a skeleton .xcodeproj as your own template — a pre-made minimal project with
43
+ placeholder names, then script the find-and-replace of ___PACKAGENAME___-style variables
44
+ yourself. This is essentially what Xcode does internally.
45
+ 3. Use tuist init or xcodegen — third-party tools that generate .xcodeproj files from a
46
+ YAML/Swift manifest. These are the closest thing to "command-line project creation" that
47
+ actually works well.
48
+ 4. UI scripting via AppleScript/System Events — you could automate clicking through
49
+ Xcode's "New Project" dialog, but it's extremely fragile.
50
+
51
+ The template system is deeply embedded in Xcode's private frameworks with no public API or
52
+ CLI exposure. Apple clearly built IDETemplateCommandLineVerb for something, but it's
53
+ never been shipped as a user-facing tool.
54
+
55
+ ✻ Churned for 46s
56
+
57
+ ❯ You just said we could do it right?
58
+
59
+ 2. IDETemplate — loads TemplateInfo.plist, resolves the Ancestors inheritance chain, and
60
+
61
+ merges all options/definitions/nodes
62
+
63
+ 3. IDETemplateFactory — the workhorse: instantiateTemplateForContext:options:whenDone:
64
+ takes a template + user's option choices and creates the project on disk
65
+
66
+ ⏺ You're right — I contradicted myself. The process is all right there on disk and it's not
67
+ magic:
68
+
69
+ 1. Parse TemplateInfo.plist files and walk the Ancestors chain
70
+ 2. Evaluate Options / RequiredOptions to pick which files/settings apply
71
+ 3. Copy the source files, doing ___PACKAGENAME___ etc. substitution
72
+ 4. Generate a valid .xcodeproj/project.pbxproj
73
+
74
+ Steps 1–3 are straightforward. Step 4 is the only non-trivial part — but the .pbxproj
75
+ format is well-understood (it's an old-style NeXT plist with UUIDs as keys), and tools
76
+ like XcodeGen already generate them from scratch.
77
+
78
+ We could absolutely write a tool that reads Xcode's own templates and instantiates them.
79
+ Would you like me to build that?
80
+ ---
@@ -4,7 +4,7 @@
4
4
  <dict>
5
5
  <key>SchemeUserState</key>
6
6
  <dict>
7
- <key>BrokenApp.xcscheme_^#shared#^_</key>
7
+ <key>iosEmptySwiftUIApp.xcscheme_^#shared#^_</key>
8
8
  <dict>
9
9
  <key>orderHint</key>
10
10
  <integer>0</integer>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>macosEmptyCommandLineApp.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>macosEmptySwiftUIApp.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>macosEmptyCommandLineApp.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>macosEmptyCommandLineApp.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>macosEmptyCommandLineApp.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>macosEmptySwiftUIApp.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>iOSTestApp.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ <key>iosEmptySwiftUIApp.xcscheme_^#shared#^_</key>
13
+ <dict>
14
+ <key>orderHint</key>
15
+ <integer>0</integer>
16
+ </dict>
17
+ </dict>
18
+ </dict>
19
+ </plist>
@@ -46,20 +46,20 @@ class BasicTests(XcodeMCPTestRunner):
46
46
  assert "SimpleApp.xcodeproj" in project_names, "SimpleApp.xcodeproj not found"
47
47
  assert "ConsoleApp.xcodeproj" in project_names, "ConsoleApp.xcodeproj not found"
48
48
 
49
- def test_get_project_hierarchy(self):
50
- """Test getting project file hierarchy."""
49
+ def test_get_directory_tree(self):
50
+ """Test getting project directory tree."""
51
51
  # Copy SimpleApp
52
52
  project_path = self.copy_project("SimpleApp")
53
53
  xcodeproj_path = project_path / "SimpleApp.xcodeproj"
54
54
 
55
- # Get hierarchy
56
- result = self.run_mcp_tool("get_project_hierarchy", project_path=str(xcodeproj_path))
55
+ # Get tree (accepts .xcodeproj path, scans parent)
56
+ result = self.run_mcp_tool("get_directory_tree", directory_path=str(xcodeproj_path))
57
57
  self.assert_success(result)
58
58
 
59
- # Check that hierarchy contains expected elements
60
- hierarchy = result["result"]
61
- self.assert_contains(hierarchy, "SimpleApp/", "Hierarchy should show SimpleApp directory")
62
- self.assert_contains(hierarchy, "SimpleApp.xcodeproj", "Hierarchy should show xcodeproj")
59
+ # Check that tree contains expected elements
60
+ tree = result["result"]
61
+ self.assert_contains(tree, "SimpleApp", "Tree should show SimpleApp directory")
62
+ self.assert_contains(tree, "SimpleApp.xcodeproj", "Tree should show xcodeproj")
63
63
 
64
64
  def test_get_project_schemes(self):
65
65
  """Test getting available build schemes."""
@@ -81,12 +81,21 @@ class BasicTests(XcodeMCPTestRunner):
81
81
 
82
82
  def test_path_validation(self):
83
83
  """Test path validation and security checks."""
84
- # Test with non-existent path
84
+ # Test with path outside allowed folders (security check fires first)
85
85
  result = self.run_mcp_tool(
86
- "get_project_hierarchy",
86
+ "get_project_schemes",
87
87
  project_path="/nonexistent/path/Project.xcodeproj"
88
88
  )
89
89
  self.assert_failure(result)
90
+ self.assert_contains(result["error"], "not allowed")
91
+
92
+ # Test with non-existent path inside allowed folders
93
+ fake_proj = self.working_dir / "DoesNotExist.xcodeproj"
94
+ result = self.run_mcp_tool(
95
+ "get_project_schemes",
96
+ project_path=str(fake_proj)
97
+ )
98
+ self.assert_failure(result)
90
99
  self.assert_contains(result["error"], "does not exist")
91
100
 
92
101
  # Test with invalid extension
@@ -94,14 +103,14 @@ class BasicTests(XcodeMCPTestRunner):
94
103
  valid_dir.mkdir(exist_ok=True)
95
104
 
96
105
  result = self.run_mcp_tool(
97
- "get_project_hierarchy",
106
+ "get_project_schemes",
98
107
  project_path=str(valid_dir)
99
108
  )
100
109
  self.assert_failure(result)
101
110
  self.assert_contains(result["error"], "must end with")
102
111
 
103
112
  # Test with empty path
104
- result = self.run_mcp_tool("get_project_hierarchy", project_path="")
113
+ result = self.run_mcp_tool("get_project_schemes", project_path="")
105
114
  self.assert_failure(result)
106
115
  self.assert_contains(result["error"], "cannot be empty")
107
116
 
@@ -130,8 +139,8 @@ class BasicTests(XcodeMCPTestRunner):
130
139
  symlink_path.unlink()
131
140
  symlink_path.symlink_to(xcodeproj_path)
132
141
 
133
- # Try to get hierarchy through symlink
134
- result = self.run_mcp_tool("get_project_hierarchy", project_path=str(symlink_path))
142
+ # Try to get directory tree through symlink
143
+ result = self.run_mcp_tool("get_directory_tree", directory_path=str(symlink_path))
135
144
 
136
145
  # Should work with normalized path
137
146
  if result["success"]:
@@ -153,7 +162,7 @@ def run_basic_tests():
153
162
  tests.run_test(tests.test_version, "Version Command")
154
163
  tests.run_test(tests.test_get_xcode_projects_empty, "Find Projects - Empty Dir")
155
164
  tests.run_test(tests.test_get_xcode_projects_with_projects, "Find Projects - With Projects")
156
- tests.run_test(tests.test_get_project_hierarchy, "Get Project Hierarchy")
165
+ tests.run_test(tests.test_get_directory_tree, "Get Directory Tree")
157
166
  tests.run_test(tests.test_get_project_schemes, "Get Project Schemes")
158
167
  tests.run_test(tests.test_path_validation, "Path Validation")
159
168
  tests.run_test(tests.test_search_all_allowed_folders, "Search All Allowed Folders")
@@ -43,10 +43,10 @@ class XcodeMCPTestRunner:
43
43
  os.environ["XCODEMCP_ALLOWED_FOLDERS"] = str(self.working_dir)
44
44
  print(f"Set allowed folders to: {self.working_dir}")
45
45
 
46
- # Also set the global variable in the MCP server module
47
- import xcode_mcp_server.__main__ as mcp_server
48
- mcp_server.ALLOWED_FOLDERS = {str(self.working_dir)}
49
- print(f"Set MCP server ALLOWED_FOLDERS to: {mcp_server.ALLOWED_FOLDERS}")
46
+ # Set the global variable in the security module where it's actually used
47
+ from xcode_mcp_server.security import set_allowed_folders
48
+ set_allowed_folders({str(self.working_dir)})
49
+ print(f"Set ALLOWED_FOLDERS to: {self.working_dir}")
50
50
 
51
51
  def teardown(self):
52
52
  """Clean up the test environment."""
@@ -79,24 +79,17 @@ class XcodeMCPTestRunner:
79
79
  """
80
80
  Run an MCP tool and return the result.
81
81
 
82
- This simulates calling the MCP server tools directly.
82
+ Looks up the tool function from the FastMCP registry and calls it directly.
83
83
  """
84
- # Import the MCP server module
85
- import xcode_mcp_server.__main__ as mcp_server
84
+ from xcode_mcp_server.server import mcp
85
+ import xcode_mcp_server.tools # noqa: F401 — triggers @mcp.tool() registration
86
86
 
87
- # Get the tool function directly from the module
88
- tool_func = None
89
-
90
- # The tools are registered as functions with the @mcp.tool() decorator
91
- # We can access them directly by name
92
- tool_func = getattr(mcp_server, tool_name, None)
93
-
94
- if not tool_func or not callable(tool_func):
87
+ tool = mcp._tool_manager._tools.get(tool_name)
88
+ if not tool:
95
89
  raise ValueError(f"Tool not found: {tool_name}")
96
90
 
97
91
  try:
98
- # Call the tool with parameters
99
- result = tool_func(**params)
92
+ result = tool.fn(**params)
100
93
  return {"success": True, "result": result}
101
94
  except Exception as e:
102
95
  return {"success": False, "error": str(e), "error_type": type(e).__name__}
@@ -1,6 +1,6 @@
1
1
  """Xcode MCP Server - Model Context Protocol server for Xcode integration"""
2
2
 
3
- __version__ = "1.3.7"
3
+ __version__ = "1.3.9"
4
4
 
5
5
 
6
6
  def main():
@@ -2,6 +2,7 @@
2
2
  """Security and path validation utilities for Xcode MCP Server"""
3
3
 
4
4
  import os
5
+ import re
5
6
  import sys
6
7
  from typing import Optional, List, Set
7
8
 
@@ -159,3 +160,67 @@ def validate_and_normalize_project_path(project_path: str, function_name: str) -
159
160
 
160
161
  # Normalize the path to resolve symlinks
161
162
  return os.path.realpath(project_path)
163
+
164
+
165
+ def validate_parent_for_new_project(parent_path: str, project_name: str) -> str:
166
+ """
167
+ Validate that a parent directory is allowed and a project name is safe
168
+ for creating a new Xcode project.
169
+
170
+ Args:
171
+ parent_path: Directory where the project folder will be created
172
+ project_name: Name of the new project
173
+
174
+ Returns:
175
+ Normalized parent path
176
+
177
+ Raises:
178
+ InvalidParameterError: If validation fails
179
+ AccessDeniedError: If path access is denied
180
+ """
181
+ from xcode_mcp_server.utils.applescript import show_access_denied_notification, show_error_notification
182
+
183
+ if not parent_path or parent_path.strip() == "":
184
+ raise InvalidParameterError("parent_directory cannot be empty")
185
+
186
+ if not project_name or project_name.strip() == "":
187
+ raise InvalidParameterError("project_name cannot be empty")
188
+
189
+ parent_path = parent_path.strip().rstrip("/")
190
+ project_name = project_name.strip()
191
+
192
+ if not os.path.isabs(parent_path):
193
+ raise InvalidParameterError("parent_directory must be an absolute path")
194
+
195
+ if ".." in parent_path:
196
+ raise InvalidParameterError("parent_directory must not contain '..' components")
197
+
198
+ if not os.path.exists(parent_path):
199
+ show_error_notification(f"Path not found: {parent_path}")
200
+ raise InvalidParameterError(f"parent_directory does not exist: {parent_path}")
201
+
202
+ if not os.path.isdir(parent_path):
203
+ raise InvalidParameterError(f"parent_directory is not a directory: {parent_path}")
204
+
205
+ if not is_path_allowed(parent_path):
206
+ show_access_denied_notification(f"Access denied: {parent_path}")
207
+ raise AccessDeniedError(
208
+ f"Access to path '{parent_path}' is not allowed. "
209
+ "Set XCODEMCP_ALLOWED_FOLDERS environment variable."
210
+ )
211
+
212
+ # Validate project name contains only safe characters
213
+ if not re.match(r'^[A-Za-z0-9][A-Za-z0-9 _-]*$', project_name):
214
+ raise InvalidParameterError(
215
+ "project_name must start with a letter or digit and contain only "
216
+ "letters, digits, spaces, hyphens, or underscores"
217
+ )
218
+
219
+ # Prevent overwriting existing projects
220
+ project_dir = os.path.join(parent_path, project_name)
221
+ if os.path.exists(project_dir):
222
+ raise InvalidParameterError(
223
+ f"A file or directory already exists at: {project_dir}"
224
+ )
225
+
226
+ return os.path.realpath(parent_path)
@@ -26,3 +26,7 @@ from . import run_project_tests
26
26
  from . import get_latest_test_results
27
27
  from . import debug_list_notification_history
28
28
  from . import get_build_results
29
+ from . import create_project
30
+ from . import list_run_destinations
31
+ from . import set_run_destination
32
+ from . import get_active_run_destination
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env python3
2
+ """create_project tool - Create a new Xcode project from a built-in template"""
3
+
4
+ import json
5
+ import os
6
+ from typing import Optional
7
+
8
+ from xcode_mcp_server.server import mcp
9
+ from xcode_mcp_server.config_manager import apply_config
10
+ from xcode_mcp_server.security import validate_parent_for_new_project
11
+ from xcode_mcp_server.exceptions import InvalidParameterError
12
+ from xcode_mcp_server.utils.applescript import (
13
+ show_notification,
14
+ show_result_notification,
15
+ )
16
+ from xcode_mcp_server.utils.project_templates import (
17
+ generate_project,
18
+ sanitize_to_identifier,
19
+ )
20
+ from xcode_mcp_server.tools.get_xcode_projects import register_created_project
21
+
22
+
23
+ SUPPORTED_PLATFORMS = {"ios", "macos"}
24
+
25
+
26
+ @mcp.tool()
27
+ @apply_config
28
+ def create_project(
29
+ parent_directory: str,
30
+ project_name: str,
31
+ platform: str = "ios",
32
+ bundle_identifier: str = "",
33
+ deployment_target: str = "",
34
+ ) -> str:
35
+ """
36
+ Create a new Xcode project with a SwiftUI app template.
37
+
38
+ Creates a complete, buildable Xcode project with a SwiftUI app entry point,
39
+ ContentView, and asset catalog. The project uses the modern Xcode 16+ format
40
+ (objectVersion 77) with automatic file discovery.
41
+
42
+ Args:
43
+ parent_directory: Directory where the project folder will be created.
44
+ Must be within the allowed folders configured for this server.
45
+ project_name: Name of the project (e.g. "MyApp"). Used for the folder
46
+ name, target name, and scheme name.
47
+ platform: Target platform - "ios" or "macos" (case-insensitive).
48
+ Defaults to "ios".
49
+ bundle_identifier: Bundle identifier (e.g. "com.mycompany.MyApp").
50
+ Defaults to "com.example.{ProjectName}".
51
+ deployment_target: Minimum deployment target version (e.g. "26.0").
52
+ Defaults to "26.0".
53
+
54
+ Returns:
55
+ JSON string with project_path, project_directory, platform,
56
+ bundle_identifier, and files_created.
57
+ """
58
+ # Validate platform
59
+ platform = platform.lower().strip()
60
+ if platform not in SUPPORTED_PLATFORMS:
61
+ raise InvalidParameterError(
62
+ f"platform must be one of: {', '.join(sorted(SUPPORTED_PLATFORMS))}. "
63
+ f"Got: '{platform}'"
64
+ )
65
+
66
+ # Validate parent directory and project name
67
+ parent_directory = validate_parent_for_new_project(parent_directory, project_name)
68
+
69
+ show_notification(
70
+ "Creating Project",
71
+ project_name,
72
+ f"Platform: {platform}",
73
+ )
74
+
75
+ # Generate the project
76
+ result = generate_project(
77
+ parent_dir=parent_directory,
78
+ project_name=project_name,
79
+ platform=platform,
80
+ bundle_identifier=bundle_identifier or None,
81
+ deployment_target=deployment_target or None,
82
+ )
83
+
84
+ # Register so get_xcode_projects finds it before Spotlight indexes it
85
+ register_created_project(result["project_path"])
86
+
87
+ show_result_notification(
88
+ f"Created: {project_name}",
89
+ f"Platform: {platform}",
90
+ )
91
+
92
+ # Compute the actual bundle identifier used
93
+ if not bundle_identifier:
94
+ identifier = sanitize_to_identifier(project_name)
95
+ bundle_identifier = f"com.example.{identifier}"
96
+
97
+ result["platform"] = platform
98
+ result["bundle_identifier"] = bundle_identifier
99
+
100
+ return json.dumps(result, indent=2)