-
Notifications
You must be signed in to change notification settings - Fork 132
feat: add more details about atlas connect flow - MCP-124 #500
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
c4f2d5a
114c745
9ff88ed
8aeee07
bba7218
c2edf9f
c609434
bd94eae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,11 @@ import type { AtlasClusterConnectionInfo } from "../../../common/connectionManag | |
import { getDefaultRoleFromConfig } from "../../../common/atlas/roles.js"; | ||
|
||
const EXPIRY_MS = 1000 * 60 * 60 * 12; // 12 hours | ||
const addedIpAccessListMessage = | ||
"Note: Your current IP address has been added to the Atlas project's IP access list to enable secure connection."; | ||
|
||
const createdUserMessage = | ||
"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"; | ||
|
||
function sleep(ms: number): Promise<void> { | ||
return new Promise((resolve) => setTimeout(resolve, ms)); | ||
|
@@ -62,7 +67,7 @@ export class ConnectClusterTool extends AtlasToolBase { | |
private async prepareClusterConnection( | ||
projectId: string, | ||
clusterName: string | ||
): Promise<{ connectionString: string; atlas: AtlasClusterConnectionInfo }> { | ||
): Promise<{ connectionString: string; atlas: AtlasClusterConnectionInfo; userCreated: boolean }> { | ||
const cluster = await inspectCluster(this.session.apiClient, projectId, clusterName); | ||
|
||
if (!cluster.connectionString) { | ||
|
@@ -110,7 +115,7 @@ export class ConnectClusterTool extends AtlasToolBase { | |
cn.password = password; | ||
cn.searchParams.set("authSource", "admin"); | ||
|
||
return { connectionString: cn.toString(), atlas: connectedAtlasCluster }; | ||
return { connectionString: cn.toString(), atlas: connectedAtlasCluster, userCreated: true }; | ||
|
||
} | ||
|
||
private async connectToCluster(connectionString: string, atlas: AtlasClusterConnectionInfo): Promise<void> { | ||
|
@@ -190,19 +195,35 @@ export class ConnectClusterTool extends AtlasToolBase { | |
} | ||
|
||
protected async execute({ projectId, clusterName }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> { | ||
await ensureCurrentIpInAccessList(this.session.apiClient, projectId); | ||
const ipAccessListUpdated = await ensureCurrentIpInAccessList(this.session.apiClient, projectId); | ||
let createdUser = false; | ||
|
||
for (let i = 0; i < 60; i++) { | ||
const state = this.queryConnection(projectId, clusterName); | ||
switch (state) { | ||
case "connected": { | ||
return { | ||
content: [ | ||
{ | ||
type: "text", | ||
text: `Connected to cluster "${clusterName}".`, | ||
}, | ||
], | ||
}; | ||
const content: CallToolResult["content"] = [ | ||
{ | ||
type: "text", | ||
text: `Connected to cluster "${clusterName}".`, | ||
}, | ||
]; | ||
|
||
if (ipAccessListUpdated) { | ||
content.push({ | ||
type: "text", | ||
text: addedIpAccessListMessage, | ||
}); | ||
} | ||
|
||
if (createdUser) { | ||
content.push({ | ||
type: "text", | ||
text: createdUserMessage, | ||
}); | ||
} | ||
|
||
return { content }; | ||
} | ||
case "connecting": | ||
case "unknown": { | ||
|
@@ -212,8 +233,12 @@ export class ConnectClusterTool extends AtlasToolBase { | |
case "disconnected": | ||
default: { | ||
await this.session.disconnect(); | ||
const { connectionString, atlas } = await this.prepareClusterConnection(projectId, clusterName); | ||
const { connectionString, atlas, userCreated } = await this.prepareClusterConnection( | ||
projectId, | ||
clusterName | ||
); | ||
|
||
createdUser = userCreated; | ||
// try to connect for about 5 minutes asynchronously | ||
void this.connectToCluster(connectionString, atlas).catch((err: unknown) => { | ||
const error = err instanceof Error ? err : new Error(String(err)); | ||
|
@@ -230,21 +255,31 @@ export class ConnectClusterTool extends AtlasToolBase { | |
await sleep(500); | ||
} | ||
|
||
return { | ||
content: [ | ||
{ | ||
type: "text" as const, | ||
text: `Attempting to connect to cluster "${clusterName}"...`, | ||
}, | ||
{ | ||
type: "text" as const, | ||
text: `Warning: Provisioning a user and connecting to the cluster may take more time, please check again in a few seconds.`, | ||
}, | ||
{ | ||
type: "text" as const, | ||
text: `Warning: Make sure your IP address was enabled in the allow list setting of the Atlas cluster.`, | ||
}, | ||
], | ||
}; | ||
const content: CallToolResult["content"] = [ | ||
{ | ||
type: "text" as const, | ||
text: `Attempting to connect to cluster "${clusterName}"...`, | ||
}, | ||
{ | ||
type: "text" as const, | ||
text: `Warning: Provisioning a user and connecting to the cluster may take more time, please check again in a few seconds.`, | ||
}, | ||
]; | ||
|
||
if (ipAccessListUpdated) { | ||
content.push({ | ||
type: "text" as const, | ||
text: addedIpAccessListMessage, | ||
}); | ||
} | ||
|
||
if (createdUser) { | ||
content.push({ | ||
type: "text" as const, | ||
text: createdUserMessage, | ||
}); | ||
} | ||
|
||
return { content }; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too lazy to test it, but during manual testing, did you experience the model correctly relaying the url to users?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't find the LLM propagating the link. But it does show up in the tool call logs if the toggle is clicked
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we try tweaking the response and seeing what the output is? E.g. we could add something like:
Note 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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that did the trick!
