DEV Community

Cover image for react-render-profile-mcp v0.3.1 - 4 new diagnostic tools for React Compiler, hydration, Zustand, and state cascades
Albert Alov
Albert Alov

Posted on

react-render-profile-mcp v0.3.1 - 4 new diagnostic tools for React Compiler, hydration, Zustand, and state cascades

A few weeks ago I published a post about react-render-profile-mcp — an MCP server that decodes React DevTools Profiler exports so AI agents can actually diagnose render performance instead of guessing at raw fiber IDs.

v0.1 shipped with 5 tools. v0.3.1 adds 4 more, each targeting a class of problems the original couldn't touch. Here's what's new. 🐸


What was already there (v0.1)

Quick recap for anyone who missed the first post:

  • get_render_summary — total commits, render time, top components, lifecycle anomaly flags
  • find_spurious_renders — components that re-rendered with no actual prop/state change
  • get_hottest_components — ranked by CPU self-time
  • trace_render_cascade — what triggered a commit and what re-rendered as a result
  • suggest_memoization — ROI-scored React.memo recommendations

These covered the "something is rendering too much" class of problems. What they couldn't tell you: why your React Compiler isn't helping, where hydration broke, which Zustand selector is in a loop, or how deep a context update actually propagates.


What's new in v0.3.1

1. analyze_compiler_efficacy

React Compiler (React 19) and manual React.memo should eliminate spurious renders. Often they don't — because of inline object allocations or unstable parent refs that bypass memoization entirely.

This tool computes an Invalidation Index per component:

I = (spurious_count / total_count) × wasted_ms
Enter fullscreen mode Exit fullscreen mode

High index = memoization is present but not working. The tool tells you exactly why:

{
  "severity": "CRITICAL",
  "component_name": "ProductList",
  "ineffective_render_count": 23,
  "wasted_ms": 84.3,
  "trigger_cause": "UNSTABLE_PARENT_PROP_REFERENCE",
  "recommendation": "Memoize parent props with useMemo/useCallback or hoist static objects out of the parent render function."
}
Enter fullscreen mode Exit fullscreen mode

Without this, your agent might suggest adding React.memo to a component that already has it — and has it for a reason that makes it useless.


2. diagnose_hydration_and_suspense

Two separate problems, one tool:

Hydration mismatches — when React discards server HTML and remounts the entire tree from scratch. Shows up as an abnormally long initial mount with a spike of unmounts immediately after. The tool flags these as HYDRATION_MISMATCH_RECOVERY with the affected Suspense boundaries and blocking duration.

Suspense waterfalls — nested boundaries fetching sequentially instead of in parallel. Detected by measuring the gap between consecutive Suspense resolves against a configurable waterfall_threshold_ms (default: 100ms).

{
  "severity": "WARNING",
  "anomaly_type": "NESTED_MOUNT_FETCH_WATERFALL",
  "root_component": "ProfileDetails",
  "blocking_duration_ms": 120.5,
  "recommendation": "Prefetch data at the parent level or use Promise.all."
}
Enter fullscreen mode Exit fullscreen mode

3. evaluate_external_store_performance

Zustand and Redux with useSyncExternalStore have two failure modes that are hard to catch manually:

Unstable selector object allocation — a selector returns a new object reference every call, triggering rapid consecutive renders. The tool detects components that render multiple times in consecutive frames and flags the selector as the cause.

Sync concurrency bypass — a heavy store update runs synchronously in a high-priority lane, blocking the main thread. Should be in startTransition instead.

{
  "severity": "CRITICAL",
  "impacted_components": ["CartSummary"],
  "is_infinite_loop": true,
  "trigger_cause": "UNSTABLE_SELECTOR_OBJECT_ALLOCATION",
  "recommendation": "Wrap the selector in useCallback or return primitive values."
}
Enter fullscreen mode Exit fullscreen mode

4. trace_state_cascade_footprint

Given a commit index, this reconstructs the virtual component tree and measures how far an update actually propagated:

  • Which component triggered the update
  • Whether it went through a context provider or a store subscriber
  • How many levels deep it reached
  • How many consumer components re-rendered
{
  "severity": "HIGH_FOOTPRINT",
  "update_trigger_source": "ThemeButton",
  "propagation_channel": "CONTEXT_PROVIDER",
  "cascade_render_depth": 7,
  "rendered_consumer_count": 28,
  "recommendation": "Split the context provider or memoize its value and children."
}
Enter fullscreen mode Exit fullscreen mode

This is the tool that answers "why did 28 components re-render when I clicked one button."


Updated: find_spurious_renders trigger classification

The existing tool now classifies why a render was spurious, not just that it was:

  • UNSTABLE_PARENT_REF — parent passed a new object/array/function reference with identical values
  • CONTEXT_UPDATE — context changed, but this component doesn't actually use the changed value
  • INTENTIONAL_CONCURRENT_YIELD — React's scheduler, not a bug

This matters because React.memo fixes the first case but can't help with the second. The recommendation now reflects the correct fix path.


Recommended agent workflow (updated)

1. get_render_summary              → overview + lifecycle_anomaly flags
2. find_spurious_renders           → classify unnecessary renders by trigger type
3. analyze_compiler_efficacy       → check where React.memo / Compiler is being bypassed
4. diagnose_hydration_and_suspense → catch hydration recovery + Suspense waterfalls
5. evaluate_external_store_performance → Zustand/Redux selector loops + sync bypasses
6. trace_state_cascade_footprint   → propagation depth for expensive commits
7. suggest_memoization             → ROI-scored final recommendations
Enter fullscreen mode Exit fullscreen mode

Setup (unchanged)

{
  "mcpServers": {
    "react-render-profile": {
      "command": "npx",
      "args": ["-y", "react-render-profile-mcp"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Export a profile from React DevTools → Profiler tab → Record → Save. Pass the .json path as profile_path to any tool.

npm: react-render-profile-mcp
GitHub: vola-trebla/react-render-profile-mcp


Happy to answer questions about the hydration detection heuristics or the Invalidation Index math. And if you're hitting a React performance pattern this doesn't cover yet — open an issue. 🐸

Top comments (0)