From 1148bfc4f8497d7913ca281ca992776114cd1510 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Thu, 11 Sep 2025 16:04:07 +0300 Subject: [PATCH] fix: add untrusted data wrapper around logs response --- src/tools/mongodb/metadata/logs.ts | 25 ++++------- .../tools/mongodb/metadata/logs.test.ts | 42 +++++++++++++++---- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/tools/mongodb/metadata/logs.ts b/src/tools/mongodb/metadata/logs.ts index 844d0283f..b19fa72c2 100644 --- a/src/tools/mongodb/metadata/logs.ts +++ b/src/tools/mongodb/metadata/logs.ts @@ -1,6 +1,6 @@ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { MongoDBToolBase } from "../mongodbTool.js"; -import type { ToolArgs, OperationType } from "../../tool.js"; +import { type ToolArgs, type OperationType, formatUntrustedData } from "../../tool.js"; import { z } from "zod"; export class LogsTool extends MongoDBToolBase { @@ -33,23 +33,16 @@ export class LogsTool extends MongoDBToolBase { getLog: type, }); - const logs = (result.log as string[]).slice(0, limit); + // Trim ending newlines so that when we join the logs we don't insert empty lines + // between messages. + const logs = (result.log as string[]).slice(0, limit).map((l) => l.trimEnd()); + let message = `Found: ${result.totalLinesWritten} messages`; + if (result.totalLinesWritten > limit) { + message += ` (showing only the first ${limit})`; + } return { - content: [ - { - text: `Found: ${result.totalLinesWritten} messages`, - type: "text", - }, - - ...logs.map( - (log) => - ({ - text: log, - type: "text", - }) as const - ), - ], + content: formatUntrustedData(message, logs.join("\n")), }; } } diff --git a/tests/integration/tools/mongodb/metadata/logs.test.ts b/tests/integration/tools/mongodb/metadata/logs.test.ts index 27c1f0e28..aa7e4ea44 100644 --- a/tests/integration/tools/mongodb/metadata/logs.test.ts +++ b/tests/integration/tools/mongodb/metadata/logs.test.ts @@ -1,5 +1,10 @@ import { expect, it } from "vitest"; -import { validateToolMetadata, validateThrowsForInvalidArguments, getResponseElements } from "../../../helpers.js"; +import { + validateToolMetadata, + validateThrowsForInvalidArguments, + getResponseElements, + getDataFromUntrustedContent, +} from "../../../helpers.js"; import { describeWithMongoDB, validateAutoConnectBehavior } from "../mongodbHelpers.js"; describeWithMongoDB("logs tool", (integration) => { @@ -36,13 +41,27 @@ describeWithMongoDB("logs tool", (integration) => { const elements = getResponseElements(response); + expect(elements).toHaveLength(2); + expect(elements[1]?.text).toContain(" logs.length) { + expect(elements[0]?.text).toContain(`(showing only the first ${logs.length})`); + } - for (let i = 1; i < elements.length; i++) { + for (const message of logs) { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const log = JSON.parse(elements[i]?.text ?? "{}"); + const log = JSON.parse(message ?? "{}"); expect(log).toHaveProperty("t"); expect(log).toHaveProperty("msg"); } @@ -58,9 +77,18 @@ describeWithMongoDB("logs tool", (integration) => { }); const elements = getResponseElements(response); - expect(elements.length).toBeLessThanOrEqual(51); - for (let i = 1; i < elements.length; i++) { - const log = JSON.parse(elements[i]?.text ?? "{}") as { tags: string[] }; + expect(elements).toHaveLength(2); + expect(elements[1]?.text).toContain("