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.
@@ -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