npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@iflow-mcp/nemanjavlahovic-instrumentsmcp

v0.4.0

Published

AI-native performance profiling for iOS and macOS apps. Profile while you use the app — start/stop recording, simulator control, scenario automation, all through Xcode Instruments via MCP.

Readme

InstrumentsMCP

AI-native performance profiling for iOS and macOS apps.

InstrumentsMCP gives AI agents the ability to record Instruments traces, automate simulator interaction, parse the results, and tell you exactly what's slow — without you opening Instruments once.

"Profile CPU while scrolling the feed" → agent starts recording, taps through the app, scrolls the feed → stops → structured findings with severity ratings → AI suggests the fix

How It Works

Hands-Free Profiling (UI Automation + Instruments)

The agent records an Instruments trace while programmatically interacting with your app — no human interaction needed:

You:   "Profile CPU while scrolling through the feed and searching for users"
Agent: calls profile_scenario({
         bundle_id: "com.example.MyApp",
         template: "Time Profiler",
         duration: "20s",
         scenario: [
           { action: "launch" },
           { action: "wait", seconds: 2 },
           { action: "gesture", preset: "scroll-down" },
           { action: "wait", seconds: 1 },
           { action: "gesture", preset: "scroll-down" },
           { action: "tap", label: "Search" },
           { action: "type_text", text: "nema" },
           { action: "wait", seconds: 2 },
           { action: "snapshot_ui", label: "search-results" }
         ]
       })
Agent: "=== Time Profiler ===  severity: [WARNING]  samples: 1587

       Hotspots:
         UpdateStack::update() (AttributeGraph)  42.3ms self ━━━━━━╌╌╌╌╌╌╌╌╌ 12.1%
         FeedViewModel.loadItems() (MyApp)        28.1ms self ━━━━╌╌╌╌╌╌╌╌╌╌╌ 8.0%

       Main thread blockers:
         [WARNING] FeedViewModel.loadItems()  28.1ms

       trace: abc123 | path: ~/.instruments-mcp/traces/..."

UI automation is powered by AXe CLI — tap, type, swipe, and read the accessibility hierarchy on any booted simulator.

CLI Recording (Ctrl+C to stop)

The fastest way to profile. Open a terminal, run one command, use your app, hit Ctrl+C:

instrumentsmcp record --process MyApp --template "Time Profiler"
  Recording: Time Profiler
  Target:    MyApp

  Interact with your app. Press Ctrl+C to stop.

  ^C
  Stopping recording...
  Recording stopped (23.4s)

  === Time Profiler ===  severity: [CRITICAL]  samples: 2341

  Hotspots:
    FeedViewModel.loadItems() (MyApp)  42.3ms self ━━━━━━━━━╌╌╌╌╌╌ 18.3%

  Trace saved: ~/.instruments-mcp/traces/profile-1234567890.trace
  Re-analyze: Tell your AI agent "Analyze the trace at ~/.instruments-mcp/traces/..."

No AI needed for timing — you control when to start and stop. Then feed the trace to your agent for deeper analysis and code fixes.

Agent-Driven Profiling (start/stop via MCP)

The agent controls the recording while you interact with the app:

You:   "Start profiling my app for CPU while I test the feed"
Agent: calls start_profiling({ process: "MyApp", template: "Time Profiler" })
Agent: "Recording started. Go ahead — scroll, tap, navigate. Tell me when you're done."

... you scroll the feed, open a detail view, go back ...

You:   "Done"
Agent: calls stop_profiling()
Agent: "Found 3 issues:
        1. FeedViewModel.loadItems() — 18.3% CPU (critical)
        2. DateFormatter created on every cell (warning)
        3. CGPath recreation in card corners — 10K allocations in 15s (warning)"

One-Shot Profiling

For quick checks, every profiling tool works standalone:

You:   "Check my app for memory leaks"
Agent: calls profile_leaks({ process: "MyApp", duration: "30s" })

Prepare Your App

The single biggest thing you can do for efficient AI-driven profiling: add accessibilityIdentifier to your key UI elements.

With accessibility identifiers, the agent composes an entire profiling scenario in one tool call — no screenshots, no guessing, no wasted context:

You:   "Profile CPU while logging in and scrolling the feed"
Agent: calls profile_scenario with tap(id: "emailField"), type("[email protected]"),
       tap(id: "loginButton"), gesture(scroll-down)...
       → Done. Structured results. One call.

Without them, the agent has to snapshot the screen, parse a JSON tree of every UI element, find the right button by label or coordinates, tap, snapshot again to verify... repeat for every interaction. That's 6+ tool calls and 10KB+ of context burned on navigation instead of profiling.

// These identifiers let the agent tap directly — no discovery needed
emailField.accessibilityIdentifier = "emailField"
loginButton.accessibilityIdentifier = "loginButton"
feedList.accessibilityIdentifier = "feedList"
searchBar.accessibilityIdentifier = "searchBar"

| Targeting method | Reliability | Speed | Context cost | |---|---|---|---| | accessibilityIdentifier | Best — unique, stable across layouts | Instant | Zero | | accessibilityLabel | Good — but may match multiple elements | Instant | Zero | | Coordinates (x, y) | Fragile — breaks on layout changes | Instant | Requires snapshot first |

Tip: If your app already uses accessibilityLabel for VoiceOver, you're most of the way there. Add accessibilityIdentifier to key interactive elements (buttons, fields, tabs) and the agent can drive your entire app without ever snapshotting.

What You Can Profile

| Tool | What It Finds | Severity Thresholds | |---|---|---| | profile_cpu | CPU hotspots, per-thread utilization, severity classification | >15% self-time critical, >8% warning | | profile_swiftui | Excessive view body re-evaluations, slow view rendering | >100 evals or >50ms critical | | profile_memory | Memory by category, persistent vs transient, largest allocators | >50MB or >100k allocs critical | | profile_hitches | Animation hangs with backtraces and duration classification | >1s critical, >250ms warning | | profile_launch | App launch time, phase breakdown, cold/warm/resume detection | >1s cold critical, >500ms warm critical | | profile_energy | Energy impact scores (0-20), per-component breakdown, thermal state | Avg >=13 or peak >=20 critical | | profile_leaks | Leaked objects by type, sizes, responsible libraries | >100 leaks or >10MB total critical | | profile_network | HTTP traffic: request counts, durations, error rates, per-domain breakdown | >10% errors or >5s response critical | | performance_audit | Combined CPU + Hitches + Leaks + Energy + Network health check | Worst severity across all five | | profile_raw | Any template - raw table of contents for custom analysis | - |

UI Automation

InstrumentsMCP can interact with simulator UI elements directly — tap buttons, type text, swipe, scroll, and read the accessibility hierarchy. These tools work standalone for UI testing or as steps in profile_scenario for hands-free performance profiling.

Requires AXe CLI: brew tap cameroncooke/axe && brew install axe

| Tool | What It Does | |---|---| | ui_snapshot | Get the accessibility hierarchy — element roles, labels, identifiers, and frame coordinates | | ui_tap | Tap by accessibility id (most reliable), label, or x/y coordinates | | ui_type | Type text into the currently focused field | | ui_swipe | Swipe between two points | | ui_gesture | Preset gestures: scroll-up/down/left/right, swipe-from-*-edge | | ui_long_press | Touch-and-hold at coordinates |

The agent reads the screen with ui_snapshot, finds elements, and interacts with them — just like a human would, but programmatically.

Simulator Control

InstrumentsMCP can manage iOS Simulators directly — launch apps, navigate via deep links, take screenshots, send push notifications, and more. These tools work standalone or as building blocks for profile_scenario.

| Tool | What It Does | |---|---| | sim_list_booted | List running simulators and their installed apps | | sim_launch_app | Launch an app by bundle ID, returns PID | | sim_terminate_app | Terminate a running app | | sim_open_url | Open a URL or deep link on the simulator | | sim_push_notification | Send a simulated push notification | | sim_screenshot | Capture the simulator screen as PNG | | sim_set_appearance | Toggle light/dark mode | | sim_set_location | Set simulated GPS coordinates |

Example Output

=== Time Profiler ===  severity: [WARNING]  samples: 1587

Hotspots:
  UpdateStack::update() (AttributeGraph)  42.3ms self ━━━━━━╌╌╌╌╌╌╌╌╌ 12.1%
  FeedViewModel.loadItems() (MyApp)        28.1ms self ━━━━╌╌╌╌╌╌╌╌╌╌╌ 8.0%
  LayoutComputer::doAlignment() (SwiftUI)  15.2ms self ━━╌╌╌╌╌╌╌╌╌╌╌╌╌ 4.3%

Main thread blockers:
  [WARNING] FeedViewModel.loadItems()  28.1ms

trace: abc123 | path: ~/.instruments-mcp/traces/profile-1234567890.trace
=== SwiftUI ===  severity: [WARNING]  total evals: 847  views: 23

Views:
  [CRITICAL] FeedCardView  x156  65.5ms
  [WARNING] AvatarView     x89   12.3ms
  [OK] HeaderView          x12   1.2ms

Excessive re-renders: 2 views flagged

trace: abc123 | path: ~/.instruments-mcp/traces/profile-1234567890.trace
=== App Launch ===  severity: [CRITICAL]  total: 1340ms  type: cold

Phases:
  [CRITICAL] Dynamic Library Loading  580ms  ━━━━━━━━━━━━━━━
  [CRITICAL] UIKit Initialization     310ms  ━━━━━━━━╌╌╌╌╌╌╌
  [WARNING] Initial Frame Rendering   290ms  ━━━━━━━╌╌╌╌╌╌╌╌

trace: abc123 | path: ~/.instruments-mcp/traces/profile-1234567890.trace
=== Animation Hitches ===  severity: [CRITICAL]  total: 3 (1 critical, 2 warning, 0 minor, 0 micro)

Hang events:
  [CRITICAL] 1240ms  start: 5.2s
    stack: FeedViewModel.loadItems() > NetworkManager.fetch() > URLSession.data()
  [WARNING] 380ms  start: 12.1s

trace: abc123 | path: ~/.instruments-mcp/traces/profile-1234567890.trace
=== Leaks ===  severity: [WARNING]  total: 12 objects  4.8 KB

Leak groups:
  [WARNING] NSMutableArray (Foundation)  x5  2.1 KB
  [minor] ClosureContext (MyApp)         x4  1.6 KB
  [minor] NSObject (CoreFoundation)      x3  1.1 KB

By library:
  Foundation  5 leaks  2.1 KB
  MyApp       4 leaks  1.6 KB

trace: abc123 | path: ~/.instruments-mcp/traces/profile-1234567890.trace

All 35 Tools

Interactive Profiling

| Tool | What It Does | |---|---| | start_profiling | Start recording a trace in the background - user interacts with the app manually | | stop_profiling | Stop recording, parse the trace, return structured results | | profile_scenario | Record a trace while executing a scripted scenario (deep links + UI automation) |

One-Shot Profiling

| Tool | Template | What It Returns | |---|---|---| | profile_cpu | Time Profiler | Top CPU hotspots, per-thread utilization, severity classification | | profile_swiftui | SwiftUI | View body evaluation counts, excessive re-renders, duration per view | | profile_memory | Allocations | Memory usage by category, persistent vs transient, largest allocators | | profile_hitches | Animation Hitches | Hang events by severity with backtraces | | profile_launch | App Launch | Launch time, phases, cold/warm/resume classification | | profile_energy | Energy Log | Energy impact scores, component breakdown, thermal state | | profile_leaks | Leaks | Leaked objects by type, sizes, responsible libraries | | profile_network | Network | HTTP request counts, durations, error rates, per-domain breakdown | | profile_raw | Any | Raw table of contents for templates without a dedicated parser | | performance_audit | 5 templates | Combined CPU + Hitches + Leaks + Energy + Network health check |

UI Automation

| Tool | What It Does | |---|---| | ui_snapshot | Get accessibility hierarchy - element roles, labels, identifiers, frame coordinates | | ui_tap | Tap by accessibility id, label, or x/y coordinates | | ui_type | Type text into focused field | | ui_swipe | Swipe between two points | | ui_gesture | Preset gestures (scroll, edge swipes) | | ui_long_press | Touch-and-hold at coordinates |

Simulator Control

| Tool | What It Does | |---|---| | sim_list_booted | List running simulators and installed apps | | sim_launch_app | Launch app by bundle ID | | sim_terminate_app | Terminate a running app | | sim_open_url | Open a URL or deep link | | sim_push_notification | Send a simulated push notification | | sim_screenshot | Capture simulator screen | | sim_set_appearance | Toggle light/dark mode | | sim_set_location | Set simulated GPS coordinates |

Analysis & Investigation

| Tool | What It Does | |---|---| | analyze_trace | Export specific tables from existing .trace files by xpath | | drill_down | Drill into a specific function, domain, or view from a previous profile result | | list_traces | List recently profiled traces available for re-analysis | | symbolicate_trace | Add debug symbols so function names appear instead of addresses | | performance_baseline | Save, compare, list, or delete performance baselines for regression tracking | | performance_report | Generate shareable Markdown performance reports from profile results |

Discovery

| Tool | What It Does | |---|---| | instruments_status | Check if xctrace is available and its version | | instruments_list_templates | List all available profiling templates | | instruments_list_devices | List connected devices and running simulators | | instruments_list_instruments | List individual instruments |

Setup

Requirements

  • macOS with Xcode installed (xctrace CLI)
  • Node.js >= 20
  • Optional: AXe CLI for UI automation (brew tap cameroncooke/axe && brew install axe)

Claude Code

npx instrumentsmcp@latest

Or add to your project's .mcp.json:

{
  "mcpServers": {
    "instruments": {
      "command": "npx",
      "args": ["-y", "instrumentsmcp@latest"]
    }
  }
}

Cursor / Windsurf / Other MCP Clients

Use the same npx command in your client's MCP server settings.

Install from Source

git clone https://github.com/nemanjavlahovic/instruments-mcp-server.git
cd instruments-mcp-server
npm install && npm run build

Then point your MCP client to dist/index.js.

CLI Recording (no MCP client needed)

Record a trace from any terminal - no AI agent required:

npx instrumentsmcp record --process MyApp
npx instrumentsmcp record --process MyApp --template Allocations
npx instrumentsmcp record --process MyApp --device booted --template "Time Profiler"

Press Ctrl+C to stop. Results print to stdout, trace is saved for later re-analysis.

Architecture

src/
├── index.ts              # MCP server entry point + CLI router
├── cli.ts                # Interactive CLI mode (instrumentsmcp record)
├── tools/
│   ├── profile.ts        # One-shot profiling tools (cpu, swiftui, memory, etc.)
│   ├── simulator.ts      # Simulator control + start/stop + scenario profiling
│   ├── analyze.ts        # Trace analysis + symbolication + performance audit
│   ├── baseline.ts       # Baseline comparison + Markdown report generation
│   ├── investigate.ts    # Drill-down into specific functions/views + trace listing
│   ├── ui.ts             # UI automation tools (snapshot, tap, type, swipe, gesture)
│   └── list.ts           # Discovery tools (status, templates, devices)
├── parsers/              # Template-specific XML→JSON parsers with severity classification
│   ├── time-profiler.ts, swiftui.ts, allocations.ts, hangs.ts,
│   ├── app-launch.ts, energy.ts, leaks.ts, network.ts
└── utils/
    ├── xctrace.ts        # xctrace CLI wrapper (record, export, spawn, symbolicate)
    ├── simctl.ts         # simctl CLI wrapper (simulator interaction + device resolution)
    ├── axe.ts            # AXe CLI wrapper (UI automation — tap, type, swipe, describe)
    ├── trace-helpers.ts  # Shared xpath resolution and timing helpers
    ├── trace-store.ts    # In-memory trace store for multi-turn investigation
    ├── parse-trace.ts    # Template→parser routing (shared by CLI, tools, scenario)
    ├── format-output.ts  # Compact text formatters for LLM-friendly output
    ├── auto-investigate.ts # Pre-computed investigation findings from profile results
    ├── extractors.ts     # Shared XML row/field extractors
    └── xml.ts            # XML parsing (fast-xml-parser)

Each Instruments template has a dedicated parser with domain-specific heuristics. Severity thresholds are tuned per metric type. Profile results use compact text formatting (~80% smaller than JSON) optimized for LLM context windows. Traces are stored in ~/.instruments-mcp/traces/ for reuse and comparison.

Compatibility

  • Xcode Instruments (xctrace) 15.x through 26.x
  • Handles xctrace 26 Deferred recording mode (automatic time-sample fallback)
  • Retry logic for intermittent xctrace export failures
  • Device identifiers (booted, device name, UDID) are automatically resolved to simulator UDIDs
  • Simulator interaction requires a booted iOS Simulator
  • UI automation requires AXe CLI (graceful degradation with install instructions if missing)

License

MIT