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

mongodb-js / mongodb-mcp-server / 16649148739

31 Jul 2025 12:36PM UTC coverage: 81.276% (+0.3%) from 81.014%
16649148739

Pull #414

github

web-flow
Merge ae3b4b85e into e6615c364
Pull Request #414: chore: follow up from reactive resource PR MCP-80

595 of 773 branches covered (76.97%)

Branch coverage included in aggregate %.

2 of 2 new or added lines in 2 files covered. (100.0%)

5 existing lines in 1 file now uncovered.

3290 of 4007 relevant lines covered (82.11%)

53.09 hits per line

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

75.85
/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
import { ensureCurrentIpInAccessList } from "../../../common/atlas/accessListUtils.js";
2✔
9

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

153
                lastError = error;
1✔
154

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

161
                await sleep(500); // wait for 500ms before retrying
1✔
162
            }
1✔
163
        }
2!
164

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

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

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

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

239
            await sleep(500);
4✔
240
        }
4✔
241

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