apple-instruments-mcp 1.0.0__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.
- apple_instruments_mcp-1.0.0/.github/workflows/ci.yml +40 -0
- apple_instruments_mcp-1.0.0/.github/workflows/release.yml +58 -0
- apple_instruments_mcp-1.0.0/.gitignore +43 -0
- apple_instruments_mcp-1.0.0/PKG-INFO +372 -0
- apple_instruments_mcp-1.0.0/README.md +343 -0
- apple_instruments_mcp-1.0.0/pyproject.toml +74 -0
- apple_instruments_mcp-1.0.0/src/apple_instruments_mcp/__init__.py +8 -0
- apple_instruments_mcp-1.0.0/src/apple_instruments_mcp/__main__.py +4 -0
- apple_instruments_mcp-1.0.0/src/apple_instruments_mcp/analysis.py +1331 -0
- apple_instruments_mcp-1.0.0/src/apple_instruments_mcp/py.typed +0 -0
- apple_instruments_mcp-1.0.0/src/apple_instruments_mcp/server.py +823 -0
- apple_instruments_mcp-1.0.0/tests/test_analysis.py +431 -0
- apple_instruments_mcp-1.0.0/uv.lock +773 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
lint-typecheck-test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
23
|
+
uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: ${{ matrix.python-version }}
|
|
26
|
+
cache: pip
|
|
27
|
+
|
|
28
|
+
- name: Install package and dev tools
|
|
29
|
+
run: |
|
|
30
|
+
python -m pip install --upgrade pip
|
|
31
|
+
python -m pip install -e ".[dev]"
|
|
32
|
+
|
|
33
|
+
- name: Ruff
|
|
34
|
+
run: ruff check src tests
|
|
35
|
+
|
|
36
|
+
- name: Pyright
|
|
37
|
+
run: pyright
|
|
38
|
+
|
|
39
|
+
- name: Unit tests
|
|
40
|
+
run: python -m unittest discover -s tests -v
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "[0-9]*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
|
|
22
|
+
- name: Install build backend
|
|
23
|
+
run: python -m pip install --upgrade pip build
|
|
24
|
+
|
|
25
|
+
- name: Verify tag matches package version
|
|
26
|
+
run: |
|
|
27
|
+
PKG_VERSION="$(python -c 'import tomllib, pathlib; print(tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"])')"
|
|
28
|
+
if [ "$GITHUB_REF_NAME" != "$PKG_VERSION" ]; then
|
|
29
|
+
echo "Tag $GITHUB_REF_NAME does not match pyproject version $PKG_VERSION" >&2
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
- name: Build sdist and wheel
|
|
34
|
+
run: python -m build
|
|
35
|
+
|
|
36
|
+
- name: Upload distribution artifacts
|
|
37
|
+
uses: actions/upload-artifact@v4
|
|
38
|
+
with:
|
|
39
|
+
name: dist
|
|
40
|
+
path: dist/
|
|
41
|
+
|
|
42
|
+
publish-pypi:
|
|
43
|
+
needs: build
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
environment:
|
|
46
|
+
name: pypi
|
|
47
|
+
url: https://pypi.org/p/apple-instruments-mcp
|
|
48
|
+
permissions:
|
|
49
|
+
id-token: write
|
|
50
|
+
steps:
|
|
51
|
+
- name: Download distribution artifacts
|
|
52
|
+
uses: actions/download-artifact@v4
|
|
53
|
+
with:
|
|
54
|
+
name: dist
|
|
55
|
+
path: dist/
|
|
56
|
+
|
|
57
|
+
- name: Publish to PyPI
|
|
58
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Byte-compiled / cache
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
|
|
7
|
+
# Distribution / packaging
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
wheels/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
*.egg
|
|
13
|
+
.eggs/
|
|
14
|
+
|
|
15
|
+
# Virtual environments
|
|
16
|
+
.venv/
|
|
17
|
+
venv/
|
|
18
|
+
env/
|
|
19
|
+
ENV/
|
|
20
|
+
|
|
21
|
+
# Installer / package manager state
|
|
22
|
+
pip-wheel-metadata/
|
|
23
|
+
|
|
24
|
+
# Test / type-check / lint caches
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
.ruff_cache/
|
|
27
|
+
.pyright/
|
|
28
|
+
.mypy_cache/
|
|
29
|
+
.coverage
|
|
30
|
+
.coverage.*
|
|
31
|
+
htmlcov/
|
|
32
|
+
|
|
33
|
+
# Editor / OS
|
|
34
|
+
.vscode/
|
|
35
|
+
.idea/
|
|
36
|
+
*.swp
|
|
37
|
+
*.swo
|
|
38
|
+
.DS_Store
|
|
39
|
+
|
|
40
|
+
# Profiling artifacts produced by this tool
|
|
41
|
+
*.xctrace
|
|
42
|
+
*.trace
|
|
43
|
+
instruments-mcp-*/
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: apple-instruments-mcp
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: MCP server for Apple platform profiling via xctrace/Instruments
|
|
5
|
+
Project-URL: Homepage, https://github.com/dogo/apple-instruments-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/dogo/apple-instruments-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/dogo/apple-instruments-mcp/issues
|
|
8
|
+
Author-email: Diogo Autilio <diautilio@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: instruments,ios,macos,mcp,model-context-protocol,performance,profiling,xctrace
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
20
|
+
Classifier: Topic :: System :: Monitoring
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: mcp>=1.0.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pyright>=1.1.380; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# apple-instruments-mcp
|
|
31
|
+
|
|
32
|
+
`apple-instruments-mcp` is a Python MCP server for profiling Apple platform apps and processes with Instruments through `xcrun xctrace`. It lets MCP clients such as Claude Desktop record traces, inspect existing `.xctrace` bundles, and return concise performance reports with actionable recommendations.
|
|
33
|
+
|
|
34
|
+
The server can target iOS, iPadOS, macOS, tvOS, watchOS, visionOS, simulators, physical devices, and host processes when those targets are visible to the installed Xcode/Instruments toolchain. Actual template and device support is determined by `xcrun xctrace list devices` and `xcrun xctrace list templates` on your Mac.
|
|
35
|
+
|
|
36
|
+
## Features
|
|
37
|
+
|
|
38
|
+
- Record new traces with `xctrace` from an MCP client.
|
|
39
|
+
- Analyze existing `.xctrace` files without recording again.
|
|
40
|
+
- Report launch time, memory allocations, leaks, CPU hot spots, and network activity.
|
|
41
|
+
- Launch apps by bundle ID or executable path.
|
|
42
|
+
- Attach to running processes by process name or PID.
|
|
43
|
+
- Record all processes when an Instruments template supports it.
|
|
44
|
+
- List available devices, simulators, runtimes, and Instruments templates.
|
|
45
|
+
- Return raw or JSON-structured device/template listings.
|
|
46
|
+
- Preview the generated `xctrace` command with `dry_run`.
|
|
47
|
+
- Keep `.xctrace` and XML artifacts for later inspection.
|
|
48
|
+
- Return human-readable summaries with top offenders and suggested fixes.
|
|
49
|
+
- Runs as a standard stdio MCP server.
|
|
50
|
+
|
|
51
|
+
## Requirements
|
|
52
|
+
|
|
53
|
+
- macOS
|
|
54
|
+
- Xcode with Instruments installed
|
|
55
|
+
- Xcode Command Line Tools: `xcode-select --install`
|
|
56
|
+
- Python 3.11 or newer
|
|
57
|
+
- A supported target visible to `xctrace`: booted simulator, connected device, local macOS app, running process, or all-processes recording.
|
|
58
|
+
|
|
59
|
+
Physical devices may require enabling UI automation in `Settings > Developer`.
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
The package is published on PyPI. The recommended way is to run it through [`uvx`](https://github.com/astral-sh/uv), which downloads and caches the server on demand without polluting your environment:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uvx apple-instruments-mcp
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Alternatively, install it globally with `pipx` or `pip`:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pipx install apple-instruments-mcp
|
|
73
|
+
# or
|
|
74
|
+
python -m pip install apple-instruments-mcp
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Either path provides the `apple-instruments-mcp` executable.
|
|
78
|
+
|
|
79
|
+
## MCP Client Configuration
|
|
80
|
+
|
|
81
|
+
`apple-instruments-mcp` is a standard stdio MCP server, so any MCP-compatible client works — Claude Desktop, Claude Code, Codex CLI, Kiro, Cursor, Cline, Continue, Windsurf, Zed, or anything else that speaks MCP.
|
|
82
|
+
|
|
83
|
+
The simplest config uses `uvx`, so the client launches the server on demand with no separate install step. Example for Claude Desktop (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"mcpServers": {
|
|
88
|
+
"apple-instruments": {
|
|
89
|
+
"command": "uvx",
|
|
90
|
+
"args": ["apple-instruments-mcp"]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
To pin a specific version, replace the arg with `apple-instruments-mcp@1.0.0`.
|
|
97
|
+
|
|
98
|
+
For Claude Code:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
claude mcp add apple-instruments -- uvx apple-instruments-mcp
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
If you prefer a global install (`pipx` or `pip`), point the client at the resulting binary instead:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"mcpServers": {
|
|
109
|
+
"apple-instruments": {
|
|
110
|
+
"command": "apple-instruments-mcp"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Other clients (Codex CLI, Kiro, Cursor, Cline, Continue, Windsurf, Zed) accept the same `command` / `args` shape under their own MCP server config — check the client's docs for the exact file path. Restart the client after saving.
|
|
117
|
+
|
|
118
|
+
## Example Prompts
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
List the devices and Instruments templates available on this Mac.
|
|
122
|
+
Record an App Launch trace for com.example.app on this iPhone simulator and show the startup offenders.
|
|
123
|
+
Launch /Applications/MyMacApp.app with Time Profiler and show CPU hot methods.
|
|
124
|
+
Attach Allocations to the running process named MyMacApp for 30 seconds.
|
|
125
|
+
Attach Time Profiler to PID 1234.
|
|
126
|
+
Record all processes with Time Profiler for 10 seconds.
|
|
127
|
+
Analyze network activity for com.example.app and flag slow requests.
|
|
128
|
+
Analyze the existing trace at ~/Desktop/launch.xctrace.
|
|
129
|
+
Compare ~/Desktop/baseline.xctrace and ~/Desktop/candidate.xctrace for launch regressions.
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Tools
|
|
133
|
+
|
|
134
|
+
| Tool | Instruments template | Description |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| `list_devices` | - | Lists devices, simulators, runtimes, and host targets visible to `xctrace`. |
|
|
137
|
+
| `list_devices_structured` | - | Returns the device/runtime listing as JSON. |
|
|
138
|
+
| `list_templates` | - | Lists Instruments templates installed on this Mac. |
|
|
139
|
+
| `list_templates_structured` | - | Returns the template listing as JSON. |
|
|
140
|
+
| `profile_ios_app` | Selected by `profile_type` | Profiles an iOS, iPadOS, tvOS, watchOS, or visionOS app by bundle ID on a simulator/device. |
|
|
141
|
+
| `profile_mac_app` | Selected by `profile_type` | Profiles a macOS `.app` or executable by launch path. |
|
|
142
|
+
| `profile_process` | Selected by `profile_type` | Profiles a running process by process name or PID. |
|
|
143
|
+
| `profile_all_processes` | Selected by `profile_type` | Profiles all processes on the host or selected device. |
|
|
144
|
+
| `analyze_launch` | App Launch | Records and analyzes app startup time. |
|
|
145
|
+
| `analyze_launch_trace` | App Launch | Analyzes an existing App Launch `.xctrace`. |
|
|
146
|
+
| `analyze_allocations` | Allocations | Records memory allocations and reports top allocation types. |
|
|
147
|
+
| `analyze_allocations_trace` | Allocations | Analyzes an existing Allocations `.xctrace`. |
|
|
148
|
+
| `analyze_leaks` | Leaks | Records leak information and reports likely retain-cycle issues. |
|
|
149
|
+
| `analyze_leaks_trace` | Leaks | Analyzes an existing Leaks `.xctrace`. |
|
|
150
|
+
| `analyze_time_profiler` | Time Profiler | Records CPU samples and reports hot methods. |
|
|
151
|
+
| `analyze_time_profiler_trace` | Time Profiler | Analyzes an existing Time Profiler `.xctrace`. |
|
|
152
|
+
| `analyze_network` | Network | Records network requests, latency, transfer sizes, and status codes. |
|
|
153
|
+
| `analyze_network_trace` | Network | Analyzes an existing Network `.xctrace`. |
|
|
154
|
+
| `compare_launch_traces` | App Launch | Compares two App Launch traces and reports startup deltas. |
|
|
155
|
+
| `compare_memory_traces` | Allocations | Compares two Allocations traces and reports memory deltas. |
|
|
156
|
+
| `compare_cpu_traces` | Time Profiler | Compares two Time Profiler traces and reports CPU deltas. |
|
|
157
|
+
| `build_xctrace_command` | Any | Returns the exact `xcrun xctrace record` command for a target without executing it. |
|
|
158
|
+
|
|
159
|
+
## Recording Targets
|
|
160
|
+
|
|
161
|
+
Recording tools accept exactly one target mode:
|
|
162
|
+
|
|
163
|
+
- `bundle_id`: app bundle identifier, for example `com.example.app`. Use with `device_id` for iOS, iPadOS, tvOS, watchOS, and visionOS simulator/device launches.
|
|
164
|
+
- `launch_path`: executable path or `.app` path. Use this for macOS apps and command-line tools.
|
|
165
|
+
- `process_name`: attach to a running process by name.
|
|
166
|
+
- `pid`: attach to a running process by process ID.
|
|
167
|
+
- `all_processes`: record all processes when the selected template supports it.
|
|
168
|
+
|
|
169
|
+
Additional recording arguments:
|
|
170
|
+
|
|
171
|
+
- `device_id`: optional simulator UUID or physical device identifier from `list_devices`. Omit it for host macOS profiling.
|
|
172
|
+
- `launch_args`: optional shell-style arguments passed after `launch_path`.
|
|
173
|
+
- `time_limit_seconds`: recording duration, from 5 to 120 seconds. Defaults to 20.
|
|
174
|
+
- `dry_run`: return the generated `xctrace` command without recording.
|
|
175
|
+
- `keep_trace`: keep generated `.xctrace` and XML artifacts, and include their paths in the report.
|
|
176
|
+
- `output_dir`: optional parent directory for generated artifacts. Each run creates a dedicated subdirectory inside it.
|
|
177
|
+
|
|
178
|
+
Examples:
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{ "bundle_id": "com.example.app", "device_id": "SIMULATOR-UUID" }
|
|
182
|
+
{ "launch_path": "/Applications/MyMacApp.app" }
|
|
183
|
+
{ "launch_path": "/usr/bin/python3", "launch_args": "--version" }
|
|
184
|
+
{ "process_name": "MyMacApp" }
|
|
185
|
+
{ "pid": 1234 }
|
|
186
|
+
{ "all_processes": true }
|
|
187
|
+
{ "launch_path": "/Applications/MyMacApp.app", "dry_run": true }
|
|
188
|
+
{ "bundle_id": "com.example.app", "device_id": "SIMULATOR-UUID", "keep_trace": true, "output_dir": "~/Desktop/traces" }
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
The `profile_*` tools are higher-level wrappers around the generic `analyze_*` tools. Prefer them when you know the target shape:
|
|
192
|
+
|
|
193
|
+
```json
|
|
194
|
+
{ "profile_type": "launch", "bundle_id": "com.example.app", "device_id": "SIMULATOR-UUID" }
|
|
195
|
+
{ "profile_type": "time_profiler", "launch_path": "/Applications/MyMacApp.app" }
|
|
196
|
+
{ "profile_type": "allocations", "process_name": "MyMacApp" }
|
|
197
|
+
{ "profile_type": "time_profiler", "pid": 1234 }
|
|
198
|
+
{ "profile_type": "time_profiler" }
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Supported `profile_type` values are `launch`, `allocations`, `leaks`, `time_profiler`, and `network`.
|
|
202
|
+
|
|
203
|
+
## Custom Thresholds
|
|
204
|
+
|
|
205
|
+
The generic `analyze_*` and `analyze_*_trace` tools expose parser-specific thresholds. Use these when the defaults are too strict or too loose for a device class, platform, workload, or CI budget.
|
|
206
|
+
|
|
207
|
+
Launch:
|
|
208
|
+
|
|
209
|
+
- `launch_good_ms`
|
|
210
|
+
- `launch_critical_ms`
|
|
211
|
+
- `offender_warning_ms`
|
|
212
|
+
- `offender_critical_ms`
|
|
213
|
+
|
|
214
|
+
Allocations:
|
|
215
|
+
|
|
216
|
+
- `memory_warning_mb`
|
|
217
|
+
- `memory_critical_mb`
|
|
218
|
+
- `memory_cache_warning_mb`
|
|
219
|
+
|
|
220
|
+
Leaks:
|
|
221
|
+
|
|
222
|
+
- `leak_critical_count`
|
|
223
|
+
|
|
224
|
+
Time Profiler:
|
|
225
|
+
|
|
226
|
+
- `total_good_ms`
|
|
227
|
+
- `total_critical_ms`
|
|
228
|
+
- `method_warning_ms`
|
|
229
|
+
- `method_critical_ms`
|
|
230
|
+
|
|
231
|
+
Network:
|
|
232
|
+
|
|
233
|
+
- `request_warning_ms`
|
|
234
|
+
- `request_critical_ms`
|
|
235
|
+
- `slow_request_critical_count`
|
|
236
|
+
- `transfer_warning_mb`
|
|
237
|
+
|
|
238
|
+
Example:
|
|
239
|
+
|
|
240
|
+
```json
|
|
241
|
+
{
|
|
242
|
+
"bundle_id": "com.example.app",
|
|
243
|
+
"device_id": "SIMULATOR-UUID",
|
|
244
|
+
"launch_good_ms": 700,
|
|
245
|
+
"launch_critical_ms": 1500,
|
|
246
|
+
"offender_warning_ms": 150,
|
|
247
|
+
"offender_critical_ms": 500
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Trace Analysis Arguments
|
|
252
|
+
|
|
253
|
+
Trace analysis tools accept:
|
|
254
|
+
|
|
255
|
+
- `trace_path`: absolute path to an existing `.xctrace` bundle.
|
|
256
|
+
- `bundle_id`: optional target name used in the generated report.
|
|
257
|
+
|
|
258
|
+
Trace comparison tools accept:
|
|
259
|
+
|
|
260
|
+
- `baseline_trace_path`: absolute path to the baseline `.xctrace` bundle.
|
|
261
|
+
- `candidate_trace_path`: absolute path to the candidate `.xctrace` bundle.
|
|
262
|
+
- `bundle_id`: optional target name used in the generated report.
|
|
263
|
+
|
|
264
|
+
Example:
|
|
265
|
+
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"baseline_trace_path": "~/Desktop/baseline.xctrace",
|
|
269
|
+
"candidate_trace_path": "~/Desktop/candidate.xctrace",
|
|
270
|
+
"bundle_id": "com.example.app"
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Example Report
|
|
275
|
+
|
|
276
|
+
```markdown
|
|
277
|
+
# App Launch Analysis - com.example.app
|
|
278
|
+
|
|
279
|
+
Warning: Launch time 1240ms - above 400ms. Users may notice the delay.
|
|
280
|
+
|
|
281
|
+
**Total:** 1240ms
|
|
282
|
+
|
|
283
|
+
## Phases
|
|
284
|
+
- **pre-main (dyld + static init):** 434ms (35%)
|
|
285
|
+
- **post-main (AppDelegate + UI):** 806ms (65%)
|
|
286
|
+
|
|
287
|
+
## Top Offenders
|
|
288
|
+
|
|
289
|
+
Critical: `-[DatabaseManager setup]` [post-main]
|
|
290
|
+
Self: **540ms** | Total: 540ms | 43%
|
|
291
|
+
Suggestion: Move database initialization to a background queue or use lazy loading.
|
|
292
|
+
|
|
293
|
+
Warning: `+[AnalyticsSDK configure:]` [post-main]
|
|
294
|
+
Self: **210ms** | Total: 210ms | 17%
|
|
295
|
+
Suggestion: Defer analytics SDK initialization after first frame is rendered.
|
|
296
|
+
|
|
297
|
+
## Recommendations
|
|
298
|
+
- Fix 1 critical offender(s) - each adds 300ms+ to launch.
|
|
299
|
+
- Target: total launch under 400ms.
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Notes
|
|
303
|
+
|
|
304
|
+
- Temporary `.xctrace` files created by recording tools are cleaned up after each run.
|
|
305
|
+
- All analysis is based on the XML exported by `xcrun xctrace export`.
|
|
306
|
+
- The parsers support multiple XML shapes emitted by different Xcode/Instruments versions, but Instruments output can vary between releases.
|
|
307
|
+
- Reports include an `Analysis Quality` section when the exported XML is empty or no recognizable data was found for the selected parser.
|
|
308
|
+
- If you already have a trace, prefer the `_trace` tools to avoid recording again.
|
|
309
|
+
|
|
310
|
+
## Troubleshooting
|
|
311
|
+
|
|
312
|
+
Recording tools run a few pre-flight checks before invoking `xctrace`. A target is rejected up front when `launch_path` does not exist on this Mac, `pid` is not a positive integer or no longer running, or `bundle_id` contains characters Instruments does not accept. When `xctrace` itself fails, the error message is classified per target (bundle not installed, dead process, unresolved device, invalid `launch_path`, missing Xcode tools) and the report includes a fix hint scoped to that target instead of a generic checklist.
|
|
313
|
+
|
|
314
|
+
If recording fails, check these first:
|
|
315
|
+
|
|
316
|
+
- The target app is installed on the selected simulator or device, or the local launch path exists.
|
|
317
|
+
- The simulator/device is booted and visible in `xcrun xctrace list devices`.
|
|
318
|
+
- The process exists when using `process_name` or `pid`.
|
|
319
|
+
- Xcode and command line tools are selected correctly: `xcode-select -p`.
|
|
320
|
+
- The Instruments template exists on your machine: use `list_templates`.
|
|
321
|
+
- Physical devices are trusted, unlocked, connected, and allowed to run UI automation.
|
|
322
|
+
|
|
323
|
+
Use `build_xctrace_command` to inspect the exact command that would run, without recording. The returned command also surfaces any pre-flight warnings detected against the chosen target.
|
|
324
|
+
|
|
325
|
+
You can also verify `xctrace` directly:
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
xcrun xctrace list devices
|
|
329
|
+
xcrun xctrace list templates
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Development
|
|
333
|
+
|
|
334
|
+
Clone the repository and install the editable build with the `dev` extra:
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
git clone git@github.com:dogo/apple-instruments-mcp.git
|
|
338
|
+
cd apple-instruments-mcp
|
|
339
|
+
python3 -m venv .venv
|
|
340
|
+
. .venv/bin/activate
|
|
341
|
+
python -m pip install -e ".[dev]"
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Run linters, type check, and the test suite:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
ruff check src tests
|
|
348
|
+
pyright
|
|
349
|
+
PYTHONPATH=src python -m unittest discover -s tests -v
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
The package ships a `py.typed` marker so downstream consumers can type-check against its public API. A `uv.lock` is committed for reproducible dependency installs with [uv](https://github.com/astral-sh/uv); CI runs the same checks across Python 3.11–3.13 via `.github/workflows/ci.yml`.
|
|
353
|
+
|
|
354
|
+
Run the MCP server locally:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
python -m apple_instruments_mcp
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Releasing
|
|
361
|
+
|
|
362
|
+
Releases are published to PyPI through GitHub Actions trusted publishing — no API tokens stored in the repo. Steps:
|
|
363
|
+
|
|
364
|
+
1. Bump `version` in `pyproject.toml`, commit, and push to `main`.
|
|
365
|
+
2. Tag the commit with `X.Y.Z` (no `v` prefix) matching that version and push the tag.
|
|
366
|
+
3. The `Release` workflow builds `sdist` + `wheel`, verifies the tag matches `pyproject.toml`, and uploads to PyPI via OIDC.
|
|
367
|
+
|
|
368
|
+
One-time PyPI setup: on https://pypi.org, register the project name and add a Trusted Publisher pointing at this repository, the `release.yml` workflow, and the `pypi` environment.
|
|
369
|
+
|
|
370
|
+
## License
|
|
371
|
+
|
|
372
|
+
MIT
|