Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 0 additions & 1 deletion src/McpResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,6 @@ Call ${handleDialog.name} to handle it before continuing.`);
return response;
}

response.push(`## Console Message ${data.consoleMessageStableId}`);
response.push(formatConsoleEventVerbose(data));
return response;
}
Expand Down
73 changes: 29 additions & 44 deletions src/formatters/consoleFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,64 +6,49 @@

import type {ConsoleMessageData} from '../McpResponse.js';

const logLevels: Record<string, string> = {
log: 'Log',
info: 'Info',
warning: 'Warning',
error: 'Error',
exception: 'Exception',
assert: 'Assert',
};

// 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}`;
return `msgid=${msg.consoleMessageStableId} [${msg.type}] ${msg.message} (${msg.args?.length ?? 0} 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}`;
function getArgs(msg: ConsoleMessageData) {
const args = [...(msg.args ?? [])];

if (msg.args && msg.args.length > 0) {
result += formatArgs(msg, true);
// If there is no text, the first argument serves as text (see formatMessage).
if (!msg.message) {
args.shift();
}

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

// The verbose format for a console message, including all details.
export function formatConsoleEventVerbose(msg: ConsoleMessageData): string {
const result = [
`ID: ${msg.consoleMessageStableId}`,
`Message: ${msg.type}> ${msg.message}`,
formatArgs(msg),
];

return result.join('\n');
}

return result;
function formatArg(arg: unknown) {
return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
}

// 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) {
function formatArgs(consoleData: ConsoleMessageData): string {
const args = getArgs(consoleData);

if (!args.length) {
return '';
}

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

for (const arg of messageArgsToFormat) {
if (arg !== consoleData.message) {
formattedArgs += ' ';
formattedArgs +=
typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
}
}
const result = ['### Arguments'];

if (!includeAllArgs && consoleData.args.length > 1) {
formattedArgs += ` ...`;
for (const [key, arg] of args.entries()) {
result.push(`Arg #${key}: ${formatArg(arg)}`);
}

return formattedArgs.length > 0 ? ` Args:${formattedArgs}` : '';
return result.join('\n');
}
38 changes: 38 additions & 0 deletions tests/formatters/consoleFormatter.test.js.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
exports[`consoleFormatter > formatConsoleEventShort > formats a console.log message 1`] = `
msgid=1 [log] Hello, world! (0 args)
`;

exports[`consoleFormatter > formatConsoleEventShort > formats a console.log message with multiple arguments 1`] = `
msgid=3 [log] Processing file: (2 args)
`;

exports[`consoleFormatter > formatConsoleEventShort > formats a console.log message with one argument 1`] = `
msgid=2 [log] Processing file: (1 args)
`;

exports[`consoleFormatter > formatConsoleEventVerbose > formats a console.error message 1`] = `
ID: 4
Message: error> Something went wrong

`;

exports[`consoleFormatter > formatConsoleEventVerbose > formats a console.log message 1`] = `
ID: 1
Message: log> Hello, world!

`;

exports[`consoleFormatter > formatConsoleEventVerbose > formats a console.log message with multiple arguments 1`] = `
ID: 3
Message: log> Processing file:
### Arguments
Arg #0: file.txt
Arg #1: another file
`;

exports[`consoleFormatter > formatConsoleEventVerbose > formats a console.log message with one argument 1`] = `
ID: 2
Message: log> Processing file:
### Arguments
Arg #0: file.txt
`;
76 changes: 14 additions & 62 deletions tests/formatters/consoleFormatter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* SPDX-License-Identifier: Apache-2.0
*/

import assert from 'node:assert';
import {describe, it} from 'node:test';

import {
Expand All @@ -15,129 +14,82 @@ import type {ConsoleMessageData} from '../../src/McpResponse.js';

describe('consoleFormatter', () => {
describe('formatConsoleEventShort', () => {
it('formats a console.log message', () => {
it('formats a console.log message', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 1,
type: 'log',
message: 'Hello, world!',
args: [],
};
const result = formatConsoleEventShort(message);
assert.equal(result, 'msgid=1 [log] Hello, world!');
t.assert.snapshot?.(result);
});

it('formats a console.log message with one argument', () => {
it('formats a console.log message with one argument', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 2,
type: 'log',
message: 'Processing file:',
args: ['file.txt'],
};
const result = formatConsoleEventShort(message);
assert.equal(result, 'msgid=2 [log] Processing file: Args: file.txt');
t.assert.snapshot?.(result);
});

it('formats a console.log message with multiple arguments', () => {
it('formats a console.log message with multiple arguments', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 3,
type: 'log',
message: 'Processing file:',
args: ['file.txt', 'another file'],
};
const result = formatConsoleEventShort(message);
assert.equal(result, 'msgid=3 [log] Processing file: Args: file.txt ...');
});

it('does not include args if message is the same as arg', () => {
const message: ConsoleMessageData = {
consoleMessageStableId: 4,
type: 'log',
message: 'Hello',
args: ['Hello'],
};
const result = formatConsoleEventShort(message);
assert.equal(result, 'msgid=4 [log] Hello');
t.assert.snapshot?.(result);
});
});

describe('formatConsoleEventVerbose', () => {
it('formats a console.log message', () => {
it('formats a console.log message', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 1,
type: 'log',
message: 'Hello, world!',
args: [],
};
const result = formatConsoleEventVerbose(message);
assert.equal(
result,
`Log> Hello, world!
ID: 1
Type: log`,
);
t.assert.snapshot?.(result);
});

it('formats a console.log message with one argument', () => {
it('formats a console.log message with one argument', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 2,
type: 'log',
message: 'Processing file:',
args: ['file.txt'],
};
const result = formatConsoleEventVerbose(message);
assert.equal(
result,
`Log> Processing file: Args: file.txt
ID: 2
Type: log`,
);
t.assert.snapshot?.(result);
});

it('formats a console.log message with multiple arguments', () => {
it('formats a console.log message with multiple arguments', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 3,
type: 'log',
message: 'Processing file:',
args: ['file.txt', 'another file'],
};
const result = formatConsoleEventVerbose(message);
assert.equal(
result,
`Log> Processing file: Args: file.txt another file
ID: 3
Type: log`,
);
t.assert.snapshot?.(result);
});

it('formats a console.error message', () => {
it('formats a console.error message', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 4,
type: 'error',
message: 'Something went wrong',
};
const result = formatConsoleEventVerbose(message);
assert.equal(
result,
`Error> Something went wrong
ID: 4
Type: error`,
);
});

it('does not include args if message is the same as arg', () => {
const message: ConsoleMessageData = {
consoleMessageStableId: 5,
type: 'log',
message: 'Hello',
args: ['Hello', 'World'],
};
const result = formatConsoleEventVerbose(message);
assert.equal(
result,
`Log> Hello Args: World
ID: 5
Type: log`,
);
t.assert.snapshot?.(result);
});
});
});
4 changes: 0 additions & 4 deletions tests/tools/console.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ describe('console', () => {

const formattedResponse = response.format('test', context);
const textContent = formattedResponse[0] as {text: string};
assert.ok(
textContent.text.includes('## Console Message 1'),
'Should contain console message title',
);
assert.ok(
textContent.text.includes('msgid=1 [error] This is an error'),
'Should contain console message body',
Expand Down