From c5ec47e3b64f5b2b4af9ea8c37d7f52bc262b69b Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 6 Nov 2025 19:02:07 +0000 Subject: [PATCH 01/11] chore: cleanup telemetry --- src/tools/atlas/atlasTool.ts | 5 +---- src/tools/atlas/read/getPerformanceAdvisor.ts | 3 +-- src/tools/mongodb/mongodbTool.ts | 2 -- src/tools/tool.ts | 3 +-- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/tools/atlas/atlasTool.ts b/src/tools/atlas/atlasTool.ts index 594d832a..b27d3e7b 100644 --- a/src/tools/atlas/atlasTool.ts +++ b/src/tools/atlas/atlasTool.ts @@ -82,10 +82,7 @@ For more information on Atlas API access roles, visit: https://www.mongodb.com/d * @param args - The arguments passed to the tool * @returns The tool metadata */ - protected resolveTelemetryMetadata( - result: CallToolResult, - ...args: Parameters> - ): AtlasToolMetadata { + protected resolveTelemetryMetadata(...args: Parameters>): AtlasToolMetadata { const toolMetadata: AtlasToolMetadata = {}; if (!args.length) { return toolMetadata; diff --git a/src/tools/atlas/read/getPerformanceAdvisor.ts b/src/tools/atlas/read/getPerformanceAdvisor.ts index f6245010..f0922be4 100644 --- a/src/tools/atlas/read/getPerformanceAdvisor.ts +++ b/src/tools/atlas/read/getPerformanceAdvisor.ts @@ -134,12 +134,11 @@ export class GetPerformanceAdvisorTool extends AtlasToolBase { } protected override resolveTelemetryMetadata( - result: CallToolResult, args: ToolArgs, extra: RequestHandlerExtra ): PerfAdvisorToolMetadata { return { - ...super.resolveTelemetryMetadata(result, args, extra), + ...super.resolveTelemetryMetadata(args, extra), operations: args.operations, }; } diff --git a/src/tools/mongodb/mongodbTool.ts b/src/tools/mongodb/mongodbTool.ts index 735579a7..ebf93860 100644 --- a/src/tools/mongodb/mongodbTool.ts +++ b/src/tools/mongodb/mongodbTool.ts @@ -112,8 +112,6 @@ export abstract class MongoDBToolBase extends ToolBase { } protected resolveTelemetryMetadata( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - result: CallToolResult, // eslint-disable-next-line @typescript-eslint/no-unused-vars args: ToolArgs ): AtlasToolMetadata { diff --git a/src/tools/tool.ts b/src/tools/tool.ts index 60cc9a04..f432e020 100644 --- a/src/tools/tool.ts +++ b/src/tools/tool.ts @@ -264,7 +264,6 @@ export abstract class ToolBase { } protected abstract resolveTelemetryMetadata( - result: CallToolResult, ...args: Parameters> ): TelemetryToolMetadata; @@ -283,7 +282,7 @@ export abstract class ToolBase { return; } const duration = Date.now() - startTime; - const metadata = this.resolveTelemetryMetadata(result, ...args); + const metadata = this.resolveTelemetryMetadata(...args); const event: ToolEvent = { timestamp: new Date().toISOString(), source: "mdbmcp", From 3b9e5951cd703cb618ed1acda3d7d480755bd1c7 Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 6 Nov 2025 19:03:58 +0000 Subject: [PATCH 02/11] rename atlas metadata --- src/telemetry/types.ts | 6 +++--- src/tools/atlas/atlasTool.ts | 6 +++--- src/tools/mongodb/mongodbTool.ts | 6 +++--- tests/unit/toolBase.test.ts | 5 +---- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/telemetry/types.ts b/src/telemetry/types.ts index 268c7400..6927f687 100644 --- a/src/telemetry/types.ts +++ b/src/telemetry/types.ts @@ -141,17 +141,17 @@ export type CommonProperties = { * For MongoDB tools, this is typically empty, while for Atlas tools, this should include * the project and organization IDs if available. */ -export type TelemetryToolMetadata = AtlasLocalToolMetadata | AtlasToolMetadata | PerfAdvisorToolMetadata; +export type TelemetryToolMetadata = AtlasLocalToolMetadata | AtlasMetadata | PerfAdvisorToolMetadata; export type AtlasLocalToolMetadata = { atlas_local_deployment_id?: string; }; -export type AtlasToolMetadata = { +export type AtlasMetadata = { project_id?: string; org_id?: string; }; -export type PerfAdvisorToolMetadata = AtlasToolMetadata & { +export type PerfAdvisorToolMetadata = AtlasMetadata & { operations: string[]; }; diff --git a/src/tools/atlas/atlasTool.ts b/src/tools/atlas/atlasTool.ts index b27d3e7b..3533d088 100644 --- a/src/tools/atlas/atlasTool.ts +++ b/src/tools/atlas/atlasTool.ts @@ -1,5 +1,5 @@ import type { ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js"; -import type { AtlasToolMetadata } from "../../telemetry/types.js"; +import type { AtlasMetadata } from "../../telemetry/types.js"; import { ToolBase, type ToolArgs, type ToolCategory } from "../tool.js"; import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { LogId } from "../../common/logger.js"; @@ -82,8 +82,8 @@ For more information on Atlas API access roles, visit: https://www.mongodb.com/d * @param args - The arguments passed to the tool * @returns The tool metadata */ - protected resolveTelemetryMetadata(...args: Parameters>): AtlasToolMetadata { - const toolMetadata: AtlasToolMetadata = {}; + protected resolveTelemetryMetadata(...args: Parameters>): AtlasMetadata { + const toolMetadata: AtlasMetadata = {}; if (!args.length) { return toolMetadata; } diff --git a/src/tools/mongodb/mongodbTool.ts b/src/tools/mongodb/mongodbTool.ts index ebf93860..b2a03d19 100644 --- a/src/tools/mongodb/mongodbTool.ts +++ b/src/tools/mongodb/mongodbTool.ts @@ -6,7 +6,7 @@ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { ErrorCodes, MongoDBError } from "../../common/errors.js"; import { LogId } from "../../common/logger.js"; import type { Server } from "../../server.js"; -import type { AtlasToolMetadata } from "../../telemetry/types.js"; +import type { AtlasMetadata } from "../../telemetry/types.js"; export const DbOperationArgs = { database: z.string().describe("Database name"), @@ -114,8 +114,8 @@ export abstract class MongoDBToolBase extends ToolBase { protected resolveTelemetryMetadata( // eslint-disable-next-line @typescript-eslint/no-unused-vars args: ToolArgs - ): AtlasToolMetadata { - const metadata: AtlasToolMetadata = {}; + ): AtlasMetadata { + const metadata: AtlasMetadata = {}; // Add projectId to the metadata if running a MongoDB operation to an Atlas cluster if (this.session.connectedAtlasCluster?.projectId) { diff --git a/tests/unit/toolBase.test.ts b/tests/unit/toolBase.test.ts index a71c483b..d2b1e30d 100644 --- a/tests/unit/toolBase.test.ts +++ b/tests/unit/toolBase.test.ts @@ -198,10 +198,7 @@ class TestTool extends ToolBase { }); } - protected resolveTelemetryMetadata( - result: CallToolResult, - args: ToolArgs - ): TelemetryToolMetadata { + protected resolveTelemetryMetadata(args: ToolArgs): TelemetryToolMetadata { if (args.param2 === 3) { return { test_param2: "three", From fcbfcff117c9a7b9ad3686f6e7fe1278601a1f1a Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 6 Nov 2025 19:40:08 +0000 Subject: [PATCH 03/11] Revert "chore: cleanup telemetry" This reverts commit c5ec47e3b64f5b2b4af9ea8c37d7f52bc262b69b. --- src/tools/atlas/atlasTool.ts | 5 ++++- src/tools/atlas/read/getPerformanceAdvisor.ts | 3 ++- src/tools/mongodb/mongodbTool.ts | 2 ++ src/tools/tool.ts | 3 ++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/tools/atlas/atlasTool.ts b/src/tools/atlas/atlasTool.ts index 3533d088..f1d6ee4e 100644 --- a/src/tools/atlas/atlasTool.ts +++ b/src/tools/atlas/atlasTool.ts @@ -82,7 +82,10 @@ For more information on Atlas API access roles, visit: https://www.mongodb.com/d * @param args - The arguments passed to the tool * @returns The tool metadata */ - protected resolveTelemetryMetadata(...args: Parameters>): AtlasMetadata { + protected resolveTelemetryMetadata( + result: CallToolResult, + ...args: Parameters> + ): AtlasMetadata { const toolMetadata: AtlasMetadata = {}; if (!args.length) { return toolMetadata; diff --git a/src/tools/atlas/read/getPerformanceAdvisor.ts b/src/tools/atlas/read/getPerformanceAdvisor.ts index f0922be4..f6245010 100644 --- a/src/tools/atlas/read/getPerformanceAdvisor.ts +++ b/src/tools/atlas/read/getPerformanceAdvisor.ts @@ -134,11 +134,12 @@ export class GetPerformanceAdvisorTool extends AtlasToolBase { } protected override resolveTelemetryMetadata( + result: CallToolResult, args: ToolArgs, extra: RequestHandlerExtra ): PerfAdvisorToolMetadata { return { - ...super.resolveTelemetryMetadata(args, extra), + ...super.resolveTelemetryMetadata(result, args, extra), operations: args.operations, }; } diff --git a/src/tools/mongodb/mongodbTool.ts b/src/tools/mongodb/mongodbTool.ts index b2a03d19..c1a5c643 100644 --- a/src/tools/mongodb/mongodbTool.ts +++ b/src/tools/mongodb/mongodbTool.ts @@ -112,6 +112,8 @@ export abstract class MongoDBToolBase extends ToolBase { } protected resolveTelemetryMetadata( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + result: CallToolResult, // eslint-disable-next-line @typescript-eslint/no-unused-vars args: ToolArgs ): AtlasMetadata { diff --git a/src/tools/tool.ts b/src/tools/tool.ts index f432e020..60cc9a04 100644 --- a/src/tools/tool.ts +++ b/src/tools/tool.ts @@ -264,6 +264,7 @@ export abstract class ToolBase { } protected abstract resolveTelemetryMetadata( + result: CallToolResult, ...args: Parameters> ): TelemetryToolMetadata; @@ -282,7 +283,7 @@ export abstract class ToolBase { return; } const duration = Date.now() - startTime; - const metadata = this.resolveTelemetryMetadata(...args); + const metadata = this.resolveTelemetryMetadata(result, ...args); const event: ToolEvent = { timestamp: new Date().toISOString(), source: "mdbmcp", From 1319767a9dc3fc028a1260e4f20491304a41fb32 Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 6 Nov 2025 20:20:50 +0000 Subject: [PATCH 04/11] wip --- src/telemetry/types.ts | 15 ++++++++----- src/tools/atlas/connect/connectCluster.ts | 16 ++++++++++++++ src/tools/atlasLocal/atlasLocalTool.ts | 12 +++++----- src/tools/mongodb/connect/connect.ts | 1 + src/tools/mongodb/mongodbTool.ts | 27 +++++++++++++---------- src/tools/tool.ts | 16 +++++++++++++- 6 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/telemetry/types.ts b/src/telemetry/types.ts index 6927f687..46b91f3b 100644 --- a/src/telemetry/types.ts +++ b/src/telemetry/types.ts @@ -141,11 +141,7 @@ export type CommonProperties = { * For MongoDB tools, this is typically empty, while for Atlas tools, this should include * the project and organization IDs if available. */ -export type TelemetryToolMetadata = AtlasLocalToolMetadata | AtlasMetadata | PerfAdvisorToolMetadata; - -export type AtlasLocalToolMetadata = { - atlas_local_deployment_id?: string; -}; +export type TelemetryToolMetadata = AtlasMetadata | PerfAdvisorToolMetadata | ConnectionMetadata; export type AtlasMetadata = { project_id?: string; @@ -155,3 +151,12 @@ export type AtlasMetadata = { export type PerfAdvisorToolMetadata = AtlasMetadata & { operations: string[]; }; + +export type ConnectionMetadata = AtlasMetadata & + AtlasLocalToolMetadata & { + connection_auth_type?: string; + }; + +type AtlasLocalToolMetadata = { + atlas_local_deployment_id?: string; +}; diff --git a/src/tools/atlas/connect/connectCluster.ts b/src/tools/atlas/connect/connectCluster.ts index 3ba519fc..1dcea114 100644 --- a/src/tools/atlas/connect/connectCluster.ts +++ b/src/tools/atlas/connect/connectCluster.ts @@ -8,6 +8,7 @@ import { ensureCurrentIpInAccessList } from "../../../common/atlas/accessListUti import type { AtlasClusterConnectionInfo } from "../../../common/connectionManager.js"; import { getDefaultRoleFromConfig } from "../../../common/atlas/roles.js"; import { AtlasArgs } from "../../args.js"; +import { AtlasLocalToolMetadata } from "../../../telemetry/types.js"; const addedIpAccessListMessage = "Note: Your current IP address has been added to the Atlas project's IP access list to enable secure connection."; @@ -303,4 +304,19 @@ export class ConnectClusterTool extends AtlasToolBase { return { content }; } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected override resolveTelemetryMetadata(_args: ToolArgs): AtlasLocalToolMetadata { + const metadata: AtlasLocalToolMetadata = {}; + const connectionStringAuthType = this.session.connectionManager.currentConnectionState.connectionStringAuthType; + if (connectionStringAuthType) { + metadata.connection_auth_type = connectionStringAuthType; + } + + if (this.session.connectedAtlasCluster?.projectId) { + metadata.project_id = this.session.connectedAtlasCluster.projectId; + } + + return metadata; + } } diff --git a/src/tools/atlasLocal/atlasLocalTool.ts b/src/tools/atlasLocal/atlasLocalTool.ts index dc548e20..6bdb0a0b 100644 --- a/src/tools/atlasLocal/atlasLocalTool.ts +++ b/src/tools/atlasLocal/atlasLocalTool.ts @@ -4,9 +4,9 @@ import { ToolBase } from "../tool.js"; import type { ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js"; import type { Client } from "@mongodb-js/atlas-local"; import { LogId } from "../../common/logger.js"; -import type { AtlasLocalToolMetadata } from "../../telemetry/types.js"; +import type { ConnectionMetadata } from "../../telemetry/types.js"; -export const AtlasLocalToolMetadataDeploymentIdKey = "deploymentId"; +export const ConnectionMetadataDeploymentIdKey = "deploymentId"; export abstract class AtlasLocalToolBase extends ToolBase { public category: ToolCategory = "atlas-local"; @@ -67,7 +67,7 @@ please log a ticket here: https://github.com/mongodb-js/mongodb-mcp-server/issue } return { - [AtlasLocalToolMetadataDeploymentIdKey]: deploymentId, + [ConnectionMetadataDeploymentIdKey]: deploymentId, }; } @@ -119,12 +119,12 @@ please log a ticket here: https://github.com/mongodb-js/mongodb-mcp-server/issue return super.handleError(error, args); } - protected resolveTelemetryMetadata(result: CallToolResult): AtlasLocalToolMetadata { - const toolMetadata: AtlasLocalToolMetadata = {}; + protected resolveTelemetryMetadata(result: CallToolResult): ConnectionMetadata { + const toolMetadata: ConnectionMetadata = {}; // Atlas Local tools set the deployment ID in the result metadata for telemetry // If the deployment ID is set, we use it for telemetry - const resultDeploymentId = result._meta?.[AtlasLocalToolMetadataDeploymentIdKey]; + const resultDeploymentId = result._meta?.[ConnectionMetadataDeploymentIdKey]; if (resultDeploymentId !== undefined && typeof resultDeploymentId === "string") { toolMetadata.atlas_local_deployment_id = resultDeploymentId; } diff --git a/src/tools/mongodb/connect/connect.ts b/src/tools/mongodb/connect/connect.ts index 601fcb36..d04438c5 100644 --- a/src/tools/mongodb/connect/connect.ts +++ b/src/tools/mongodb/connect/connect.ts @@ -5,6 +5,7 @@ import type { ToolArgs, OperationType, ToolConstructorParams } from "../../tool. import assert from "assert"; import type { Server } from "../../../server.js"; import { LogId } from "../../../common/logger.js"; +import { AtlasLocalToolMetadata } from "../../../telemetry/types.js"; const disconnectedSchema = z .object({ diff --git a/src/tools/mongodb/mongodbTool.ts b/src/tools/mongodb/mongodbTool.ts index c1a5c643..e28338b3 100644 --- a/src/tools/mongodb/mongodbTool.ts +++ b/src/tools/mongodb/mongodbTool.ts @@ -6,7 +6,8 @@ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { ErrorCodes, MongoDBError } from "../../common/errors.js"; import { LogId } from "../../common/logger.js"; import type { Server } from "../../server.js"; -import type { AtlasMetadata } from "../../telemetry/types.js"; +import type { ConnectionMetadata } from "../../telemetry/types.js"; +import type { ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js"; export const DbOperationArgs = { database: z.string().describe("Database name"), @@ -111,19 +112,21 @@ export abstract class MongoDBToolBase extends ToolBase { return this.session.connectToMongoDB({ connectionString }); } + /** + * Resolves the tool metadata from the arguments passed to the mongoDB tools. + * + * Since MongoDB tools are executed against a MongoDB instance, the tool calls will always have the connection information. + * + * @param result - The result of the tool call. + * @param args - The arguments passed to the tool + * @returns The tool metadata + */ protected resolveTelemetryMetadata( // eslint-disable-next-line @typescript-eslint/no-unused-vars - result: CallToolResult, + _result: CallToolResult, // eslint-disable-next-line @typescript-eslint/no-unused-vars - args: ToolArgs - ): AtlasMetadata { - const metadata: AtlasMetadata = {}; - - // Add projectId to the metadata if running a MongoDB operation to an Atlas cluster - if (this.session.connectedAtlasCluster?.projectId) { - metadata.project_id = this.session.connectedAtlasCluster.projectId; - } - - return metadata; + _args: Parameters> + ): ConnectionMetadata { + return this.getConnectionInfoMetadata(); } } diff --git a/src/tools/tool.ts b/src/tools/tool.ts index 60cc9a04..0ad9377a 100644 --- a/src/tools/tool.ts +++ b/src/tools/tool.ts @@ -5,7 +5,7 @@ import type { CallToolResult, ToolAnnotations } from "@modelcontextprotocol/sdk/ import type { Session } from "../common/session.js"; import { LogId } from "../common/logger.js"; import type { Telemetry } from "../telemetry/telemetry.js"; -import type { TelemetryToolMetadata, ToolEvent } from "../telemetry/types.js"; +import type { ConnectionMetadata, TelemetryToolMetadata, ToolEvent } from "../telemetry/types.js"; import type { UserConfig } from "../common/config.js"; import type { Server } from "../server.js"; import type { Elicitation } from "../elicitation.js"; @@ -303,6 +303,20 @@ export abstract class ToolBase { protected isFeatureEnabled(feature: PreviewFeature): boolean { return this.config.previewFeatures.includes(feature); } + + protected getConnectionInfoMetadata(): ConnectionMetadata { + const metadata: ConnectionMetadata = {}; + const connectionStringAuthType = this.session.connectionManager.currentConnectionState.connectionStringAuthType; + if (connectionStringAuthType) { + metadata.connection_auth_type = connectionStringAuthType; + } + + if (this.session.connectedAtlasCluster?.projectId) { + metadata.project_id = this.session.connectedAtlasCluster.projectId; + } + + return metadata; + } } /** From 94af53dc6338690047c47c8e112b1077d0784753 Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 6 Nov 2025 20:21:40 +0000 Subject: [PATCH 05/11] fix deploymentid name --- src/tools/atlasLocal/atlasLocalTool.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/atlasLocal/atlasLocalTool.ts b/src/tools/atlasLocal/atlasLocalTool.ts index 6bdb0a0b..67b66872 100644 --- a/src/tools/atlasLocal/atlasLocalTool.ts +++ b/src/tools/atlasLocal/atlasLocalTool.ts @@ -6,7 +6,7 @@ import type { Client } from "@mongodb-js/atlas-local"; import { LogId } from "../../common/logger.js"; import type { ConnectionMetadata } from "../../telemetry/types.js"; -export const ConnectionMetadataDeploymentIdKey = "deploymentId"; +export const AtlasLocalToolMetadataDeploymentIdKey = "deploymentId"; export abstract class AtlasLocalToolBase extends ToolBase { public category: ToolCategory = "atlas-local"; @@ -67,7 +67,7 @@ please log a ticket here: https://github.com/mongodb-js/mongodb-mcp-server/issue } return { - [ConnectionMetadataDeploymentIdKey]: deploymentId, + [AtlasLocalToolMetadataDeploymentIdKey]: deploymentId, }; } @@ -124,7 +124,7 @@ please log a ticket here: https://github.com/mongodb-js/mongodb-mcp-server/issue // Atlas Local tools set the deployment ID in the result metadata for telemetry // If the deployment ID is set, we use it for telemetry - const resultDeploymentId = result._meta?.[ConnectionMetadataDeploymentIdKey]; + const resultDeploymentId = result._meta?.[AtlasLocalToolMetadataDeploymentIdKey]; if (resultDeploymentId !== undefined && typeof resultDeploymentId === "string") { toolMetadata.atlas_local_deployment_id = resultDeploymentId; } From b6c97908428bf91598f11f924ffb727d30866f09 Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 6 Nov 2025 20:23:12 +0000 Subject: [PATCH 06/11] revert test change --- tests/unit/toolBase.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/toolBase.test.ts b/tests/unit/toolBase.test.ts index d2b1e30d..a71c483b 100644 --- a/tests/unit/toolBase.test.ts +++ b/tests/unit/toolBase.test.ts @@ -198,7 +198,10 @@ class TestTool extends ToolBase { }); } - protected resolveTelemetryMetadata(args: ToolArgs): TelemetryToolMetadata { + protected resolveTelemetryMetadata( + result: CallToolResult, + args: ToolArgs + ): TelemetryToolMetadata { if (args.param2 === 3) { return { test_param2: "three", From 9a28985be031d770a7c868d86b2944398d8d59df Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 6 Nov 2025 21:24:23 +0000 Subject: [PATCH 07/11] update --- src/common/session.ts | 5 ++ src/tools/atlas/connect/connectCluster.ts | 6 +- src/tools/mongodb/connect/connect.ts | 2 +- src/tools/tool.ts | 10 +-- tests/unit/toolBase.test.ts | 84 +++++++++++++++++++++++ 5 files changed, 98 insertions(+), 9 deletions(-) diff --git a/src/common/session.ts b/src/common/session.ts index e692a7a4..4a8a0213 100644 --- a/src/common/session.ts +++ b/src/common/session.ts @@ -11,6 +11,7 @@ import type { ConnectionSettings, ConnectionStateConnected, ConnectionStateErrored, + ConnectionStringAuthType, } from "./connectionManager.js"; import type { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver"; import { ErrorCodes, MongoDBError } from "./errors.js"; @@ -182,4 +183,8 @@ export class Session extends EventEmitter { get connectedAtlasCluster(): AtlasClusterConnectionInfo | undefined { return this.connectionManager.currentConnectionState.connectedAtlasCluster; } + + get connectionStringAuthType(): ConnectionStringAuthType | undefined { + return this.connectionManager.currentConnectionState.connectionStringAuthType; + } } diff --git a/src/tools/atlas/connect/connectCluster.ts b/src/tools/atlas/connect/connectCluster.ts index 1dcea114..4fc1a5c3 100644 --- a/src/tools/atlas/connect/connectCluster.ts +++ b/src/tools/atlas/connect/connectCluster.ts @@ -8,7 +8,7 @@ import { ensureCurrentIpInAccessList } from "../../../common/atlas/accessListUti import type { AtlasClusterConnectionInfo } from "../../../common/connectionManager.js"; import { getDefaultRoleFromConfig } from "../../../common/atlas/roles.js"; import { AtlasArgs } from "../../args.js"; -import { AtlasLocalToolMetadata } from "../../../telemetry/types.js"; +import { ConnectionMetadata } from "../../../telemetry/types.js"; const addedIpAccessListMessage = "Note: Your current IP address has been added to the Atlas project's IP access list to enable secure connection."; @@ -306,8 +306,8 @@ export class ConnectClusterTool extends AtlasToolBase { } // eslint-disable-next-line @typescript-eslint/no-unused-vars - protected override resolveTelemetryMetadata(_args: ToolArgs): AtlasLocalToolMetadata { - const metadata: AtlasLocalToolMetadata = {}; + protected override resolveTelemetryMetadata(_args: ToolArgs): ConnectionMetadata { + const metadata: ConnectionMetadata = {}; const connectionStringAuthType = this.session.connectionManager.currentConnectionState.connectionStringAuthType; if (connectionStringAuthType) { metadata.connection_auth_type = connectionStringAuthType; diff --git a/src/tools/mongodb/connect/connect.ts b/src/tools/mongodb/connect/connect.ts index d04438c5..661b0bc6 100644 --- a/src/tools/mongodb/connect/connect.ts +++ b/src/tools/mongodb/connect/connect.ts @@ -5,7 +5,7 @@ import type { ToolArgs, OperationType, ToolConstructorParams } from "../../tool. import assert from "assert"; import type { Server } from "../../../server.js"; import { LogId } from "../../../common/logger.js"; -import { AtlasLocalToolMetadata } from "../../../telemetry/types.js"; +import { ConnectionMetadata } from "../../../telemetry/types.js"; const disconnectedSchema = z .object({ diff --git a/src/tools/tool.ts b/src/tools/tool.ts index 0ad9377a..ac650215 100644 --- a/src/tools/tool.ts +++ b/src/tools/tool.ts @@ -306,15 +306,15 @@ export abstract class ToolBase { protected getConnectionInfoMetadata(): ConnectionMetadata { const metadata: ConnectionMetadata = {}; - const connectionStringAuthType = this.session.connectionManager.currentConnectionState.connectionStringAuthType; - if (connectionStringAuthType) { - metadata.connection_auth_type = connectionStringAuthType; - } - if (this.session.connectedAtlasCluster?.projectId) { metadata.project_id = this.session.connectedAtlasCluster.projectId; } + const connectionStringAuthType = this.session.connectionStringAuthType; + if (connectionStringAuthType !== undefined) { + metadata.connection_auth_type = connectionStringAuthType; + } + return metadata; } } diff --git a/tests/unit/toolBase.test.ts b/tests/unit/toolBase.test.ts index a71c483b..e6d7c58e 100644 --- a/tests/unit/toolBase.test.ts +++ b/tests/unit/toolBase.test.ts @@ -175,6 +175,90 @@ describe("ToolBase", () => { expect(event.properties).toHaveProperty("test_param2", "three"); }); }); + + describe("getConnectionInfoMetadata", () => { + it("should return empty metadata when neither connectedAtlasCluster nor connectionStringAuthType are set", () => { + (mockSession as { connectedAtlasCluster?: unknown }).connectedAtlasCluster = undefined; + (mockSession as { connectionStringAuthType?: unknown }).connectionStringAuthType = undefined; + + const metadata = testTool["getConnectionInfoMetadata"](); + + expect(metadata).toEqual({}); + expect(metadata).not.toHaveProperty("project_id"); + expect(metadata).not.toHaveProperty("connection_auth_type"); + }); + + it("should return metadata with project_id when connectedAtlasCluster.projectId is set", () => { + (mockSession as { connectedAtlasCluster?: unknown }).connectedAtlasCluster = { + projectId: "test-project-id", + username: "test-user", + clusterName: "test-cluster", + expiryDate: new Date(), + }; + (mockSession as { connectionStringAuthType?: unknown }).connectionStringAuthType = undefined; + + const metadata = testTool["getConnectionInfoMetadata"](); + + expect(metadata).toEqual({ + project_id: "test-project-id", + }); + expect(metadata).not.toHaveProperty("connection_auth_type"); + }); + + it("should return empty metadata when connectedAtlasCluster exists but projectId is falsy", () => { + (mockSession as { connectedAtlasCluster?: unknown }).connectedAtlasCluster = { + projectId: "", + username: "test-user", + clusterName: "test-cluster", + expiryDate: new Date(), + }; + (mockSession as { connectionStringAuthType?: unknown }).connectionStringAuthType = undefined; + + const metadata = testTool["getConnectionInfoMetadata"](); + + expect(metadata).toEqual({}); + expect(metadata).not.toHaveProperty("project_id"); + }); + + it("should return metadata with connection_auth_type when connectionStringAuthType is set", () => { + (mockSession as { connectedAtlasCluster?: unknown }).connectedAtlasCluster = undefined; + (mockSession as { connectionStringAuthType?: unknown }).connectionStringAuthType = "scram"; + + const metadata = testTool["getConnectionInfoMetadata"](); + + expect(metadata).toEqual({ + connection_auth_type: "scram", + }); + expect(metadata).not.toHaveProperty("project_id"); + }); + + it("should return metadata with both project_id and connection_auth_type when both are set", () => { + (mockSession as { connectedAtlasCluster?: unknown }).connectedAtlasCluster = { + projectId: "test-project-id", + username: "test-user", + clusterName: "test-cluster", + expiryDate: new Date(), + }; + (mockSession as { connectionStringAuthType?: unknown }).connectionStringAuthType = "oidc-auth-flow"; + + const metadata = testTool["getConnectionInfoMetadata"](); + + expect(metadata).toEqual({ + project_id: "test-project-id", + connection_auth_type: "oidc-auth-flow", + }); + }); + + it("should handle different connectionStringAuthType values", () => { + const authTypes = ["scram", "ldap", "kerberos", "oidc-auth-flow", "oidc-device-flow", "x.509"] as const; + + for (const authType of authTypes) { + (mockSession as { connectionStringAuthType?: unknown }).connectionStringAuthType = authType; + const metadata = testTool["getConnectionInfoMetadata"](); + expect(metadata.connection_auth_type).toBe(authType); + } + }); + }); }); class TestTool extends ToolBase { From 55cb171cb92bd80e590f9a67f13a7190050dd15d Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 6 Nov 2025 21:35:01 +0000 Subject: [PATCH 08/11] update connection tools --- src/tools/atlas/connect/connectCluster.ts | 24 ++++++++----------- .../atlasLocal/connect/connectDeployment.ts | 8 +++++++ src/tools/mongodb/connect/connect.ts | 1 - 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/tools/atlas/connect/connectCluster.ts b/src/tools/atlas/connect/connectCluster.ts index 4fc1a5c3..300089b9 100644 --- a/src/tools/atlas/connect/connectCluster.ts +++ b/src/tools/atlas/connect/connectCluster.ts @@ -8,7 +8,8 @@ import { ensureCurrentIpInAccessList } from "../../../common/atlas/accessListUti import type { AtlasClusterConnectionInfo } from "../../../common/connectionManager.js"; import { getDefaultRoleFromConfig } from "../../../common/atlas/roles.js"; import { AtlasArgs } from "../../args.js"; -import { ConnectionMetadata } from "../../../telemetry/types.js"; +import type { ConnectionMetadata } from "../../../telemetry/types.js"; +import type { ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js"; const addedIpAccessListMessage = "Note: Your current IP address has been added to the Atlas project's IP access list to enable secure connection."; @@ -305,18 +306,13 @@ export class ConnectClusterTool extends AtlasToolBase { return { content }; } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - protected override resolveTelemetryMetadata(_args: ToolArgs): ConnectionMetadata { - const metadata: ConnectionMetadata = {}; - const connectionStringAuthType = this.session.connectionManager.currentConnectionState.connectionStringAuthType; - if (connectionStringAuthType) { - metadata.connection_auth_type = connectionStringAuthType; - } - - if (this.session.connectedAtlasCluster?.projectId) { - metadata.project_id = this.session.connectedAtlasCluster.projectId; - } - - return metadata; + protected override resolveTelemetryMetadata( + result: CallToolResult, + args: Parameters> + ): ConnectionMetadata { + return { + ...super.resolveTelemetryMetadata(result, ...args), + ...this.getConnectionInfoMetadata(), + }; } } diff --git a/src/tools/atlasLocal/connect/connectDeployment.ts b/src/tools/atlasLocal/connect/connectDeployment.ts index c8523bb1..35f5e584 100644 --- a/src/tools/atlasLocal/connect/connectDeployment.ts +++ b/src/tools/atlasLocal/connect/connectDeployment.ts @@ -3,6 +3,7 @@ import { AtlasLocalToolBase } from "../atlasLocalTool.js"; import type { OperationType, ToolArgs } from "../../tool.js"; import type { Client } from "@mongodb-js/atlas-local"; import { CommonArgs } from "../../args.js"; +import type { ConnectionMetadata } from "../../../telemetry/types.js"; export class ConnectDeploymentTool extends AtlasLocalToolBase { public name = "atlas-local-connect-deployment"; @@ -34,4 +35,11 @@ export class ConnectDeploymentTool extends AtlasLocalToolBase { }, }; } + + protected override resolveTelemetryMetadata(result: CallToolResult): ConnectionMetadata { + return { + ...super.resolveTelemetryMetadata(result), + ...this.getConnectionInfoMetadata(), + }; + } } diff --git a/src/tools/mongodb/connect/connect.ts b/src/tools/mongodb/connect/connect.ts index 661b0bc6..601fcb36 100644 --- a/src/tools/mongodb/connect/connect.ts +++ b/src/tools/mongodb/connect/connect.ts @@ -5,7 +5,6 @@ import type { ToolArgs, OperationType, ToolConstructorParams } from "../../tool. import assert from "assert"; import type { Server } from "../../../server.js"; import { LogId } from "../../../common/logger.js"; -import { ConnectionMetadata } from "../../../telemetry/types.js"; const disconnectedSchema = z .object({ From d2709e04c0ac79c77b5e17625c34f4db21d7979c Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 6 Nov 2025 22:04:55 +0000 Subject: [PATCH 09/11] add mongodbtool test --- .../tools/mongodb/mongodbTool.test.ts | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/tests/integration/tools/mongodb/mongodbTool.test.ts b/tests/integration/tools/mongodb/mongodbTool.test.ts index ca3bc423..94b3ced4 100644 --- a/tests/integration/tools/mongodb/mongodbTool.test.ts +++ b/tests/integration/tools/mongodb/mongodbTool.test.ts @@ -5,7 +5,11 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { MongoDBToolBase } from "../../../../src/tools/mongodb/mongodbTool.js"; import { type ToolBase, type ToolConstructorParams, type OperationType } from "../../../../src/tools/tool.js"; import { defaultDriverOptions, type UserConfig } from "../../../../src/common/config.js"; -import { MCPConnectionManager } from "../../../../src/common/connectionManager.js"; +import { + MCPConnectionManager, + ConnectionStateConnected, + type AtlasClusterConnectionInfo, +} from "../../../../src/common/connectionManager.js"; import { Session } from "../../../../src/common/session.js"; import { CompositeLogger } from "../../../../src/common/logger.js"; import { DeviceId } from "../../../../src/helpers/deviceId.js"; @@ -14,13 +18,14 @@ import { InMemoryTransport } from "../../inMemoryTransport.js"; import { Telemetry } from "../../../../src/telemetry/telemetry.js"; import { Server } from "../../../../src/server.js"; import { type ConnectionErrorHandler, connectionErrorHandler } from "../../../../src/common/connectionErrorHandler.js"; -import { defaultTestConfig } from "../../helpers.js"; +import { defaultTestConfig, expectDefined } from "../../helpers.js"; import { setupMongoDBIntegrationTest } from "./mongodbHelpers.js"; import { ErrorCodes } from "../../../../src/common/errors.js"; import { Keychain } from "../../../../src/common/keychain.js"; import { Elicitation } from "../../../../src/elicitation.js"; import { MongoDbTools } from "../../../../src/tools/mongodb/tools.js"; import { VectorSearchEmbeddingsManager } from "../../../../src/common/search/vectorSearchEmbeddingsManager.js"; +import { type TestConnectionManager } from "../../../utils/index.js"; const injectedErrorHandler: ConnectionErrorHandler = (error) => { switch (error.code) { @@ -327,4 +332,42 @@ describe("MongoDBTool implementations", () => { expect(tools?.tools.find((tool) => tool.name === "UnusableVoyageTool")).toBeUndefined(); }); }); + + describe("resolveTelemetryMetadata", () => { + it("should return empty metadata when not connected", async () => { + await cleanupAndStartServer(); + const tool = mcpServer?.tools.find((t) => t.name === "Random"); + expectDefined(tool); + const randomTool = tool as RandomTool; + + const result: CallToolResult = { content: [{ type: "text", text: "test" }] }; + const metadata = randomTool["resolveTelemetryMetadata"](result, {} as never); + + expect(metadata).toEqual({}); + expect(metadata).not.toHaveProperty("project_id"); + expect(metadata).not.toHaveProperty("connection_auth_type"); + }); + + it("should return metadata with connection_auth_type when connected via connection string", async () => { + await cleanupAndStartServer({ connectionString: mdbIntegration.connectionString() }); + // Connect to MongoDB to set the connection state + await mcpClient?.callTool({ + name: "Random", + arguments: {}, + }); + + const tool = mcpServer?.tools.find((t) => t.name === "Random"); + expectDefined(tool); + const randomTool = tool as RandomTool; + + const result: CallToolResult = { content: [{ type: "text", text: "test" }] }; + const metadata = randomTool["resolveTelemetryMetadata"](result, {} as never); + + // When connected via connection string, connection_auth_type should be set + // The actual value depends on the connection string, but it should be present + expect(metadata).toHaveProperty("connection_auth_type"); + expect(typeof metadata.connection_auth_type).toBe("string"); + expect(metadata.connection_auth_type).toBe("scram"); + }); + }); }); From ac8aa2da3def158f653fcfcd5a3a2b157381e8f8 Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 6 Nov 2025 22:08:27 +0000 Subject: [PATCH 10/11] fix check --- tests/integration/tools/mongodb/mongodbTool.test.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/integration/tools/mongodb/mongodbTool.test.ts b/tests/integration/tools/mongodb/mongodbTool.test.ts index 94b3ced4..6692c6ef 100644 --- a/tests/integration/tools/mongodb/mongodbTool.test.ts +++ b/tests/integration/tools/mongodb/mongodbTool.test.ts @@ -5,11 +5,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { MongoDBToolBase } from "../../../../src/tools/mongodb/mongodbTool.js"; import { type ToolBase, type ToolConstructorParams, type OperationType } from "../../../../src/tools/tool.js"; import { defaultDriverOptions, type UserConfig } from "../../../../src/common/config.js"; -import { - MCPConnectionManager, - ConnectionStateConnected, - type AtlasClusterConnectionInfo, -} from "../../../../src/common/connectionManager.js"; +import { MCPConnectionManager } from "../../../../src/common/connectionManager.js"; import { Session } from "../../../../src/common/session.js"; import { CompositeLogger } from "../../../../src/common/logger.js"; import { DeviceId } from "../../../../src/helpers/deviceId.js"; @@ -25,7 +21,6 @@ import { Keychain } from "../../../../src/common/keychain.js"; import { Elicitation } from "../../../../src/elicitation.js"; import { MongoDbTools } from "../../../../src/tools/mongodb/tools.js"; import { VectorSearchEmbeddingsManager } from "../../../../src/common/search/vectorSearchEmbeddingsManager.js"; -import { type TestConnectionManager } from "../../../utils/index.js"; const injectedErrorHandler: ConnectionErrorHandler = (error) => { switch (error.code) { From b5964dd5c54ebb3c8244bfa3c513281f4d18fbb2 Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Fri, 7 Nov 2025 10:49:15 +0000 Subject: [PATCH 11/11] address copilot comments --- src/tools/atlas/connect/connectCluster.ts | 14 ++++++++++++-- src/tools/atlasLocal/connect/connectDeployment.ts | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/tools/atlas/connect/connectCluster.ts b/src/tools/atlas/connect/connectCluster.ts index 300089b9..c12f1709 100644 --- a/src/tools/atlas/connect/connectCluster.ts +++ b/src/tools/atlas/connect/connectCluster.ts @@ -310,9 +310,19 @@ export class ConnectClusterTool extends AtlasToolBase { result: CallToolResult, args: Parameters> ): ConnectionMetadata { + const parentMetadata = super.resolveTelemetryMetadata(result, ...args); + const connectionMetadata = this.getConnectionInfoMetadata(); + // Explicitly merge, preferring parentMetadata for known overlapping keys (project_id, org_id) + // since parent has more complete information from tool arguments + const { project_id, org_id, ...restConnectionMetadata } = connectionMetadata; + const finalProjectId = parentMetadata.project_id ?? project_id; + const finalOrgId = parentMetadata.org_id ?? org_id; return { - ...super.resolveTelemetryMetadata(result, ...args), - ...this.getConnectionInfoMetadata(), + ...parentMetadata, + ...restConnectionMetadata, + // Only include project_id and org_id if they are defined + ...(finalProjectId !== undefined && { project_id: finalProjectId }), + ...(finalOrgId !== undefined && { org_id: finalOrgId }), }; } } diff --git a/src/tools/atlasLocal/connect/connectDeployment.ts b/src/tools/atlasLocal/connect/connectDeployment.ts index 35f5e584..f183a556 100644 --- a/src/tools/atlasLocal/connect/connectDeployment.ts +++ b/src/tools/atlasLocal/connect/connectDeployment.ts @@ -37,9 +37,19 @@ export class ConnectDeploymentTool extends AtlasLocalToolBase { } protected override resolveTelemetryMetadata(result: CallToolResult): ConnectionMetadata { + const parentMetadata = super.resolveTelemetryMetadata(result); + const connectionMetadata = this.getConnectionInfoMetadata(); + // Explicitly merge, preferring parentMetadata for known overlapping keys (project_id, org_id) + // since parent has deployment-specific information + const { project_id, org_id, ...restConnectionMetadata } = connectionMetadata; + const finalProjectId = parentMetadata.project_id ?? project_id; + const finalOrgId = parentMetadata.org_id ?? org_id; return { - ...super.resolveTelemetryMetadata(result), - ...this.getConnectionInfoMetadata(), + ...parentMetadata, + ...restConnectionMetadata, + // Only include project_id and org_id if they are defined + ...(finalProjectId !== undefined && { project_id: finalProjectId }), + ...(finalOrgId !== undefined && { org_id: finalOrgId }), }; } }