React DevTools Profiler gives you all the data you need to fix re-renders. Your AI agent can't read it. Here's how to fix that with an MCP server.
You open React DevTools Profiler, record a session, and export the .json file. It's got everything: which components re-rendered, how long each one took, which props changed, which hooks fired.
Then you paste it into Claude or Cursor and ask: "What's causing the performance problem?"
The agent stares at raw JSON — thousands of lines of fiber IDs, opcode arrays, and microsecond timestamps — and does its best. But it's reading tea leaves. It doesn't know what a "spurious render" is in this format. It can't decode the operations integer array. It doesn't know that props: [] means a component re-rendered even though no props actually changed.
That's the gap react-render-profile-mcp fills. 🔍
🤔 What the profiler actually exports
React DevTools serializes profiler data in a specific binary-ish format that most developers have never had to parse manually:
{
"version": 5,
"dataForRoots": [{
"commitData": [{
"changeDescriptions": [[3, {"isFirstMount": true, "props": null}], [4, {...}]],
"fiberActualDurations": [[3, 15.2], [4, 8.1]],
"fiberSelfDurations": [[3, 3.9], [4, 4.9]],
"duration": 15.2,
"timestamp": 100.0
}],
"snapshots": [[3, {"displayName": "App", "children": [4, 5]}]],
"operations": [1, 0, 3, 2, 65, 112, 112, ...]
}]
}
A few non-obvious things buried in there:
⚠️ changeDescriptions is an array of pairs, not an object. It's serialized as Map.entries() — [[fiberID, desc], ...]. If you parse it naively as JSON object keys, you'll get garbage.
⚠️ props: [] means spurious render. An empty array means the component re-rendered but zero prop keys actually changed — the reference was unstable. props: null means unknown. props: ["value"] means the value prop genuinely changed.
⚠️ operations is an opcode array. It encodes tree mutations (mount, unmount, reorder) with a string table at the start. You need to decode it to map fiber IDs to component names when snapshots aren't present.
⚠️ fiberSelfDuration ≠ fiberActualDuration. Self = time in this component only. Actual = self + children. For finding hotspots, you want self time.
The MCP server handles all of this so the agent doesn't have to.
🛠️ The 5 tools
get_render_summary
High-level overview of the entire recording:
Total commits: 12
Total render time: 847.3ms
Spurious renders: 8
Top components by self time:
ProductList — 312.4ms (6 renders)
SearchInput — 89.1ms (12 renders)
Sidebar — 44.2ms (3 renders)
find_spurious_renders
Detects components that re-rendered but had no actual prop or state changes:
Spurious renders found:
ProductList — 6 spurious renders, 312.4ms wasted
→ props ref changed but no keys differed
This is the classic "missing React.memo" pattern. The component re-renders every time a parent renders, even though nothing it depends on changed.
get_hottest_components
Components ranked by total self time across all commits. Useful for finding where to optimize first.
trace_render_cascade
Given a commit index, shows what triggered it and what else re-rendered as a result:
Commit 3 — triggered by: SearchInput (hook changed)
Cascade:
ProductList — re-rendered (unstable props)
Sidebar — re-rendered (context changed)
This is how you find the root cause instead of just the symptom.
suggest_memoization
Combines spurious render detection with self-time data to generate specific recommendations:
Suggestions:
ProductList → React.memo
Reason: 6 spurious renders, 312.4ms wasted
Self time: 52.1ms avg per render
⚡ Setup
{
"mcpServers": {
"react-render-profile": {
"command": "npx",
"args": ["-y", "react-render-profile-mcp"]
}
}
}
Then record a session in React DevTools → Profiler → export as JSON → give the file path to your agent.
🚀 The workflow
Instead of pasting raw JSON and hoping:
"Load the profile at
/tmp/myapp.profile.jsonand find spurious renders"
The agent calls find_spurious_renders with the file path, gets back structured data with component names, counts, and wasted milliseconds — and gives you a concrete list of what to fix.
"Load the profile and trace what caused the slow commit at index 3"
trace_render_cascade returns the trigger component, the cascade, and the reason for each re-render.
The agent goes from "I see some fiber IDs with large durations" to "ProductList is re-rendering 6 times spuriously, wrapping it in React.memo would save 312ms."
📦 Links
- npm: npmjs.com/package/react-render-profile-mcp
- GitHub: github.com/vola-trebla/react-render-profile-mcp
npx react-render-profile-mcp
Top comments (0)