Skip to content

Commit 7f9f956

Browse files
committed
feat: support filePath in performance tools
1 parent ab2340f commit 7f9f956

File tree

3 files changed

+102
-7
lines changed

3 files changed

+102
-7
lines changed

docs/tool-reference.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,14 +234,17 @@
234234

235235
- **autoStop** (boolean) **(required)**: Determines if the trace recording should be automatically stopped.
236236
- **reload** (boolean) **(required)**: Determines if, once tracing has started, the page should be automatically reloaded.
237+
- **filePath** (string) _(optional)_: The absolute path, or a path relative to the current working directory, to save the raw trace data.
237238

238239
---
239240

240241
### `performance_stop_trace`
241242

242243
**Description:** Stops the active performance trace recording on the selected page.
243244

244-
**Parameters:** None
245+
**Parameters:**
246+
247+
- **filePath** (string) _(optional)_: The absolute path, or a path relative to the current working directory, to save the raw trace data.
245248

246249
---
247250

src/tools/performance.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const startTrace = defineTool({
2525
'Starts a performance trace recording on the selected page. This can be used to look for performance problems and insights to improve the performance of the page. It will also report Core Web Vital (CWV) scores for the page.',
2626
annotations: {
2727
category: ToolCategory.PERFORMANCE,
28-
readOnlyHint: true,
28+
readOnlyHint: false,
2929
},
3030
schema: {
3131
reload: zod
@@ -38,6 +38,12 @@ export const startTrace = defineTool({
3838
.describe(
3939
'Determines if the trace recording should be automatically stopped.',
4040
),
41+
filePath: zod
42+
.string()
43+
.optional()
44+
.describe(
45+
'The absolute path, or a path relative to the current working directory, to save the raw trace data.',
46+
),
4147
},
4248
handler: async (request, response, context) => {
4349
if (context.isRunningPerformanceTrace()) {
@@ -91,7 +97,12 @@ export const startTrace = defineTool({
9197

9298
if (request.params.autoStop) {
9399
await new Promise(resolve => setTimeout(resolve, 5_000));
94-
await stopTracingAndAppendOutput(page, response, context);
100+
await stopTracingAndAppendOutput(
101+
page,
102+
response,
103+
context,
104+
request.params.filePath,
105+
);
95106
} else {
96107
response.appendResponseLine(
97108
`The performance trace is being recorded. Use performance_stop_trace to stop it.`,
@@ -106,15 +117,27 @@ export const stopTrace = defineTool({
106117
'Stops the active performance trace recording on the selected page.',
107118
annotations: {
108119
category: ToolCategory.PERFORMANCE,
109-
readOnlyHint: true,
120+
readOnlyHint: false,
121+
},
122+
schema: {
123+
filePath: zod
124+
.string()
125+
.optional()
126+
.describe(
127+
'The absolute path, or a path relative to the current working directory, to save the raw trace data.',
128+
),
110129
},
111-
schema: {},
112-
handler: async (_request, response, context) => {
130+
handler: async (request, response, context) => {
113131
if (!context.isRunningPerformanceTrace()) {
114132
return;
115133
}
116134
const page = context.getSelectedPage();
117-
await stopTracingAndAppendOutput(page, response, context);
135+
await stopTracingAndAppendOutput(
136+
page,
137+
response,
138+
context,
139+
request.params.filePath,
140+
);
118141
},
119142
});
120143

@@ -165,9 +188,16 @@ async function stopTracingAndAppendOutput(
165188
page: Page,
166189
response: Response,
167190
context: Context,
191+
filePath?: string,
168192
): Promise<void> {
169193
try {
170194
const traceEventsBuffer = await page.tracing.stop();
195+
if (filePath && traceEventsBuffer) {
196+
const file = await context.saveFile(traceEventsBuffer, filePath);
197+
response.appendResponseLine(
198+
`The raw trace data was saved to ${file.filename}.`,
199+
);
200+
}
171201
const result = await parseRawTraceBuffer(traceEventsBuffer);
172202
response.appendResponseLine('The performance trace has been stopped.');
173203
if (traceResultIsSuccess(result)) {

tests/tools/performance.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,42 @@ describe('performance', () => {
138138
);
139139
});
140140
});
141+
142+
it('supports filePath', async () => {
143+
const rawData = loadTraceAsBuffer('basic-trace.json.gz');
144+
await withMcpContext(async (response, context) => {
145+
const filePath = 'test-trace.json';
146+
const selectedPage = context.getSelectedPage();
147+
sinon.stub(selectedPage, 'url').callsFake(() => 'https://www.test.com');
148+
sinon.stub(selectedPage, 'goto').callsFake(() => Promise.resolve(null));
149+
sinon.stub(selectedPage.tracing, 'start');
150+
sinon.stub(selectedPage.tracing, 'stop').resolves(rawData);
151+
const saveFileStub = sinon
152+
.stub(context, 'saveFile')
153+
.resolves({filename: filePath});
154+
155+
const clock = sinon.useFakeTimers({shouldClearNativeTimers: true});
156+
try {
157+
const handlerPromise = startTrace.handler(
158+
{params: {reload: true, autoStop: true, filePath}},
159+
response,
160+
context,
161+
);
162+
await clock.tickAsync(6_000);
163+
await handlerPromise;
164+
165+
assert.ok(
166+
response.responseLines.includes(
167+
`The raw trace data was saved to ${filePath}.`,
168+
),
169+
);
170+
sinon.assert.calledOnce(saveFileStub);
171+
sinon.assert.calledWith(saveFileStub, rawData, filePath);
172+
} finally {
173+
clock.restore();
174+
}
175+
});
176+
});
141177
});
142178

143179
describe('performance_analyze_insight', () => {
@@ -275,5 +311,31 @@ describe('performance', () => {
275311
t.assert.snapshot?.(response.responseLines.join('\n'));
276312
});
277313
});
314+
315+
it('supports filePath', async () => {
316+
const rawData = loadTraceAsBuffer('basic-trace.json.gz');
317+
await withMcpContext(async (response, context) => {
318+
const filePath = 'test-trace.json';
319+
context.setIsRunningPerformanceTrace(true);
320+
const selectedPage = context.getSelectedPage();
321+
const stopTracingStub = sinon
322+
.stub(selectedPage.tracing, 'stop')
323+
.resolves(rawData);
324+
const saveFileStub = sinon
325+
.stub(context, 'saveFile')
326+
.resolves({filename: filePath});
327+
328+
await stopTrace.handler({params: {filePath}}, response, context);
329+
330+
sinon.assert.calledOnce(stopTracingStub);
331+
sinon.assert.calledOnce(saveFileStub);
332+
sinon.assert.calledWith(saveFileStub, rawData, filePath);
333+
assert.ok(
334+
response.responseLines.includes(
335+
`The raw trace data was saved to ${filePath}.`,
336+
),
337+
);
338+
});
339+
});
278340
});
279341
});

0 commit comments

Comments
 (0)