mongodb-mcp-server 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/pull_request_template.md +5 -0
- package/.github/workflows/accuracy-tests.yml +55 -0
- package/.github/workflows/check.yml +1 -1
- package/.github/workflows/code_health.yaml +4 -4
- package/.github/workflows/code_health_fork.yaml +0 -14
- package/.github/workflows/dependabot_pr.yaml +26 -0
- package/.github/workflows/docker.yaml +1 -1
- package/.github/workflows/jira-issue.yml +72 -0
- package/.smithery/smithery.yaml +10 -0
- package/.vscode/extensions.json +1 -1
- package/.vscode/launch.json +11 -1
- package/.vscode/settings.json +1 -11
- package/Dockerfile +1 -0
- package/README.md +132 -31
- package/dist/common/atlas/accessListUtils.js +36 -0
- package/dist/common/atlas/accessListUtils.js.map +1 -0
- package/dist/common/atlas/apiClient.js +25 -6
- package/dist/common/atlas/apiClient.js.map +1 -1
- package/dist/common/atlas/cluster.js +1 -1
- package/dist/common/atlas/cluster.js.map +1 -1
- package/dist/{config.js → common/config.js} +8 -1
- package/dist/common/config.js.map +1 -0
- package/dist/{errors.js → common/errors.js} +1 -0
- package/dist/common/errors.js.map +1 -0
- package/dist/{logger.js → common/logger.js} +20 -19
- package/dist/common/logger.js.map +1 -0
- package/dist/common/managedTimeout.js +20 -0
- package/dist/common/managedTimeout.js.map +1 -0
- package/dist/common/packageInfo.js.map +1 -0
- package/dist/{session.js → common/session.js} +20 -21
- package/dist/common/session.js.map +1 -0
- package/dist/common/sessionStore.js +73 -0
- package/dist/common/sessionStore.js.map +1 -0
- package/dist/helpers/container.js +28 -0
- package/dist/helpers/container.js.map +1 -0
- package/dist/helpers/generatePassword.js.map +1 -0
- package/dist/helpers/indexCheck.js +63 -0
- package/dist/helpers/indexCheck.js.map +1 -0
- package/dist/index.js +30 -37
- package/dist/index.js.map +1 -1
- package/dist/server.js +44 -7
- package/dist/server.js.map +1 -1
- package/dist/telemetry/constants.js +1 -1
- package/dist/telemetry/constants.js.map +1 -1
- package/dist/telemetry/telemetry.js +86 -116
- package/dist/telemetry/telemetry.js.map +1 -1
- package/dist/tools/atlas/atlasTool.js +3 -3
- package/dist/tools/atlas/atlasTool.js.map +1 -1
- package/dist/tools/atlas/connect/connectCluster.js +198 -0
- package/dist/tools/atlas/connect/connectCluster.js.map +1 -0
- package/dist/tools/atlas/create/createAccessList.js +9 -10
- package/dist/tools/atlas/create/createAccessList.js.map +1 -1
- package/dist/tools/atlas/create/createDBUser.js +3 -1
- package/dist/tools/atlas/create/createDBUser.js.map +1 -1
- package/dist/tools/atlas/create/createFreeCluster.js +2 -0
- package/dist/tools/atlas/create/createFreeCluster.js.map +1 -1
- package/dist/tools/atlas/create/createProject.js.map +1 -1
- package/dist/tools/atlas/read/inspectAccessList.js.map +1 -1
- package/dist/tools/atlas/read/inspectCluster.js.map +1 -1
- package/dist/tools/atlas/read/listAlerts.js.map +1 -1
- package/dist/tools/atlas/read/listClusters.js.map +1 -1
- package/dist/tools/atlas/read/listDBUsers.js.map +1 -1
- package/dist/tools/atlas/read/listOrgs.js.map +1 -1
- package/dist/tools/atlas/read/listProjects.js.map +1 -1
- package/dist/tools/atlas/tools.js +1 -1
- package/dist/tools/atlas/tools.js.map +1 -1
- package/dist/tools/mongodb/{metadata → connect}/connect.js +7 -4
- package/dist/tools/mongodb/connect/connect.js.map +1 -0
- package/dist/tools/mongodb/create/createCollection.js.map +1 -1
- package/dist/tools/mongodb/create/createIndex.js +1 -1
- package/dist/tools/mongodb/create/createIndex.js.map +1 -1
- package/dist/tools/mongodb/create/insertMany.js +1 -1
- package/dist/tools/mongodb/create/insertMany.js.map +1 -1
- package/dist/tools/mongodb/delete/deleteMany.js +20 -1
- package/dist/tools/mongodb/delete/deleteMany.js.map +1 -1
- package/dist/tools/mongodb/delete/dropCollection.js.map +1 -1
- package/dist/tools/mongodb/delete/dropDatabase.js.map +1 -1
- package/dist/tools/mongodb/metadata/collectionSchema.js.map +1 -1
- package/dist/tools/mongodb/metadata/collectionStorageSize.js.map +1 -1
- package/dist/tools/mongodb/metadata/dbStats.js.map +1 -1
- package/dist/tools/mongodb/metadata/explain.js +2 -2
- package/dist/tools/mongodb/metadata/explain.js.map +1 -1
- package/dist/tools/mongodb/metadata/listCollections.js.map +1 -1
- package/dist/tools/mongodb/metadata/listDatabases.js.map +1 -1
- package/dist/tools/mongodb/metadata/logs.js.map +1 -1
- package/dist/tools/mongodb/mongodbTool.js +47 -10
- package/dist/tools/mongodb/mongodbTool.js.map +1 -1
- package/dist/tools/mongodb/read/aggregate.js +10 -1
- package/dist/tools/mongodb/read/aggregate.js.map +1 -1
- package/dist/tools/mongodb/read/collectionIndexes.js.map +1 -1
- package/dist/tools/mongodb/read/count.js +15 -1
- package/dist/tools/mongodb/read/count.js.map +1 -1
- package/dist/tools/mongodb/read/find.js +14 -4
- package/dist/tools/mongodb/read/find.js.map +1 -1
- package/dist/tools/mongodb/tools.js +1 -1
- package/dist/tools/mongodb/tools.js.map +1 -1
- package/dist/tools/mongodb/update/renameCollection.js.map +1 -1
- package/dist/tools/mongodb/update/updateMany.js +24 -2
- package/dist/tools/mongodb/update/updateMany.js.map +1 -1
- package/dist/tools/tool.js +12 -9
- package/dist/tools/tool.js.map +1 -1
- package/dist/transports/base.js +26 -0
- package/dist/transports/base.js.map +1 -0
- package/dist/{helpers/EJsonTransport.js → transports/stdio.js} +24 -2
- package/dist/transports/stdio.js.map +1 -0
- package/dist/transports/streamableHttp.js +140 -0
- package/dist/transports/streamableHttp.js.map +1 -0
- package/eslint.config.js +13 -4
- package/package.json +43 -33
- package/resources/test-summary-template.html +415 -0
- package/scripts/accuracy/generateTestSummary.ts +335 -0
- package/scripts/accuracy/runAccuracyTests.sh +45 -0
- package/scripts/accuracy/updateAccuracyRunStatus.ts +21 -0
- package/src/common/atlas/accessListUtils.ts +54 -0
- package/src/common/atlas/apiClient.ts +25 -6
- package/src/common/atlas/cluster.ts +1 -1
- package/src/{config.ts → common/config.ts} +16 -2
- package/src/{errors.ts → common/errors.ts} +1 -0
- package/src/{logger.ts → common/logger.ts} +21 -24
- package/src/common/managedTimeout.ts +27 -0
- package/src/{session.ts → common/session.ts} +24 -26
- package/src/common/sessionStore.ts +111 -0
- package/src/helpers/container.ts +35 -0
- package/src/helpers/indexCheck.ts +83 -0
- package/src/index.ts +30 -40
- package/src/server.ts +55 -11
- package/src/telemetry/constants.ts +1 -1
- package/src/telemetry/telemetry.ts +109 -153
- package/src/telemetry/types.ts +2 -1
- package/src/tools/atlas/atlasTool.ts +4 -4
- package/src/tools/atlas/connect/connectCluster.ts +259 -0
- package/src/tools/atlas/create/createAccessList.ts +15 -13
- package/src/tools/atlas/create/createDBUser.ts +5 -3
- package/src/tools/atlas/create/createFreeCluster.ts +4 -2
- package/src/tools/atlas/create/createProject.ts +2 -2
- package/src/tools/atlas/read/inspectAccessList.ts +2 -2
- package/src/tools/atlas/read/inspectCluster.ts +2 -2
- package/src/tools/atlas/read/listAlerts.ts +2 -2
- package/src/tools/atlas/read/listClusters.ts +2 -2
- package/src/tools/atlas/read/listDBUsers.ts +2 -2
- package/src/tools/atlas/read/listOrgs.ts +2 -2
- package/src/tools/atlas/read/listProjects.ts +2 -2
- package/src/tools/atlas/tools.ts +1 -1
- package/src/tools/mongodb/{metadata → connect}/connect.ts +12 -9
- package/src/tools/mongodb/create/createCollection.ts +2 -2
- package/src/tools/mongodb/create/createIndex.ts +3 -3
- package/src/tools/mongodb/create/insertMany.ts +3 -3
- package/src/tools/mongodb/delete/deleteMany.ts +24 -3
- package/src/tools/mongodb/delete/dropCollection.ts +2 -2
- package/src/tools/mongodb/delete/dropDatabase.ts +2 -2
- package/src/tools/mongodb/metadata/collectionSchema.ts +2 -2
- package/src/tools/mongodb/metadata/collectionStorageSize.ts +2 -2
- package/src/tools/mongodb/metadata/dbStats.ts +2 -2
- package/src/tools/mongodb/metadata/explain.ts +4 -4
- package/src/tools/mongodb/metadata/listCollections.ts +2 -2
- package/src/tools/mongodb/metadata/listDatabases.ts +2 -2
- package/src/tools/mongodb/metadata/logs.ts +2 -2
- package/src/tools/mongodb/mongodbTool.ts +60 -14
- package/src/tools/mongodb/read/aggregate.ts +14 -3
- package/src/tools/mongodb/read/collectionIndexes.ts +2 -2
- package/src/tools/mongodb/read/count.ts +19 -3
- package/src/tools/mongodb/read/find.ts +20 -6
- package/src/tools/mongodb/tools.ts +1 -1
- package/src/tools/mongodb/update/renameCollection.ts +2 -2
- package/src/tools/mongodb/update/updateMany.ts +28 -4
- package/src/tools/tool.ts +23 -18
- package/src/transports/base.ts +34 -0
- package/src/{helpers/EJsonTransport.ts → transports/stdio.ts} +30 -1
- package/src/transports/streamableHttp.ts +178 -0
- package/tests/accuracy/aggregate.test.ts +27 -0
- package/tests/accuracy/collectionIndexes.test.ts +40 -0
- package/tests/accuracy/collectionSchema.test.ts +28 -0
- package/tests/accuracy/collectionStorageSize.test.ts +41 -0
- package/tests/accuracy/count.test.ts +44 -0
- package/tests/accuracy/createCollection.test.ts +46 -0
- package/tests/accuracy/createIndex.test.ts +37 -0
- package/tests/accuracy/dbStats.test.ts +15 -0
- package/tests/accuracy/deleteMany.test.ts +44 -0
- package/tests/accuracy/dropCollection.test.ts +74 -0
- package/tests/accuracy/dropDatabase.test.ts +41 -0
- package/tests/accuracy/explain.test.ts +73 -0
- package/tests/accuracy/find.test.ts +114 -0
- package/tests/accuracy/insertMany.test.ts +48 -0
- package/tests/accuracy/listCollections.test.ts +60 -0
- package/tests/accuracy/listDatabases.test.ts +31 -0
- package/tests/accuracy/logs.test.ts +28 -0
- package/tests/accuracy/renameCollection.test.ts +31 -0
- package/tests/accuracy/sdk/accuracyResultStorage/diskStorage.ts +189 -0
- package/tests/accuracy/sdk/accuracyResultStorage/getAccuracyResultStorage.ts +11 -0
- package/tests/accuracy/sdk/accuracyResultStorage/mongodbStorage.ts +151 -0
- package/tests/accuracy/sdk/accuracyResultStorage/resultStorage.ts +117 -0
- package/tests/accuracy/sdk/accuracyScorer.ts +93 -0
- package/tests/accuracy/sdk/accuracyTestingClient.ts +94 -0
- package/tests/accuracy/sdk/agent.ts +56 -0
- package/tests/accuracy/sdk/constants.ts +26 -0
- package/tests/accuracy/sdk/describeAccuracyTests.ts +126 -0
- package/tests/accuracy/sdk/gitInfo.ts +7 -0
- package/tests/accuracy/sdk/matcher.ts +193 -0
- package/tests/accuracy/sdk/models.ts +95 -0
- package/tests/accuracy/test-data-dumps/comics.books.json +417 -0
- package/tests/accuracy/test-data-dumps/comics.characters.json +402 -0
- package/tests/accuracy/test-data-dumps/mflix.movies.json +496 -0
- package/tests/accuracy/test-data-dumps/mflix.shows.json +572 -0
- package/tests/accuracy/updateMany.test.ts +42 -0
- package/tests/integration/helpers.ts +9 -9
- package/tests/integration/indexCheck.test.ts +464 -0
- package/tests/integration/server.test.ts +6 -4
- package/tests/integration/telemetry.test.ts +29 -0
- package/tests/integration/tools/atlas/accessLists.test.ts +22 -2
- package/tests/integration/tools/atlas/alerts.test.ts +3 -2
- package/tests/integration/tools/atlas/atlasHelpers.ts +3 -0
- package/tests/integration/tools/atlas/clusters.test.ts +68 -16
- package/tests/integration/tools/atlas/dbUsers.test.ts +14 -1
- package/tests/integration/tools/atlas/orgs.test.ts +2 -1
- package/tests/integration/tools/atlas/projects.test.ts +4 -3
- package/tests/integration/tools/mongodb/{metadata → connect}/connect.test.ts +34 -3
- package/tests/integration/tools/mongodb/create/createCollection.test.ts +1 -0
- package/tests/integration/tools/mongodb/create/createIndex.test.ts +1 -0
- package/tests/integration/tools/mongodb/create/insertMany.test.ts +1 -0
- package/tests/integration/tools/mongodb/delete/deleteMany.test.ts +1 -0
- package/tests/integration/tools/mongodb/delete/dropCollection.test.ts +1 -1
- package/tests/integration/tools/mongodb/delete/dropDatabase.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/collectionSchema.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/collectionStorageSize.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/dbStats.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/explain.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/listCollections.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/listDatabases.test.ts +3 -2
- package/tests/integration/tools/mongodb/metadata/logs.test.ts +1 -0
- package/tests/integration/tools/mongodb/mongodbHelpers.ts +67 -2
- package/tests/integration/tools/mongodb/read/aggregate.test.ts +2 -1
- package/tests/integration/tools/mongodb/read/collectionIndexes.test.ts +1 -0
- package/tests/integration/tools/mongodb/read/count.test.ts +1 -0
- package/tests/integration/tools/mongodb/read/find.test.ts +2 -1
- package/tests/integration/tools/mongodb/update/renameCollection.test.ts +1 -0
- package/tests/integration/tools/mongodb/update/updateMany.test.ts +1 -0
- package/tests/integration/transports/stdio.test.ts +40 -0
- package/tests/integration/transports/streamableHttp.test.ts +56 -0
- package/tests/matchers/toIncludeSameMembers.test.ts +59 -0
- package/tests/matchers/toIncludeSameMembers.ts +12 -0
- package/tests/setup.ts +7 -0
- package/tests/unit/accessListUtils.test.ts +39 -0
- package/tests/unit/accuracyScorer.test.ts +390 -0
- package/tests/unit/{apiClient.test.ts → common/apiClient.test.ts} +15 -15
- package/tests/unit/common/managedTimeout.test.ts +67 -0
- package/tests/unit/{session.test.ts → common/session.test.ts} +7 -12
- package/tests/unit/helpers/indexCheck.test.ts +150 -0
- package/tests/unit/telemetry.test.ts +99 -137
- package/tests/unit/{EJsonTransport.test.ts → transports/stdio.test.ts} +4 -4
- package/tests/vitest.d.ts +11 -0
- package/tsconfig.json +0 -1
- package/{tsconfig.jest.json → tsconfig.test.json} +1 -2
- package/vitest.config.ts +41 -0
- package/dist/common/atlas/generatePassword.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/helpers/EJsonTransport.js.map +0 -1
- package/dist/helpers/packageInfo.js.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/session.js.map +0 -1
- package/dist/tools/atlas/metadata/connectCluster.js +0 -100
- package/dist/tools/atlas/metadata/connectCluster.js.map +0 -1
- package/dist/tools/mongodb/metadata/connect.js.map +0 -1
- package/global.d.ts +0 -1
- package/jest.config.cjs +0 -22
- package/src/tools/atlas/metadata/connectCluster.ts +0 -121
- /package/dist/{helpers → common}/packageInfo.js +0 -0
- /package/dist/{common/atlas → helpers}/generatePassword.js +0 -0
- /package/src/{helpers → common}/packageInfo.ts +0 -0
- /package/src/{common/atlas → helpers}/generatePassword.ts +0 -0
|
@@ -1,158 +1,128 @@
|
|
|
1
|
-
import { Session } from "../session.js";
|
|
1
|
+
import { Session } from "../common/session.js";
|
|
2
2
|
import { BaseEvent, CommonProperties } from "./types.js";
|
|
3
|
-
import { UserConfig } from "../config.js";
|
|
4
|
-
import logger, { LogId } from "../logger.js";
|
|
3
|
+
import { UserConfig } from "../common/config.js";
|
|
4
|
+
import logger, { LogId } from "../common/logger.js";
|
|
5
5
|
import { ApiClient } from "../common/atlas/apiClient.js";
|
|
6
6
|
import { MACHINE_METADATA } from "./constants.js";
|
|
7
7
|
import { EventCache } from "./eventCache.js";
|
|
8
8
|
import nodeMachineId from "node-machine-id";
|
|
9
9
|
import { getDeviceId } from "@mongodb-js/device-id";
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
async function fileExists(filePath: string): Promise<boolean> {
|
|
13
|
-
try {
|
|
14
|
-
await fs.access(filePath, fs.constants.F_OK);
|
|
15
|
-
return true; // File exists
|
|
16
|
-
} catch (e: unknown) {
|
|
17
|
-
if (
|
|
18
|
-
e instanceof Error &&
|
|
19
|
-
(
|
|
20
|
-
e as Error & {
|
|
21
|
-
code: string;
|
|
22
|
-
}
|
|
23
|
-
).code === "ENOENT"
|
|
24
|
-
) {
|
|
25
|
-
return false; // File does not exist
|
|
26
|
-
}
|
|
27
|
-
throw e; // Re-throw unexpected errors
|
|
28
|
-
}
|
|
29
|
-
}
|
|
10
|
+
import { detectContainerEnv } from "../helpers/container.js";
|
|
30
11
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const exists = await Promise.all(["/.dockerenv", "/run/.containerenv", "/var/run/.containerenv"].map(fileExists));
|
|
12
|
+
type EventResult = {
|
|
13
|
+
success: boolean;
|
|
14
|
+
error?: Error;
|
|
15
|
+
};
|
|
37
16
|
|
|
38
|
-
|
|
39
|
-
}
|
|
17
|
+
export const DEVICE_ID_TIMEOUT = 3000;
|
|
40
18
|
|
|
41
19
|
export class Telemetry {
|
|
20
|
+
private isBufferingEvents: boolean = true;
|
|
21
|
+
/** Resolves when the setup is complete or a timeout occurs */
|
|
22
|
+
public setupPromise: Promise<[string, boolean]> | undefined;
|
|
42
23
|
private deviceIdAbortController = new AbortController();
|
|
43
24
|
private eventCache: EventCache;
|
|
44
25
|
private getRawMachineId: () => Promise<string>;
|
|
45
|
-
private getContainerEnv: () => Promise<boolean>;
|
|
46
|
-
private cachedCommonProperties?: CommonProperties;
|
|
47
|
-
private flushing: boolean = false;
|
|
48
26
|
|
|
49
27
|
private constructor(
|
|
50
28
|
private readonly session: Session,
|
|
51
29
|
private readonly userConfig: UserConfig,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
getRawMachineId,
|
|
55
|
-
getContainerEnv,
|
|
56
|
-
}: {
|
|
57
|
-
eventCache: EventCache;
|
|
58
|
-
getRawMachineId: () => Promise<string>;
|
|
59
|
-
getContainerEnv: () => Promise<boolean>;
|
|
60
|
-
}
|
|
30
|
+
private readonly commonProperties: CommonProperties,
|
|
31
|
+
{ eventCache, getRawMachineId }: { eventCache: EventCache; getRawMachineId: () => Promise<string> }
|
|
61
32
|
) {
|
|
62
33
|
this.eventCache = eventCache;
|
|
63
34
|
this.getRawMachineId = getRawMachineId;
|
|
64
|
-
this.getContainerEnv = getContainerEnv;
|
|
65
35
|
}
|
|
66
36
|
|
|
67
37
|
static create(
|
|
68
38
|
session: Session,
|
|
69
39
|
userConfig: UserConfig,
|
|
70
40
|
{
|
|
41
|
+
commonProperties = { ...MACHINE_METADATA },
|
|
71
42
|
eventCache = EventCache.getInstance(),
|
|
72
43
|
getRawMachineId = () => nodeMachineId.machineId(true),
|
|
73
|
-
getContainerEnv = isContainerized,
|
|
74
44
|
}: {
|
|
75
45
|
eventCache?: EventCache;
|
|
76
46
|
getRawMachineId?: () => Promise<string>;
|
|
77
|
-
|
|
47
|
+
commonProperties?: CommonProperties;
|
|
78
48
|
} = {}
|
|
79
49
|
): Telemetry {
|
|
80
|
-
const instance = new Telemetry(session, userConfig, {
|
|
81
|
-
eventCache,
|
|
82
|
-
getRawMachineId,
|
|
83
|
-
getContainerEnv,
|
|
84
|
-
});
|
|
50
|
+
const instance = new Telemetry(session, userConfig, commonProperties, { eventCache, getRawMachineId });
|
|
85
51
|
|
|
52
|
+
void instance.setup();
|
|
86
53
|
return instance;
|
|
87
54
|
}
|
|
88
55
|
|
|
56
|
+
private async setup(): Promise<void> {
|
|
57
|
+
if (!this.isTelemetryEnabled()) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this.setupPromise = Promise.all([
|
|
61
|
+
getDeviceId({
|
|
62
|
+
getMachineId: () => this.getRawMachineId(),
|
|
63
|
+
onError: (reason, error) => {
|
|
64
|
+
switch (reason) {
|
|
65
|
+
case "resolutionError":
|
|
66
|
+
logger.debug(LogId.telemetryDeviceIdFailure, "telemetry", String(error));
|
|
67
|
+
break;
|
|
68
|
+
case "timeout":
|
|
69
|
+
logger.debug(LogId.telemetryDeviceIdTimeout, "telemetry", "Device ID retrieval timed out");
|
|
70
|
+
break;
|
|
71
|
+
case "abort":
|
|
72
|
+
// No need to log in the case of aborts
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
abortSignal: this.deviceIdAbortController.signal,
|
|
77
|
+
}),
|
|
78
|
+
detectContainerEnv(),
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
const [deviceId, containerEnv] = await this.setupPromise;
|
|
82
|
+
|
|
83
|
+
this.commonProperties.device_id = deviceId;
|
|
84
|
+
this.commonProperties.is_container_env = containerEnv;
|
|
85
|
+
|
|
86
|
+
this.isBufferingEvents = false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
89
|
public async close(): Promise<void> {
|
|
90
90
|
this.deviceIdAbortController.abort();
|
|
91
|
-
|
|
91
|
+
this.isBufferingEvents = false;
|
|
92
|
+
await this.emitEvents(this.eventCache.getEvents());
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
/**
|
|
95
96
|
* Emits events through the telemetry pipeline
|
|
96
97
|
* @param events - The events to emit
|
|
97
98
|
*/
|
|
98
|
-
public emitEvents(events: BaseEvent[]): void {
|
|
99
|
-
|
|
99
|
+
public async emitEvents(events: BaseEvent[]): Promise<void> {
|
|
100
|
+
try {
|
|
101
|
+
if (!this.isTelemetryEnabled()) {
|
|
102
|
+
logger.info(LogId.telemetryEmitFailure, "telemetry", `Telemetry is disabled.`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
await this.emit(events);
|
|
107
|
+
} catch {
|
|
108
|
+
logger.debug(LogId.telemetryEmitFailure, "telemetry", `Error emitting telemetry events.`);
|
|
109
|
+
}
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
/**
|
|
103
113
|
* Gets the common properties for events
|
|
104
114
|
* @returns Object containing common properties for all events
|
|
105
115
|
*/
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
case "resolutionError":
|
|
117
|
-
logger.debug(LogId.telemetryDeviceIdFailure, "telemetry", String(error));
|
|
118
|
-
break;
|
|
119
|
-
case "timeout":
|
|
120
|
-
logger.debug(
|
|
121
|
-
LogId.telemetryDeviceIdTimeout,
|
|
122
|
-
"telemetry",
|
|
123
|
-
"Device ID retrieval timed out"
|
|
124
|
-
);
|
|
125
|
-
break;
|
|
126
|
-
case "abort":
|
|
127
|
-
// No need to log in the case of aborts
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
abortSignal: this.deviceIdAbortController.signal,
|
|
132
|
-
}).then((id) => {
|
|
133
|
-
deviceId = id;
|
|
134
|
-
}),
|
|
135
|
-
this.getContainerEnv().then((env) => {
|
|
136
|
-
containerEnv = env;
|
|
137
|
-
}),
|
|
138
|
-
]);
|
|
139
|
-
} catch (error: unknown) {
|
|
140
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
141
|
-
logger.debug(LogId.telemetryDeviceIdFailure, "telemetry", err.message);
|
|
142
|
-
}
|
|
143
|
-
this.cachedCommonProperties = {
|
|
144
|
-
...MACHINE_METADATA,
|
|
145
|
-
mcp_client_version: this.session.agentRunner?.version,
|
|
146
|
-
mcp_client_name: this.session.agentRunner?.name,
|
|
147
|
-
session_id: this.session.sessionId,
|
|
148
|
-
config_atlas_auth: this.session.apiClient.hasCredentials() ? "true" : "false",
|
|
149
|
-
config_connection_string: this.userConfig.connectionString ? "true" : "false",
|
|
150
|
-
is_container_env: containerEnv ? "true" : "false",
|
|
151
|
-
device_id: deviceId,
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return this.cachedCommonProperties;
|
|
116
|
+
public getCommonProperties(): CommonProperties {
|
|
117
|
+
return {
|
|
118
|
+
...this.commonProperties,
|
|
119
|
+
transport: this.userConfig.transport,
|
|
120
|
+
mcp_client_version: this.session.agentRunner?.version,
|
|
121
|
+
mcp_client_name: this.session.agentRunner?.name,
|
|
122
|
+
session_id: this.session.sessionId,
|
|
123
|
+
config_atlas_auth: this.session.apiClient.hasCredentials() ? "true" : "false",
|
|
124
|
+
config_connection_string: this.userConfig.connectionString ? "true" : "false",
|
|
125
|
+
};
|
|
156
126
|
}
|
|
157
127
|
|
|
158
128
|
/**
|
|
@@ -173,74 +143,60 @@ export class Telemetry {
|
|
|
173
143
|
}
|
|
174
144
|
|
|
175
145
|
/**
|
|
176
|
-
* Attempts to
|
|
146
|
+
* Attempts to emit events through authenticated and unauthenticated clients
|
|
177
147
|
* Falls back to caching if both attempts fail
|
|
178
148
|
*/
|
|
179
|
-
|
|
180
|
-
if (
|
|
181
|
-
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (this.flushing) {
|
|
186
|
-
this.eventCache.appendEvents(events ?? []);
|
|
187
|
-
process.nextTick(async () => {
|
|
188
|
-
// try again if in the middle of a flush
|
|
189
|
-
await this.flush();
|
|
190
|
-
});
|
|
149
|
+
private async emit(events: BaseEvent[]): Promise<void> {
|
|
150
|
+
if (this.isBufferingEvents) {
|
|
151
|
+
this.eventCache.appendEvents(events);
|
|
191
152
|
return;
|
|
192
153
|
}
|
|
193
154
|
|
|
194
|
-
|
|
155
|
+
const cachedEvents = this.eventCache.getEvents();
|
|
156
|
+
const allEvents = [...cachedEvents, ...events];
|
|
195
157
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
logger.debug(
|
|
205
|
-
LogId.telemetryEmitStart,
|
|
206
|
-
"telemetry",
|
|
207
|
-
`Attempting to send ${allEvents.length} events (${cachedEvents.length} cached)`
|
|
208
|
-
);
|
|
158
|
+
logger.debug(
|
|
159
|
+
LogId.telemetryEmitStart,
|
|
160
|
+
"telemetry",
|
|
161
|
+
`Attempting to send ${allEvents.length} events (${cachedEvents.length} cached)`
|
|
162
|
+
);
|
|
209
163
|
|
|
210
|
-
|
|
164
|
+
const result = await this.sendEvents(this.session.apiClient, allEvents);
|
|
165
|
+
if (result.success) {
|
|
211
166
|
this.eventCache.clearEvents();
|
|
212
167
|
logger.debug(
|
|
213
168
|
LogId.telemetryEmitSuccess,
|
|
214
169
|
"telemetry",
|
|
215
170
|
`Sent ${allEvents.length} events successfully: ${JSON.stringify(allEvents, null, 2)}`
|
|
216
171
|
);
|
|
217
|
-
|
|
218
|
-
logger.debug(
|
|
219
|
-
LogId.telemetryEmitFailure,
|
|
220
|
-
"telemetry",
|
|
221
|
-
`Error sending event to client: ${error instanceof Error ? error.message : String(error)}`
|
|
222
|
-
);
|
|
223
|
-
this.eventCache.appendEvents(events ?? []);
|
|
224
|
-
process.nextTick(async () => {
|
|
225
|
-
// try again
|
|
226
|
-
await this.flush();
|
|
227
|
-
});
|
|
172
|
+
return;
|
|
228
173
|
}
|
|
229
174
|
|
|
230
|
-
|
|
175
|
+
logger.debug(
|
|
176
|
+
LogId.telemetryEmitFailure,
|
|
177
|
+
"telemetry",
|
|
178
|
+
`Error sending event to client: ${result.error instanceof Error ? result.error.message : String(result.error)}`
|
|
179
|
+
);
|
|
180
|
+
this.eventCache.appendEvents(events);
|
|
231
181
|
}
|
|
232
182
|
|
|
233
183
|
/**
|
|
234
184
|
* Attempts to send events through the provided API client
|
|
235
185
|
*/
|
|
236
|
-
private async sendEvents(client: ApiClient, events: BaseEvent[]): Promise<
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
186
|
+
private async sendEvents(client: ApiClient, events: BaseEvent[]): Promise<EventResult> {
|
|
187
|
+
try {
|
|
188
|
+
await client.sendEvents(
|
|
189
|
+
events.map((event) => ({
|
|
190
|
+
...event,
|
|
191
|
+
properties: { ...this.getCommonProperties(), ...event.properties },
|
|
192
|
+
}))
|
|
193
|
+
);
|
|
194
|
+
return { success: true };
|
|
195
|
+
} catch (error) {
|
|
196
|
+
return {
|
|
197
|
+
success: false,
|
|
198
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
245
201
|
}
|
|
246
202
|
}
|
package/src/telemetry/types.ts
CHANGED
|
@@ -66,10 +66,11 @@ export type CommonStaticProperties = {
|
|
|
66
66
|
*/
|
|
67
67
|
export type CommonProperties = {
|
|
68
68
|
device_id?: string;
|
|
69
|
+
is_container_env?: boolean;
|
|
69
70
|
mcp_client_version?: string;
|
|
70
71
|
mcp_client_name?: string;
|
|
72
|
+
transport?: "stdio" | "http";
|
|
71
73
|
config_atlas_auth?: TelemetryBoolSet;
|
|
72
74
|
config_connection_string?: TelemetryBoolSet;
|
|
73
75
|
session_id?: string;
|
|
74
|
-
is_container_env?: TelemetryBoolSet;
|
|
75
76
|
} & CommonStaticProperties;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { ToolBase, ToolCategory, TelemetryToolMetadata, ToolArgs } from "../tool.js";
|
|
2
2
|
import { ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
-
import logger, { LogId } from "../../logger.js";
|
|
4
|
+
import logger, { LogId } from "../../common/logger.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { ApiClientError } from "../../common/atlas/apiClientError.js";
|
|
7
7
|
|
|
8
8
|
export abstract class AtlasToolBase extends ToolBase {
|
|
9
|
-
|
|
9
|
+
public category: ToolCategory = "atlas";
|
|
10
10
|
|
|
11
11
|
protected verifyAllowed(): boolean {
|
|
12
12
|
if (!this.config.apiClientId || !this.config.apiClientSecret) {
|
|
@@ -29,7 +29,7 @@ export abstract class AtlasToolBase extends ToolBase {
|
|
|
29
29
|
type: "text",
|
|
30
30
|
text: `Unable to authenticate with MongoDB Atlas, API error: ${error.message}
|
|
31
31
|
|
|
32
|
-
Hint: Your API credentials may be invalid, expired or lack permissions.
|
|
32
|
+
Hint: Your API credentials may be invalid, expired or lack permissions.
|
|
33
33
|
Please check your Atlas API credentials and ensure they have the appropriate permissions.
|
|
34
34
|
For more information on setting up API keys, visit: https://www.mongodb.com/docs/atlas/configure-api-access/`,
|
|
35
35
|
},
|
|
@@ -44,7 +44,7 @@ For more information on setting up API keys, visit: https://www.mongodb.com/docs
|
|
|
44
44
|
{
|
|
45
45
|
type: "text",
|
|
46
46
|
text: `Received a Forbidden API Error: ${error.message}
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
You don't have sufficient permissions to perform this action in MongoDB Atlas
|
|
49
49
|
Please ensure your API key has the necessary roles assigned.
|
|
50
50
|
For more information on Atlas API access roles, visit: https://www.mongodb.com/docs/atlas/api/service-accounts-overview/`,
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { AtlasToolBase } from "../atlasTool.js";
|
|
4
|
+
import { ToolArgs, OperationType } from "../../tool.js";
|
|
5
|
+
import { generateSecurePassword } from "../../../helpers/generatePassword.js";
|
|
6
|
+
import logger, { LogId } from "../../../common/logger.js";
|
|
7
|
+
import { inspectCluster } from "../../../common/atlas/cluster.js";
|
|
8
|
+
import { ensureCurrentIpInAccessList } from "../../../common/atlas/accessListUtils.js";
|
|
9
|
+
|
|
10
|
+
const EXPIRY_MS = 1000 * 60 * 60 * 12; // 12 hours
|
|
11
|
+
|
|
12
|
+
function sleep(ms: number): Promise<void> {
|
|
13
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class ConnectClusterTool extends AtlasToolBase {
|
|
17
|
+
public name = "atlas-connect-cluster";
|
|
18
|
+
protected description = "Connect to MongoDB Atlas cluster";
|
|
19
|
+
public operationType: OperationType = "connect";
|
|
20
|
+
protected argsShape = {
|
|
21
|
+
projectId: z.string().describe("Atlas project ID"),
|
|
22
|
+
clusterName: z.string().describe("Atlas cluster name"),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
private async queryConnection(
|
|
26
|
+
projectId: string,
|
|
27
|
+
clusterName: string
|
|
28
|
+
): Promise<"connected" | "disconnected" | "connecting" | "connected-to-other-cluster" | "unknown"> {
|
|
29
|
+
if (!this.session.connectedAtlasCluster) {
|
|
30
|
+
if (this.session.serviceProvider) {
|
|
31
|
+
return "connected-to-other-cluster";
|
|
32
|
+
}
|
|
33
|
+
return "disconnected";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
this.session.connectedAtlasCluster.projectId !== projectId ||
|
|
38
|
+
this.session.connectedAtlasCluster.clusterName !== clusterName
|
|
39
|
+
) {
|
|
40
|
+
return "connected-to-other-cluster";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!this.session.serviceProvider) {
|
|
44
|
+
return "connecting";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
await this.session.serviceProvider.runCommand("admin", {
|
|
49
|
+
ping: 1,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return "connected";
|
|
53
|
+
} catch (err: unknown) {
|
|
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
|
+
}
|
|
63
|
+
|
|
64
|
+
private async prepareClusterConnection(projectId: string, clusterName: string): Promise<string> {
|
|
65
|
+
const cluster = await inspectCluster(this.session.apiClient, projectId, clusterName);
|
|
66
|
+
|
|
67
|
+
if (!cluster.connectionString) {
|
|
68
|
+
throw new Error("Connection string not available");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const username = `mcpUser${Math.floor(Math.random() * 100000)}`;
|
|
72
|
+
const password = await generateSecurePassword();
|
|
73
|
+
|
|
74
|
+
const expiryDate = new Date(Date.now() + EXPIRY_MS);
|
|
75
|
+
|
|
76
|
+
const readOnly =
|
|
77
|
+
this.config.readOnly ||
|
|
78
|
+
(this.config.disabledTools?.includes("create") &&
|
|
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";
|
|
85
|
+
|
|
86
|
+
await this.session.apiClient.createDatabaseUser({
|
|
87
|
+
params: {
|
|
88
|
+
path: {
|
|
89
|
+
groupId: projectId,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
body: {
|
|
93
|
+
databaseName: "admin",
|
|
94
|
+
groupId: projectId,
|
|
95
|
+
roles: [
|
|
96
|
+
{
|
|
97
|
+
roleName,
|
|
98
|
+
databaseName: "admin",
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
scopes: [{ type: "CLUSTER", name: clusterName }],
|
|
102
|
+
username,
|
|
103
|
+
password,
|
|
104
|
+
awsIAMType: "NONE",
|
|
105
|
+
ldapAuthType: "NONE",
|
|
106
|
+
oidcAuthType: "NONE",
|
|
107
|
+
x509Type: "NONE",
|
|
108
|
+
deleteAfterDate: expiryDate.toISOString(),
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
this.session.connectedAtlasCluster = {
|
|
113
|
+
username,
|
|
114
|
+
projectId,
|
|
115
|
+
clusterName,
|
|
116
|
+
expiryDate,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const cn = new URL(cluster.connectionString);
|
|
120
|
+
cn.username = username;
|
|
121
|
+
cn.password = password;
|
|
122
|
+
cn.searchParams.set("authSource", "admin");
|
|
123
|
+
return cn.toString();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private async connectToCluster(projectId: string, clusterName: string, connectionString: string): Promise<void> {
|
|
127
|
+
let lastError: Error | undefined = undefined;
|
|
128
|
+
|
|
129
|
+
logger.debug(
|
|
130
|
+
LogId.atlasConnectAttempt,
|
|
131
|
+
"atlas-connect-cluster",
|
|
132
|
+
`attempting to connect to cluster: ${this.session.connectedAtlasCluster?.clusterName}`
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// try to connect for about 5 minutes
|
|
136
|
+
for (let i = 0; i < 600; i++) {
|
|
137
|
+
if (
|
|
138
|
+
!this.session.connectedAtlasCluster ||
|
|
139
|
+
this.session.connectedAtlasCluster.projectId != projectId ||
|
|
140
|
+
this.session.connectedAtlasCluster.clusterName != clusterName
|
|
141
|
+
) {
|
|
142
|
+
throw new Error("Cluster connection aborted");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
lastError = undefined;
|
|
147
|
+
|
|
148
|
+
await this.session.connectToMongoDB(connectionString, this.config.connectOptions);
|
|
149
|
+
break;
|
|
150
|
+
} catch (err: unknown) {
|
|
151
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
152
|
+
|
|
153
|
+
lastError = error;
|
|
154
|
+
|
|
155
|
+
logger.debug(
|
|
156
|
+
LogId.atlasConnectFailure,
|
|
157
|
+
"atlas-connect-cluster",
|
|
158
|
+
`error connecting to cluster: ${error.message}`
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
await sleep(500); // wait for 500ms before retrying
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
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
|
+
|
|
194
|
+
logger.debug(
|
|
195
|
+
LogId.atlasConnectSucceeded,
|
|
196
|
+
"atlas-connect-cluster",
|
|
197
|
+
`connected to cluster: ${this.session.connectedAtlasCluster?.clusterName}`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
protected async execute({ projectId, clusterName }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
|
|
202
|
+
await ensureCurrentIpInAccessList(this.session.apiClient, projectId);
|
|
203
|
+
for (let i = 0; i < 60; i++) {
|
|
204
|
+
const state = await this.queryConnection(projectId, clusterName);
|
|
205
|
+
switch (state) {
|
|
206
|
+
case "connected": {
|
|
207
|
+
return {
|
|
208
|
+
content: [
|
|
209
|
+
{
|
|
210
|
+
type: "text",
|
|
211
|
+
text: `Connected to cluster "${clusterName}".`,
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
case "connecting":
|
|
217
|
+
case "unknown": {
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
case "connected-to-other-cluster":
|
|
221
|
+
case "disconnected":
|
|
222
|
+
default: {
|
|
223
|
+
await this.session.disconnect();
|
|
224
|
+
const connectionString = await this.prepareClusterConnection(projectId, clusterName);
|
|
225
|
+
|
|
226
|
+
// try to connect for about 5 minutes asynchronously
|
|
227
|
+
void this.connectToCluster(projectId, clusterName, connectionString).catch((err: unknown) => {
|
|
228
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
229
|
+
logger.error(
|
|
230
|
+
LogId.atlasConnectFailure,
|
|
231
|
+
"atlas-connect-cluster",
|
|
232
|
+
`error connecting to cluster: ${error.message}`
|
|
233
|
+
);
|
|
234
|
+
});
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
await sleep(500);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
content: [
|
|
244
|
+
{
|
|
245
|
+
type: "text" as const,
|
|
246
|
+
text: `Attempting to connect to cluster "${clusterName}"...`,
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
type: "text" as const,
|
|
250
|
+
text: `Warning: Provisioning a user and connecting to the cluster may take more time, please check again in a few seconds.`,
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
type: "text" as const,
|
|
254
|
+
text: `Warning: Make sure your IP address was enabled in the allow list setting of the Atlas cluster.`,
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|