Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,9 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
- **Network** (2 tools)
- [`get_network_request`](docs/tool-reference.md#get_network_request)
- [`list_network_requests`](docs/tool-reference.md#list_network_requests)
- **Debugging** (4 tools)
- **Debugging** (5 tools)
- [`evaluate_script`](docs/tool-reference.md#evaluate_script)
- [`get_console_message`](docs/tool-reference.md#get_console_message)
- [`list_console_messages`](docs/tool-reference.md#list_console_messages)
- [`take_screenshot`](docs/tool-reference.md#take_screenshot)
- [`take_snapshot`](docs/tool-reference.md#take_snapshot)
Expand Down
13 changes: 12 additions & 1 deletion docs/tool-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@
- **[Network](#network)** (2 tools)
- [`get_network_request`](#get_network_request)
- [`list_network_requests`](#list_network_requests)
- **[Debugging](#debugging)** (4 tools)
- **[Debugging](#debugging)** (5 tools)
- [`evaluate_script`](#evaluate_script)
- [`get_console_message`](#get_console_message)
- [`list_console_messages`](#list_console_messages)
- [`take_screenshot`](#take_screenshot)
- [`take_snapshot`](#take_snapshot)
Expand Down Expand Up @@ -296,6 +297,16 @@ so returned values have to JSON-serializable.

---

### `get_console_message`

**Description:** Gets a console message by its ID. You can get all messages by calling [`list_console_messages`](#list_console_messages).

**Parameters:**

- **msgid** (number) **(required)**: The msgid of a console message on the page from the listed console messages

---

### `list_console_messages`

**Description:** List all console messages for the currently selected page since the last navigation.
Expand Down
8 changes: 8 additions & 0 deletions src/McpContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ export class McpContext implements Context {
return this.#consoleCollector.getData(page);
}

getConsoleMessageStableId(message: ConsoleMessage | Error): number {
return this.#consoleCollector.getIdForResource(message);
}

getConsoleMessageById(id: number): ConsoleMessage | Error {
return this.#consoleCollector.getById(this.getSelectedPage(), id);
}

async newPage(): Promise<Page> {
const page = await this.browser.newPage();
const pages = await this.createPagesSnapshot();
Expand Down
85 changes: 79 additions & 6 deletions src/McpResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
*/
import type {ConsoleMessage, ResourceType} from 'puppeteer-core';

import {formatConsoleEvent} from './formatters/consoleFormatter.js';
import {
formatConsoleEventShort,
formatConsoleEventVerbose,
} from './formatters/consoleFormatter.js';
import {
getFormattedHeaderValue,
getFormattedResponseBody,
Expand All @@ -31,16 +34,18 @@ interface NetworkRequestData {
}

export interface ConsoleMessageData {
type: string;
message: string;
args: string[];
consoleMessageStableId: number;
type?: string;
message?: string;
args?: string[];
}

export class McpResponse implements Response {
#includePages = false;
#includeSnapshot = false;
#includeVerboseSnapshot = false;
#attachedNetworkRequestData?: NetworkRequestData;
#attachedConsoleMessageData?: ConsoleMessageData;
#consoleMessagesData?: ConsoleMessageData[];
#textResponseLines: string[] = [];
#images: ImageContentData[] = [];
Expand Down Expand Up @@ -118,6 +123,12 @@ export class McpResponse implements Response {
};
}

attachConsoleMessage(id: number): void {
this.#attachedConsoleMessageData = {
consoleMessageStableId: id,
};
}

get includePages(): boolean {
return this.#includePages;
}
Expand Down Expand Up @@ -192,14 +203,62 @@ export class McpResponse implements Response {
}
}

if (this.#attachedConsoleMessageData?.consoleMessageStableId) {
const message = context.getConsoleMessageById(
this.#attachedConsoleMessageData.consoleMessageStableId,
);
const consoleMessageStableId =
this.#attachedConsoleMessageData.consoleMessageStableId;
let data: ConsoleMessageData;
if ('args' in message) {
const consoleMessage = message as ConsoleMessage;
data = {
consoleMessageStableId,
type: consoleMessage.type(),
message: consoleMessage.text(),
args: await Promise.all(
consoleMessage.args().map(async arg => {
const stringArg = await arg.jsonValue().catch(() => {
// Ignore errors.
});
return typeof stringArg === 'object'
? JSON.stringify(stringArg)
: String(stringArg);
}),
),
};
} else {
data = {
consoleMessageStableId,
type: 'error',
message: (message as Error).message,
args: [],
};
}
this.#attachedConsoleMessageData = data;
}

if (this.#consoleDataOptions?.include) {
const messages = context.getConsoleData();
let messages = context.getConsoleData();

if (this.#consoleDataOptions.types?.length) {
const normalizedTypes = new Set(this.#consoleDataOptions.types);
messages = messages.filter(message => {
if ('type' in message) {
return normalizedTypes.has(message.type());
}
return normalizedTypes.has('error');
});
}

this.#consoleMessagesData = await Promise.all(
messages.map(async (item): Promise<ConsoleMessageData> => {
const consoleMessageStableId =
context.getConsoleMessageStableId(item);
if ('args' in item) {
const consoleMessage = item as ConsoleMessage;
return {
consoleMessageStableId,
type: consoleMessage.type(),
message: consoleMessage.text(),
args: await Promise.all(
Expand All @@ -215,6 +274,7 @@ export class McpResponse implements Response {
};
}
return {
consoleMessageStableId,
type: 'error',
message: (item as Error).message,
args: [],
Expand Down Expand Up @@ -283,6 +343,7 @@ Call ${handleDialog.name} to handle it before continuing.`);
}

response.push(...this.#getIncludeNetworkRequestsData(context));
response.push(...this.#getAttachedConsoleMessageData());

if (this.#networkRequestsOptions?.include) {
let requests = context.getNetworkRequests();
Expand Down Expand Up @@ -329,7 +390,7 @@ Call ${handleDialog.name} to handle it before continuing.`);
);
response.push(...data.info);
response.push(
...data.items.map(message => formatConsoleEvent(message)),
...data.items.map(message => formatConsoleEventShort(message)),
);
} else {
response.push('<no console messages found>');
Expand Down Expand Up @@ -376,6 +437,18 @@ Call ${handleDialog.name} to handle it before continuing.`);
};
}

#getAttachedConsoleMessageData(): string[] {
const response: string[] = [];
const data = this.#attachedConsoleMessageData;
if (!data) {
return response;
}

response.push(`## Console Message ${data.consoleMessageStableId}`);
response.push(formatConsoleEventVerbose(data));
return response;
}

#getIncludeNetworkRequestsData(context: McpContext): string[] {
const response: string[] = [];
const url = this.#attachedNetworkRequestData?.networkRequestStableId;
Expand Down
56 changes: 39 additions & 17 deletions src/formatters/consoleFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,55 @@ const logLevels: Record<string, string> = {
assert: 'Assert',
};

export function formatConsoleEvent(msg: ConsoleMessageData): string {
const logLevel = logLevels[msg.type] ?? 'Log';
const text = msg.message;
// The short format for a console message, based on a previous format.
export function formatConsoleEventShort(msg: ConsoleMessageData): string {
const args = msg.args ? formatArgs(msg, false) : '';
return `msgid=${msg.consoleMessageStableId} [${msg.type}] ${msg.message}${args}`;
}

// The verbose format for a console message, including all details.
export function formatConsoleEventVerbose(msg: ConsoleMessageData): string {
const logLevel = msg.type ? (logLevels[msg.type] ?? 'Log') : 'Log';
let result = `${logLevel}> ${msg.message}`;

if (msg.args && msg.args.length > 0) {
result += formatArgs(msg, true);
}

result += `
ID: ${msg.consoleMessageStableId}`;
result += `
Type: ${msg.type}`;

const formattedArgs = formatArgs(msg.args, text);
return `${logLevel}> ${text} ${formattedArgs}`.trim();
return result;
}

// Only includes the first arg and indicates that there are more args
function formatArgs(args: string[], messageText: string): string {
if (args.length === 0) {
// If `includeAllArgs` is false, only includes the first arg and indicates that there are more args.
function formatArgs(
consoleData: ConsoleMessageData,
includeAllArgs = false,
): string {
if (!consoleData.args || consoleData.args.length === 0) {
return '';
}

let formattedArgs = '';
const firstArg = args[0];
// In the short format version, we only include the first arg.
const messageArgsToFormat = includeAllArgs
? consoleData.args
: [consoleData.args[0]];

if (firstArg !== messageText) {
formattedArgs +=
typeof firstArg === 'object'
? JSON.stringify(firstArg)
: String(firstArg);
for (const arg of messageArgsToFormat) {
if (arg !== consoleData.message) {
formattedArgs += ' ';
formattedArgs +=
typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
}
}

if (args.length > 1) {
return `${formattedArgs} ...`;
if (!includeAllArgs && consoleData.args.length > 1) {
formattedArgs += ` ...`;
}

return formattedArgs;
return formattedArgs.length > 0 ? ` Args:${formattedArgs}` : '';
}
1 change: 1 addition & 0 deletions src/tools/ToolDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export interface Response {
setIncludeSnapshot(value: boolean, verbose?: boolean): void;
attachImage(value: ImageContentData): void;
attachNetworkRequest(reqid: number): void;
attachConsoleMessage(msgid: number): void;
}

/**
Expand Down
21 changes: 20 additions & 1 deletion src/tools/console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
'verbose',
];

export const consoleTool = defineTool({
export const listConsoleMessages = defineTool({
name: 'list_console_messages',
description:
'List all console messages for the currently selected page since the last navigation.',
Expand Down Expand Up @@ -76,3 +76,22 @@
});
},
});

export const getConsoleMessage = defineTool({
name: 'get_console_message',
description: `Gets a console message by its ID. You can get all messages by calling ${listConsoleMessages.name}.`,
annotations: {
category: ToolCategories.DEBUGGING,
readOnlyHint: true,
},
schema: {
msgid: z

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on windows-latest with node 22

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on macos-latest with node 24

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on ubuntu-latest with node 20

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on ubuntu-latest with node 22

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on windows-latest with node 24

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on ubuntu-latest with node 23

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on windows-latest with node 20

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on macos-latest with node 20

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on windows-latest with node 23

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on macos-latest with node 23

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on macos-latest with node 22

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on ubuntu-latest with node 24

Cannot find name 'z'.

Check failure on line 88 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / [Required] Check docs updated

Cannot find name 'z'.
.number()
.describe(
'The msgid of a console message on the page from the listed console messages',
),
},
handler: async (request, response) => {
response.attachConsoleMessage(request.params.msgid);

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on windows-latest with node 22

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on macos-latest with node 24

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on ubuntu-latest with node 20

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on ubuntu-latest with node 22

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on windows-latest with node 24

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on ubuntu-latest with node 23

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on windows-latest with node 20

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on macos-latest with node 20

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on windows-latest with node 23

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on macos-latest with node 23

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on macos-latest with node 22

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / Tests on ubuntu-latest with node 24

Argument of type 'unknown' is not assignable to parameter of type 'number'.

Check failure on line 95 in src/tools/console.ts

View workflow job for this annotation

GitHub Actions / [Required] Check docs updated

Argument of type 'unknown' is not assignable to parameter of type 'number'.
},
});
Loading
Loading