drews-xcode-mcp 1.3.16b1__py3-none-any.whl

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 (54) hide show
  1. drews_xcode_mcp/__init__.py +12 -0
  2. drews_xcode_mcp/__main__.py +7 -0
  3. drews_xcode_mcp/cli.py +188 -0
  4. drews_xcode_mcp/config_manager.py +530 -0
  5. drews_xcode_mcp/config_ui.py +538 -0
  6. drews_xcode_mcp/exceptions.py +20 -0
  7. drews_xcode_mcp/security.py +298 -0
  8. drews_xcode_mcp/server.py +165 -0
  9. drews_xcode_mcp/tools/__init__.py +32 -0
  10. drews_xcode_mcp/tools/build_project.py +424 -0
  11. drews_xcode_mcp/tools/clean_project.py +76 -0
  12. drews_xcode_mcp/tools/create_project.py +133 -0
  13. drews_xcode_mcp/tools/debug_list_notification_history.py +69 -0
  14. drews_xcode_mcp/tools/get_active_run_destination.py +145 -0
  15. drews_xcode_mcp/tools/get_build_errors.py +109 -0
  16. drews_xcode_mcp/tools/get_build_results.py +134 -0
  17. drews_xcode_mcp/tools/get_directory_listing.py +133 -0
  18. drews_xcode_mcp/tools/get_directory_tree.py +195 -0
  19. drews_xcode_mcp/tools/get_latest_test_results.py +120 -0
  20. drews_xcode_mcp/tools/get_project_schemes.py +88 -0
  21. drews_xcode_mcp/tools/get_runtime_output.py +83 -0
  22. drews_xcode_mcp/tools/get_xcode_projects.py +352 -0
  23. drews_xcode_mcp/tools/list_booted_simulators.py +61 -0
  24. drews_xcode_mcp/tools/list_mac_app_windows.py +146 -0
  25. drews_xcode_mcp/tools/list_project_tests.py +240 -0
  26. drews_xcode_mcp/tools/list_run_destinations.py +117 -0
  27. drews_xcode_mcp/tools/list_running_mac_apps.py +113 -0
  28. drews_xcode_mcp/tools/run_project_tests.py +381 -0
  29. drews_xcode_mcp/tools/run_project_unmonitored.py +83 -0
  30. drews_xcode_mcp/tools/run_project_until_terminated.py +210 -0
  31. drews_xcode_mcp/tools/run_project_with_user_interaction.py +305 -0
  32. drews_xcode_mcp/tools/set_run_destination.py +90 -0
  33. drews_xcode_mcp/tools/stop_project.py +69 -0
  34. drews_xcode_mcp/tools/take_app_screenshot.py +115 -0
  35. drews_xcode_mcp/tools/take_simulator_screenshot.py +110 -0
  36. drews_xcode_mcp/tools/take_window_screenshot.py +121 -0
  37. drews_xcode_mcp/tools/take_xcode_screenshot.py +115 -0
  38. drews_xcode_mcp/tools/version.py +71 -0
  39. drews_xcode_mcp/utils/__init__.py +1 -0
  40. drews_xcode_mcp/utils/applescript.py +439 -0
  41. drews_xcode_mcp/utils/build_log_parser.py +787 -0
  42. drews_xcode_mcp/utils/decode_active_destination.swift +104 -0
  43. drews_xcode_mcp/utils/decode_xcode_recents.swift +47 -0
  44. drews_xcode_mcp/utils/paths.py +16 -0
  45. drews_xcode_mcp/utils/project_templates.py +666 -0
  46. drews_xcode_mcp/utils/run_guard.py +87 -0
  47. drews_xcode_mcp/utils/screenshot.py +180 -0
  48. drews_xcode_mcp/utils/xcodebuild_query.py +341 -0
  49. drews_xcode_mcp/utils/xcresult.py +996 -0
  50. drews_xcode_mcp-1.3.16b1.dist-info/METADATA +208 -0
  51. drews_xcode_mcp-1.3.16b1.dist-info/RECORD +54 -0
  52. drews_xcode_mcp-1.3.16b1.dist-info/WHEEL +4 -0
  53. drews_xcode_mcp-1.3.16b1.dist-info/entry_points.txt +2 -0
  54. drews_xcode_mcp-1.3.16b1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,12 @@
1
+ """Xcode MCP Server - Model Context Protocol server for Xcode integration"""
2
+
3
+ __version__ = "1.3.16b1"
4
+
5
+
6
+ def main():
7
+ """Entry point that delegates to CLI"""
8
+ from drews_xcode_mcp.cli import initialize_server
9
+ return initialize_server()
10
+
11
+
12
+ __all__ = ["main", "__version__"]
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env python3
2
+ """Xcode MCP Server - Main entry point for python -m"""
3
+
4
+ from drews_xcode_mcp import main
5
+
6
+ if __name__ == "__main__":
7
+ main()
drews_xcode_mcp/cli.py ADDED
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env python3
2
+ """Command-line interface and server initialization"""
3
+
4
+ import os
5
+ import sys
6
+ import subprocess
7
+ import argparse
8
+ import time
9
+
10
+ from drews_xcode_mcp import __version__
11
+ from drews_xcode_mcp.server import mcp, LEGACY_PACKAGE_NAME
12
+ from drews_xcode_mcp.security import get_allowed_folders, set_allowed_folders
13
+ from drews_xcode_mcp.utils.applescript import set_notifications_enabled, show_notification
14
+ from drews_xcode_mcp.utils.xcresult import set_build_warnings_enabled, freeze_build_warnings_settings
15
+
16
+ _LEGACY_RENAME_NOTIFICATION_INTERVAL_SECONDS = 24 * 60 * 60
17
+
18
+
19
+ def _show_legacy_rename_notification_if_needed():
20
+ """Show a macOS notification about the package rename, at most once a day.
21
+
22
+ This pop-up is the migration channel the user sees directly; the LLM-facing
23
+ channels (server instructions, version tool, migration prompt) live in
24
+ server.py. Throttled via a marker file because MCP clients start a fresh
25
+ server process per session, which could otherwise nag on every restart.
26
+ """
27
+ if not LEGACY_PACKAGE_NAME:
28
+ return
29
+
30
+ # Constructing the ConfigManager first lets it migrate ~/.xcode-mcp-server
31
+ # to ~/.drews-xcode-mcp; touching the marker path directly here would create
32
+ # the new directory prematurely and strand the old settings.
33
+ from drews_xcode_mcp.config_manager import ConfigManager
34
+ try:
35
+ marker = ConfigManager()._config_dir / "legacy-rename-notified"
36
+ if marker.exists() and time.time() - marker.stat().st_mtime < _LEGACY_RENAME_NOTIFICATION_INTERVAL_SECONDS:
37
+ return
38
+ marker.parent.mkdir(parents=True, exist_ok=True)
39
+ marker.touch()
40
+ except OSError:
41
+ # A notification is never worth failing startup over.
42
+ return
43
+
44
+ show_notification(
45
+ "Xcode MCP Server renamed",
46
+ subtitle=f"'{LEGACY_PACKAGE_NAME}' is now 'drews-xcode-mcp'",
47
+ message="Your current setup still works. When convenient, update your MCP config to run 'drews-xcode-mcp'.",
48
+ )
49
+
50
+
51
+ def initialize_server():
52
+ """Entry point for the drews-xcode-mcp command"""
53
+ # Debug
54
+ print(f"Drew's Xcode MCP Server (drews-xcode-mcp) v{__version__}", file=sys.stderr)
55
+
56
+ # Parse command line arguments
57
+ parser = argparse.ArgumentParser(description="Drew's Xcode MCP Server")
58
+ parser.add_argument("--version", action="version", version=f"drews-xcode-mcp {__version__}")
59
+ parser.add_argument("--configure", action="store_true", help="Launch configuration UI")
60
+ parser.add_argument("--allowed", action="append", help="Add an allowed folder path (can be used multiple times)")
61
+ parser.add_argument("--show-notifications", action="store_true", help="Enable notifications for tool invocations")
62
+ parser.add_argument("--hide-notifications", action="store_true", help="Disable notifications for tool invocations")
63
+ parser.add_argument("--no-build-warnings", action="store_true", help="Exclude warnings from build output")
64
+ parser.add_argument("--always-include-build-warnings", action="store_true", help="Always include warnings in build output")
65
+ args = parser.parse_args()
66
+
67
+ # Handle --configure flag
68
+ if args.configure:
69
+ from drews_xcode_mcp.config_ui import run_configuration_ui
70
+ run_configuration_ui()
71
+ sys.exit(0)
72
+
73
+ # Handle notification settings
74
+ if args.show_notifications and args.hide_notifications:
75
+ print("Error: Cannot use both --show-notifications and --hide-notifications", file=sys.stderr)
76
+ sys.exit(1)
77
+ elif args.show_notifications:
78
+ set_notifications_enabled(True)
79
+ print("Notifications enabled", file=sys.stderr)
80
+ elif args.hide_notifications:
81
+ set_notifications_enabled(False)
82
+ print("Notifications disabled", file=sys.stderr)
83
+
84
+ # Handle build warning settings
85
+ if args.no_build_warnings and args.always_include_build_warnings:
86
+ print("Error: Cannot use both --no-build-warnings and --always-include-build-warnings", file=sys.stderr)
87
+ sys.exit(1)
88
+ elif args.no_build_warnings:
89
+ set_build_warnings_enabled(False, forced=True)
90
+ print("Build warnings forcibly disabled", file=sys.stderr)
91
+ elif args.always_include_build_warnings:
92
+ set_build_warnings_enabled(True, forced=True)
93
+ print("Build warnings forcibly enabled", file=sys.stderr)
94
+
95
+ # Construct the ConfigManager up front so the one-time migration of
96
+ # ~/.xcode-mcp-server to ~/.drews-xcode-mcp happens at startup, where its
97
+ # stderr note lands in the launch log, rather than lazily inside the first
98
+ # tool call. This also protects any future startup code that touches the
99
+ # config directory from stranding the legacy settings.
100
+ from drews_xcode_mcp.config_manager import ConfigManager
101
+ try:
102
+ ConfigManager()
103
+ except OSError as e:
104
+ # An unusable config directory is not worth failing startup over;
105
+ # before this eager construction the same failure surfaced at the
106
+ # first tool call, and it still will (the singleton is only cached
107
+ # on successful construction).
108
+ print(f"Warning: could not initialize config directory: {e}", file=sys.stderr)
109
+
110
+ # After notification settings are applied, so --hide-notifications is honored
111
+ _show_legacy_rename_notification_if_needed()
112
+
113
+ # Initialize allowed folders from environment and command line
114
+ allowed_folders = get_allowed_folders(args.allowed)
115
+ set_allowed_folders(allowed_folders)
116
+
117
+ # Check if we have any allowed folders
118
+ if not allowed_folders:
119
+ error_msg = """
120
+ ========================================================================
121
+ ERROR: Xcode MCP Server cannot start - No valid allowed folders!
122
+ ========================================================================
123
+
124
+ No valid folders were found to allow access to.
125
+
126
+ To fix this, you can either:
127
+
128
+ 1. Set the XCODEMCP_ALLOWED_FOLDERS environment variable:
129
+ export XCODEMCP_ALLOWED_FOLDERS="/path/to/folder1:/path/to/folder2"
130
+
131
+ 2. Use the --allowed command line option:
132
+ drews-xcode-mcp --allowed /path/to/folder1 --allowed /path/to/folder2
133
+
134
+ 3. Ensure your $HOME directory exists and is accessible
135
+
136
+ All specified folders must:
137
+ - Be absolute paths
138
+ - Exist on the filesystem
139
+ - Be directories (not files)
140
+ - Not contain '..' components
141
+
142
+ ========================================================================
143
+ """
144
+ print(error_msg, file=sys.stderr)
145
+
146
+ # Show macOS notification
147
+ try:
148
+ subprocess.run(['osascript', '-e',
149
+ 'display alert "Drew\'s Xcode MCP Server Error" message "No valid allowed folders found. Check your configuration."'],
150
+ capture_output=True)
151
+ except Exception:
152
+ pass
153
+
154
+ sys.exit(1)
155
+
156
+ # Debug info
157
+ print(f"Total allowed folders: {allowed_folders}", file=sys.stderr)
158
+ cwd = os.getcwd()
159
+ print(f"Working directory: {cwd}", file=sys.stderr)
160
+
161
+ # Import all tools to register them with the MCP server
162
+ # This must be done before mcp.run()
163
+ from drews_xcode_mcp import tools
164
+
165
+ # Show startup notification
166
+ from drews_xcode_mcp.utils.applescript import show_notification
167
+
168
+ # Format the working directory relative to home if possible
169
+ home = os.path.expanduser("~")
170
+ if cwd.startswith(home):
171
+ # Make it relative to home with ~ prefix
172
+ display_cwd = "~" + cwd[len(home):]
173
+ else:
174
+ display_cwd = cwd
175
+
176
+ show_notification(
177
+ f"Drew's Xcode MCP Server - v{__version__}",
178
+
179
+ message="Working dir: " + display_cwd,
180
+ subtitle="✅ Server started"
181
+ )
182
+
183
+ # Lock startup-only globals so any later mutation surfaces as a
184
+ # RuntimeError instead of silently racing concurrent tool readers.
185
+ freeze_build_warnings_settings()
186
+
187
+ # Run the server
188
+ mcp.run()