Skip to content

Repository files navigation

react-profiler-mcp

Give your AI agent real React performance data. Get specific fixes, not guesses.

CI npm collector npm server License: MIT MCP Compatible


"Which components are making my app slow, and how do I fix them?"

— a question your AI agent can now answer with real data


The problem

React DevTools Profiler gives you raw render timings. But staring at a flame graph and knowing exactly what to change in your code are two different things. Most developers either ignore the data or spend hours guessing.

react-profiler-mcp streams live profiler data from your app directly to your AI agent — so instead of a flame graph you can't read, you get this:

ProductList re-renders 47× on this page, averaging 68ms per render.

The root cause is onAddToCart being recreated on every parent render,
which breaks React.memo() on the child. Fix:

  const onAddToCart = useCallback((id) => {
    dispatch({ type: 'ADD', id });
  }, [dispatch]);

That alone should drop renders from 47 to 3.

How it works

Your React app                      AI agent
─────────────────                   ────────────────────────
<ProfilerBridge>    →  POST  →    HTTP ingest (:8787)
  records every                          │
  render commit                    in-memory store
                                         │
                                   MCP stdio server
                                         │
                              "analyze_performance" tool
                                         │
                              Cursor / Claude / Copilot
                              reads real samples and
                              gives you targeted fixes

One local Node process handles both sides. The browser POSTs render samples over loopback; your editor connects to the same process over MCP stdio.


Works with any MCP-compatible agent

Editor / Agent Setup
Cursor Add to .cursor/mcp.json
Claude Desktop Add to claude_desktop_config.json
Windsurf Add to MCP settings
GitHub Copilot (VS Code) Add to .vscode/mcp.json
Gemini CLI Add to ~/.gemini/settings.json
Any MCP client Same config, same server

Quickstart

1. Install the collector

npm install @react-profiler-mcp/react-collector

2. Wrap your app

import { ProfilerBridge } from '@react-profiler-mcp/react-collector';

export function App() {
  return (
    <ProfilerBridge
      ingestUrl="http://127.0.0.1:8787/v1/profile-samples"
      sessionId="my-app"
      profilerId="main-shell"
    >
      <YourApp />
    </ProfilerBridge>
  );
}

3. Add the MCP server to your editor

Cursor / Windsurf / VS Code — add to your project's .cursor/mcp.json or .vscode/mcp.json:

{
  "mcpServers": {
    "react-profiler": {
      "command": "npx",
      "args": ["-y", "@react-profiler-mcp/mcp-server"]
    }
  }
}
Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "react-profiler": {
      "command": "npx",
      "args": ["-y", "@react-profiler-mcp/mcp-server"]
    }
  }
}
Gemini CLI

~/.gemini/settings.json:

{
  "mcpServers": {
    "react-profiler": {
      "command": "npx",
      "args": ["-y", "@react-profiler-mcp/mcp-server"]
    }
  }
}

4. Use your app, then ask

Open your React app and interact with it normally for 30–60 seconds. Then in your AI agent's chat:

Analyze my React app's performance. Which components are
the worst offenders and what exactly should I change?

The agent calls the profiler tools, reads the real samples from your session, and gives you specific fixes — component names, line-level suggestions, and why each change helps.


Next.js

ProfilerBridge uses client hooks. Keep it inside a Client Component:

'use client';

import { ProfilerBridge } from '@react-profiler-mcp/react-collector';

const ingestUrl =
  process.env.NEXT_PUBLIC_PROFILER_INGEST_URL ?? 'http://127.0.0.1:8787/v1/profile-samples';

export default function Page() {
  return (
    <ProfilerBridge ingestUrl={ingestUrl} sessionId="my-next-app" profilerId="page-root">
      {/* page content */}
    </ProfilerBridge>
  );
}

Add to next.config.js:

const nextConfig = {
  transpilePackages: ['@react-profiler-mcp/react-collector'],
};
export default nextConfig;

ProfilerBridge props

Prop Type Default Description
ingestUrl string Required. Full URL to POST samples to.
sessionId string (omit) If set, sent as X-React-Profiler-Session. If omitted, the server stores samples under default — match that in MCP tools like session_summary, or set a custom id here and pass the same string as sessionId in tools.
profilerId string "react-profiler-mcp-root" React <Profiler id={...}>. Becomes componentName in ingest/MCP. Prefer distinct ids per subtree you care about ("checkout-form", "data-table").
enabled boolean true Set false to disable profiling and HTTP traffic (e.g. production).

MCP tools

The agent can call these tools once connected (names match the server in packages/mcp-server/src/mcp/server.ts):

Tool What it returns
list_sessions All ingest buckets: sessionId, counts, timestamps
get_profiler_data Raw sample tail (ids, phases, durations); optional sessionId defaults to most recently updated session
get_component_summary Per Profiler id (profilerId) stats, sortable
get_slow_renders Renders over thresholdMs (default 16ms)
analyze_performance Composite report: offenders, re-renders, heuristic suggestions
clear_data Clears all in-memory sessions
session_summary Aggregate stats for one session (sessionId defaults to default if omitted)
list_recent_samples Recent raw rows for citations
explain_jank Heuristic jank signals over a time window
suggest_fixes Ranked remediation ideas tied to captured labels

⚠️ One process rule

Run either a manually started server or the one your editor spawns — not both. Two processes means two separate in-memory stores. MCP will connect to one; the browser posts to the other. Data never meets.

stdio MCP: Your editor usually spawns the server (npx / node …) and owns stdin/stdout for the protocol. You generally do not attach MCP to a server you already started in a separate terminal (that process’s stdio is tied to the shell). For logs, rely on stderr from the editor-spawned process, or run a second terminal only for HTTP debugging (accepting that MCP in the editor will use a different store unless you use a single process — see docs/MCP_USAGE.md).

Quick check — the process logs the ingest URL on stderr (stdout is reserved for MCP when an editor spawns it):

npx -y @react-profiler-mcp/mcp-server

Notes

  • Production: React’s <Profiler> still runs onRender in normal production builds (with some overhead). For shipped apps, set enabled={false} (or omit ProfilerBridge) unless you deliberately want field metrics.
  • In-memory store. Data resets when the server restarts. This is intentional — it's a dev tool, not a database.
  • Loopback only. The ingest listener binds to 127.0.0.1 (see packages/mcp-server/src/index.ts). Override port with env PORT; do not expose the port publicly.

Packages

Package npm Description
@react-profiler-mcp/react-collector npm React component — goes in your UI bundle
@react-profiler-mcp/mcp-server npm Local server — HTTP ingest + MCP stdio

Contributing

See CONTRIBUTING.md. Issues and PRs welcome.

To run locally:

git clone https://github.com/YOUR_USERNAME/react-profiler-mcp.git
cd react-profiler-mcp
npm install
npm run build
node packages/mcp-server/dist/index.js

Then in another terminal:

npm run dev -w @react-profiler-mcp/demo

Full contributor guide: docs/LOCAL_DEVELOPMENT.md


License

MIT — see LICENSE.

About

Bridge React’s Profiler API to Model Context Protocol (MCP): a local companion server + browser collector so agents answer performance questions from real render data.

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages