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

mongodb-js / mongodb-mcp-server / 16790782045

06 Aug 2025 11:09PM UTC coverage: 81.233% (-0.07%) from 81.298%
16790782045

Pull #425

github

web-flow
Merge 7712da066 into 53ac631ea
Pull Request #425: fix: remove global logger MCP-103

681 of 881 branches covered (77.3%)

Branch coverage included in aggregate %.

158 of 207 new or added lines in 17 files covered. (76.33%)

6 existing lines in 2 files now uncovered.

3522 of 4293 relevant lines covered (82.04%)

58.12 hits per line

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

77.44
/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 { 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
import { AtlasClusterConnectionInfo } from "../../../common/connectionManager.js";
10

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

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

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

26
    private queryConnection(
2✔
27
        projectId: string,
16✔
28
        clusterName: string
16✔
29
    ): "connected" | "disconnected" | "connecting" | "connected-to-other-cluster" | "unknown" {
16✔
30
        if (!this.session.connectedAtlasCluster) {
16✔
31
            if (this.session.isConnectedToMongoDB) {
3!
32
                return "connected-to-other-cluster";
×
33
            }
×
34
            return "disconnected";
3✔
35
        }
3✔
36

37
        const currentConectionState = this.session.connectionManager.currentConnectionState;
13✔
38
        if (
13✔
39
            this.session.connectedAtlasCluster.projectId !== projectId ||
13✔
40
            this.session.connectedAtlasCluster.clusterName !== clusterName
13✔
41
        ) {
16!
42
            return "connected-to-other-cluster";
×
43
        }
✔
44

45
        switch (currentConectionState.tag) {
13✔
46
            case "connecting":
16!
47
            case "disconnected": // we might still be calling Atlas APIs and not attempted yet to connect to MongoDB, but we are still "connecting"
16!
48
                return "connecting";
×
49
            case "connected":
16✔
50
                return "connected";
1✔
51
            case "errored":
16✔
52
                this.session.logger.debug({
12✔
53
                    id: LogId.atlasConnectFailure,
12✔
54
                    context: "atlas-connect-cluster",
12✔
55
                    message: `error querying cluster: ${currentConectionState.errorReason}`,
12✔
56
                });
12✔
57
                return "unknown";
12✔
58
        }
16✔
59
    }
16✔
60

61
    private async prepareClusterConnection(
2✔
62
        projectId: string,
3✔
63
        clusterName: string
3✔
64
    ): Promise<{ connectionString: string; atlas: AtlasClusterConnectionInfo }> {
3✔
65
        const cluster = await inspectCluster(this.session.apiClient, projectId, clusterName);
3✔
66

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

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

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

76
        const readOnly =
3✔
77
            this.config.readOnly ||
3✔
78
            (this.config.disabledTools?.includes("create") &&
3!
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";
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: [
3✔
96
                    {
3✔
97
                        roleName,
3✔
98
                        databaseName: "admin",
3✔
99
                    },
3✔
100
                ],
3✔
101
                scopes: [{ type: "CLUSTER", name: clusterName }],
3✔
102
                username,
3✔
103
                password,
3✔
104
                awsIAMType: "NONE",
3✔
105
                ldapAuthType: "NONE",
3✔
106
                oidcAuthType: "NONE",
3✔
107
                x509Type: "NONE",
3✔
108
                deleteAfterDate: expiryDate.toISOString(),
3✔
109
            },
3✔
110
        });
3✔
111

112
        const connectedAtlasCluster = {
3✔
113
            username,
3✔
114
            projectId,
3✔
115
            clusterName,
3✔
116
            expiryDate,
3✔
117
        };
3✔
118

119
        const cn = new URL(cluster.connectionString);
3✔
120
        cn.username = username;
3✔
121
        cn.password = password;
3✔
122
        cn.searchParams.set("authSource", "admin");
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 {
13✔
140
                lastError = undefined;
13✔
141

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

147
                lastError = error;
10✔
148

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

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

158
            if (
10✔
159
                !this.session.connectedAtlasCluster ||
10✔
160
                this.session.connectedAtlasCluster.projectId !== atlas.projectId ||
10✔
161
                this.session.connectedAtlasCluster.clusterName !== atlas.clusterName
10✔
162
            ) {
13!
163
                throw new Error("Cluster connection aborted");
×
164
            }
×
165
        }
13✔
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));
×
NEW
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({
3✔
196
            id: LogId.atlasConnectSucceeded,
3✔
197
            context: "atlas-connect-cluster",
3✔
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
        await ensureCurrentIpInAccessList(this.session.apiClient, projectId);
1✔
205
        for (let i = 0; i < 60; i++) {
1✔
206
            const state = this.queryConnection(projectId, clusterName);
16✔
207
            switch (state) {
16✔
208
                case "connected": {
16✔
209
                    return {
1✔
210
                        content: [
1✔
211
                            {
1✔
212
                                type: "text",
1✔
213
                                text: `Connected to cluster "${clusterName}".`,
1✔
214
                            },
1✔
215
                        ],
1✔
216
                    };
1✔
217
                }
1✔
218
                case "connecting":
16!
219
                case "unknown": {
16✔
220
                    break;
12✔
221
                }
12✔
222
                case "connected-to-other-cluster":
16!
223
                case "disconnected":
16✔
224
                default: {
16✔
225
                    await this.session.disconnect();
3✔
226
                    const { connectionString, atlas } = await this.prepareClusterConnection(projectId, clusterName);
3✔
227

228
                    // try to connect for about 5 minutes asynchronously
229
                    void this.connectToCluster(connectionString, atlas).catch((err: unknown) => {
3✔
230
                        const error = err instanceof Error ? err : new Error(String(err));
×
NEW
231
                        this.session.logger.error({
×
232
                            id: LogId.atlasConnectFailure,
×
233
                            context: "atlas-connect-cluster",
×
234
                            message: `error connecting to cluster: ${error.message}`,
×
235
                        });
×
236
                    });
3✔
237
                    break;
3✔
238
                }
3✔
239
            }
16✔
240

241
            await sleep(500);
15✔
242
        }
15✔
243

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