• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mongodb-js / mongodb-mcp-server / 18555147447

16 Oct 2025 08:27AM UTC coverage: 82.404% (-0.1%) from 82.527%
18555147447

Pull #656

github

web-flow
Merge b8e73800b into 87ce0cf2d
Pull Request #656: chore: disable code health runs on forks and add dependabot cooldown

1189 of 1578 branches covered (75.35%)

Branch coverage included in aggregate %.

5798 of 6901 relevant lines covered (84.02%)

70.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.5
/src/tools/atlas/connect/connectCluster.ts
1
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
import { type OperationType, type ToolArgs } from "../../tool.js";
3
import { AtlasToolBase } from "../atlasTool.js";
2✔
4
import { generateSecurePassword } from "../../../helpers/generatePassword.js";
2✔
5
import { LogId } from "../../../common/logger.js";
2✔
6
import { inspectCluster } from "../../../common/atlas/cluster.js";
2✔
7
import { ensureCurrentIpInAccessList } from "../../../common/atlas/accessListUtils.js";
2✔
8
import type { AtlasClusterConnectionInfo } from "../../../common/connectionManager.js";
9
import { getDefaultRoleFromConfig } from "../../../common/atlas/roles.js";
2✔
10
import { AtlasArgs } from "../../args.js";
2✔
11

12
const addedIpAccessListMessage =
2✔
13
    "Note: Your current IP address has been added to the Atlas project's IP access list to enable secure connection.";
2✔
14

15
const createdUserMessage =
2✔
16
    "Note: A temporary user has been created to enable secure connection to the cluster. For more information, see https://dochub.mongodb.org/core/mongodb-mcp-server-tools-considerations\n\nNote to LLM Agent: it is important to include the following link in your response to the user in case they want to get more information about the temporary user created: https://dochub.mongodb.org/core/mongodb-mcp-server-tools-considerations";
2✔
17

18
function sleep(ms: number): Promise<void> {
4✔
19
    return new Promise((resolve) => setTimeout(resolve, ms));
4✔
20
}
4✔
21

22
export const ConnectClusterArgs = {
2✔
23
    projectId: AtlasArgs.projectId().describe("Atlas project ID"),
2✔
24
    clusterName: AtlasArgs.clusterName().describe("Atlas cluster name"),
2✔
25
};
2✔
26

27
export class ConnectClusterTool extends AtlasToolBase {
2✔
28
    public name = "atlas-connect-cluster";
71✔
29
    protected description = "Connect to MongoDB Atlas cluster";
71✔
30
    public operationType: OperationType = "connect";
71✔
31
    protected argsShape = {
71✔
32
        ...ConnectClusterArgs,
71✔
33
    };
71✔
34

35
    private queryConnection(
2✔
36
        projectId: string,
4✔
37
        clusterName: string
4✔
38
    ): "connected" | "disconnected" | "connecting" | "connected-to-other-cluster" | "unknown" {
4✔
39
        if (!this.session.connectedAtlasCluster) {
4✔
40
            if (this.session.isConnectedToMongoDB) {
3!
41
                return "connected-to-other-cluster";
×
42
            }
×
43
            return "disconnected";
3✔
44
        }
3✔
45

46
        const currentConectionState = this.session.connectionManager.currentConnectionState;
1✔
47
        if (
1✔
48
            this.session.connectedAtlasCluster.projectId !== projectId ||
1✔
49
            this.session.connectedAtlasCluster.clusterName !== clusterName
1✔
50
        ) {
4!
51
            return "connected-to-other-cluster";
×
52
        }
✔
53

54
        switch (currentConectionState.tag) {
1✔
55
            case "connecting":
4!
56
            case "disconnected": // we might still be calling Atlas APIs and not attempted yet to connect to MongoDB, but we are still "connecting"
4!
57
                return "connecting";
×
58
            case "connected":
4✔
59
                return "connected";
1✔
60
            case "errored":
4!
61
                this.session.logger.debug({
×
62
                    id: LogId.atlasConnectFailure,
×
63
                    context: "atlas-connect-cluster",
×
64
                    message: `error querying cluster: ${currentConectionState.errorReason}`,
×
65
                });
×
66
                return "unknown";
×
67
        }
4✔
68
    }
4✔
69

70
    private async prepareClusterConnection(
2✔
71
        projectId: string,
3✔
72
        clusterName: string
3✔
73
    ): Promise<{ connectionString: string; atlas: AtlasClusterConnectionInfo }> {
3✔
74
        const cluster = await inspectCluster(this.session.apiClient, projectId, clusterName);
3✔
75

76
        if (!cluster.connectionString) {
3!
77
            throw new Error("Connection string not available");
×
78
        }
×
79

80
        const username = `mcpUser${Math.floor(Math.random() * 100000)}`;
3✔
81
        const password = await generateSecurePassword();
3✔
82

83
        const expiryDate = new Date(Date.now() + this.config.atlasTemporaryDatabaseUserLifetimeMs);
3✔
84
        const role = getDefaultRoleFromConfig(this.config);
3✔
85

86
        await this.session.apiClient.createDatabaseUser({
3✔
87
            params: {
3✔
88
                path: {
3✔
89
                    groupId: projectId,
3✔
90
                },
3✔
91
            },
3✔
92
            body: {
3✔
93
                databaseName: "admin",
3✔
94
                groupId: projectId,
3✔
95
                roles: [role],
3✔
96
                scopes: [{ type: "CLUSTER", name: clusterName }],
3✔
97
                username,
3✔
98
                password,
3✔
99
                awsIAMType: "NONE",
3✔
100
                ldapAuthType: "NONE",
3✔
101
                oidcAuthType: "NONE",
3✔
102
                x509Type: "NONE",
3✔
103
                deleteAfterDate: expiryDate.toISOString(),
3✔
104
                description:
3✔
105
                    "MDB MCP Temporary user, see https://dochub.mongodb.org/core/mongodb-mcp-server-tools-considerations",
3✔
106
            },
3✔
107
        });
3✔
108

109
        const connectedAtlasCluster = {
3✔
110
            username,
3✔
111
            projectId,
3✔
112
            clusterName,
3✔
113
            expiryDate,
3✔
114
        };
3✔
115

116
        const cn = new URL(cluster.connectionString);
3✔
117
        cn.username = username;
3✔
118
        cn.password = password;
3✔
119
        cn.searchParams.set("authSource", "admin");
3✔
120

121
        this.session.keychain.register(username, "user");
3✔
122
        this.session.keychain.register(password, "password");
3✔
123

124
        return { connectionString: cn.toString(), atlas: connectedAtlasCluster };
3✔
125
    }
3✔
126

127
    private async connectToCluster(connectionString: string, atlas: AtlasClusterConnectionInfo): Promise<void> {
2✔
128
        let lastError: Error | undefined = undefined;
3✔
129

130
        this.session.logger.debug({
3✔
131
            id: LogId.atlasConnectAttempt,
3✔
132
            context: "atlas-connect-cluster",
3✔
133
            message: `attempting to connect to cluster: ${this.session.connectedAtlasCluster?.clusterName}`,
3!
134
            noRedaction: true,
3✔
135
        });
3✔
136

137
        // try to connect for about 5 minutes
138
        for (let i = 0; i < 600; i++) {
3✔
139
            try {
4✔
140
                lastError = undefined;
4✔
141

142
                await this.session.connectToMongoDB({ connectionString, atlas });
4✔
143
                break;
2✔
144
            } catch (err: unknown) {
4✔
145
                const error = err instanceof Error ? err : new Error(String(err));
1!
146

147
                lastError = error;
1✔
148

149
                this.session.logger.debug({
1✔
150
                    id: LogId.atlasConnectFailure,
1✔
151
                    context: "atlas-connect-cluster",
1✔
152
                    message: `error connecting to cluster: ${error.message}`,
1✔
153
                });
1✔
154

155
                await sleep(500); // wait for 500ms before retrying
1✔
156
            }
1✔
157

158
            if (
1✔
159
                !this.session.connectedAtlasCluster ||
1✔
160
                this.session.connectedAtlasCluster.projectId !== atlas.projectId ||
1✔
161
                this.session.connectedAtlasCluster.clusterName !== atlas.clusterName
1✔
162
            ) {
4!
163
                throw new Error("Cluster connection aborted");
×
164
            }
×
165
        }
4✔
166

167
        if (lastError) {
3!
168
            if (
×
169
                this.session.connectedAtlasCluster?.projectId === atlas.projectId &&
×
170
                this.session.connectedAtlasCluster?.clusterName === atlas.clusterName &&
×
171
                this.session.connectedAtlasCluster?.username
×
172
            ) {
×
173
                void this.session.apiClient
×
174
                    .deleteDatabaseUser({
×
175
                        params: {
×
176
                            path: {
×
177
                                groupId: this.session.connectedAtlasCluster.projectId,
×
178
                                username: this.session.connectedAtlasCluster.username,
×
179
                                databaseName: "admin",
×
180
                            },
×
181
                        },
×
182
                    })
×
183
                    .catch((err: unknown) => {
×
184
                        const error = err instanceof Error ? err : new Error(String(err));
×
185
                        this.session.logger.debug({
×
186
                            id: LogId.atlasConnectFailure,
×
187
                            context: "atlas-connect-cluster",
×
188
                            message: `error deleting database user: ${error.message}`,
×
189
                        });
×
190
                    });
×
191
            }
×
192
            throw lastError;
×
193
        }
✔
194

195
        this.session.logger.debug({
2✔
196
            id: LogId.atlasConnectSucceeded,
2✔
197
            context: "atlas-connect-cluster",
2✔
198
            message: `connected to cluster: ${this.session.connectedAtlasCluster?.clusterName}`,
3✔
199
            noRedaction: true,
3✔
200
        });
3✔
201
    }
3✔
202

203
    protected async execute({ projectId, clusterName }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
2✔
204
        const ipAccessListUpdated = await ensureCurrentIpInAccessList(this.session.apiClient, projectId);
1✔
205
        let createdUser = false;
1✔
206

207
        for (let i = 0; i < 60; i++) {
1✔
208
            const state = this.queryConnection(projectId, clusterName);
4✔
209
            switch (state) {
4✔
210
                case "connected": {
4✔
211
                    const content: CallToolResult["content"] = [
1✔
212
                        {
1✔
213
                            type: "text",
1✔
214
                            text: `Connected to cluster "${clusterName}".`,
1✔
215
                        },
1✔
216
                    ];
1✔
217

218
                    if (ipAccessListUpdated) {
1✔
219
                        content.push({
1✔
220
                            type: "text",
1✔
221
                            text: addedIpAccessListMessage,
1✔
222
                        });
1✔
223
                    }
1✔
224

225
                    if (createdUser) {
1✔
226
                        content.push({
1✔
227
                            type: "text",
1✔
228
                            text: createdUserMessage,
1✔
229
                        });
1✔
230
                    }
1✔
231

232
                    return { content };
1✔
233
                }
1✔
234
                case "connecting":
4!
235
                case "unknown": {
4!
236
                    break;
×
237
                }
×
238
                case "connected-to-other-cluster":
4!
239
                case "disconnected":
4✔
240
                default: {
4✔
241
                    await this.session.disconnect();
3✔
242
                    const { connectionString, atlas } = await this.prepareClusterConnection(projectId, clusterName);
3✔
243

244
                    createdUser = true;
3✔
245
                    // try to connect for about 5 minutes asynchronously
246
                    void this.connectToCluster(connectionString, atlas).catch((err: unknown) => {
3✔
247
                        const error = err instanceof Error ? err : new Error(String(err));
×
248
                        this.session.logger.error({
×
249
                            id: LogId.atlasConnectFailure,
×
250
                            context: "atlas-connect-cluster",
×
251
                            message: `error connecting to cluster: ${error.message}`,
×
252
                        });
×
253
                    });
3✔
254
                    break;
3✔
255
                }
3✔
256
            }
4✔
257

258
            await sleep(500);
3✔
259
        }
3✔
260

261
        const content: CallToolResult["content"] = [
3✔
262
            {
3✔
263
                type: "text" as const,
3✔
264
                text: `Attempting to connect to cluster "${clusterName}"...`,
3✔
265
            },
3✔
266
            {
3✔
267
                type: "text" as const,
3✔
268
                text: `Warning: Provisioning a user and connecting to the cluster may take more time, please check again in a few seconds.`,
3✔
269
            },
3✔
270
        ];
3✔
271

272
        if (ipAccessListUpdated) {
1!
273
            content.push({
×
274
                type: "text" as const,
×
275
                text: addedIpAccessListMessage,
×
276
            });
×
277
        }
×
278

279
        if (createdUser) {
×
280
            content.push({
×
281
                type: "text" as const,
×
282
                text: createdUserMessage,
×
283
            });
×
284
        }
×
285

286
        return { content };
×
287
    }
1✔
288
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc