@xctrace-analyzer/mcp-server
v0.1.7
Published
MCP server for Xcode Instruments trace analysis
Maintainers
Readme
Xcode Instruments Trace Analyzer MCP Server
Model Context Protocol server for intelligent Xcode Instruments trace analysis
This MCP server provides AI assistants like Claude with the ability to automate xcrun xctrace workflows: record traces, symbolicate traces, export TOC/XML/HAR data, detect Time Profiler bottlenecks, summarize exportable Memory/Network/Energy/Allocations/Leaks data, identify Time Profiler regressions, clean up generated traces, and provide actionable recommendations.
It is an honest Instruments companion, not a complete GUI replacement. Recording tools open the saved .trace in Instruments.app by default, and any template or view that is absent from the trace or not exportable through xctrace is reported explicitly.
Features
- 🔍 Intelligent Analysis - Automatically identifies performance bottlenecks
- 🎥 Automated Recording - Attach to a running app, save a trace, and analyze it in one tool call
- 🧭 Multi-Instrument Analysis - Auto-detects Memory, Network, Energy, Allocations, and Leaks data when exportable
- 📊 Regression Detection - Compare traces to find performance regressions
- 💡 Actionable Recommendations - Get specific optimization suggestions with code examples
- 🧾 Structured Diagnostics - Support matrix, export attempts, and JSON output for CI or agents
- 🧹 Trace Cleanup - Preview or delete generated
.tracebundles after inspection - 🤖 Natural Language Interface - Use Claude to interact with your performance data
- ⚙️ Local-first - Runs through your installed Xcode Command Line Tools
Installation
Claude Code
claude mcp add --transport stdio --scope user xctrace-analyzer -- npx -y @xctrace-analyzer/mcp-server@latestVerify the local machine has a usable xcrun xctrace:
npx -y @xctrace-analyzer/mcp-server@latest --checkClaude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"xctrace-analyzer": {
"command": "npx",
"args": ["-y", "@xctrace-analyzer/mcp-server@latest"]
}
}
}Codex CLI
codex mcp add xctrace-analyzer -- npx -y @xctrace-analyzer/mcp-server@latestCheck that Codex registered the server:
codex mcp listBuilding from Source
# From the monorepo root
pnpm install --frozen-lockfile
pnpm verifyAvailable Tools
Recommended User Experience
For human-facing use, register the bundled skill in clients that support skills. Source checkouts provide it at ../../skills/xctrace-profiler; npm installs include it at node_modules/@xctrace-analyzer/mcp-server/skills/xctrace-profiler. Then users can stay at the prompt level:
Profile this app.
Find why this app is slow.
Profile this app for hangs.
Profile this app for hangs and tell me which of my code is responsible.
Check this build for leaks and allocation churn.
Analyze network activity.
Launch this app and profile startup hangs.
I will launch MyApp; record it for 60 seconds when it appears.
Analyze this trace.
Compare these two traces.
Clean up profiling traces when we are done.The skill is the planner for this MCP server. It chooses between recording, existing trace analysis, single-template tracking, device/template checks, scoped hang follow-ups, trace comparisons, and safe cleanup once the user no longer needs the saved trace. When the user says they will launch the app manually, the skill starts watching for the app process immediately and attaches to the first valid PID without waiting for a second prompt. The MCP server itself exposes execution tools only.
Tool Selection Guide
- Use
profile_running_appfor "start profiling", "full report", or "record all issues" requests against an already-running app. - Use
track_running_appfor a single explicit Instruments template such as Leaks or Allocations. - Use
analyze_tracewhen the user already has a.tracefile, especially for scoped follow-up analysis withtimeRangeMsand app attribution via Top User-Code Frames. - Use
compare_traceswhen the user asks whether a current build regressed against a baseline. - Use
cleanup_tracesafter the user confirms recorded traces are no longer needed, or as a dry-run preview for stale trace directories. - Use
list_templates,list_devices, andcheck_xctracefor setup and troubleshooting.
Security Defaults
Attach profiling and trace analysis work by default. The secure defaults do not reduce the Instruments recorded by the full, memory, network, or full-ios presets; they restrict higher-risk MCP operations.
| Option | Default | Why it is useful and important |
| --- | --- | --- |
| XCTRACE_ANALYZER_ALLOW_LAUNCH=1 | Disabled | Enables true startup/cold-launch profiling. It is disabled by default because launchCommand asks the MCP server to execute a local program through xcrun xctrace --launch. |
| XCTRACE_ANALYZER_ALLOW_ALL_PROCESSES=1 | Disabled | Enables system-wide traces when one process is not enough. It is disabled by default because the trace can include unrelated apps, services, paths, URLs, and symbols. |
| XCTRACE_ANALYZER_TRACE_ROOT=/path/to/traces | ~/Library/Application Support/xctrace-analyzer/traces | Sets the allowed trace output root. Keeping traces in one user-level folder reduces accidental project churn and makes cleanup safer. |
| XCTRACE_ANALYZER_ALLOW_EXTERNAL_OUTPUT=1 | Disabled | Allows outputPath, outputDirectory, targetStdin, and targetStdout outside the trace root. It is useful for CI or shared scratch volumes, but broadens where the MCP server can write. |
| XCTRACE_ANALYZER_ALLOW_EXTERNAL_CLEANUP=1 | Disabled | Allows destructive cleanup outside the trace root. It is useful for maintenance of a trusted trace archive, but should be paired with a dry run or exact trace paths. |
| XCTRACE_ANALYZER_MAX_DURATION_SECONDS=300 | 300 | Caps recording duration to avoid accidental long-running captures and very large .trace bundles. Raise it only for expected long repros. |
| XCTRACE_ANALYZER_REDACTION=balanced | balanced | Controls report redaction. balanced hides common secrets and user paths, strict also hides hostnames, and off preserves full details for trusted local debugging. |
For startup profiling with the default security posture, manually launch the app and attach by exact PID as soon as it appears. For trusted local launch profiling, start the server with:
XCTRACE_ANALYZER_ALLOW_LAUNCH=1 npx -y @xctrace-analyzer/mcp-server@latestClaude Desktop-style MCP configs can pass the same settings through env:
{
"mcpServers": {
"xctrace-analyzer": {
"command": "npx",
"args": ["-y", "@xctrace-analyzer/mcp-server@latest"],
"env": {
"XCTRACE_ANALYZER_ALLOW_LAUNCH": "1",
"XCTRACE_ANALYZER_TRACE_ROOT": "/Users/you/Library/Application Support/xctrace-analyzer/traces"
}
}
}
}Codex can pass the same settings with --env:
codex mcp add xctrace-analyzer \
--env XCTRACE_ANALYZER_ALLOW_LAUNCH=1 \
--env XCTRACE_ANALYZER_TRACE_ROOT="/Users/you/Library/Application Support/xctrace-analyzer/traces" \
-- npx -y @xctrace-analyzer/mcp-server@latestprofile_running_app
Record a running app once with a profiling preset and return one combined report. durationSeconds: 60 means one 60-second recording. The preset uses a base template plus additional Instruments where Xcode supports it.
Parameters:
processName(optional): Running process name or pid to attach to; required for attach modetarget(optional):attach,launch, orall-processeslaunchCommand,launchArguments,environment(optional): launch target detailspreset(optional):full,full-ios,cpu,memory,network, orenergy(default:full)durationSeconds(optional): Total recording duration in seconds (default: 60)device(optional): Device or simulator name/UDIDoutputDirectory(optional): Directory where generated.tracefiles should be saved (default: configured trace root)analyze(optional): Analyze after recording (default: true)openInInstruments(optional): Open the saved.tracein Instruments.app after recording (default: true). Set false for CI or headless runs.outputFormat(optional):markdown,json, orboth(default:markdown)
Preset recordings:
full: Time Profiler base with Leaks, Allocations, and HTTP Traffic instrumentsfull-ios: Time Profiler base with Leaks, Allocations, HTTP Traffic, and Power Profiler instrumentscpu: Time Profilermemory: Allocations base with Leaks instrumentnetwork: Time Profiler base with HTTP Traffic instrumentenergy: Power Profiler. This is for iOS/iPadOS targets; Xcode commonly does not expose Power Profiler data for macOS recordings.
Report contents:
- Recording metadata: process, preset, duration, trace path, base template, instruments, and Instruments.app open status
- Support matrix and export diagnostics
- CPU / Time Profiler: bottlenecks, top functions, threads, slow function count, and CPU recommendations
- Hangs: main-thread hang events; severe hangs affect Overall status and Prioritized Recommendations even when Time Profiler CPU thresholds are otherwise clean
- Top User-Code Frames: app-attributed CPU frames from Time Profiler samples
- Time Profiler parse-failure callouts when CPU samples could not be parsed
- Leaks: leak count, leaked bytes, top leak sites, and leak findings when Xcode exports usable data
- Allocations: allocation counts, allocated bytes, top allocation sites, and churn findings when exportable
- Network: request count, failed requests, transferred bytes, top hosts, and network failure findings when HAR/CFNetwork data is available
- Prioritized Recommendations: deduplicated CPU and instrument recommendations sorted for review
Reports retain trace paths and include a cleanup reminder. Use cleanup_traces after the user is finished inspecting the trace in Instruments.app.
Example with Claude:
Start profiling MyApp for 60 seconds and report all issuestrack_running_app
Attach to a running process with xcrun xctrace record, save the generated .trace, and optionally analyze it immediately.
Parameters:
processName(optional): Running process name or pid to attach to; required for attach modetarget(optional):attach,launch, orall-processeslaunchCommand,launchArguments,environment(optional): launch target detailstemplate(optional): Instruments template, for exampleLeaks,Allocations,Network,Power Profiler, orTime Profiler(default:Leaks)durationSeconds(optional): Recording duration in seconds (default: 60)device(optional): Device or simulator name/UDIDoutputDirectory(optional): Directory where the.tracefile should be saved (default: configured trace root)outputPath(optional): Exact output.tracepath. OverridesoutputDirectoryanalyze(optional): Analyze after recording (default: true)openInInstruments(optional): Open the saved.tracein Instruments.app after recording (default: true). Set false for CI or headless runs.outputFormat(optional):markdown,json, orboth(default:markdown)
Example with Claude:
Track MyApp for leaks for 60 seconds on the iPhone 16 Pro SimulatorUse this tool when the user names a template. For broad profiling, prefer profile_running_app.
If Leaks, Allocations, or another analysis family is not_exportable, the trace may still show a GUI track in Instruments.app while xcrun export --toc exposes no exportable table schema. Use the opened Instruments trace to verify that GUI-only data.
The trace remains on disk after recording. Use cleanup_traces after the user is done inspecting it.
analyze_trace
Analyze a single trace file for performance issues. The server auto-detects supported Time Profiler, Memory, Network, Energy, Allocations, and Leaks data from the trace TOC.
Parameters:
tracePath(required): Path to .trace fileslowThreshold(optional): Threshold in ms for slow functions (default: 100)topN(optional): Number of top functions to show (default: 10)dsymPath(optional): dSYM file or directory. The server writes a temporary symbolicated trace before analysis.timeRangeMs(optional):{ startMs, endMs }trace-relative window in milliseconds. Use this for follow-up questions like "what ran during this 5 second hang?"userBinaryHints(optional): app or module names used when trace metadata cannot identify user binariesoutputFormat(optional):markdown,json, orboth
The report distinguishes data that is not present in the trace from data that is present but not exportable. A Time Profiler parse failure is reported as a failed CPU analysis with Export Diagnostics; do not read it as zero CPU work.
Scoped analysis filters Time Profiler samples before function aggregation and filters hang events that overlap the requested window. Top User-Code Frames walks each sample backtrace from leaf to root and aggregates the deepest frame whose module matches the trace's user process names or userBinaryHints.
Example with Claude:
Analyze /Users/me/app.trace and show me the performance bottlenecksThis tool does not record anything. It only reads trace files that already exist.
compare_traces
Compare two Time Profiler traces to detect regressions or improvements.
Parameters:
baselinePath(required): Path to baseline .trace filecurrentPath(required): Path to current .trace fileregressionThreshold(optional): % increase to flag (default: 10)failOnRegression(optional): Mark the MCP tool result as an error if a regression is detected (default: false)baselineDsymPath,currentDsymPath(optional): dSYM paths used to symbolicate temporary traces before comparisonoutputFormat(optional):markdown,json, orboth
Example with Claude:
Compare baseline.trace with current.trace and tell me if performance regressedThis comparison currently focuses on Time Profiler data. Additional instrument comparison is future work.
cleanup_traces
Preview or delete .trace bundles created by profiling runs.
Parameters:
tracePaths(optional): Exact.tracepaths to preview or delete. This is the preferred post-report cleanup path.directory(optional): Directory to scan whentracePathsis omitted (default: configured trace root)recursive(optional): Recursively scan subdirectories in directory mode (default: false)olderThanMinutes(optional): Only match traces older than this many minutes. Required for destructive directory cleanup.dryRun(optional): Preview only by default. Set false after the user confirms deletion.outputFormat(optional):markdown,json, orboth
Safety rules:
- Only paths ending in
.traceare deleted. dryRundefaults to true.dryRun: falsewith directory scanning requiresolderThanMinutes, unless exacttracePathsare provided.
Example with Claude:
Clean up the traces from the last profiling run.list_templates
List all available Instruments templates on the system.
Example with Claude:
What Instruments templates are available?list_devices
List available devices for profiling.
Example with Claude:
Show me available devices for profilingcheck_xctrace
Check if xctrace is available and report command capabilities, templates, devices, instruments, export modes, and warnings.
Example with Claude:
Is xctrace available on this system?Usage Examples
Full Profiling Report
You: Start profiling MyApp for 60 seconds and report all issues.
Claude: I'll record the full profiling preset and combine the results.
# Profiling Report
- Process: MyApp
- Preset: full
- Recording strategy: combined
- Duration: 60s
- Base template: Time Profiler
- Instruments: Leaks, Allocations, HTTP Traffic
## Summary
- Overall status: critical issues found
- Traces recorded: 1/1
- Traces analyzed: 1/1
## Trace Files
- Time Profiler: ~/Library/Application Support/xctrace-analyzer/traces/MyApp-full-...trace
## Prioritized Recommendations
- critical Leaks Analysis: Leaks detected - The trace contains leaked memory.Automated Leak Tracking
You: Track MyApp for memory leaks for 60 seconds.
Claude: I'll record the running app with the Leaks template and analyze the trace.
# Running App Trace Report
- Process: MyApp
- Template: Leaks
- Duration: 60s
- Trace: ~/Library/Application Support/xctrace-analyzer/traces/MyApp-Leaks-2026-05-02T16-30-00-000Z.trace
## Additional Instrument Analysis
### Leaks Analysis
3 leaks were detected.Manual Launch Recording
You: I will launch MyApp; record it for 60 seconds when it appears.
Claude: I'm watching for MyApp now; launch it when ready.
# Profiling Report
- Target: MyApp PID 12345, attached immediately after launch
- Duration: 60s
- Preset: full
- Trace: ~/Library/Application Support/xctrace-analyzer/traces/MyApp-full-...trace
- Instruments.app: openedBasic Analysis
You: Claude, analyze my latest performance trace at ~/traces/myapp.trace
Claude: I've analyzed your trace. Here's what I found:
# Performance Analysis Report
**Duration:** 5.2s
**Template:** Time Profiler
## Summary
⚠️ Found 1 critical performance issue.
Total execution time: 5.2s across 3 threads.
Primary bottleneck: ImageProcessor.resize() (450ms, 8.7% of time).
## Performance Bottlenecks
### 🔴 1. ImageProcessor.resize()
- **Impact:** critical
- **Duration:** 450ms (8.7% of total)
- **Call count:** 24
- **Suggestion:** Consider caching rendered images or using lower resolution
## Optimization Recommendations
### ⚠️ Implement Image Caching
**Priority:** high | **Type:** caching
Frequent image operations detected. Consider implementing NSCache
or disk-based caching to avoid repeated processing.
**Potential improvement:** 50-70% reduction in image processing time
**Example:**
```swift
let imageCache = NSCache<NSString, UIImage>()
func cachedImage(for key: String) -> UIImage? {
if let cached = imageCache.object(forKey: key as NSString) {
return cached
}
let image = processImage(key)
imageCache.setObject(image, forKey: key as NSString)
return image
}
### Comparing Traces
You: Compare my baseline trace with the current build. Baseline: ~/traces/v1.0.trace Current: ~/traces/v2.0.trace
Claude: I've compared the two traces. Here's the analysis:
Trace Comparison Report
Baseline: v1.0.trace Current: v2.0.trace
Summary
⚠️ Performance regressed by 15.3% (+0.65s slower). 🔴 Found 2 critical regressions.
Performance Delta
⚠️ Total time change: +0.65s (+15.3%)
- Regressions: 3
- Improvements: 2
- Unchanged: 15
Regressions
🔴 NetworkClient.parseJSON() (critical) 50ms → 85ms (+70%)
🟠 DatabaseManager.fetchAll() (major) 120ms → 180ms (+50%)
Improvements
✅ ImageProcessor.cache()* 200ms → 80ms (-60%)
The NetworkClient regression is concerning and should be investigated.
### Development Workflow
You: I just profiled my app. Analyze the latest trace and help me optimize.
Claude: Let me analyze the latest trace...
[Analyzes trace]
I found 3 optimization opportunities:
- 🎯 High Impact - ImageCache missing (save ~400ms)
- 🎯 Medium Impact - JSON parsing on main thread (save ~150ms)
- 🎯 Low Impact - Multiple small allocations (save ~50ms)
Would you like me to help implement any of these optimizations?
You: Yes, help with #1
Claude: Great! Let's implement image caching... [Provides implementation guidance]
## Requirements
- **macOS** with Xcode Command Line Tools installed
- **Node.js** 18+ (for running the MCP server)
- **Claude Desktop** or another MCP-compatible client
- Time Profiler, Memory, Network, Energy, Allocations, or Leaks `.trace` files. Exported table availability depends on Xcode and the trace template.
## How It Works
1. **MCP Request**: The client calls a JSON-RPC tool such as `profile_running_app`.
2. **Capability Check**: The server can inspect local `xctrace` version, templates, devices, instruments, export modes, and symbolication support.
3. **xctrace Record**: Recording tools call `xcrun xctrace record` with attach, launch, or all-processes targets.
4. **xctrace Export**: Analysis calls `xcrun xctrace export --toc`, TOC-discovered XPath table exports, and HAR export when available.
5. **XML / HAR Parsing**: The core parser normalizes Time Profiler rows and supported instrument tables into typed data with export diagnostics.
6. **Analysis Engine**: The analyzer finds bottlenecks, instrument findings, support status, and recommendations.
7. **MCP Response**: The server returns Markdown, JSON, or both.
## Troubleshooting
### xctrace not found
Make sure Xcode Command Line Tools are installed:
```bash
xcode-select --installPermission errors
The .trace files must be readable. Check file permissions:
ls -la /path/to/trace.traceNo supported data
The server reads supported tables from xcrun xctrace export --toc and uses HAR export for Network traces when available. If Xcode does not expose usable tables for a template, analysis may return a clear no-data section instead of findings.
pnpm/Corepack warnings
The root package.json pins pnpm through packageManager. Use Corepack or install pnpm 10.6.3:
corepack enable
pnpm install --frozen-lockfileServer not connecting
- Check Claude Desktop config file syntax (must be valid JSON)
- Verify the path to index.js is correct
- Restart Claude Desktop after config changes
Development
# Install dependencies
pnpm install
# Build
pnpm build
# Typecheck, test, and build
pnpm verify
# Start the built server, initialize MCP, and verify tools/list
pnpm test:mcp-smoke
# Inspect schemas exposed by local traces
pnpm inspect:trace test-traces/memory.trace
# Development with watch mode
pnpm dev:mcpArchitecture
MCP Client (Claude)
↓ JSON-RPC 2.0
MCP Server (this package)
↓
@xctrace-analyzer/core
↓
xcrun xctrace (macOS)License
MIT
Contributing
Contributions welcome! Please see the main repository README for guidelines.
