Skip to content

Commit 3107fa1

Browse files
committed
make format not async
1 parent f6e67b4 commit 3107fa1

4 files changed

Lines changed: 119 additions & 150 deletions

File tree

src/McpResponse.ts

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type {
77
ImageContent,
88
TextContent,
99
} from '@modelcontextprotocol/sdk/types.js';
10-
import type {ResourceType} from 'puppeteer-core';
10+
import type {ConsoleMessage, ResourceType} from 'puppeteer-core';
1111

1212
import {formatConsoleEvent} from './formatters/consoleFormatter.js';
1313
import {
@@ -29,10 +29,17 @@ interface NetworkRequestData {
2929
responseBody?: string;
3030
}
3131

32+
export interface ConsoleMessageData {
33+
type: string;
34+
message: string;
35+
args: string[];
36+
}
37+
3238
export class McpResponse implements Response {
3339
#includePages = false;
3440
#includeSnapshot = false;
3541
#attachedNetworkRequestData?: NetworkRequestData;
42+
#consoleMessagesData?: ConsoleMessageData[];
3643
#textResponseLines: string[] = [];
3744
#images: ImageContentData[] = [];
3845
#networkRequestsOptions?: {
@@ -182,13 +189,44 @@ export class McpResponse implements Response {
182189
}
183190
}
184191

185-
return await this.format(toolName, context);
192+
if (this.#consoleDataOptions?.include) {
193+
const messages = context.getConsoleData();
194+
195+
this.#consoleMessagesData = await Promise.all(
196+
messages.map(async (item): Promise<ConsoleMessageData> => {
197+
if ('args' in item) {
198+
const consoleMessage = item as ConsoleMessage;
199+
return {
200+
type: consoleMessage.type(),
201+
message: consoleMessage.text(),
202+
args: await Promise.all(
203+
consoleMessage.args().map(async arg => {
204+
const stringArg = await arg.jsonValue().catch(() => {
205+
// Ignore errors.
206+
});
207+
return typeof stringArg === 'object'
208+
? JSON.stringify(stringArg)
209+
: String(stringArg);
210+
}),
211+
),
212+
};
213+
}
214+
return {
215+
type: 'error',
216+
message: (item as Error).message,
217+
args: [],
218+
};
219+
}),
220+
);
221+
}
222+
223+
return this.format(toolName, context);
186224
}
187225

188-
async format(
226+
format(
189227
toolName: string,
190228
context: McpContext,
191-
): Promise<Array<TextContent | ImageContent>> {
229+
): Array<TextContent | ImageContent> {
192230
const response = [`# ${toolName} response`];
193231
for (const line of this.#textResponseLines) {
194232
response.push(line);
@@ -278,18 +316,7 @@ Call ${handleDialog.name} to handle it before continuing.`);
278316
}
279317

280318
if (this.#consoleDataOptions?.include) {
281-
let messages = context.getConsoleData();
282-
283-
if (this.#consoleDataOptions.types?.length) {
284-
const normalizedTypes = new Set(this.#consoleDataOptions.types);
285-
messages = messages.filter(message => {
286-
if (!('type' in message)) {
287-
return normalizedTypes.has('error');
288-
}
289-
const type = message.type();
290-
return normalizedTypes.has(type);
291-
});
292-
}
319+
const messages = this.#consoleMessagesData ?? [];
293320

294321
response.push('## Console messages');
295322
if (messages.length) {
@@ -299,9 +326,7 @@ Call ${handleDialog.name} to handle it before continuing.`);
299326
);
300327
response.push(...data.info);
301328
response.push(
302-
...(await Promise.all(
303-
data.items.map(message => formatConsoleEvent(message)),
304-
)),
329+
...data.items.map(message => formatConsoleEvent(message)),
305330
);
306331
} else {
307332
response.push('<no console messages found>');

src/formatters/consoleFormatter.ts

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

7-
import type {ConsoleMessage, JSHandle} from 'puppeteer-core';
7+
import type {ConsoleMessageData} from '../McpResponse.js';
88

99
const logLevels: Record<string, string> = {
1010
log: 'Log',
@@ -15,38 +15,22 @@ const logLevels: Record<string, string> = {
1515
assert: 'Assert',
1616
};
1717

18-
export async function formatConsoleEvent(
19-
event: ConsoleMessage | Error,
20-
): Promise<string> {
21-
// Check if the event object has the .type() method, which is unique to ConsoleMessage
22-
if ('type' in event) {
23-
return await formatConsoleMessage(event);
24-
}
25-
return `Error: ${event.message}`;
26-
}
27-
28-
async function formatConsoleMessage(msg: ConsoleMessage): Promise<string> {
29-
const logLevel = logLevels[msg.type()];
30-
const text = msg.text();
31-
const args = msg.args();
18+
export function formatConsoleEvent(msg: ConsoleMessageData): string {
19+
const logLevel = logLevels[msg.type] ?? 'Log';
20+
const text = msg.message;
3221

33-
const formattedArgs = await formatArgs(args, text);
22+
const formattedArgs = formatArgs(msg.args, text);
3423
return `${logLevel}> ${text} ${formattedArgs}`.trim();
3524
}
3625

3726
// Only includes the first arg and indicates that there are more args
38-
async function formatArgs(
39-
args: readonly JSHandle[],
40-
messageText: string,
41-
): Promise<string> {
27+
function formatArgs(args: string[], messageText: string): string {
4228
if (args.length === 0) {
4329
return '';
4430
}
4531

4632
let formattedArgs = '';
47-
const firstArg = await args[0].jsonValue().catch(() => {
48-
// Ignore errors
49-
});
33+
const firstArg = args[0];
5034

5135
if (firstArg !== messageText) {
5236
formattedArgs +=

tests/formatters/consoleFormatter.test.ts

Lines changed: 63 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -7,153 +7,109 @@
77
import assert from 'node:assert';
88
import {describe, it} from 'node:test';
99

10-
import type {ConsoleMessage} from 'puppeteer-core';
11-
1210
import {formatConsoleEvent} from '../../src/formatters/consoleFormatter.js';
13-
14-
function getMockConsoleMessage(options: {
15-
type: string;
16-
text: string;
17-
location?: {
18-
url?: string;
19-
lineNumber?: number;
20-
columnNumber?: number;
21-
};
22-
stackTrace?: Array<{
23-
url: string;
24-
lineNumber: number;
25-
columnNumber: number;
26-
}>;
27-
args?: unknown[];
28-
}): ConsoleMessage {
29-
return {
30-
type() {
31-
return options.type;
32-
},
33-
text() {
34-
return options.text;
35-
},
36-
location() {
37-
return options.location ?? {};
38-
},
39-
stackTrace() {
40-
return options.stackTrace ?? [];
41-
},
42-
args() {
43-
return (
44-
options.args?.map(arg => {
45-
return {
46-
evaluate(fn: (arg: unknown) => unknown) {
47-
return Promise.resolve(fn(arg));
48-
},
49-
jsonValue() {
50-
return Promise.resolve(arg);
51-
},
52-
dispose() {
53-
return Promise.resolve();
54-
},
55-
};
56-
}) ?? []
57-
);
58-
},
59-
} as ConsoleMessage;
60-
}
11+
import type {ConsoleMessageData} from '../../src/McpResponse.js';
6112

6213
describe('consoleFormatter', () => {
6314
describe('formatConsoleEvent', () => {
64-
it('formats a console.log message', async () => {
65-
const message = getMockConsoleMessage({
15+
it('formats a console.log message', () => {
16+
const message: ConsoleMessageData = {
6617
type: 'log',
67-
text: 'Hello, world!',
68-
});
69-
const result = await formatConsoleEvent(message);
18+
message: 'Hello, world!',
19+
args: [],
20+
};
21+
const result = formatConsoleEvent(message);
7022
assert.equal(result, 'Log> Hello, world!');
7123
});
7224

73-
it('formats a console.log message with one argument', async () => {
74-
const message = getMockConsoleMessage({
25+
it('formats a console.log message with one argument', () => {
26+
const message: ConsoleMessageData = {
7527
type: 'log',
76-
text: 'Processing file:',
28+
message: 'Processing file:',
7729
args: ['file.txt'],
78-
});
79-
const result = await formatConsoleEvent(message);
30+
};
31+
const result = formatConsoleEvent(message);
8032
assert.equal(result, 'Log> Processing file: file.txt');
8133
});
8234

83-
it('formats a console.log message with multiple arguments', async () => {
84-
const message = getMockConsoleMessage({
35+
it('formats a console.log message with multiple arguments', () => {
36+
const message: ConsoleMessageData = {
8537
type: 'log',
86-
text: 'Processing file:',
87-
args: ['file.txt', {id: 1, status: 'done'}],
88-
location: {
89-
url: 'http://example.com/script.js',
90-
lineNumber: 10,
91-
columnNumber: 5,
92-
},
93-
});
94-
const result = await formatConsoleEvent(message);
38+
message: 'Processing file:',
39+
args: ['file.txt', JSON.stringify({id: 1, status: 'done'})],
40+
};
41+
const result = formatConsoleEvent(message);
9542
assert.equal(result, 'Log> Processing file: file.txt ...');
9643
});
9744

98-
it('formats a console.error message', async () => {
99-
const message = getMockConsoleMessage({
45+
it('formats a console.error message', () => {
46+
const message: ConsoleMessageData = {
10047
type: 'error',
101-
text: 'Something went wrong',
102-
});
103-
const result = await formatConsoleEvent(message);
48+
message: 'Something went wrong',
49+
args: [],
50+
};
51+
const result = formatConsoleEvent(message);
10452
assert.equal(result, 'Error> Something went wrong');
10553
});
10654

107-
it('formats a console.error message with one argument', async () => {
108-
const message = getMockConsoleMessage({
55+
it('formats a console.error message with one argument', () => {
56+
const message: ConsoleMessageData = {
10957
type: 'error',
110-
text: 'Something went wrong:',
58+
message: 'Something went wrong:',
11159
args: ['details'],
112-
});
113-
const result = await formatConsoleEvent(message);
60+
};
61+
const result = formatConsoleEvent(message);
11462
assert.equal(result, 'Error> Something went wrong: details');
11563
});
11664

117-
it('formats a console.error message with multiple arguments', async () => {
118-
const message = getMockConsoleMessage({
65+
it('formats a console.error message with multiple arguments', () => {
66+
const message: ConsoleMessageData = {
11967
type: 'error',
120-
text: 'Something went wrong:',
121-
args: ['details', {code: 500}],
122-
});
123-
const result = await formatConsoleEvent(message);
68+
message: 'Something went wrong:',
69+
args: ['details', JSON.stringify({code: 500})],
70+
};
71+
const result = formatConsoleEvent(message);
12472
assert.equal(result, 'Error> Something went wrong: details ...');
12573
});
12674

127-
it('formats a console.warn message', async () => {
128-
const message = getMockConsoleMessage({
75+
it('formats a console.warn message', () => {
76+
const message: ConsoleMessageData = {
12977
type: 'warning',
130-
text: 'This is a warning',
131-
});
132-
const result = await formatConsoleEvent(message);
78+
message: 'This is a warning',
79+
args: [],
80+
};
81+
const result = formatConsoleEvent(message);
13382
assert.equal(result, 'Warning> This is a warning');
13483
});
13584

136-
it('formats a console.info message', async () => {
137-
const message = getMockConsoleMessage({
85+
it('formats a console.info message', () => {
86+
const message: ConsoleMessageData = {
13887
type: 'info',
139-
text: 'This is an info message',
140-
});
141-
const result = await formatConsoleEvent(message);
88+
message: 'This is an info message',
89+
args: [],
90+
};
91+
const result = formatConsoleEvent(message);
14292
assert.equal(result, 'Info> This is an info message');
14393
});
14494

145-
it('formats a page error', async () => {
146-
const error = new Error('Page crashed');
147-
error.stack = 'Error: Page crashed\n at <anonymous>:1:1';
148-
const result = await formatConsoleEvent(error);
149-
assert.equal(result, 'Error: Page crashed');
95+
it('formats a page error', () => {
96+
const error: ConsoleMessageData = {
97+
type: 'error',
98+
message: 'Error: Page crashed',
99+
args: [],
100+
};
101+
const result = formatConsoleEvent(error);
102+
assert.equal(result, 'Error> Error: Page crashed');
150103
});
151104

152-
it('formats a page error without a stack', async () => {
153-
const error = new Error('Page crashed');
154-
error.stack = undefined;
155-
const result = await formatConsoleEvent(error);
156-
assert.equal(result, 'Error: Page crashed');
105+
it('formats a page error without a stack', () => {
106+
const error: ConsoleMessageData = {
107+
type: 'error',
108+
message: 'Error: Page crashed',
109+
args: [],
110+
};
111+
const result = formatConsoleEvent(error);
112+
assert.equal(result, 'Error> Error: Page crashed');
157113
});
158114
});
159115
});

tests/tools/console.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@ describe('console', () => {
2525
'<script>console.error("This is an error")</script>',
2626
);
2727
await consoleTool.handler({params: {}}, response, context);
28-
const formattedResponse = await response.format('test', context);
28+
await response.handle('test', context);
29+
30+
const formattedResponse = response.format('test', context);
31+
2932
const textContent = formattedResponse[0] as {text: string};
33+
assert.ok(textContent.text.includes('Error>'));
3034
assert.ok(textContent.text.includes('This is an error'));
3135
});
3236
});

0 commit comments

Comments
 (0)