Skip to main content

apple-instruments-mcp

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 .trace bundles, and return concise performance reports with actionable recommendations.

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.

Features

  • Record new traces with xctrace from an MCP client.
  • Analyze existing .trace bundles without recording again.
  • Report launch time, memory allocations, leaks, CPU hot spots, and network activity.
  • Launch apps by bundle ID or executable path.
  • Attach to running processes by process name or PID.
  • Record all processes when an Instruments template supports it.
  • List available devices, simulators, runtimes, and Instruments templates.
  • Return raw or JSON-structured device/template listings.
  • Preview the generated xctrace command with dry_run.
  • Keep .trace and XML artifacts for later inspection.
  • Return human-readable summaries with top offenders and suggested fixes.
  • Runs as a standard stdio MCP server.

Requirements

  • macOS
  • Xcode with Instruments installed
  • Xcode Command Line Tools: xcode-select --install
  • Python 3.11 or newer
  • A supported target visible to xctrace: booted simulator, connected device, local macOS app, running process, or all-processes recording.

Physical devices may require enabling UI automation in Settings > Developer.

Installation

The package is published on PyPI. The recommended way is to run it through uvx, which downloads and caches the server on demand without polluting your environment:

uvx apple-instruments-mcp

Alternatively, install it globally with pipx or pip:

pipx install apple-instruments-mcp
# or
python -m pip install apple-instruments-mcp

Either path provides the apple-instruments-mcp executable.

MCP Client Configuration

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.

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):

{
  "mcpServers": {
    "apple-instruments": {
      "command": "uvx",
      "args": ["apple-instruments-mcp"]
    }
  }
}

To pin a specific version, replace the arg with apple-instruments-mcp@1.2.0.

For Claude Code:

claude mcp add apple-instruments -- uvx apple-instruments-mcp

If you prefer a global install (pipx or pip), point the client at the resulting binary instead:

{
  "mcpServers": {
    "apple-instruments": {
      "command": "apple-instruments-mcp"
    }
  }
}

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.

Example Prompts

Run the xctrace doctor and tell me if recording is currently possible.
List the devices and Instruments templates available on this Mac.
Profile com.example.app on this simulator with the full preset for 15 seconds.
Record an App Launch trace for com.example.app on this iPhone simulator and show the startup offenders.
Launch /Applications/MyMacApp.app with Time Profiler and show CPU hot methods.
Time-profile com.example.app, then zoom into the 8000ms–12000ms window and flag main-thread stalls above 200ms.
Time-profile this release build and symbolicate raw addresses with ~/Build/MyApp.dSYM.
Attach Allocations to the running process named MyMacApp for 30 seconds.
Attach Time Profiler to PID 1234.
Record all processes with Time Profiler for 10 seconds.
Analyze network activity for com.example.app and flag slow requests.
Analyze the existing trace at ~/Desktop/launch.trace.
Compare ~/Desktop/baseline.trace and ~/Desktop/candidate.trace for launch regressions.

Tools

Tool Instruments template Description
doctor - One-shot health check: xctrace version/path, device/template/instrument counts, and a problems section when probes or listings fail. Run this first if anything looks wedged.
list_devices - Lists devices, simulators, runtimes, and host targets visible to xctrace.
list_devices_structured - Returns the device/runtime listing as JSON.
list_templates - Lists Instruments templates installed on this Mac.
list_templates_structured - Returns the template listing as JSON.
profile_preset cpu / memory / network / full Records a bundle of instruments in one trace, then reports each family that produced data. full covers CPU + Allocations + Leaks + Network in a single run.
profile_ios_app Selected by profile_type Profiles an iOS, iPadOS, tvOS, watchOS, or visionOS app by bundle ID on a simulator/device.
profile_mac_app Selected by profile_type Profiles a macOS .app or executable by launch path.
profile_process Selected by profile_type Profiles a running process by process name or PID.
profile_all_processes Selected by profile_type Profiles all processes on the host or selected device.
analyze_launch App Launch Records and analyzes app startup time.
analyze_launch_trace App Launch Analyzes an existing App Launch .trace.
analyze_allocations Allocations Records memory allocations and reports live heap/VM totals plus top allocation categories.
analyze_allocations_trace Allocations Analyzes an existing Allocations .trace.
analyze_leaks Leaks Records a Leaks trace and reports exported leak details when available.
analyze_leaks_trace Leaks Analyzes an existing Leaks .trace when leak details are exportable.
analyze_time_profiler Time Profiler Records CPU samples and reports hot methods. Supports scope_start_ms/scope_end_ms windowing, main-thread hang detection, user-binary filtering, and dsym_path for symbolicating release-build frames.
analyze_time_profiler_trace Time Profiler Analyzes an existing Time Profiler .trace. Same scope/hang/user-binary/dSYM options as analyze_time_profiler.
analyze_network Network Records network requests, latency, transfer sizes, and status codes.
analyze_network_trace Network Analyzes an existing Network .trace.
compare_launch_traces App Launch Compares two App Launch traces and reports startup deltas.
compare_memory_traces Allocations Compares two Allocations traces and reports memory deltas.
compare_cpu_traces Time Profiler Compares two Time Profiler traces and reports CPU deltas.
build_xctrace_command Any Returns the exact xcrun xctrace record command for a target without executing it.

Recording Targets

Recording tools accept exactly one target mode:

  • bundle_id: app bundle identifier, for example com.example.app. Use with device_id for iOS, iPadOS, tvOS, watchOS, and visionOS simulator/device launches.
  • launch_path: executable path or .app path. Use this for macOS apps and command-line tools.
  • process_name: attach to a running process by name.
  • pid: attach to a running process by process ID.
  • all_processes: record all processes when the selected template supports it.

Additional recording arguments:

  • device_id: optional simulator UUID or physical device identifier from list_devices. Omit it for host macOS profiling.
  • launch_args: optional shell-style arguments passed after launch_path.
  • time_limit_seconds: recording duration, from 5 to 120 seconds. Defaults to 20.
  • dry_run: return the generated xctrace command without recording.
  • keep_trace: keep the run directory and generated .trace/XML artifacts, including on failures, and include their paths in the report.
  • output_dir: optional parent directory for generated artifacts. Each run creates a dedicated subdirectory inside it.

Examples:

{ "bundle_id": "com.example.app", "device_id": "SIMULATOR-UUID" }
{ "launch_path": "/Applications/MyMacApp.app" }
{ "launch_path": "/usr/bin/python3", "launch_args": "--version" }
{ "process_name": "MyMacApp" }
{ "pid": 1234 }
{ "all_processes": true }
{ "launch_path": "/Applications/MyMacApp.app", "dry_run": true }
{ "bundle_id": "com.example.app", "device_id": "SIMULATOR-UUID", "keep_trace": true, "output_dir": "~/Desktop/traces" }

The profile_* tools are higher-level wrappers around the generic analyze_* tools. Prefer them when you know the target shape:

{ "profile_type": "launch", "bundle_id": "com.example.app", "device_id": "SIMULATOR-UUID" }
{ "profile_type": "time_profiler", "launch_path": "/Applications/MyMacApp.app" }
{ "profile_type": "allocations", "process_name": "MyMacApp" }
{ "profile_type": "time_profiler", "pid": 1234 }
{ "profile_type": "time_profiler" }

Supported profile_type values are launch, allocations, leaks, time_profiler, and network.

Custom Thresholds

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.

Launch:

  • launch_good_ms
  • launch_critical_ms
  • offender_warning_ms
  • offender_critical_ms

Allocations:

  • memory_warning_mb
  • memory_critical_mb
  • memory_cache_warning_mb

Leaks:

  • leak_critical_count

Time Profiler:

  • total_good_ms — good threshold for normalized CPU load, measured as CPU-active milliseconds per wall-clock second.
  • total_critical_ms — critical threshold for the same normalized CPU-load metric. Defaults of 100/500 correspond to roughly 10%/50% of one fully occupied core.
  • method_warning_ms
  • method_critical_ms

Network:

  • request_warning_ms
  • request_critical_ms
  • slow_request_critical_count
  • transfer_warning_mb

Example:

{
  "bundle_id": "com.example.app",
  "device_id": "SIMULATOR-UUID",
  "launch_good_ms": 700,
  "launch_critical_ms": 1500,
  "offender_warning_ms": 150,
  "offender_critical_ms": 500
}

Trace Analysis Arguments

Trace analysis tools accept:

  • trace_path: absolute path to an existing .trace bundle.
  • bundle_id: optional target name used in the generated report.

Trace comparison tools accept:

  • baseline_trace_path: absolute path to the baseline .trace bundle.
  • candidate_trace_path: absolute path to the candidate .trace bundle.
  • bundle_id: optional target name used in the generated report.

Example:

{
  "baseline_trace_path": "~/Desktop/baseline.trace",
  "candidate_trace_path": "~/Desktop/candidate.trace",
  "bundle_id": "com.example.app"
}

Example Report

# App Launch Analysis - com.example.app

Warning: Launch time 1240ms - above 400ms. Users may notice the delay.

**Total:** 1240ms

## Phases
- **pre-main (dyld + static init):** 434ms (35%)
- **post-main (AppDelegate + UI):** 806ms (65%)

## Top Offenders

Critical: `-[DatabaseManager setup]` [post-main]
   Self: **540ms** | Total: 540ms | 43%
   Suggestion: Move database initialization to a background queue or use lazy loading.

Warning: `+[AnalyticsSDK configure:]` [post-main]
   Self: **210ms** | Total: 210ms | 17%
   Suggestion: Defer analytics SDK initialization after first frame is rendered.

## Recommendations
- Fix 1 critical offender(s) - each adds 300ms+ to launch.
- Target: total launch under 400ms.

Notes

  • Temporary .trace bundles created by recording tools are cleaned up after each run.
  • A failed recording preserves its partial .trace only when it contains non-empty artifacts; empty and zero-byte bundles are removed.
  • The server only terminates the xctrace child process it started through its watchdog. It does not sweep unrelated xctrace sessions running on the Mac.
  • All analysis is based on the XML exported by xcrun xctrace export.
  • Reports include an Analysis Quality section when the exported XML is empty or no recognizable data was found for the selected parser. Export failures (for example, an unsupported xpath) are reported under Export Warning.
  • If you already have a trace, prefer the _trace tools to avoid recording again.
  • Current Xcode versions expect xcrun xctrace record --output paths to use the .trace extension; .xctrace may be rejected before recording starts.

Parser Status

Each parser is wired to a specific xctrace export --xpath query. The tooling has been validated end-to-end against real .trace bundles for the ✅ rows.

Template xpath / schema Status
Time Profiler time-profile ✅ validated against real traces
App Launch time-profile (CPU samples, idle leaves filtered) ✅ validated against real traces
Allocations tracks/track[@name="Allocations"]/details/detail[@name="Statistics"] ✅ validated against real traces
Leaks tracks/track[@name="Leaks"]/details/detail[@name="Leaks"] ✅ validated against real traces
Network network-connection-detected (socket-level fallback) ✅ validated against a real physical-device trace; HTTP/HAR rows may be absent if Instruments does not export URLSession task details

App Launch caveats

The App Launch parser uses the same time-profile schema as Time Profiler and classifies frames into pre-main (dyld / static init / Swift runtime) vs post-main (AppDelegate / UIApplication / Cocoa methods) by symbol heuristic. Two things to keep in mind:

  • total_launch_ms is CPU-active launch time, not wall-clock. xctrace does not expose a clean "app became active" marker we can read.
  • Samples whose leaf frame is a known kernel wait (mach_msg2_trap, start_wqthread, semaphore_wait_trap, etc.) are dropped, matching Instruments' default "Hide System Libraries" behaviour. Without this, a long recording that idles after launch would dominate the totals with worker threads parked in wait.

Troubleshooting

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.

If recording fails, check these first:

  • The target app is installed on the selected simulator or device, or the local launch path exists.
  • The simulator/device is booted and visible in xcrun xctrace list devices.
  • The process exists when using process_name or pid.
  • Xcode and command line tools are selected correctly: xcode-select -p.
  • The Instruments template exists on your machine: use list_templates.
  • Physical devices are trusted, unlocked, connected, and allowed to run UI automation.

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.

You can also verify xctrace directly:

xcrun xctrace list devices
xcrun xctrace list templates

Development

Clone the repository and install the editable build with the dev extra:

git clone git@github.com:dogo/apple-instruments-mcp.git
cd apple-instruments-mcp
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e ".[dev]"

Run linters, type check, and the test suite:

ruff check src tests
pyright
PYTHONPATH=src python -m unittest discover -s tests -v

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; CI runs the same checks across Python 3.11–3.13 and includes a macOS smoke test against the installed xcrun xctrace.

Run the MCP server locally:

python -m apple_instruments_mcp

Releasing

Releases are published to PyPI through GitHub Actions trusted publishing — no API tokens stored in the repo. Steps:

  1. Bump version in pyproject.toml, commit, and push to main.
  2. Tag the commit with X.Y.Z (no v prefix) matching that version and push the tag.
  3. The Release workflow builds sdist + wheel, verifies the tag matches pyproject.toml, and uploads to PyPI via OIDC.

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.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

apple_instruments_mcp-1.2.0.tar.gz (112.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

apple_instruments_mcp-1.2.0-py3-none-any.whl (58.1 kB view details)

Uploaded Python 3

File details

Details for the file apple_instruments_mcp-1.2.0.tar.gz.

File metadata

  • Download URL: apple_instruments_mcp-1.2.0.tar.gz
  • Upload date:
  • Size: 112.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for apple_instruments_mcp-1.2.0.tar.gz
Algorithm Hash digest
SHA256 9ea262d3f8b92896b3a1a65c6982991451d6f6b92d5399e1c361ec0ba9b29eae
MD5 4349999bee6025f26b0869d3a4fe03b8
BLAKE2b-256 48694df20475b6ef131eaf64ea38fafb72a8f1fa812cd44a1309c1a038143455

See more details on using hashes here.

Provenance

The following attestation bundles were made for apple_instruments_mcp-1.2.0.tar.gz:

Publisher: release.yml on dogo/apple-instruments-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file apple_instruments_mcp-1.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for apple_instruments_mcp-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 aaea62bba6555ece28f31bff7acbc85d5493bb0f4e13ebc9cbd8a0c4a0465526
MD5 e3eb525634269ca35754ad6f632d761b
BLAKE2b-256 a60bd5d74fcd524b96e59cab6660e2842afff5c9efcc6ef2166450fd48c5a18f

See more details on using hashes here.

Provenance

The following attestation bundles were made for apple_instruments_mcp-1.2.0-py3-none-any.whl:

Publisher: release.yml on dogo/apple-instruments-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

1.2.1

2 files

This release

1.2.0 This release

2 files

1.1.0

2 files

1.0.4

2 files

1.0.3

2 files

1.0.2

2 files

1.0.1

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page