react-profiler-mcp
README.md
<div align="center">
# react-profiler-mcp
**Give your AI agent real React performance data. Get specific fixes, not guesses.**
[](https://github.com/YOUR_USERNAME/react-profiler-mcp/actions)
[](https://www.npmjs.com/package/@react-profiler-mcp/react-collector)
[](https://www.npmjs.com/package/@react-profiler-mcp/mcp-server)
[](LICENSE)
[](https://modelcontextprotocol.io)
<br />
```
"Which components are making my app slow, and how do I fix them?"
```
*— a question your AI agent can now answer with real data*
</div>
---
## 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
```bash
npm install @react-profiler-mcp/react-collector
```
### 2. Wrap your app
```tsx
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`:
```json
{
"mcpServers": {
"react-profiler": {
"command": "npx",
"args": ["-y", "@react-profiler-mcp/mcp-server"]
}
}
}
```
<details>
<summary>Claude Desktop</summary>
`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or
`%APPDATA%\Claude\claude_desktop_config.json` (Windows):
```json
{
"mcpServers": {
"react-profiler": {
"command": "npx",
"args": ["-y", "@react-profiler-mcp/mcp-server"]
}
}
}
```
</details>
<details>
<summary>Gemini CLI</summary>
`~/.gemini/settings.json`:
```json
{
"mcpServers": {
"react-profiler": {
"command": "npx",
"args": ["-y", "@react-profiler-mcp/mcp-server"]
}
}
}
```
</details>
### 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:
```tsx
'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`:
```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](docs/MCP_USAGE.md)).
**Quick check** — the process logs the ingest URL on **stderr** (stdout is reserved for MCP when an editor spawns it):
```bash
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` | [](https://npmjs.com/package/@react-profiler-mcp/react-collector) | React component — goes in your UI bundle |
| `@react-profiler-mcp/mcp-server` | [](https://npmjs.com/package/@react-profiler-mcp/mcp-server) | Local server — HTTP ingest + MCP stdio |
---
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md). Issues and PRs welcome.
To run locally:
```bash
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:
```bash
npm run dev -w @react-profiler-mcp/demo
```
Full contributor guide: [docs/LOCAL_DEVELOPMENT.md](docs/LOCAL_DEVELOPMENT.md)
---
## License
MIT — see [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues