@@ -11,16 +11,36 @@ const EXPIRY_MS = 1000 * 60 * 60 * 12; // 12 hours
11
11
function sleep ( ms : number ) : Promise < void > {
12
12
return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
13
13
}
14
+
14
15
export class ConnectClusterTool extends AtlasToolBase {
15
16
protected name = "atlas-connect-cluster" ;
16
- protected description = "Connect to MongoDB Atlas cluster" ;
17
+ protected description = "Connect to/Query status of MongoDB Atlas cluster" ;
17
18
protected operationType : OperationType = "metadata" ;
18
19
protected argsShape = {
19
20
projectId : z . string ( ) . describe ( "Atlas project ID" ) ,
20
21
clusterName : z . string ( ) . describe ( "Atlas cluster name" ) ,
21
22
} ;
22
23
23
- protected async execute ( { projectId, clusterName } : ToolArgs < typeof this . argsShape > ) : Promise < CallToolResult > {
24
+ private async queryConnection ( projectId : string , clusterName : string ) : Promise < "connected" | "disconnected" | "connecting" | "connected-to-other-cluster" > {
25
+ if ( ! this . session . connectedAtlasCluster ) {
26
+ return "disconnected" ;
27
+ }
28
+
29
+ if ( this . session . connectedAtlasCluster . projectId !== projectId || this . session . connectedAtlasCluster . clusterName !== clusterName ) {
30
+ return "connected-to-other-cluster" ;
31
+ }
32
+
33
+ if ( ! this . session . serviceProvider ) {
34
+ return "connecting" ;
35
+ }
36
+
37
+ await this . session . serviceProvider . runCommand ( "admin" , {
38
+ ping : 1 ,
39
+ } ) ;
40
+ return "connected" ;
41
+ }
42
+
43
+ private async prepareClusterConnection ( projectId : string , clusterName : string ) : Promise < string > {
24
44
await this . session . disconnect ( ) ;
25
45
26
46
const cluster = await inspectCluster ( this . session . apiClient , projectId , clusterName ) ;
@@ -83,9 +103,13 @@ export class ConnectClusterTool extends AtlasToolBase {
83
103
cn . searchParams . set ( "authSource" , "admin" ) ;
84
104
const connectionString = cn . toString ( ) ;
85
105
106
+ return connectionString ;
107
+ }
108
+
109
+ private async connectToCluster ( connectionString : string ) : Promise < void > {
86
110
let lastError : Error | undefined = undefined ;
87
111
88
- for ( let i = 0 ; i < 20 ; i ++ ) {
112
+ for ( let i = 0 ; i < 600 ; i ++ ) { // try for 5 minutes
89
113
try {
90
114
await this . session . connectToMongoDB ( connectionString , this . config . connectOptions ) ;
91
115
lastError = undefined ;
@@ -104,16 +128,81 @@ export class ConnectClusterTool extends AtlasToolBase {
104
128
await sleep ( 500 ) ; // wait for 500ms before retrying
105
129
}
106
130
}
107
-
131
+
108
132
if ( lastError ) {
133
+ void this . session . apiClient . deleteDatabaseUser ( {
134
+ params : {
135
+ path : {
136
+ groupId : this . session . connectedAtlasCluster ?. projectId || "" ,
137
+ username : this . session . connectedAtlasCluster ?. username || "" ,
138
+ databaseName : "admin" ,
139
+ } ,
140
+ } ,
141
+ } ) . catch ( ( err : unknown ) => {
142
+ const error = err instanceof Error ? err : new Error ( String ( err ) ) ;
143
+ logger . debug (
144
+ LogId . atlasConnectFailure ,
145
+ "atlas-connect-cluster" ,
146
+ `error deleting database user: ${ error . message } `
147
+ ) ;
148
+ } ) ;
149
+ this . session . connectedAtlasCluster = undefined ;
109
150
throw lastError ;
110
151
}
152
+ }
153
+
154
+ protected async execute ( { projectId, clusterName } : ToolArgs < typeof this . argsShape > ) : Promise < CallToolResult > {
155
+ try {
156
+ const state = await this . queryConnection ( projectId , clusterName ) ;
157
+ switch ( state ) {
158
+ case "connected" :
159
+ return {
160
+ content : [
161
+ {
162
+ type : "text" ,
163
+ text : "Cluster is already connected." ,
164
+ } ,
165
+ ] ,
166
+ } ;
167
+ case "connecting" :
168
+ return {
169
+ content : [
170
+ {
171
+ type : "text" ,
172
+ text : "Cluster is connecting..." ,
173
+ } ,
174
+ ] ,
175
+ } ;
176
+ }
177
+ } catch ( err : unknown ) {
178
+ const error = err instanceof Error ? err : new Error ( String ( err ) ) ;
179
+ logger . debug (
180
+ LogId . atlasConnectFailure ,
181
+ "atlas-connect-cluster" ,
182
+ `error querying cluster: ${ error . message } `
183
+ ) ;
184
+ // fall through to create new connection
185
+ }
186
+
187
+ const connectionString = await this . prepareClusterConnection ( projectId , clusterName ) ;
188
+ process . nextTick ( async ( ) => {
189
+ try {
190
+ await this . connectToCluster ( connectionString ) ;
191
+ } catch ( err : unknown ) {
192
+ const error = err instanceof Error ? err : new Error ( String ( err ) ) ;
193
+ logger . debug (
194
+ LogId . atlasConnectFailure ,
195
+ "atlas-connect-cluster" ,
196
+ `error connecting to cluster: ${ error . message } `
197
+ ) ;
198
+ }
199
+ } ) ;
111
200
112
201
return {
113
202
content : [
114
203
{
115
204
type : "text" ,
116
- text : `Connected to cluster "${ clusterName } "` ,
205
+ text : `Connecting to cluster "${ clusterName } "... ` ,
117
206
} ,
118
207
] ,
119
208
} ;
0 commit comments