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

mongodb-js / mongodb-mcp-server / 16292877152

15 Jul 2025 12:10PM UTC coverage: 77.385% (+2.1%) from 75.27%
16292877152

push

github

web-flow
chore(tests): switch to vitest (#363)

498 of 687 branches covered (72.49%)

Branch coverage included in aggregate %.

0 of 27 new or added lines in 2 files covered. (0.0%)

293 existing lines in 26 files now uncovered.

2828 of 3611 relevant lines covered (78.32%)

28.46 hits per line

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

70.59
/src/tools/atlas/connect/connectCluster.ts
1
import { z } from "zod";
2✔
2
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
import { AtlasToolBase } from "../atlasTool.js";
2✔
4
import { ToolArgs, OperationType } from "../../tool.js";
5
import { generateSecurePassword } from "../../../helpers/generatePassword.js";
2✔
6
import logger, { LogId } from "../../../common/logger.js";
2✔
7
import { inspectCluster } from "../../../common/atlas/cluster.js";
2✔
8

9
const EXPIRY_MS = 1000 * 60 * 60 * 12; // 12 hours
2✔
10

11
function sleep(ms: number): Promise<void> {
2✔
12
    return new Promise((resolve) => setTimeout(resolve, ms));
2✔
13
}
2✔
14

15
export class ConnectClusterTool extends AtlasToolBase {
2✔
16
    public name = "atlas-connect-cluster";
34✔
17
    protected description = "Connect to MongoDB Atlas cluster";
34✔
18
    public operationType: OperationType = "connect";
34✔
19
    protected argsShape = {
34✔
20
        projectId: z.string().describe("Atlas project ID"),
34✔
21
        clusterName: z.string().describe("Atlas cluster name"),
34✔
22
    };
34✔
23

24
    private async queryConnection(
2✔
25
        projectId: string,
3✔
26
        clusterName: string
3✔
27
    ): Promise<"connected" | "disconnected" | "connecting" | "connected-to-other-cluster" | "unknown"> {
3✔
28
        if (!this.session.connectedAtlasCluster) {
3✔
29
            if (this.session.serviceProvider) {
1!
30
                return "connected-to-other-cluster";
×
UNCOV
31
            }
×
32
            return "disconnected";
1✔
33
        }
1✔
34

35
        if (
2✔
36
            this.session.connectedAtlasCluster.projectId !== projectId ||
2✔
37
            this.session.connectedAtlasCluster.clusterName !== clusterName
2✔
38
        ) {
3!
39
            return "connected-to-other-cluster";
×
UNCOV
40
        }
✔
41

42
        if (!this.session.serviceProvider) {
3✔
43
            return "connecting";
1✔
44
        }
1✔
45

46
        try {
1✔
47
            await this.session.serviceProvider.runCommand("admin", {
1✔
48
                ping: 1,
1✔
49
            });
1✔
50

51
            return "connected";
1✔
52
        } catch (err: unknown) {
3!
53
            const error = err instanceof Error ? err : new Error(String(err));
×
54
            logger.debug(
×
UNCOV
55
                LogId.atlasConnectFailure,
×
UNCOV
56
                "atlas-connect-cluster",
×
UNCOV
57
                `error querying cluster: ${error.message}`
×
UNCOV
58
            );
×
59
            return "unknown";
×
UNCOV
60
        }
×
61
    }
3✔
62

63
    private async prepareClusterConnection(projectId: string, clusterName: string): Promise<string> {
2✔
64
        const cluster = await inspectCluster(this.session.apiClient, projectId, clusterName);
1✔
65

66
        if (!cluster.connectionString) {
1!
67
            throw new Error("Connection string not available");
×
UNCOV
68
        }
×
69

70
        const username = `mcpUser${Math.floor(Math.random() * 100000)}`;
1✔
71
        const password = await generateSecurePassword();
1✔
72

73
        const expiryDate = new Date(Date.now() + EXPIRY_MS);
1✔
74

75
        const readOnly =
1✔
76
            this.config.readOnly ||
1✔
77
            (this.config.disabledTools?.includes("create") &&
1!
UNCOV
78
                this.config.disabledTools?.includes("update") &&
×
UNCOV
79
                this.config.disabledTools?.includes("delete") &&
×
UNCOV
80
                !this.config.disabledTools?.includes("read") &&
×
UNCOV
81
                !this.config.disabledTools?.includes("metadata"));
×
82

83
        const roleName = readOnly ? "readAnyDatabase" : "readWriteAnyDatabase";
1!
84

85
        await this.session.apiClient.createDatabaseUser({
1✔
86
            params: {
1✔
87
                path: {
1✔
88
                    groupId: projectId,
1✔
89
                },
1✔
90
            },
1✔
91
            body: {
1✔
92
                databaseName: "admin",
1✔
93
                groupId: projectId,
1✔
94
                roles: [
1✔
95
                    {
1✔
96
                        roleName,
1✔
97
                        databaseName: "admin",
1✔
98
                    },
1✔
99
                ],
1✔
100
                scopes: [{ type: "CLUSTER", name: clusterName }],
1✔
101
                username,
1✔
102
                password,
1✔
103
                awsIAMType: "NONE",
1✔
104
                ldapAuthType: "NONE",
1✔
105
                oidcAuthType: "NONE",
1✔
106
                x509Type: "NONE",
1✔
107
                deleteAfterDate: expiryDate.toISOString(),
1✔
108
            },
1✔
109
        });
1✔
110

111
        this.session.connectedAtlasCluster = {
1✔
112
            username,
1✔
113
            projectId,
1✔
114
            clusterName,
1✔
115
            expiryDate,
1✔
116
        };
1✔
117

118
        const cn = new URL(cluster.connectionString);
1✔
119
        cn.username = username;
1✔
120
        cn.password = password;
1✔
121
        cn.searchParams.set("authSource", "admin");
1✔
122
        return cn.toString();
1✔
123
    }
1✔
124

125
    private async connectToCluster(projectId: string, clusterName: string, connectionString: string): Promise<void> {
2✔
126
        let lastError: Error | undefined = undefined;
1✔
127

128
        logger.debug(
1✔
129
            LogId.atlasConnectAttempt,
1✔
130
            "atlas-connect-cluster",
1✔
131
            `attempting to connect to cluster: ${this.session.connectedAtlasCluster?.clusterName}`
1✔
132
        );
1✔
133

134
        // try to connect for about 5 minutes
135
        for (let i = 0; i < 600; i++) {
1✔
136
            if (
1✔
137
                !this.session.connectedAtlasCluster ||
1✔
138
                this.session.connectedAtlasCluster.projectId != projectId ||
1✔
139
                this.session.connectedAtlasCluster.clusterName != clusterName
1✔
140
            ) {
1!
141
                throw new Error("Cluster connection aborted");
×
UNCOV
142
            }
×
143

144
            try {
1✔
145
                lastError = undefined;
1✔
146

147
                await this.session.connectToMongoDB(connectionString, this.config.connectOptions);
1✔
148
                break;
1✔
149
            } catch (err: unknown) {
1!
150
                const error = err instanceof Error ? err : new Error(String(err));
×
151

152
                lastError = error;
×
153

154
                logger.debug(
×
UNCOV
155
                    LogId.atlasConnectFailure,
×
UNCOV
156
                    "atlas-connect-cluster",
×
UNCOV
157
                    `error connecting to cluster: ${error.message}`
×
UNCOV
158
                );
×
159

160
                await sleep(500); // wait for 500ms before retrying
×
UNCOV
161
            }
×
162
        }
1✔
163

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

193
        logger.debug(
1✔
194
            LogId.atlasConnectSucceeded,
1✔
195
            "atlas-connect-cluster",
1✔
196
            `connected to cluster: ${this.session.connectedAtlasCluster?.clusterName}`
1✔
197
        );
1✔
198
    }
1✔
199

200
    protected async execute({ projectId, clusterName }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
2✔
201
        for (let i = 0; i < 60; i++) {
1✔
202
            const state = await this.queryConnection(projectId, clusterName);
3✔
203
            switch (state) {
3✔
204
                case "connected": {
3✔
205
                    return {
1✔
206
                        content: [
1✔
207
                            {
1✔
208
                                type: "text",
1✔
209
                                text: `Connected to cluster "${clusterName}".`,
1✔
210
                            },
1✔
211
                        ],
1✔
212
                    };
1✔
213
                }
1✔
214
                case "connecting": {
3✔
215
                    break;
1✔
216
                }
1✔
217
                case "connected-to-other-cluster":
3!
218
                case "disconnected":
3✔
219
                case "unknown":
3✔
220
                default: {
3✔
221
                    await this.session.disconnect();
1✔
222
                    const connectionString = await this.prepareClusterConnection(projectId, clusterName);
1✔
223

224
                    // try to connect for about 5 minutes asynchronously
225
                    void this.connectToCluster(projectId, clusterName, connectionString).catch((err: unknown) => {
1✔
226
                        const error = err instanceof Error ? err : new Error(String(err));
×
227
                        logger.error(
×
UNCOV
228
                            LogId.atlasConnectFailure,
×
UNCOV
229
                            "atlas-connect-cluster",
×
UNCOV
230
                            `error connecting to cluster: ${error.message}`
×
UNCOV
231
                        );
×
232
                    });
1✔
233
                    break;
1✔
234
                }
1✔
235
            }
3✔
236

237
            await sleep(500);
2✔
238
        }
2✔
239

240
        return {
2✔
241
            content: [
2✔
242
                {
2✔
243
                    type: "text" as const,
2✔
244
                    text: `Attempting to connect to cluster "${clusterName}"...`,
2✔
245
                },
2✔
246
                {
2✔
247
                    type: "text" as const,
2✔
248
                    text: `Warning: Provisioning a user and connecting to the cluster may take more time, please check again in a few seconds.`,
2✔
249
                },
2✔
250
                {
2✔
251
                    type: "text" as const,
2✔
252
                    text: `Warning: Make sure your IP address was enabled in the allow list setting of the Atlas cluster.`,
2✔
253
                },
2✔
254
            ],
2✔
255
        };
2✔
256
    }
1✔
257
}
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