Skip to content

Commit b680b80

Browse files
committed
add a tail argument to getConsoleData, to limit how much data is returned
1 parent 9b4cd8e commit b680b80

File tree

5 files changed

+102
-9
lines changed

5 files changed

+102
-9
lines changed

src/McpContext.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,16 @@ export class McpContext implements Context {
134134
return this.#networkCollector.getData(page);
135135
}
136136

137-
getConsoleData(): Array<ConsoleMessage | Error> {
137+
getConsoleData(tail?: number): Array<ConsoleMessage | Error> {
138138
const page = this.getSelectedPage();
139-
return this.#consoleCollector.getData(page);
139+
const allMessages = this.#consoleCollector.getData(page);
140+
141+
// If tail is specified, return only the last N messages
142+
if (tail !== undefined && tail > 0) {
143+
return allMessages.slice(-tail);
144+
}
145+
146+
return allMessages;
140147
}
141148

142149
async newPage(): Promise<Page> {

src/McpResponse.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export class McpResponse implements Response {
2626
#includeSnapshot = false;
2727
#attachedNetworkRequestUrl?: string;
2828
#includeConsoleData = false;
29+
#consoleTail?: number;
2930
#textResponseLines: string[] = [];
3031
#formattedConsoleData?: string[];
3132
#images: ImageContentData[] = [];
@@ -69,8 +70,9 @@ export class McpResponse implements Response {
6970
};
7071
}
7172

72-
setIncludeConsoleData(value: boolean): void {
73+
setIncludeConsoleData(value: boolean, tail?: number): void {
7374
this.#includeConsoleData = value;
75+
this.#consoleTail = tail;
7476
}
7577

7678
attachNetworkRequest(url: string): void {
@@ -128,7 +130,7 @@ export class McpResponse implements Response {
128130

129131
let formattedConsoleMessages: string[];
130132
if (this.#includeConsoleData) {
131-
const consoleMessages = context.getConsoleData();
133+
const consoleMessages = context.getConsoleData(this.#consoleTail);
132134
if (consoleMessages) {
133135
formattedConsoleMessages = await Promise.all(
134136
consoleMessages.map(message => formatConsoleEvent(message)),

src/tools/ToolDefinition.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export interface Response {
4646
value: boolean,
4747
options?: {pageSize?: number; pageIdx?: number; resourceTypes?: string[]},
4848
): void;
49-
setIncludeConsoleData(value: boolean): void;
49+
setIncludeConsoleData(value: boolean, tail?: number): void;
5050
setIncludeSnapshot(value: boolean): void;
5151
attachImage(value: ImageContentData): void;
5252
attachNetworkRequest(url: string): void;

src/tools/console.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
import z from 'zod';
8+
79
import {ToolCategories} from './categories.js';
810
import {defineTool} from './ToolDefinition.js';
911

@@ -14,8 +16,18 @@ export const consoleTool = defineTool({
1416
category: ToolCategories.DEBUGGING,
1517
readOnlyHint: true,
1618
},
17-
schema: {},
18-
handler: async (_request, response) => {
19-
response.setIncludeConsoleData(true);
19+
schema: {
20+
tail: z
21+
.number()
22+
.int()
23+
.positive()
24+
.optional()
25+
.default(50)
26+
.describe(
27+
'Maximum number of recent messages to return. Defaults to 50. Omit or set to null to return all messages.',
28+
),
29+
},
30+
handler: async (request, response) => {
31+
response.setIncludeConsoleData(true, request.params.tail);
2032
},
2133
});

tests/tools/console.test.ts

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,81 @@ describe('console', () => {
1313
describe('list_console_messages', () => {
1414
it('list messages', async () => {
1515
await withBrowser(async (response, context) => {
16-
await consoleTool.handler({params: {}}, response, context);
16+
await consoleTool.handler({params: {tail: 50}}, response, context);
1717
assert.ok(response.includeConsoleData);
1818
});
1919
});
20+
21+
it('uses default tail of 50 messages', async () => {
22+
await withBrowser(async (response, context) => {
23+
// Generate 60 console messages
24+
const page = context.getSelectedPage();
25+
await page.evaluate(() => {
26+
for (let i = 1; i <= 60; i++) {
27+
console.log(`Message ${i}`);
28+
}
29+
});
30+
31+
// Call handler without tail param (should default to 50)
32+
await consoleTool.handler({params: {tail: 50}}, response, context);
33+
34+
const result = await response.handle('test', context);
35+
const text = (result[0] as any).text.toString();
36+
37+
// Should include message 11 (first of last 50)
38+
assert.ok(text.includes('Message 11'), 'Should include Message 11');
39+
// Should include message 60 (last message)
40+
assert.ok(text.includes('Message 60'), 'Should include Message 60');
41+
// Should NOT include message 10 (51st from end)
42+
assert.ok(!text.includes('Message 10'), 'Should NOT include Message 10');
43+
});
44+
});
45+
46+
it('respects custom tail parameter', async () => {
47+
await withBrowser(async (response, context) => {
48+
// Generate 20 console messages
49+
const page = context.getSelectedPage();
50+
await page.evaluate(() => {
51+
for (let i = 1; i <= 20; i++) {
52+
console.log(`Message ${i}`);
53+
}
54+
});
55+
56+
// Call handler with tail=5
57+
await consoleTool.handler({params: {tail: 5}}, response, context);
58+
59+
const result = await response.handle('test', context);
60+
const text = (result[0] as any).text.toString();
61+
62+
// Should include messages 16-20 (last 5)
63+
assert.ok(text.includes('Message 16'), 'Should include Message 16');
64+
assert.ok(text.includes('Message 20'), 'Should include Message 20');
65+
// Should NOT include message 15
66+
assert.ok(!text.includes('Message 15'), 'Should NOT include Message 15');
67+
});
68+
});
69+
70+
it('returns only last 10 messages with default tail when less than 50 exist', async () => {
71+
await withBrowser(async (response, context) => {
72+
// Generate 10 console messages
73+
const page = context.getSelectedPage();
74+
await page.evaluate(() => {
75+
for (let i = 1; i <= 10; i++) {
76+
console.log(`Message ${i}`);
77+
}
78+
});
79+
80+
// Call handler with default tail (50, but only 10 messages exist)
81+
await consoleTool.handler({params: {tail: 50}}, response, context);
82+
83+
const result = await response.handle('test', context);
84+
const text = (result[0] as any).text.toString();
85+
86+
// Should include all 10 messages since there are less than 50
87+
for (let i = 1; i <= 10; i++) {
88+
assert.ok(text.includes(`Message ${i}`), `Should include Message ${i}`);
89+
}
90+
});
91+
});
2092
});
2193
});

0 commit comments

Comments
 (0)