From e654962b0e1c68cbace4d33e773a5bf3707bfdff Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Mon, 7 Jul 2025 18:24:12 +0100 Subject: [PATCH 01/25] fix: turn atlas-connect-cluster async --- src/tools/atlas/metadata/connectCluster.ts | 99 ++++++++++++++++++++-- 1 file changed, 94 insertions(+), 5 deletions(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 18970e24..9bb5dbc0 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -11,16 +11,36 @@ const EXPIRY_MS = 1000 * 60 * 60 * 12; // 12 hours function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } + export class ConnectClusterTool extends AtlasToolBase { protected name = "atlas-connect-cluster"; - protected description = "Connect to MongoDB Atlas cluster"; + protected description = "Connect to/Query status of MongoDB Atlas cluster"; protected operationType: OperationType = "metadata"; protected argsShape = { projectId: z.string().describe("Atlas project ID"), clusterName: z.string().describe("Atlas cluster name"), }; - protected async execute({ projectId, clusterName }: ToolArgs): Promise { + private async queryConnection(projectId: string, clusterName: string) : Promise<"connected" | "disconnected" | "connecting" | "connected-to-other-cluster"> { + if (!this.session.connectedAtlasCluster) { + return "disconnected"; + } + + if (this.session.connectedAtlasCluster.projectId !== projectId || this.session.connectedAtlasCluster.clusterName !== clusterName) { + return "connected-to-other-cluster"; + } + + if (!this.session.serviceProvider) { + return "connecting"; + } + + await this.session.serviceProvider.runCommand("admin", { + ping: 1, + }); + return "connected"; + } + + private async prepareClusterConnection(projectId: string, clusterName: string) : Promise { await this.session.disconnect(); const cluster = await inspectCluster(this.session.apiClient, projectId, clusterName); @@ -83,9 +103,13 @@ export class ConnectClusterTool extends AtlasToolBase { cn.searchParams.set("authSource", "admin"); const connectionString = cn.toString(); + return connectionString; + } + + private async connectToCluster(connectionString: string): Promise { let lastError: Error | undefined = undefined; - for (let i = 0; i < 20; i++) { + for (let i = 0; i < 600; i++) { // try for 5 minutes try { await this.session.connectToMongoDB(connectionString, this.config.connectOptions); lastError = undefined; @@ -104,16 +128,81 @@ export class ConnectClusterTool extends AtlasToolBase { await sleep(500); // wait for 500ms before retrying } } - + if (lastError) { + void this.session.apiClient.deleteDatabaseUser({ + params: { + path: { + groupId: this.session.connectedAtlasCluster?.projectId || "", + username: this.session.connectedAtlasCluster?.username || "", + databaseName: "admin", + }, + }, + }).catch((err: unknown) => { + const error = err instanceof Error ? err : new Error(String(err)); + logger.debug( + LogId.atlasConnectFailure, + "atlas-connect-cluster", + `error deleting database user: ${error.message}` + ); + }); + this.session.connectedAtlasCluster = undefined; throw lastError; } + } + + protected async execute({ projectId, clusterName }: ToolArgs): Promise { + try { + const state = await this.queryConnection(projectId, clusterName); + switch (state) { + case "connected": + return { + content: [ + { + type: "text", + text: "Cluster is already connected.", + }, + ], + }; + case "connecting": + return { + content: [ + { + type: "text", + text: "Cluster is connecting...", + }, + ], + }; + } + } catch (err: unknown) { + const error = err instanceof Error ? err : new Error(String(err)); + logger.debug( + LogId.atlasConnectFailure, + "atlas-connect-cluster", + `error querying cluster: ${error.message}` + ); + // fall through to create new connection + } + + const connectionString = await this.prepareClusterConnection(projectId, clusterName); + process.nextTick(async () => { + try { + await this.connectToCluster(connectionString); + } catch (err: unknown) { + const error = err instanceof Error ? err : new Error(String(err)); + logger.debug( + LogId.atlasConnectFailure, + "atlas-connect-cluster", + `error connecting to cluster: ${error.message}` + ); + } + }); return { content: [ { type: "text", - text: `Connected to cluster "${clusterName}"`, + text: `Connecting to cluster "${clusterName}"...`, }, ], }; From 24298edad491c905c0e43aa16be89be377077eeb Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Mon, 7 Jul 2025 18:25:03 +0100 Subject: [PATCH 02/25] fix: update decription --- src/tools/atlas/metadata/connectCluster.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 9bb5dbc0..323f571e 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -14,7 +14,7 @@ function sleep(ms: number): Promise { export class ConnectClusterTool extends AtlasToolBase { protected name = "atlas-connect-cluster"; - protected description = "Connect to/Query status of MongoDB Atlas cluster"; + protected description = "Connect to MongoDB Atlas cluster"; protected operationType: OperationType = "metadata"; protected argsShape = { projectId: z.string().describe("Atlas project ID"), From f45b22fa8d6e6aff9ea3d914078136f465827a79 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Mon, 7 Jul 2025 18:29:59 +0100 Subject: [PATCH 03/25] fix: format --- src/tools/atlas/metadata/connectCluster.ts | 51 +++++++++++++--------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 323f571e..922b0308 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -21,12 +21,18 @@ export class ConnectClusterTool extends AtlasToolBase { clusterName: z.string().describe("Atlas cluster name"), }; - private async queryConnection(projectId: string, clusterName: string) : Promise<"connected" | "disconnected" | "connecting" | "connected-to-other-cluster"> { + private async queryConnection( + projectId: string, + clusterName: string + ): Promise<"connected" | "disconnected" | "connecting" | "connected-to-other-cluster"> { if (!this.session.connectedAtlasCluster) { return "disconnected"; } - if (this.session.connectedAtlasCluster.projectId !== projectId || this.session.connectedAtlasCluster.clusterName !== clusterName) { + if ( + this.session.connectedAtlasCluster.projectId !== projectId || + this.session.connectedAtlasCluster.clusterName !== clusterName + ) { return "connected-to-other-cluster"; } @@ -40,7 +46,7 @@ export class ConnectClusterTool extends AtlasToolBase { return "connected"; } - private async prepareClusterConnection(projectId: string, clusterName: string) : Promise { + private async prepareClusterConnection(projectId: string, clusterName: string): Promise { await this.session.disconnect(); const cluster = await inspectCluster(this.session.apiClient, projectId, clusterName); @@ -109,7 +115,8 @@ export class ConnectClusterTool extends AtlasToolBase { private async connectToCluster(connectionString: string): Promise { let lastError: Error | undefined = undefined; - for (let i = 0; i < 600; i++) { // try for 5 minutes + for (let i = 0; i < 600; i++) { + // try for 5 minutes try { await this.session.connectToMongoDB(connectionString, this.config.connectOptions); lastError = undefined; @@ -128,29 +135,31 @@ export class ConnectClusterTool extends AtlasToolBase { await sleep(500); // wait for 500ms before retrying } } - + if (lastError) { - void this.session.apiClient.deleteDatabaseUser({ - params: { - path: { - groupId: this.session.connectedAtlasCluster?.projectId || "", - username: this.session.connectedAtlasCluster?.username || "", - databaseName: "admin", + void this.session.apiClient + .deleteDatabaseUser({ + params: { + path: { + groupId: this.session.connectedAtlasCluster?.projectId || "", + username: this.session.connectedAtlasCluster?.username || "", + databaseName: "admin", + }, }, - }, - }).catch((err: unknown) => { - const error = err instanceof Error ? err : new Error(String(err)); - logger.debug( - LogId.atlasConnectFailure, - "atlas-connect-cluster", - `error deleting database user: ${error.message}` - ); - }); + }) + .catch((err: unknown) => { + const error = err instanceof Error ? err : new Error(String(err)); + logger.debug( + LogId.atlasConnectFailure, + "atlas-connect-cluster", + `error deleting database user: ${error.message}` + ); + }); this.session.connectedAtlasCluster = undefined; throw lastError; } } - + protected async execute({ projectId, clusterName }: ToolArgs): Promise { try { const state = await this.queryConnection(projectId, clusterName); From d2f91d560606335b5cfef0a502cfe77293833e98 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Mon, 7 Jul 2025 18:33:23 +0100 Subject: [PATCH 04/25] fix: add logs --- src/logger.ts | 2 ++ src/tools/atlas/metadata/connectCluster.ts | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/logger.ts b/src/logger.ts index 8157324b..5bfdd1a5 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -17,6 +17,8 @@ export const LogId = { atlasDeleteDatabaseUserFailure: mongoLogId(1_001_002), atlasConnectFailure: mongoLogId(1_001_003), atlasInspectFailure: mongoLogId(1_001_004), + atlasConnectAttempt: mongoLogId(1_001_005), + atlasConnectSuccessed: mongoLogId(1_001_006), telemetryDisabled: mongoLogId(1_002_001), telemetryEmitFailure: mongoLogId(1_002_002), diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 922b0308..597cb316 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -5,6 +5,7 @@ import { ToolArgs, OperationType } from "../../tool.js"; import { generateSecurePassword } from "../../../common/atlas/generatePassword.js"; import logger, { LogId } from "../../../logger.js"; import { inspectCluster } from "../../../common/atlas/cluster.js"; +import { error } from "console"; const EXPIRY_MS = 1000 * 60 * 60 * 12; // 12 hours @@ -115,6 +116,12 @@ export class ConnectClusterTool extends AtlasToolBase { private async connectToCluster(connectionString: string): Promise { let lastError: Error | undefined = undefined; + logger.debug( + LogId.atlasConnectAttempt, + "atlas-connect-cluster", + `attempting to connect to cluster: ${this.session.connectedAtlasCluster?.clusterName}` + ); + for (let i = 0; i < 600; i++) { // try for 5 minutes try { @@ -158,6 +165,12 @@ export class ConnectClusterTool extends AtlasToolBase { this.session.connectedAtlasCluster = undefined; throw lastError; } + + logger.debug( + LogId.atlasConnectSuccessed, + "atlas-connect-cluster", + `connected to cluster: ${this.session.connectedAtlasCluster?.clusterName}` + ); } protected async execute({ projectId, clusterName }: ToolArgs): Promise { From 8eeb786fd9f62f7f598a86eb9b94c743778b0b73 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Mon, 7 Jul 2025 19:06:58 +0100 Subject: [PATCH 05/25] fix: tests --- tests/integration/tools/atlas/clusters.test.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/integration/tools/atlas/clusters.test.ts b/tests/integration/tools/atlas/clusters.test.ts index 166ee637..dc5e234e 100644 --- a/tests/integration/tools/atlas/clusters.test.ts +++ b/tests/integration/tools/atlas/clusters.test.ts @@ -178,7 +178,23 @@ describeWithAtlas("clusters", (integration) => { })) as CallToolResult; expect(response.content).toBeArray(); expect(response.content).toHaveLength(1); - expect(response.content[0]?.text).toContain(`Connected to cluster "${clusterName}"`); + expect(response.content[0]?.type).toEqual("text"); + expect(response.content[0]?.text).toContain(`Connecting to cluster "${clusterName}"...`); + + for (let i = 0; i < 600; i++) { + const response = (await integration.mcpClient().callTool({ + name: "atlas-connect-cluster", + arguments: { projectId, clusterName }, + })) as CallToolResult; + expect(response.content).toBeArray(); + expect(response.content).toHaveLength(1); + expect(response.content[0]?.type).toEqual("text"); + const c = response.content[0] as { text: string }; + if (c.text.includes("Cluster is already connected.")) { + break; // success + } + await sleep(500); + } }); }); }); From 6c841792a53a5f441b500896a506b42b4d8f6d77 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Mon, 7 Jul 2025 19:14:41 +0100 Subject: [PATCH 06/25] fix --- src/tools/atlas/metadata/connectCluster.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 597cb316..ca978ca2 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -5,7 +5,6 @@ import { ToolArgs, OperationType } from "../../tool.js"; import { generateSecurePassword } from "../../../common/atlas/generatePassword.js"; import logger, { LogId } from "../../../logger.js"; import { inspectCluster } from "../../../common/atlas/cluster.js"; -import { error } from "console"; const EXPIRY_MS = 1000 * 60 * 60 * 12; // 12 hours From dad01119035fe2ef77a0336e436c424cb6664136 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Tue, 8 Jul 2025 07:10:42 +0100 Subject: [PATCH 07/25] fix: update result --- src/tools/atlas/metadata/connectCluster.ts | 2 +- tests/integration/tools/atlas/clusters.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index ca978ca2..0a78dc93 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -223,7 +223,7 @@ export class ConnectClusterTool extends AtlasToolBase { content: [ { type: "text", - text: `Connecting to cluster "${clusterName}"...`, + text: `Attempting to connect to cluster "${clusterName}"...`, }, ], }; diff --git a/tests/integration/tools/atlas/clusters.test.ts b/tests/integration/tools/atlas/clusters.test.ts index dc5e234e..853f9408 100644 --- a/tests/integration/tools/atlas/clusters.test.ts +++ b/tests/integration/tools/atlas/clusters.test.ts @@ -179,7 +179,7 @@ describeWithAtlas("clusters", (integration) => { expect(response.content).toBeArray(); expect(response.content).toHaveLength(1); expect(response.content[0]?.type).toEqual("text"); - expect(response.content[0]?.text).toContain(`Connecting to cluster "${clusterName}"...`); + expect(response.content[0]?.text).toContain(`Attempting to connect to cluster "${clusterName}"...`); for (let i = 0; i < 600; i++) { const response = (await integration.mcpClient().callTool({ From d2c54ae0c5012c26d64c684e152862246bef21ae Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Tue, 8 Jul 2025 07:21:23 +0100 Subject: [PATCH 08/25] fix: styles --- src/tools/atlas/metadata/connectCluster.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 0a78dc93..9d81a8b5 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -47,8 +47,6 @@ export class ConnectClusterTool extends AtlasToolBase { } private async prepareClusterConnection(projectId: string, clusterName: string): Promise { - await this.session.disconnect(); - const cluster = await inspectCluster(this.session.apiClient, projectId, clusterName); if (!cluster.connectionString) { @@ -194,6 +192,11 @@ export class ConnectClusterTool extends AtlasToolBase { }, ], }; + case "connected-to-other-cluster": + case "disconnected": + default: + // fall through to create new connection + break; } } catch (err: unknown) { const error = err instanceof Error ? err : new Error(String(err)); @@ -205,6 +208,7 @@ export class ConnectClusterTool extends AtlasToolBase { // fall through to create new connection } + await this.session.disconnect(); const connectionString = await this.prepareClusterConnection(projectId, clusterName); process.nextTick(async () => { try { From 54dfd7b83c1ed3b76ec31acebe7f7fbc7e11fec7 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Tue, 8 Jul 2025 08:16:31 +0100 Subject: [PATCH 09/25] fix: improve model interpretation --- src/logger.ts | 2 +- src/tools/atlas/metadata/connectCluster.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/logger.ts b/src/logger.ts index ef7b5568..8c1e7ff2 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -18,7 +18,7 @@ export const LogId = { atlasConnectFailure: mongoLogId(1_001_003), atlasInspectFailure: mongoLogId(1_001_004), atlasConnectAttempt: mongoLogId(1_001_005), - atlasConnectSuccessed: mongoLogId(1_001_006), + atlasConnectSucceeded: mongoLogId(1_001_006), telemetryDisabled: mongoLogId(1_002_001), telemetryEmitFailure: mongoLogId(1_002_002), diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 9d81a8b5..00fc432b 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -14,7 +14,7 @@ function sleep(ms: number): Promise { export class ConnectClusterTool extends AtlasToolBase { protected name = "atlas-connect-cluster"; - protected description = "Connect to MongoDB Atlas cluster"; + protected description = "Connect to / Inspect connection of MongoDB Atlas cluster"; protected operationType: OperationType = "metadata"; protected argsShape = { projectId: z.string().describe("Atlas project ID"), @@ -164,7 +164,7 @@ export class ConnectClusterTool extends AtlasToolBase { } logger.debug( - LogId.atlasConnectSuccessed, + LogId.atlasConnectSucceeded, "atlas-connect-cluster", `connected to cluster: ${this.session.connectedAtlasCluster?.clusterName}` ); @@ -229,6 +229,10 @@ export class ConnectClusterTool extends AtlasToolBase { type: "text", text: `Attempting to connect to cluster "${clusterName}"...`, }, + { + type: "text", + text: `Warning: Check again in a few seconds.`, + }, ], }; } From 42b3e472efa854b91db5b3af60c1af7a33e6c0a5 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Tue, 8 Jul 2025 08:20:35 +0100 Subject: [PATCH 10/25] fix: tests --- tests/integration/tools/atlas/clusters.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/tools/atlas/clusters.test.ts b/tests/integration/tools/atlas/clusters.test.ts index e73b785c..ed9d5300 100644 --- a/tests/integration/tools/atlas/clusters.test.ts +++ b/tests/integration/tools/atlas/clusters.test.ts @@ -188,7 +188,7 @@ describeWithAtlas("clusters", (integration) => { arguments: { projectId, clusterName }, })) as CallToolResult; expect(response.content).toBeArray(); - expect(response.content).toHaveLength(1); + expect(response.content).toHaveLength(2); expect(response.content[0]?.type).toEqual("text"); expect(response.content[0]?.text).toContain(`Attempting to connect to cluster "${clusterName}"...`); From e267b45bac5f5ac38344078bf97293286c6a213f Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Tue, 8 Jul 2025 12:36:01 +0100 Subject: [PATCH 11/25] fix: comments --- src/tools/atlas/metadata/connectCluster.ts | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 00fc432b..fdc9063c 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -105,9 +105,7 @@ export class ConnectClusterTool extends AtlasToolBase { cn.username = username; cn.password = password; cn.searchParams.set("authSource", "admin"); - const connectionString = cn.toString(); - - return connectionString; + return cn.toString(); } private async connectToCluster(connectionString: string): Promise { @@ -141,24 +139,26 @@ export class ConnectClusterTool extends AtlasToolBase { } if (lastError) { - void this.session.apiClient - .deleteDatabaseUser({ - params: { - path: { - groupId: this.session.connectedAtlasCluster?.projectId || "", - username: this.session.connectedAtlasCluster?.username || "", - databaseName: "admin", + if (this.session.connectedAtlasCluster?.projectId && this.session.connectedAtlasCluster?.username) { + void this.session.apiClient + .deleteDatabaseUser({ + params: { + path: { + groupId: this.session.connectedAtlasCluster.projectId, + username: this.session.connectedAtlasCluster.username, + databaseName: "admin", + }, }, - }, - }) - .catch((err: unknown) => { - const error = err instanceof Error ? err : new Error(String(err)); - logger.debug( - LogId.atlasConnectFailure, - "atlas-connect-cluster", - `error deleting database user: ${error.message}` - ); - }); + }) + .catch((err: unknown) => { + const error = err instanceof Error ? err : new Error(String(err)); + logger.debug( + LogId.atlasConnectFailure, + "atlas-connect-cluster", + `error deleting database user: ${error.message}` + ); + }); + } this.session.connectedAtlasCluster = undefined; throw lastError; } From 28372beffa2ac8ec080cefdb8e7362b76938f3ab Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Tue, 8 Jul 2025 14:55:10 +0100 Subject: [PATCH 12/25] fix: mix sync and async --- src/session.ts | 43 ++++----- src/tools/atlas/metadata/connectCluster.ts | 92 +++++++++++-------- .../integration/tools/atlas/clusters.test.ts | 20 ++-- 3 files changed, 85 insertions(+), 70 deletions(-) diff --git a/src/session.ts b/src/session.ts index 0b23883b..d6df810b 100644 --- a/src/session.ts +++ b/src/session.ts @@ -67,30 +67,27 @@ export class Session extends EventEmitter<{ } this.serviceProvider = undefined; } - if (!this.connectedAtlasCluster) { - this.emit("disconnect"); - return; - } - void this.apiClient - .deleteDatabaseUser({ - params: { - path: { - groupId: this.connectedAtlasCluster.projectId, - username: this.connectedAtlasCluster.username, - databaseName: "admin", + if (this.connectedAtlasCluster?.username && this.connectedAtlasCluster?.projectId) { + void this.apiClient + .deleteDatabaseUser({ + params: { + path: { + groupId: this.connectedAtlasCluster.projectId, + username: this.connectedAtlasCluster.username, + databaseName: "admin", + }, }, - }, - }) - .catch((err: unknown) => { - const error = err instanceof Error ? err : new Error(String(err)); - logger.error( - LogId.atlasDeleteDatabaseUserFailure, - "atlas-connect-cluster", - `Error deleting previous database user: ${error.message}` - ); - }); - this.connectedAtlasCluster = undefined; - + }) + .catch((err: unknown) => { + const error = err instanceof Error ? err : new Error(String(err)); + logger.error( + LogId.atlasDeleteDatabaseUserFailure, + "atlas-connect-cluster", + `Error deleting previous database user: ${error.message}` + ); + }); + this.connectedAtlasCluster = undefined; + } this.emit("disconnect"); } diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index fdc9063c..e83f0dce 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -108,7 +108,7 @@ export class ConnectClusterTool extends AtlasToolBase { return cn.toString(); } - private async connectToCluster(connectionString: string): Promise { + private async connectToCluster(connectionString: string, tryCount: number): Promise { let lastError: Error | undefined = undefined; logger.debug( @@ -117,11 +117,15 @@ export class ConnectClusterTool extends AtlasToolBase { `attempting to connect to cluster: ${this.session.connectedAtlasCluster?.clusterName}` ); - for (let i = 0; i < 600; i++) { - // try for 5 minutes + for (let i = 0; i < tryCount; i++) { try { - await this.session.connectToMongoDB(connectionString, this.config.connectOptions); lastError = undefined; + + if (!this.session.connectedAtlasCluster) { + throw new Error("Cluster connection aborted"); + } + + await this.session.connectToMongoDB(connectionString, this.config.connectOptions); break; } catch (err: unknown) { const error = err instanceof Error ? err : new Error(String(err)); @@ -171,6 +175,19 @@ export class ConnectClusterTool extends AtlasToolBase { } protected async execute({ projectId, clusterName }: ToolArgs): Promise { + const connectingResult = { + content: [ + { + type: "text" as const, + text: `Attempting to connect to cluster "${clusterName}"...`, + }, + { + type: "text" as const, + text: `Warning: Provisioning a user and connecting to the cluster may take more time, please check again in a few seconds.`, + }, + ], + }; + try { const state = await this.queryConnection(projectId, clusterName); switch (state) { @@ -184,14 +201,7 @@ export class ConnectClusterTool extends AtlasToolBase { ], }; case "connecting": - return { - content: [ - { - type: "text", - text: "Cluster is connecting...", - }, - ], - }; + return connectingResult; case "connected-to-other-cluster": case "disconnected": default: @@ -210,30 +220,40 @@ export class ConnectClusterTool extends AtlasToolBase { await this.session.disconnect(); const connectionString = await this.prepareClusterConnection(projectId, clusterName); - process.nextTick(async () => { - try { - await this.connectToCluster(connectionString); - } catch (err: unknown) { - const error = err instanceof Error ? err : new Error(String(err)); - logger.debug( - LogId.atlasConnectFailure, - "atlas-connect-cluster", - `error connecting to cluster: ${error.message}` - ); - } - }); - return { - content: [ - { - type: "text", - text: `Attempting to connect to cluster "${clusterName}"...`, - }, - { - type: "text", - text: `Warning: Check again in a few seconds.`, - }, - ], - }; + try { + await this.connectToCluster(connectionString, 60); + + return { + content: [ + { + type: "text", + text: `Connected to cluster "${clusterName}".`, + }, + ], + }; + } catch (err: unknown) { + const error = err instanceof Error ? err : new Error(String(err)); + logger.debug( + LogId.atlasConnectFailure, + "atlas-connect-cluster", + `error connecting to cluster: ${error.message}` + ); + + process.nextTick(async () => { + try { + await this.connectToCluster(connectionString, 600); + } catch (err: unknown) { + const error = err instanceof Error ? err : new Error(String(err)); + logger.debug( + LogId.atlasConnectFailure, + "atlas-connect-cluster", + `error connecting to cluster: ${error.message}` + ); + } + }); + + return connectingResult; + } } } diff --git a/tests/integration/tools/atlas/clusters.test.ts b/tests/integration/tools/atlas/clusters.test.ts index ed9d5300..a3b0585e 100644 --- a/tests/integration/tools/atlas/clusters.test.ts +++ b/tests/integration/tools/atlas/clusters.test.ts @@ -183,26 +183,24 @@ describeWithAtlas("clusters", (integration) => { it("connects to cluster", async () => { const projectId = getProjectId(); - const response = (await integration.mcpClient().callTool({ - name: "atlas-connect-cluster", - arguments: { projectId, clusterName }, - })) as CallToolResult; - expect(response.content).toBeArray(); - expect(response.content).toHaveLength(2); - expect(response.content[0]?.type).toEqual("text"); - expect(response.content[0]?.text).toContain(`Attempting to connect to cluster "${clusterName}"...`); - for (let i = 0; i < 600; i++) { const response = (await integration.mcpClient().callTool({ name: "atlas-connect-cluster", arguments: { projectId, clusterName }, })) as CallToolResult; expect(response.content).toBeArray(); - expect(response.content).toHaveLength(1); + expect(response.content.length).toBeGreaterThanOrEqual(1); expect(response.content[0]?.type).toEqual("text"); const c = response.content[0] as { text: string }; - if (c.text.includes("Cluster is already connected.")) { + if ( + c.text.includes("Cluster is already connected.") || + c.text.includes(`Connected to cluster "${clusterName}"`) + ) { break; // success + } else { + expect(response.content[0]?.text).toContain( + `Attempting to connect to cluster "${clusterName}"...` + ); } await sleep(500); } From 2134f16c50ec846cb52a9854b5d4d2271c1f8940 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 10:46:33 +0100 Subject: [PATCH 13/25] fix: address comments --- src/tools/atlas/metadata/connectCluster.ts | 35 ++++++++++++---------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index e83f0dce..0438b075 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -118,13 +118,14 @@ export class ConnectClusterTool extends AtlasToolBase { ); for (let i = 0; i < tryCount; i++) { + if (!this.session.connectedAtlasCluster) { + lastError = new Error("Cluster connection aborted"); + break; + } + try { lastError = undefined; - if (!this.session.connectedAtlasCluster) { - throw new Error("Cluster connection aborted"); - } - await this.session.connectToMongoDB(connectionString, this.config.connectOptions); break; } catch (err: unknown) { @@ -222,6 +223,8 @@ export class ConnectClusterTool extends AtlasToolBase { const connectionString = await this.prepareClusterConnection(projectId, clusterName); try { + // First, try to connect to the cluster within the current tool call. + // We give it 60 attempts with 500 ms delay between each, so ~30 seconds await this.connectToCluster(connectionString, 60); return { @@ -240,17 +243,19 @@ export class ConnectClusterTool extends AtlasToolBase { `error connecting to cluster: ${error.message}` ); - process.nextTick(async () => { - try { - await this.connectToCluster(connectionString, 600); - } catch (err: unknown) { - const error = err instanceof Error ? err : new Error(String(err)); - logger.debug( - LogId.atlasConnectFailure, - "atlas-connect-cluster", - `error connecting to cluster: ${error.message}` - ); - } + // We couldn't connect in ~30 seconds, likely because user creation is taking longer + // Retry the connection with longer timeout (~5 minutes), while also returning a response + // to the client. Many clients will have a 1 minute timeout for tool calls, so we want to + // return well before that. + // + // Once we add support for streamable http, we'd want to use progress notifications here. + void this.connectToCluster(connectionString, 600).catch((err) => { + const error = err instanceof Error ? err : new Error(String(err)); + logger.debug( + LogId.atlasConnectFailure, + "atlas-connect-cluster", + `error connecting to cluster: ${error.message}` + ); }); return connectingResult; From 57981cba763b969b7415c604563b61de1699fc77 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 10:47:13 +0100 Subject: [PATCH 14/25] fix: comment --- src/tools/atlas/metadata/connectCluster.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 0438b075..f85f7179 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -243,7 +243,7 @@ export class ConnectClusterTool extends AtlasToolBase { `error connecting to cluster: ${error.message}` ); - // We couldn't connect in ~30 seconds, likely because user creation is taking longer + // We couldn't connect in ~30 seconds, likely because user creation is taking longer. // Retry the connection with longer timeout (~5 minutes), while also returning a response // to the client. Many clients will have a 1 minute timeout for tool calls, so we want to // return well before that. From 693d31cdc87f2ff2402f974d977c676c5f7e0e50 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 10:50:41 +0100 Subject: [PATCH 15/25] fix: check --- src/tools/atlas/metadata/connectCluster.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index f85f7179..da49a9ca 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -108,7 +108,12 @@ export class ConnectClusterTool extends AtlasToolBase { return cn.toString(); } - private async connectToCluster(connectionString: string, tryCount: number): Promise { + private async connectToCluster( + projectId: string, + clusterName: string, + connectionString: string, + tryCount: number + ): Promise { let lastError: Error | undefined = undefined; logger.debug( @@ -118,7 +123,11 @@ export class ConnectClusterTool extends AtlasToolBase { ); for (let i = 0; i < tryCount; i++) { - if (!this.session.connectedAtlasCluster) { + if ( + !this.session.connectedAtlasCluster || + this.session.connectedAtlasCluster.projectId != projectId || + this.session.connectedAtlasCluster.clusterName != clusterName + ) { lastError = new Error("Cluster connection aborted"); break; } @@ -225,7 +234,7 @@ export class ConnectClusterTool extends AtlasToolBase { try { // First, try to connect to the cluster within the current tool call. // We give it 60 attempts with 500 ms delay between each, so ~30 seconds - await this.connectToCluster(connectionString, 60); + await this.connectToCluster(projectId, clusterName, connectionString, 60); return { content: [ @@ -249,7 +258,7 @@ export class ConnectClusterTool extends AtlasToolBase { // return well before that. // // Once we add support for streamable http, we'd want to use progress notifications here. - void this.connectToCluster(connectionString, 600).catch((err) => { + void this.connectToCluster(projectId, clusterName, connectionString, 600).catch((err) => { const error = err instanceof Error ? err : new Error(String(err)); logger.debug( LogId.atlasConnectFailure, From 4274f1b7edbccc3db197daaa73e2c46430a98e7c Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 11:22:22 +0100 Subject: [PATCH 16/25] fix: move connect to always wait 30secs --- src/tools/atlas/metadata/connectCluster.ts | 126 ++++++++---------- src/tools/mongodb/mongodbTool.ts | 29 ++-- .../integration/tools/atlas/clusters.test.ts | 2 +- 3 files changed, 71 insertions(+), 86 deletions(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index da49a9ca..2a4008ea 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -24,8 +24,11 @@ export class ConnectClusterTool extends AtlasToolBase { private async queryConnection( projectId: string, clusterName: string - ): Promise<"connected" | "disconnected" | "connecting" | "connected-to-other-cluster"> { + ): Promise<"connected" | "disconnected" | "connecting" | "connected-to-other-cluster" | "unknown"> { if (!this.session.connectedAtlasCluster) { + if (this.session.serviceProvider) { + return "connected-to-other-cluster"; + } return "disconnected"; } @@ -40,10 +43,21 @@ export class ConnectClusterTool extends AtlasToolBase { return "connecting"; } - await this.session.serviceProvider.runCommand("admin", { - ping: 1, - }); - return "connected"; + try { + await this.session.serviceProvider.runCommand("admin", { + ping: 1, + }); + + return "connected"; + } catch (err: unknown) { + const error = err instanceof Error ? err : new Error(String(err)); + logger.debug( + LogId.atlasConnectFailure, + "atlas-connect-cluster", + `error querying cluster: ${error.message}` + ); + return "unknown"; + } } private async prepareClusterConnection(projectId: string, clusterName: string): Promise { @@ -111,8 +125,7 @@ export class ConnectClusterTool extends AtlasToolBase { private async connectToCluster( projectId: string, clusterName: string, - connectionString: string, - tryCount: number + connectionString: string ): Promise { let lastError: Error | undefined = undefined; @@ -122,7 +135,8 @@ export class ConnectClusterTool extends AtlasToolBase { `attempting to connect to cluster: ${this.session.connectedAtlasCluster?.clusterName}` ); - for (let i = 0; i < tryCount; i++) { + // try to connect for about 5 minutes + for (let i = 0; i < 600; i++) { if ( !this.session.connectedAtlasCluster || this.session.connectedAtlasCluster.projectId != projectId || @@ -185,20 +199,7 @@ export class ConnectClusterTool extends AtlasToolBase { } protected async execute({ projectId, clusterName }: ToolArgs): Promise { - const connectingResult = { - content: [ - { - type: "text" as const, - text: `Attempting to connect to cluster "${clusterName}"...`, - }, - { - type: "text" as const, - text: `Warning: Provisioning a user and connecting to the cluster may take more time, please check again in a few seconds.`, - }, - ], - }; - - try { + for (let i = 0; i < 60; i++) { const state = await this.queryConnection(projectId, clusterName); switch (state) { case "connected": @@ -206,68 +207,45 @@ export class ConnectClusterTool extends AtlasToolBase { content: [ { type: "text", - text: "Cluster is already connected.", + text: `Connected to cluster "${clusterName}".`, }, ], }; case "connecting": - return connectingResult; + break; case "connected-to-other-cluster": case "disconnected": + case "unknown": default: - // fall through to create new connection + await this.session.disconnect(); + const connectionString = await this.prepareClusterConnection(projectId, clusterName); + + // try to connect for about 5 minutes asynchronously + void this.connectToCluster(projectId, clusterName, connectionString).catch((err: unknown) => { + const error = err instanceof Error ? err : new Error(String(err)); + logger.error( + LogId.atlasConnectFailure, + "atlas-connect-cluster", + `error connecting to cluster: ${error.message}` + ); + }); break; } - } catch (err: unknown) { - const error = err instanceof Error ? err : new Error(String(err)); - logger.debug( - LogId.atlasConnectFailure, - "atlas-connect-cluster", - `error querying cluster: ${error.message}` - ); - // fall through to create new connection - } - - await this.session.disconnect(); - const connectionString = await this.prepareClusterConnection(projectId, clusterName); - - try { - // First, try to connect to the cluster within the current tool call. - // We give it 60 attempts with 500 ms delay between each, so ~30 seconds - await this.connectToCluster(projectId, clusterName, connectionString, 60); - - return { - content: [ - { - type: "text", - text: `Connected to cluster "${clusterName}".`, - }, - ], - }; - } catch (err: unknown) { - const error = err instanceof Error ? err : new Error(String(err)); - logger.debug( - LogId.atlasConnectFailure, - "atlas-connect-cluster", - `error connecting to cluster: ${error.message}` - ); - - // We couldn't connect in ~30 seconds, likely because user creation is taking longer. - // Retry the connection with longer timeout (~5 minutes), while also returning a response - // to the client. Many clients will have a 1 minute timeout for tool calls, so we want to - // return well before that. - // - // Once we add support for streamable http, we'd want to use progress notifications here. - void this.connectToCluster(projectId, clusterName, connectionString, 600).catch((err) => { - const error = err instanceof Error ? err : new Error(String(err)); - logger.debug( - LogId.atlasConnectFailure, - "atlas-connect-cluster", - `error connecting to cluster: ${error.message}` - ); - }); - return connectingResult; + await sleep(500); } + + return { + content: [ + { + type: "text" as const, + text: `Attempting to connect to cluster "${clusterName}"...`, + }, + { + type: "text" as const, + text: `Warning: Provisioning a user and connecting to the cluster may take more time, please check again in a few seconds.`, + }, + ], + }; } } diff --git a/src/tools/mongodb/mongodbTool.ts b/src/tools/mongodb/mongodbTool.ts index f215f9a2..120f98a3 100644 --- a/src/tools/mongodb/mongodbTool.ts +++ b/src/tools/mongodb/mongodbTool.ts @@ -14,20 +14,27 @@ export abstract class MongoDBToolBase extends ToolBase { protected category: ToolCategory = "mongodb"; protected async ensureConnected(): Promise { - if (!this.session.serviceProvider && this.config.connectionString) { - try { - await this.connectToMongoDB(this.config.connectionString); - } catch (error) { - logger.error( - LogId.mongodbConnectFailure, - "mongodbTool", - `Failed to connect to MongoDB instance using the connection string from the config: ${error as string}` + if (!this.session.serviceProvider) { + if (this.session.connectedAtlasCluster) { + throw new MongoDBError( + ErrorCodes.NotConnectedToMongoDB, + `Attempting to connect to Atlas cluster "${this.session.connectedAtlasCluster.clusterName}", try again in a few seconds.` ); - throw new MongoDBError(ErrorCodes.MisconfiguredConnectionString, "Not connected to MongoDB."); } - } - if (!this.session.serviceProvider) { + if (this.config.connectionString) { + try { + await this.connectToMongoDB(this.config.connectionString); + } catch (error) { + logger.error( + LogId.mongodbConnectFailure, + "mongodbTool", + `Failed to connect to MongoDB instance using the connection string from the config: ${error as string}` + ); + throw new MongoDBError(ErrorCodes.MisconfiguredConnectionString, "Not connected to MongoDB."); + } + } + throw new MongoDBError(ErrorCodes.NotConnectedToMongoDB, "Not connected to MongoDB"); } diff --git a/tests/integration/tools/atlas/clusters.test.ts b/tests/integration/tools/atlas/clusters.test.ts index a3b0585e..62bd422c 100644 --- a/tests/integration/tools/atlas/clusters.test.ts +++ b/tests/integration/tools/atlas/clusters.test.ts @@ -183,7 +183,7 @@ describeWithAtlas("clusters", (integration) => { it("connects to cluster", async () => { const projectId = getProjectId(); - for (let i = 0; i < 600; i++) { + for (let i = 0; i < 10; i++) { const response = (await integration.mcpClient().callTool({ name: "atlas-connect-cluster", arguments: { projectId, clusterName }, From d1b2324d1789f559e428f9065294fca0686f0c9d Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 11:27:06 +0100 Subject: [PATCH 17/25] fix: user --- src/tools/atlas/metadata/connectCluster.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 2a4008ea..7ec05e6e 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -142,8 +142,7 @@ export class ConnectClusterTool extends AtlasToolBase { this.session.connectedAtlasCluster.projectId != projectId || this.session.connectedAtlasCluster.clusterName != clusterName ) { - lastError = new Error("Cluster connection aborted"); - break; + throw new Error("Cluster connection aborted"); } try { @@ -167,7 +166,7 @@ export class ConnectClusterTool extends AtlasToolBase { } if (lastError) { - if (this.session.connectedAtlasCluster?.projectId && this.session.connectedAtlasCluster?.username) { + if (this.session.connectedAtlasCluster?.projectId == projectId && this.session.connectedAtlasCluster?.clusterName == clusterName && this.session.connectedAtlasCluster?.username) { void this.session.apiClient .deleteDatabaseUser({ params: { From 0acc685da3ec262c16d0395b6c7491c2b1a93f47 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 11:38:00 +0100 Subject: [PATCH 18/25] fix: add IP warning --- src/tools/atlas/metadata/connectCluster.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 7ec05e6e..c2909d96 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -244,6 +244,10 @@ export class ConnectClusterTool extends AtlasToolBase { type: "text" as const, text: `Warning: Provisioning a user and connecting to the cluster may take more time, please check again in a few seconds.`, }, + { + type: "text" as const, + text: `Warning: Make sure your IP address is whitelisted in the Atlas cluster settings.`, + }, ], }; } From a0ce60c3ed2897685ba61e7603b0a07aa1b809f2 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 11:39:07 +0100 Subject: [PATCH 19/25] fix: add IP warning --- src/tools/atlas/metadata/connectCluster.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index c2909d96..67419d57 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -246,7 +246,7 @@ export class ConnectClusterTool extends AtlasToolBase { }, { type: "text" as const, - text: `Warning: Make sure your IP address is whitelisted in the Atlas cluster settings.`, + text: `Warning: Make sure your IP address was enabled in the allow list setting of the Atlas cluster.`, }, ], }; From 11d3a14fb63e1a08bca245d636459b5c666bf026 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 11:41:41 +0100 Subject: [PATCH 20/25] fix: styles --- src/tools/atlas/metadata/connectCluster.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 67419d57..9eeb97ea 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -122,11 +122,7 @@ export class ConnectClusterTool extends AtlasToolBase { return cn.toString(); } - private async connectToCluster( - projectId: string, - clusterName: string, - connectionString: string - ): Promise { + private async connectToCluster(projectId: string, clusterName: string, connectionString: string): Promise { let lastError: Error | undefined = undefined; logger.debug( @@ -166,7 +162,11 @@ export class ConnectClusterTool extends AtlasToolBase { } if (lastError) { - if (this.session.connectedAtlasCluster?.projectId == projectId && this.session.connectedAtlasCluster?.clusterName == clusterName && this.session.connectedAtlasCluster?.username) { + if ( + this.session.connectedAtlasCluster?.projectId == projectId && + this.session.connectedAtlasCluster?.clusterName == clusterName && + this.session.connectedAtlasCluster?.username + ) { void this.session.apiClient .deleteDatabaseUser({ params: { @@ -218,7 +218,7 @@ export class ConnectClusterTool extends AtlasToolBase { default: await this.session.disconnect(); const connectionString = await this.prepareClusterConnection(projectId, clusterName); - + // try to connect for about 5 minutes asynchronously void this.connectToCluster(projectId, clusterName, connectionString).catch((err: unknown) => { const error = err instanceof Error ? err : new Error(String(err)); From 0286a89f12e7f61ac8bd554378cb0ac196e76977 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 12:08:07 +0100 Subject: [PATCH 21/25] fix: styles --- src/tools/atlas/metadata/connectCluster.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index 9eeb97ea..de8f79e7 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -201,7 +201,7 @@ export class ConnectClusterTool extends AtlasToolBase { for (let i = 0; i < 60; i++) { const state = await this.queryConnection(projectId, clusterName); switch (state) { - case "connected": + case "connected": { return { content: [ { @@ -210,12 +210,14 @@ export class ConnectClusterTool extends AtlasToolBase { }, ], }; - case "connecting": + } + case "connecting": { break; + } case "connected-to-other-cluster": case "disconnected": case "unknown": - default: + default: { await this.session.disconnect(); const connectionString = await this.prepareClusterConnection(projectId, clusterName); @@ -229,6 +231,7 @@ export class ConnectClusterTool extends AtlasToolBase { ); }); break; + } } await sleep(500); From 1127f4c881b82705a66652d92ede05681381d8e3 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 12:41:41 +0100 Subject: [PATCH 22/25] fix: tests --- src/tools/mongodb/mongodbTool.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/tools/mongodb/mongodbTool.ts b/src/tools/mongodb/mongodbTool.ts index 120f98a3..7b43e370 100644 --- a/src/tools/mongodb/mongodbTool.ts +++ b/src/tools/mongodb/mongodbTool.ts @@ -22,23 +22,23 @@ export abstract class MongoDBToolBase extends ToolBase { ); } - if (this.config.connectionString) { - try { - await this.connectToMongoDB(this.config.connectionString); - } catch (error) { - logger.error( - LogId.mongodbConnectFailure, - "mongodbTool", - `Failed to connect to MongoDB instance using the connection string from the config: ${error as string}` - ); - throw new MongoDBError(ErrorCodes.MisconfiguredConnectionString, "Not connected to MongoDB."); - } + if (!this.config.connectionString) { + throw new MongoDBError(ErrorCodes.NotConnectedToMongoDB, "Not connected to MongoDB"); } - throw new MongoDBError(ErrorCodes.NotConnectedToMongoDB, "Not connected to MongoDB"); + try { + await this.connectToMongoDB(this.config.connectionString); + } catch (error) { + logger.error( + LogId.mongodbConnectFailure, + "mongodbTool", + `Failed to connect to MongoDB instance using the connection string from the config: ${error as string}` + ); + throw new MongoDBError(ErrorCodes.MisconfiguredConnectionString, "Not connected to MongoDB."); + } } - return this.session.serviceProvider; + return this.session.serviceProvider!; } protected handleError( From 0a1e57ca9df0d2d2829e5e5513c54c7b4ce1b807 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 13:00:22 +0100 Subject: [PATCH 23/25] fix: tests --- src/tools/mongodb/mongodbTool.ts | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/tools/mongodb/mongodbTool.ts b/src/tools/mongodb/mongodbTool.ts index 7b43e370..3df28d1c 100644 --- a/src/tools/mongodb/mongodbTool.ts +++ b/src/tools/mongodb/mongodbTool.ts @@ -22,20 +22,22 @@ export abstract class MongoDBToolBase extends ToolBase { ); } - if (!this.config.connectionString) { - throw new MongoDBError(ErrorCodes.NotConnectedToMongoDB, "Not connected to MongoDB"); + if (this.config.connectionString) { + try { + await this.connectToMongoDB(this.config.connectionString); + } catch (error) { + logger.error( + LogId.mongodbConnectFailure, + "mongodbTool", + `Failed to connect to MongoDB instance using the connection string from the config: ${error as string}` + ); + throw new MongoDBError(ErrorCodes.MisconfiguredConnectionString, "Not connected to MongoDB."); + } } + } - try { - await this.connectToMongoDB(this.config.connectionString); - } catch (error) { - logger.error( - LogId.mongodbConnectFailure, - "mongodbTool", - `Failed to connect to MongoDB instance using the connection string from the config: ${error as string}` - ); - throw new MongoDBError(ErrorCodes.MisconfiguredConnectionString, "Not connected to MongoDB."); - } + if (!this.session.serviceProvider) { + throw new MongoDBError(ErrorCodes.NotConnectedToMongoDB, "Not connected to MongoDB"); } return this.session.serviceProvider!; From 7430d49a524a360d077a0aa5ec81e4cf339c590a Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 13:01:06 +0100 Subject: [PATCH 24/25] fix: tests --- src/tools/mongodb/mongodbTool.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/mongodb/mongodbTool.ts b/src/tools/mongodb/mongodbTool.ts index 3df28d1c..fe996a38 100644 --- a/src/tools/mongodb/mongodbTool.ts +++ b/src/tools/mongodb/mongodbTool.ts @@ -40,7 +40,7 @@ export abstract class MongoDBToolBase extends ToolBase { throw new MongoDBError(ErrorCodes.NotConnectedToMongoDB, "Not connected to MongoDB"); } - return this.session.serviceProvider!; + return this.session.serviceProvider; } protected handleError( From bf41f0d842bbac35688d8e9b859a9fdda4f080c9 Mon Sep 17 00:00:00 2001 From: Filipe Constantinov Menezes Date: Thu, 10 Jul 2025 13:03:25 +0100 Subject: [PATCH 25/25] fix: metadata --- src/tools/atlas/metadata/connectCluster.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/atlas/metadata/connectCluster.ts b/src/tools/atlas/metadata/connectCluster.ts index de8f79e7..a65913a6 100644 --- a/src/tools/atlas/metadata/connectCluster.ts +++ b/src/tools/atlas/metadata/connectCluster.ts @@ -14,7 +14,7 @@ function sleep(ms: number): Promise { export class ConnectClusterTool extends AtlasToolBase { protected name = "atlas-connect-cluster"; - protected description = "Connect to / Inspect connection of MongoDB Atlas cluster"; + protected description = "Connect to MongoDB Atlas cluster"; protected operationType: OperationType = "metadata"; protected argsShape = { projectId: z.string().describe("Atlas project ID"),