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.
- drews_xcode_mcp/__init__.py +12 -0
- drews_xcode_mcp/__main__.py +7 -0
- drews_xcode_mcp/cli.py +188 -0
- drews_xcode_mcp/config_manager.py +530 -0
- drews_xcode_mcp/config_ui.py +538 -0
- drews_xcode_mcp/exceptions.py +20 -0
- drews_xcode_mcp/security.py +298 -0
- drews_xcode_mcp/server.py +165 -0
- drews_xcode_mcp/tools/__init__.py +32 -0
- drews_xcode_mcp/tools/build_project.py +424 -0
- drews_xcode_mcp/tools/clean_project.py +76 -0
- drews_xcode_mcp/tools/create_project.py +133 -0
- drews_xcode_mcp/tools/debug_list_notification_history.py +69 -0
- drews_xcode_mcp/tools/get_active_run_destination.py +145 -0
- drews_xcode_mcp/tools/get_build_errors.py +109 -0
- drews_xcode_mcp/tools/get_build_results.py +134 -0
- drews_xcode_mcp/tools/get_directory_listing.py +133 -0
- drews_xcode_mcp/tools/get_directory_tree.py +195 -0
- drews_xcode_mcp/tools/get_latest_test_results.py +120 -0
- drews_xcode_mcp/tools/get_project_schemes.py +88 -0
- drews_xcode_mcp/tools/get_runtime_output.py +83 -0
- drews_xcode_mcp/tools/get_xcode_projects.py +352 -0
- drews_xcode_mcp/tools/list_booted_simulators.py +61 -0
- drews_xcode_mcp/tools/list_mac_app_windows.py +146 -0
- drews_xcode_mcp/tools/list_project_tests.py +240 -0
- drews_xcode_mcp/tools/list_run_destinations.py +117 -0
- drews_xcode_mcp/tools/list_running_mac_apps.py +113 -0
- drews_xcode_mcp/tools/run_project_tests.py +381 -0
- drews_xcode_mcp/tools/run_project_unmonitored.py +83 -0
- drews_xcode_mcp/tools/run_project_until_terminated.py +210 -0
- drews_xcode_mcp/tools/run_project_with_user_interaction.py +305 -0
- drews_xcode_mcp/tools/set_run_destination.py +90 -0
- drews_xcode_mcp/tools/stop_project.py +69 -0
- drews_xcode_mcp/tools/take_app_screenshot.py +115 -0
- drews_xcode_mcp/tools/take_simulator_screenshot.py +110 -0
- drews_xcode_mcp/tools/take_window_screenshot.py +121 -0
- drews_xcode_mcp/tools/take_xcode_screenshot.py +115 -0
- drews_xcode_mcp/tools/version.py +71 -0
- drews_xcode_mcp/utils/__init__.py +1 -0
- drews_xcode_mcp/utils/applescript.py +439 -0
- drews_xcode_mcp/utils/build_log_parser.py +787 -0
- drews_xcode_mcp/utils/decode_active_destination.swift +104 -0
- drews_xcode_mcp/utils/decode_xcode_recents.swift +47 -0
- drews_xcode_mcp/utils/paths.py +16 -0
- drews_xcode_mcp/utils/project_templates.py +666 -0
- drews_xcode_mcp/utils/run_guard.py +87 -0
- drews_xcode_mcp/utils/screenshot.py +180 -0
- drews_xcode_mcp/utils/xcodebuild_query.py +341 -0
- drews_xcode_mcp/utils/xcresult.py +996 -0
- drews_xcode_mcp-1.3.16b1.dist-info/METADATA +208 -0
- drews_xcode_mcp-1.3.16b1.dist-info/RECORD +54 -0
- drews_xcode_mcp-1.3.16b1.dist-info/WHEEL +4 -0
- drews_xcode_mcp-1.3.16b1.dist-info/entry_points.txt +2 -0
- 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__"]
|
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()
|