@perfonext/render-mcp 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +91 -27
  2. package/dist/index.js +9 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/ingest/server.d.ts +54 -0
  5. package/dist/ingest/server.d.ts.map +1 -0
  6. package/dist/ingest/server.js +212 -0
  7. package/dist/ingest/server.js.map +1 -0
  8. package/dist/parser/analysis.d.ts +4 -0
  9. package/dist/parser/analysis.d.ts.map +1 -1
  10. package/dist/parser/analysis.js +71 -6
  11. package/dist/parser/analysis.js.map +1 -1
  12. package/dist/parser/react-profile.d.ts.map +1 -1
  13. package/dist/parser/react-profile.js +1 -0
  14. package/dist/parser/react-profile.js.map +1 -1
  15. package/dist/parser/react-scan-lite.d.ts +8 -0
  16. package/dist/parser/react-scan-lite.d.ts.map +1 -0
  17. package/dist/parser/react-scan-lite.js +173 -0
  18. package/dist/parser/react-scan-lite.js.map +1 -0
  19. package/dist/parser/types.d.ts +23 -0
  20. package/dist/parser/types.d.ts.map +1 -1
  21. package/dist/tools/begin-render-analysis.d.ts +3 -0
  22. package/dist/tools/begin-render-analysis.d.ts.map +1 -0
  23. package/dist/tools/begin-render-analysis.js +69 -0
  24. package/dist/tools/begin-render-analysis.js.map +1 -0
  25. package/dist/tools/get-captured-renders.d.ts +3 -0
  26. package/dist/tools/get-captured-renders.d.ts.map +1 -0
  27. package/dist/tools/get-captured-renders.js +77 -0
  28. package/dist/tools/get-captured-renders.js.map +1 -0
  29. package/dist/tools/get-rerender-causes.d.ts.map +1 -1
  30. package/dist/tools/get-rerender-causes.js +8 -13
  31. package/dist/tools/get-rerender-causes.js.map +1 -1
  32. package/dist/tools/load-render-profile.d.ts.map +1 -1
  33. package/dist/tools/load-render-profile.js +3 -1
  34. package/dist/tools/load-render-profile.js.map +1 -1
  35. package/dist/tools/run-render-capture.d.ts +3 -0
  36. package/dist/tools/run-render-capture.d.ts.map +1 -0
  37. package/dist/tools/run-render-capture.js +61 -0
  38. package/dist/tools/run-render-capture.js.map +1 -0
  39. package/dist/tools/stop-render-capture.d.ts +3 -0
  40. package/dist/tools/stop-render-capture.d.ts.map +1 -0
  41. package/dist/tools/stop-render-capture.js +63 -0
  42. package/dist/tools/stop-render-capture.js.map +1 -0
  43. package/package.json +1 -1
@@ -0,0 +1,69 @@
1
+ import { z } from 'zod';
2
+ import { createCaptureSession } from '../ingest/server.js';
3
+ export function registerBeginRenderAnalysis(server) {
4
+ server.registerTool('begin_render_analysis', {
5
+ title: 'Begin Render Analysis',
6
+ description: 'Entry point for render profiling. Choose an approach:\n' +
7
+ ' live — react-scan/lite streams events in real time; exact rerender causes, source locations, changeDescription.\n' +
8
+ ' manual — no install needed; user exports a JSON from the React DevTools Profiler tab and shares the file path.\n' +
9
+ 'Ask the user which approach they prefer before calling this tool.',
10
+ inputSchema: {
11
+ approach: z
12
+ .enum(['live', 'manual'])
13
+ .describe('"live": react-scan/lite live capture (richer data, needs npm install). ' +
14
+ '"manual": React DevTools Profiler JSON export (no install, less detailed).'),
15
+ },
16
+ }, async ({ approach }) => {
17
+ if (approach === 'live') {
18
+ const session = await createCaptureSession();
19
+ const snippet = [
20
+ `import { instrument } from "react-scan/lite";`,
21
+ `instrument({`,
22
+ ` endpoint: "${session.endpoint}",`,
23
+ ` sessionId: "${session.sessionId}",`,
24
+ ` recordChangeDescriptions: true,`,
25
+ ` includeFiberSource: true,`,
26
+ ` includeFiberIdentity: true,`,
27
+ `});`,
28
+ ].join('\n');
29
+ const result = {
30
+ approach: 'live',
31
+ sessionId: session.sessionId,
32
+ endpoint: session.endpoint,
33
+ snippet,
34
+ snippetFile: 'instrumentation-client.js',
35
+ setup: [
36
+ '1. npm install --save-dev react-scan',
37
+ '2. Create (or overwrite) instrumentation-client.js at your project root with the content in `snippet`.',
38
+ ' The ingest server runs on a fixed port (7721 by default), so only the sessionId line changes between runs.',
39
+ '3. Import it from your app\'s client-side entry point (e.g. _app.tsx, root layout, main.tsx)',
40
+ ' — inspect the project structure to find the right file.',
41
+ ' The import must run on the client (add "use client" if the entry is a Server Component).',
42
+ ].join('\n'),
43
+ nextStep: `run_render_capture({ sessionId: "${session.sessionId}", method: <ask the user> })`,
44
+ };
45
+ return {
46
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
47
+ };
48
+ }
49
+ // manual path — no session created
50
+ const result = {
51
+ approach: 'manual',
52
+ setup: [
53
+ '1. Install the React DevTools browser extension if not already (Chrome/Firefox/Edge).',
54
+ '2. Run your app (next dev or next start).',
55
+ '3. Open browser DevTools → React DevTools panel → "Profiler" tab.',
56
+ '4. Click the Record button (filled circle ●) to start profiling.',
57
+ '5. Interact with your app — navigate pages, trigger state changes, etc.',
58
+ '6. Click the Stop button (■) to end the recording.',
59
+ '7. Click the Export icon (download arrow ↓ in the top-right of the Profiler panel) and save the JSON file.',
60
+ '8. Share the saved file path — Copilot will call load_render_profile to load it.',
61
+ ].join('\n'),
62
+ nextStep: 'load_render_profile({ filePath: "<path-to-exported-json>" })',
63
+ };
64
+ return {
65
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
66
+ };
67
+ });
68
+ }
69
+ //# sourceMappingURL=begin-render-analysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"begin-render-analysis.js","sourceRoot":"","sources":["../../src/tools/begin-render-analysis.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,MAAM,UAAU,2BAA2B,CAAC,MAAiB;IAC3D,MAAM,CAAC,YAAY,CAAC,uBAAuB,EAAE;QAC3C,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EACT,yDAAyD;YACzD,uHAAuH;YACvH,oHAAoH;YACpH,mEAAmE;QACrE,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC;iBACR,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;iBACxB,QAAQ,CACP,yEAAyE;gBACzE,4EAA4E,CAC7E;SACJ;KACF,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACxB,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,MAAM,oBAAoB,EAAE,CAAC;YAE7C,MAAM,OAAO,GAAG;gBACd,+CAA+C;gBAC/C,cAAc;gBACd,gBAAgB,OAAO,CAAC,QAAQ,IAAI;gBACpC,iBAAiB,OAAO,CAAC,SAAS,IAAI;gBACtC,mCAAmC;gBACnC,6BAA6B;gBAC7B,+BAA+B;gBAC/B,KAAK;aACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEb,MAAM,MAAM,GAAG;gBACb,QAAQ,EAAE,MAAM;gBAChB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,OAAO;gBACP,WAAW,EAAE,2BAA2B;gBACxC,KAAK,EAAE;oBACL,sCAAsC;oBACtC,wGAAwG;oBACxG,+GAA+G;oBAC/G,8FAA8F;oBAC9F,4DAA4D;oBAC5D,6FAA6F;iBAC9F,CAAC,IAAI,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,oCAAoC,OAAO,CAAC,SAAS,8BAA8B;aAC9F,CAAC;YAEF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAED,mCAAmC;QACnC,MAAM,MAAM,GAAG;YACb,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE;gBACL,uFAAuF;gBACvF,2CAA2C;gBAC3C,mEAAmE;gBACnE,kEAAkE;gBAClE,yEAAyE;gBACzE,oDAAoD;gBACpD,4GAA4G;gBAC5G,kFAAkF;aACnF,CAAC,IAAI,CAAC,IAAI,CAAC;YACZ,QAAQ,EAAE,8DAA8D;SACzE,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC5E,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerGetCapturedRenders(server: McpServer): void;
3
+ //# sourceMappingURL=get-captured-renders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-captured-renders.d.ts","sourceRoot":"","sources":["../../src/tools/get-captured-renders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+ElE"}
@@ -0,0 +1,77 @@
1
+ import { z } from 'zod';
2
+ import { getCaptureSession } from '../ingest/server.js';
3
+ export function registerGetCapturedRenders(server) {
4
+ server.registerTool('get_captured_renders', {
5
+ title: 'Get Captured Renders',
6
+ description: 'Optional diagnostic: peek at the live progress of a render-capture session without stopping it. ' +
7
+ 'Returns commit count, components seen, whether actualDuration is populating, and an unknownEvents ' +
8
+ 'count (non-zero = instrumentation may not be wired correctly). ' +
9
+ 'Only call this if something seems wrong — it is not a required step before stop_render_capture.',
10
+ inputSchema: {
11
+ sessionId: z.string().describe('The sessionId returned by start_render_capture'),
12
+ },
13
+ }, async ({ sessionId }) => {
14
+ const session = getCaptureSession(sessionId);
15
+ if (!session) {
16
+ return {
17
+ content: [{ type: 'text', text: JSON.stringify({ error: `Session "${sessionId}" not found` }, null, 2) }],
18
+ isError: true,
19
+ };
20
+ }
21
+ const commitCount = session.commits.length;
22
+ const unknownEvents = session.unknownEvents;
23
+ const componentsSeen = new Set();
24
+ let hasActualDuration = false;
25
+ for (const commit of session.commits) {
26
+ for (const fiber of commit.fibers ?? []) {
27
+ if (fiber.name)
28
+ componentsSeen.add(fiber.name);
29
+ if ((fiber.actualDuration ?? 0) > 0)
30
+ hasActualDuration = true;
31
+ }
32
+ }
33
+ // Summarize the top components by total actualDuration so the agent can
34
+ // see which components are hot without stopping the session.
35
+ const durationByComponent = new Map();
36
+ for (const commit of session.commits) {
37
+ for (const fiber of commit.fibers ?? []) {
38
+ const name = fiber.name ?? `(fiber:${fiber.fiberId})`;
39
+ durationByComponent.set(name, (durationByComponent.get(name) ?? 0) + (fiber.actualDuration ?? 0));
40
+ }
41
+ }
42
+ const topComponents = Array.from(durationByComponent.entries())
43
+ .sort((a, b) => b[1] - a[1])
44
+ .slice(0, 10)
45
+ .map(([componentName, totalActualDuration]) => ({ componentName, totalActualDuration }));
46
+ let profilingStatus;
47
+ if (session.profilingAvailable === null) {
48
+ profilingStatus = 'unknown (no profiling-hooks-status event received yet)';
49
+ }
50
+ else if (session.profilingAvailable) {
51
+ profilingStatus = 'available';
52
+ }
53
+ else {
54
+ profilingStatus = 'unavailable — app may be running a production build; switch to `next dev`';
55
+ }
56
+ const diagnosis = unknownEvents > 0 && commitCount === 0
57
+ ? `${unknownEvents} unrecognized POST(s) received — the instrumentation snippet may not be imported correctly, or it is running server-side. Check that the import is in a client-side entry point and the file path is correct.`
58
+ : null;
59
+ const result = {
60
+ sessionId,
61
+ status: session.status,
62
+ commitCount,
63
+ componentCount: componentsSeen.size,
64
+ hasActualDuration,
65
+ profilingStatus,
66
+ ...(diagnosis ? { diagnosis } : {}),
67
+ topComponents,
68
+ nextStep: session.status === 'active'
69
+ ? `call stop_render_capture({ sessionId: "${sessionId}" }) when you are done`
70
+ : `session is stopped — call stop_render_capture({ sessionId: "${sessionId}" }) to finalize`,
71
+ };
72
+ return {
73
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
74
+ };
75
+ });
76
+ }
77
+ //# sourceMappingURL=get-captured-renders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-captured-renders.js","sourceRoot":"","sources":["../../src/tools/get-captured-renders.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"get-rerender-causes.d.ts","sourceRoot":"","sources":["../../src/tools/get-rerender-causes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8CjE"}
1
+ {"version":3,"file":"get-rerender-causes.d.ts","sourceRoot":"","sources":["../../src/tools/get-rerender-causes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0CjE"}
@@ -21,25 +21,20 @@ export function registerGetRerenderCauses(server) {
21
21
  score: Number(cause.score.toFixed(1)),
22
22
  totalActualDuration: formatMs(cause.totalActualDuration),
23
23
  }));
24
+ const dataQuality = profile.hasChangeDescriptions ? 'exact' : 'heuristic';
25
+ const qualityNote = profile.hasChangeDescriptions
26
+ ? 'Causes are based on exact prop/state changeDescription data from react-scan/lite.'
27
+ : 'Causes are heuristic — no prop/state diff data available. Run live capture (begin_render_analysis, approach: live) in a real browser to get exact change descriptions.';
24
28
  return {
25
29
  content: [{
26
30
  type: 'text',
27
31
  text: JSON.stringify({
28
32
  profileId,
29
- note: 'Rerender causes are heuristic because exported React Profiler JSON does not include direct prop/state diff metadata.',
33
+ dataQuality,
34
+ note: qualityNote,
30
35
  scoreDocumentation: {
31
- meaning: '0-10 heuristic rerender risk score. Higher means stronger evidence that repeated rerenders are worth investigating.',
32
- thresholds: {
33
- low: '0.0-2.9',
34
- medium: '3.0-5.9',
35
- high: '6.0-10.0',
36
- },
37
- factors: [
38
- 'Repeated update-phase renders',
39
- 'Nested update propagation (component listed as updater for its own commit)',
40
- 'Presence across many commits',
41
- 'Self-intensive render (high self-to-actual ratio, low child delegation)',
42
- ],
36
+ meaning: '0-10 rerender risk score. Factors: update frequency, nested updates, commit spread, self-intensive render, average render duration.',
37
+ thresholds: { low: '0.0-2.9', medium: '3.0-5.9', high: '6.0-10.0' },
43
38
  },
44
39
  causes,
45
40
  }, null, 2),
@@ -1 +1 @@
1
- {"version":3,"file":"get-rerender-causes.js","sourceRoot":"","sources":["../../src/tools/get-rerender-causes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,MAAM,CAAC,YAAY,CAAC,qBAAqB,EAAE;QACzC,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,4HAA4H;QACzI,WAAW,EAAE;YACX,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;YACrE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;YACjH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8GAA8G,CAAC;SAC1K;KACF,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE;QAC7C,MAAM,OAAO,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,YAAY,SAAS,uFAAuF,CAAC,CAAC;QAChI,CAAC;QAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,EAAE,WAAW,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACrF,GAAG,KAAK;YACR,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACrC,mBAAmB,EAAE,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC;SACzD,CAAC,CAAC,CAAC;QAEJ,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,SAAS;wBACT,IAAI,EAAE,sHAAsH;wBAC5H,kBAAkB,EAAE;4BAClB,OAAO,EAAE,qHAAqH;4BAC9H,UAAU,EAAE;gCACV,GAAG,EAAE,SAAS;gCACd,MAAM,EAAE,SAAS;gCACjB,IAAI,EAAE,UAAU;6BACjB;4BACD,OAAO,EAAE;gCACP,+BAA+B;gCAC/B,4EAA4E;gCAC5E,8BAA8B;gCAC9B,yEAAyE;6BAC1E;yBACF;wBACD,MAAM;qBACP,EAAE,IAAI,EAAE,CAAC,CAAC;iBACZ,CAAC;SACH,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"get-rerender-causes.js","sourceRoot":"","sources":["../../src/tools/get-rerender-causes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,MAAM,CAAC,YAAY,CAAC,qBAAqB,EAAE;QACzC,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,4HAA4H;QACzI,WAAW,EAAE;YACX,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;YACrE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;YACjH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8GAA8G,CAAC;SAC1K;KACF,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE;QAC7C,MAAM,OAAO,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,YAAY,SAAS,uFAAuF,CAAC,CAAC;QAChI,CAAC;QAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,EAAE,WAAW,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACrF,GAAG,KAAK;YACR,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACrC,mBAAmB,EAAE,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC;SACzD,CAAC,CAAC,CAAC;QAEJ,MAAM,WAAW,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC;QAC1E,MAAM,WAAW,GAAG,OAAO,CAAC,qBAAqB;YAC/C,CAAC,CAAC,mFAAmF;YACrF,CAAC,CAAC,wKAAwK,CAAC;QAE7K,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,SAAS;wBACT,WAAW;wBACX,IAAI,EAAE,WAAW;wBACjB,kBAAkB,EAAE;4BAClB,OAAO,EAAE,qIAAqI;4BAC9I,UAAU,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE;yBACpE;wBACD,MAAM;qBACP,EAAE,IAAI,EAAE,CAAC,CAAC;iBACZ,CAAC;SACH,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"load-render-profile.d.ts","sourceRoot":"","sources":["../../src/tools/load-render-profile.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2BjE"}
1
+ {"version":3,"file":"load-render-profile.d.ts","sourceRoot":"","sources":["../../src/tools/load-render-profile.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6BjE"}
@@ -7,7 +7,9 @@ import { storeRenderProfile } from '../store.js';
7
7
  export function registerLoadRenderProfile(server) {
8
8
  server.registerTool('load_render_profile', {
9
9
  title: 'Load Render Profile',
10
- description: 'Parse and load a React DevTools profiler export captured from a Next.js app. Returns a profile ID for use with the other render analysis tools.',
10
+ description: 'Load a React DevTools Profiler JSON export. ' +
11
+ 'This is the entry point for the manual profiling path: open React DevTools in the browser → Profiler tab → Record → interact → Stop → Export JSON → share the file path here. ' +
12
+ 'Returns a profileId for use with get_render_summary, get_slow_components, get_rerender_causes, and the other analysis tools.',
11
13
  inputSchema: {
12
14
  filePath: z.string().describe('Absolute or relative path to the exported React Profiler JSON file'),
13
15
  },
@@ -1 +1 @@
1
- {"version":3,"file":"load-render-profile.js","sourceRoot":"","sources":["../../src/tools/load-render-profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,MAAM,CAAC,YAAY,CAAC,qBAAqB,EAAE;QACzC,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,iJAAiJ;QAC9J,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oEAAoE,CAAC;SACpG;KACF,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACrD,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAE5B,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,SAAS,EAAE,OAAO,CAAC,EAAE;wBACrB,QAAQ,EAAE,OAAO,CAAC,QAAQ;wBAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;wBACxB,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM;wBACnC,cAAc,EAAE,OAAO,CAAC,UAAU,CAAC,MAAM;wBACzC,mBAAmB,EAAE,QAAQ,CAAC,OAAO,CAAC,mBAAmB,CAAC;qBAC3D,EAAE,IAAI,EAAE,CAAC,CAAC;iBACZ,CAAC;SACH,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"load-render-profile.js","sourceRoot":"","sources":["../../src/tools/load-render-profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,MAAM,CAAC,YAAY,CAAC,qBAAqB,EAAE;QACzC,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,8CAA8C;YACzD,gLAAgL;YAChL,8HAA8H;QAChI,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oEAAoE,CAAC;SACpG;KACF,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACrD,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAE5B,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,SAAS,EAAE,OAAO,CAAC,EAAE;wBACrB,QAAQ,EAAE,OAAO,CAAC,QAAQ;wBAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;wBACxB,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM;wBACnC,cAAc,EAAE,OAAO,CAAC,UAAU,CAAC,MAAM;wBACzC,mBAAmB,EAAE,QAAQ,CAAC,OAAO,CAAC,mBAAmB,CAAC;qBAC3D,EAAE,IAAI,EAAE,CAAC,CAAC;iBACZ,CAAC;SACH,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerRunRenderCapture(server: McpServer): void;
3
+ //# sourceMappingURL=run-render-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-render-capture.d.ts","sourceRoot":"","sources":["../../src/tools/run-render-capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8DhE"}
@@ -0,0 +1,61 @@
1
+ import { z } from 'zod';
2
+ import { getCaptureSession } from '../ingest/server.js';
3
+ export function registerRunRenderCapture(server) {
4
+ server.registerTool('run_render_capture', {
5
+ title: 'Run Render Capture',
6
+ description: 'Called after instrumentation is wired up (steps 1–3 of begin_render_analysis). ' +
7
+ 'Ask the user how they want to generate renders before calling this tool:\n' +
8
+ ' manual-interaction — start the dev server and the user clicks through the app.\n' +
9
+ ' test-suite — run an existing automated test suite against the running app.',
10
+ inputSchema: {
11
+ sessionId: z.string().describe('The sessionId returned by begin_render_analysis.'),
12
+ method: z
13
+ .enum(['manual-interaction', 'test-suite'])
14
+ .describe('"manual-interaction": user navigates the app manually (fast, focused). ' +
15
+ '"test-suite": run an existing test suite (automated; scope to one file/feature to keep payload manageable).'),
16
+ },
17
+ }, async ({ sessionId, method }) => {
18
+ const session = getCaptureSession(sessionId);
19
+ if (!session || session.status !== 'active') {
20
+ return {
21
+ content: [{
22
+ type: 'text',
23
+ text: JSON.stringify({ error: `No active session for sessionId "${sessionId}". Call begin_render_analysis first.` }, null, 2),
24
+ }],
25
+ isError: true,
26
+ };
27
+ }
28
+ if (method === 'manual-interaction') {
29
+ const result = {
30
+ method,
31
+ sessionId,
32
+ instructions: [
33
+ '1. Start the dev server (e.g. `npm run dev`).',
34
+ '2. Open the app in your browser and interact with the pages/flows you want to profile.',
35
+ '3. When done, call stop_render_capture to end the session.',
36
+ ].join('\n'),
37
+ nextStep: `stop_render_capture({ sessionId: "${sessionId}" })`,
38
+ };
39
+ return {
40
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
41
+ };
42
+ }
43
+ // test-suite
44
+ const result = {
45
+ method,
46
+ sessionId,
47
+ instructions: [
48
+ '1. Start the dev server if not already running (e.g. `npm run dev`).',
49
+ '2. Inspect the project to find available Playwright test files. Pick one relevant to what you want to profile.',
50
+ '3. Run the test suite with the --headed flag:',
51
+ ' npx playwright test <test-file> --headed',
52
+ '4. When the test run finishes, call stop_render_capture to end the session.',
53
+ ].join('\n'),
54
+ nextStep: `stop_render_capture({ sessionId: "${sessionId}" })`,
55
+ };
56
+ return {
57
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
58
+ };
59
+ });
60
+ }
61
+ //# sourceMappingURL=run-render-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-render-capture.js","sourceRoot":"","sources":["../../src/tools/run-render-capture.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,CAAC,YAAY,CAAC,oBAAoB,EAAE;QACxC,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,iFAAiF;YACjF,4EAA4E;YAC5E,oFAAoF;YACpF,sFAAsF;QACxF,WAAW,EAAE;YACX,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC;YAClF,MAAM,EAAE,CAAC;iBACN,IAAI,CAAC,CAAC,oBAAoB,EAAE,YAAY,CAAC,CAAC;iBAC1C,QAAQ,CACP,yEAAyE;gBACzE,6GAA6G,CAC9G;SACJ;KACF,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC5C,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,oCAAoC,SAAS,sCAAsC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;qBAC9H,CAAC;gBACF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,KAAK,oBAAoB,EAAE,CAAC;YACpC,MAAM,MAAM,GAAG;gBACb,MAAM;gBACN,SAAS;gBACT,YAAY,EAAE;oBACZ,+CAA+C;oBAC/C,wFAAwF;oBACxF,4DAA4D;iBAC7D,CAAC,IAAI,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,qCAAqC,SAAS,MAAM;aAC/D,CAAC;YACF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAED,aAAa;QACb,MAAM,MAAM,GAAG;YACb,MAAM;YACN,SAAS;YACT,YAAY,EAAE;gBACZ,sEAAsE;gBACtE,gHAAgH;gBAChH,+CAA+C;gBAC/C,6CAA6C;gBAC7C,6EAA6E;aAC9E,CAAC,IAAI,CAAC,IAAI,CAAC;YACZ,QAAQ,EAAE,qCAAqC,SAAS,MAAM;SAC/D,CAAC;QACF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC5E,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerStopRenderCapture(server: McpServer): void;
3
+ //# sourceMappingURL=stop-render-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop-render-capture.d.ts","sourceRoot":"","sources":["../../src/tools/stop-render-capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkEjE"}
@@ -0,0 +1,63 @@
1
+ import { z } from 'zod';
2
+ import { deleteCaptureSession, getCaptureSession, stopCaptureSession } from '../ingest/server.js';
3
+ import { isAnalyzableComponent } from '../parser/analysis.js';
4
+ import { adaptReactScanEvents } from '../parser/react-scan-lite.js';
5
+ import { storeRenderProfile } from '../store.js';
6
+ import { formatMs } from '../format.js';
7
+ export function registerStopRenderCapture(server) {
8
+ server.registerTool('stop_render_capture', {
9
+ title: 'Stop Render Capture',
10
+ description: 'Stop a live render-capture session, finalize the buffered events into a render profile, ' +
11
+ 'and return a profileId you can use with get_render_summary, get_slow_components, ' +
12
+ 'get_rerender_causes, and compare_renders.',
13
+ inputSchema: {
14
+ sessionId: z.string().describe('The sessionId returned by start_render_capture'),
15
+ },
16
+ }, async ({ sessionId }) => {
17
+ const session = getCaptureSession(sessionId);
18
+ if (!session) {
19
+ return {
20
+ content: [{ type: 'text', text: JSON.stringify({ error: `Session "${sessionId}" not found` }, null, 2) }],
21
+ isError: true,
22
+ };
23
+ }
24
+ if (session.status === 'stopped') {
25
+ return {
26
+ content: [{ type: 'text', text: JSON.stringify({ error: `Session "${sessionId}" is already stopped` }, null, 2) }],
27
+ isError: true,
28
+ };
29
+ }
30
+ // Mark stopped before processing so no new events are accepted.
31
+ stopCaptureSession(sessionId);
32
+ const commitCount = session.commits.length;
33
+ if (commitCount === 0) {
34
+ const warning = session.profilingAvailable === false
35
+ ? 'No commits captured. The app reported profiling-hooks-status: false — ' +
36
+ 'this usually means the app is running a production build. ' +
37
+ 'Switch to `next dev` or alias react-dom to react-dom/profiling.'
38
+ : 'No commits captured. Make sure the instrumentation snippet was loaded ' +
39
+ 'and you interacted with the app while the session was active.';
40
+ return {
41
+ content: [{ type: 'text', text: JSON.stringify({ warning, sessionId, commitCount: 0 }, null, 2) }],
42
+ };
43
+ }
44
+ const profile = adaptReactScanEvents(session.commits, sessionId);
45
+ storeRenderProfile(profile);
46
+ // Session data is no longer needed — free memory.
47
+ deleteCaptureSession(sessionId);
48
+ const result = {
49
+ profileId: profile.id,
50
+ sessionId,
51
+ commitCount: profile.commits.length,
52
+ componentCount: profile.components.filter(c => isAnalyzableComponent(c.componentName)).length,
53
+ totalCommitDuration: formatMs(profile.totalCommitDuration),
54
+ profilingAvailable: session.profilingAvailable,
55
+ dataQuality: profile.hasChangeDescriptions ? 'exact' : 'heuristic',
56
+ nextStep: `call get_render_summary with profileId "${profile.id}"`,
57
+ };
58
+ return {
59
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
60
+ };
61
+ });
62
+ }
63
+ //# sourceMappingURL=stop-render-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop-render-capture.js","sourceRoot":"","sources":["../../src/tools/stop-render-capture.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perfonext/render-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "MCP server for analyzing Next.js React Profiler exports: render summaries, rerender causes, hot commits, and profile diffing",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",