Give your AI agent real React performance data. Get specific fixes, not guesses.
"Which components are making my app slow, and how do I fix them?"
— a question your AI agent can now answer with real data
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.
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.
| 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 |
npm install @react-profiler-mcp/react-collectorimport { 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>
);
}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"]
}
}
}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.
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;| 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). |
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 |
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- Production: React’s
<Profiler>still runsonRenderin normal production builds (with some overhead). For shipped apps, setenabled={false}(or omitProfilerBridge) 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(seepackages/mcp-server/src/index.ts). Override port with envPORT; do not expose the port publicly.
| Package | npm | Description |
|---|---|---|
@react-profiler-mcp/react-collector |
React component — goes in your UI bundle | |
@react-profiler-mcp/mcp-server |
Local server — HTTP ingest + MCP stdio |
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.jsThen in another terminal:
npm run dev -w @react-profiler-mcp/demoFull contributor guide: docs/LOCAL_DEVELOPMENT.md
MIT — see LICENSE.