unity-profiler-mcp
by shin0112
README.md
# unity-profiler-mcp
MCP server for **analyzing saved Unity Profiler captures**. An AI client (Claude Code, etc.) can list captures, summarize frame times, find the most expensive main-thread markers, and compare groups of captures marker by marker (e.g. 3 runs of branch A vs 3 runs of branch B) — instead of reading Profiler screenshots by hand.
Two parts:
| Part | Path | Role |
| --- | --- | --- |
| MCP server (Node, stdio) | `server/` | Tools below; reads `.highlights` and exported marker JSON, computes summaries and comparisons |
| Unity bridge (UPM, Editor-only) | `unity-package/` | Local HTTP listener on `127.0.0.1` that loads a `.data` capture with `ProfilerDriver` and exports per-marker statistics |
`.data` captures can only be read by the Unity Editor, so marker statistics need the editor open. `profiler_summary` works without the editor (it reads the `.highlights` file the Profiler saves next to each capture).
## Tools
| Tool | Input | Result |
| --- | --- | --- |
| `profiler_list_captures` | `folder?` | captures with size, time, `hasHighlights`, `hasMarkers` |
| `profiler_summary` | `capture`, `folder?` | estimated CPU/GPU frame time (p50/p95/p99/max, % over 16.7 / 33.3 ms) and main-thread frame time if exported |
| `profiler_export` | `capture`, `folder?`, `force?` | editor exports `<capture>.data.markers.json` |
| `profiler_top_markers` | `capture`, `limit?`, `sortBy?` (`avg`,`p95`,`spikeAvg`,`selfAvg`,`gcBytesAvg`), `maxDepth?`, `contains?` | most expensive markers; exports first if needed |
| `profiler_compare` | `a[]`, `b[]`, `limit?`, `sortBy?` (`avg`,`p95`,`spikeAvg`), `maxDepth?`, `contains?` | per-marker group means, delta, run-to-run spread, `beyondSpread` flag |
`capture` is a file name inside the capture folder (with or without `.data`) or an absolute path. The capture folder defaults to `UNITY_PROFILER_CAPTURES`, then `<project>/ProfilerCaptures` of the open editor.
### Marker export
- Main thread only, samples merged by name, hierarchy depth ≤ 8, markers averaging under 0.005 ms dropped.
- Per marker: frames present, total ms `avg` / `p50` / `p95` / `max`, `spikeAvg` (average over the slowest 5% of frames), `selfAvg`, `callsAvg`, `gcBytesAvg`.
- Exporting loads the capture into the Profiler window (replacing what is shown) and blocks the editor while it runs; large captures take a while. Results are cached next to the capture.
### `.highlights`
The frame-time series are decoded from the `.highlights` file the Profiler writes on save. The layout is undocumented; series 0/1 are assumed to be CPU/GPU frame time and are labelled `cpuMsEstimated` / `gpuMsEstimated`. Check them against the Profiler's Highlights module before relying on them.
## Install
### 1. Unity package
Add to `Packages/manifest.json`:
```json
"com.shin0112.unity-profiler-mcp": "https://github.com/shin0112/unity-profiler-mcp.git?path=/unity-package"
```
or, for a local clone:
```json
"com.shin0112.unity-profiler-mcp": "file:C:/projects/unity-profiler-mcp/unity-package"
```
Menu: `Tools > Unity Profiler MCP > Status / Enable Bridge / Disable Bridge`.
### 2. MCP server (Claude Code)
From GitHub:
```bash
claude mcp add unity-profiler -- npx -y github:shin0112/unity-profiler-mcp
```
From a local clone:
```bash
cd C:/projects/unity-profiler-mcp && npm install
claude mcp add unity-profiler -- node C:/projects/unity-profiler-mcp/server/index.js
```
## Configuration
| Setting | Where | Default |
| --- | --- | --- |
| Port | EditorPrefs `Shin0112.UnityProfilerMcp.Port` (editor) and env `UNITY_PROFILER_PORT` (server) — keep them equal | `17891` |
| Capture folder | env `UNITY_PROFILER_CAPTURES` or tool `folder` | `<project>/ProfilerCaptures` |
| Export timeout | env `UNITY_PROFILER_EXPORT_TIMEOUT_MS` (server); the bridge waits up to 15 min | `900000` |
## Recording captures that compare well
- Development Build, Deep Profile and allocation call stacks off.
- Same scene, spawner, unit count and camera position for every run; record after the scene settles (e.g. 300+ frames).
- Several runs per variant, so `profiler_compare` can separate real differences from run-to-run noise.
- Emulators and the Editor are fine for relative comparison only; confirm absolute numbers on a target device.
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues