Skip to content

Commit 1fb6375

Browse files
authored
Merge branch 'main' into docs-2
2 parents 735d1dd + de2c604 commit 1fb6375

File tree

13 files changed

+118
-63
lines changed

13 files changed

+118
-63
lines changed

eslint.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default defineConfig([
4848
"coverage",
4949
"global.d.ts",
5050
"eslint.config.js",
51-
"jest.config.js",
51+
"jest.config.ts",
5252
]),
5353
eslintPluginPrettierRecommended,
5454
]);

jest.config.js renamed to jest.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default {
1212
"ts-jest",
1313
{
1414
useESM: true,
15-
tsconfig: "tsconfig.jest.json", // Use specific tsconfig file for Jest
15+
tsconfig: "tsconfig.jest.json",
1616
},
1717
],
1818
},

package-lock.json

Lines changed: 10 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"check:types": "tsc --noEmit --project tsconfig.json",
3030
"reformat": "prettier --write .",
3131
"generate": "./scripts/generate.sh",
32-
"test": "jest --coverage"
32+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage"
3333
},
3434
"license": "Apache-2.0",
3535
"devDependencies": {
@@ -69,7 +69,7 @@
6969
"mongodb-log-writer": "^2.4.1",
7070
"mongodb-redact": "^1.1.6",
7171
"mongodb-schema": "^12.6.2",
72-
"native-machine-id": "^0.1.0",
72+
"node-machine-id": "^1.1.12",
7373
"openapi-fetch": "^0.13.5",
7474
"simple-oauth2": "^5.1.0",
7575
"yargs-parser": "^21.1.1",

src/logger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const LogId = {
1818
telemetryEmitStart: mongoLogId(1_002_003),
1919
telemetryEmitSuccess: mongoLogId(1_002_004),
2020
telemetryMetadataError: mongoLogId(1_002_005),
21+
telemetryDeviceIdFailure: mongoLogId(1_002_006),
2122

2223
toolExecute: mongoLogId(1_003_001),
2324
toolExecuteFailure: mongoLogId(1_003_002),

src/server.ts

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -150,39 +150,25 @@ export class Server {
150150
telemetry: this.userConfig.telemetry,
151151
logPath: this.userConfig.logPath,
152152
connectionString: this.userConfig.connectionString
153-
? "set; no explicit connect needed, use switch-connection tool to connect to a different connection if necessary"
154-
: "not set; before using any mongodb tool, you need to call the connect tool with a connection string",
153+
? "set; access to MongoDB tools are currently available to use"
154+
: "not set; before using any MongoDB tool, you need to configure a connection string, alternatively you can setup MongoDB Atlas access, more info at 'https://github.com/mongodb-js/mongodb-mcp-server'.",
155155
connectOptions: this.userConfig.connectOptions,
156+
atlas:
157+
this.userConfig.apiClientId && this.userConfig.apiClientSecret
158+
? "set; MongoDB Atlas tools are currently available to use"
159+
: "not set; MongoDB Atlas tools are currently unavailable, to have access to MongoDB Atlas tools like creating clusters or connecting to clusters make sure to setup credentials, more info at 'https://github.com/mongodb-js/mongodb-mcp-server'.",
156160
};
157161
return {
158162
contents: [
159163
{
160164
text: JSON.stringify(result),
165+
mimeType: "application/json",
161166
uri: uri.href,
162167
},
163168
],
164169
};
165170
}
166171
);
167-
if (this.userConfig.connectionString) {
168-
this.mcpServer.resource(
169-
"connection-string",
170-
"config://connection-string",
171-
{
172-
description: "Preconfigured connection string that will be used as a default in the `connect` tool",
173-
},
174-
(uri) => {
175-
return {
176-
contents: [
177-
{
178-
text: `Preconfigured connection string: ${this.userConfig.connectionString}`,
179-
uri: uri.href,
180-
},
181-
],
182-
};
183-
}
184-
);
185-
}
186172
}
187173

188174
private async validateConfig(): Promise<void> {

src/telemetry/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { getMachineIdSync } from "native-machine-id";
21
import { packageInfo } from "../packageInfo.js";
32
import { type CommonStaticProperties } from "./types.js";
3+
import { getDeviceId } from "./device-id.js";
44
/**
55
* Machine-specific metadata formatted for telemetry
66
*/
77
export const MACHINE_METADATA: CommonStaticProperties = {
8-
device_id: getMachineIdSync(),
8+
device_id: getDeviceId(),
99
mcp_server_version: packageInfo.version,
1010
mcp_server_name: packageInfo.mcpServerName,
1111
platform: process.platform,

src/telemetry/device-id.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { createHmac } from "crypto";
2+
import nodeMachineId from "node-machine-id";
3+
import logger, { LogId } from "../logger.js";
4+
5+
export function getDeviceId(): string {
6+
try {
7+
const originalId = nodeMachineId.machineIdSync(true);
8+
// Create a hashed format from the all uppercase version of the machine ID
9+
// to match it exactly with the denisbrodbeck/machineid library that Atlas CLI uses.
10+
const hmac = createHmac("sha256", originalId.toUpperCase());
11+
12+
/** This matches the message used to create the hashes in Atlas CLI */
13+
const DEVICE_ID_HASH_MESSAGE = "atlascli";
14+
15+
hmac.update(DEVICE_ID_HASH_MESSAGE);
16+
return hmac.digest("hex");
17+
} catch (error) {
18+
logger.debug(LogId.telemetryDeviceIdFailure, "telemetry", String(error));
19+
return "unknown";
20+
}
21+
}

src/tools/atlas/read/inspectCluster.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,38 @@ export class InspectClusterTool extends AtlasToolBase {
3131
throw new Error("Cluster not found");
3232
}
3333

34+
const regionConfigs = (cluster.replicationSpecs || [])
35+
.map(
36+
(replicationSpec) =>
37+
(replicationSpec.regionConfigs || []) as {
38+
providerName: string;
39+
electableSpecs?: {
40+
instanceSize: string;
41+
};
42+
readOnlySpecs?: {
43+
instanceSize: string;
44+
};
45+
}[]
46+
)
47+
.flat()
48+
.map((regionConfig) => {
49+
return {
50+
providerName: regionConfig.providerName,
51+
instanceSize: regionConfig.electableSpecs?.instanceSize || regionConfig.readOnlySpecs?.instanceSize,
52+
};
53+
});
54+
55+
const instanceSize = (regionConfigs.length <= 0 ? undefined : regionConfigs[0].instanceSize) || "UNKNOWN";
56+
57+
const clusterInstanceType = instanceSize == "M0" ? "FREE" : "DEDICATED";
58+
3459
return {
3560
content: [
3661
{
3762
type: "text",
38-
text: `Cluster Name | State | MongoDB Version | Connection String
39-
----------------|----------------|----------------|----------------|----------------
40-
${cluster.name} | ${cluster.stateName} | ${cluster.mongoDBVersion || "N/A"} | ${cluster.connectionStrings?.standard || "N/A"}`,
63+
text: `Cluster Name | Cluster Type | Tier | State | MongoDB Version | Connection String
64+
----------------|----------------|----------------|----------------|----------------|----------------
65+
${cluster.name} | ${clusterInstanceType} | ${clusterInstanceType == "DEDICATED" ? instanceSize : "N/A"} | ${cluster.stateName} | ${cluster.mongoDBVersion || "N/A"} | ${cluster.connectionStrings?.standardSrv || cluster.connectionStrings?.standard || "N/A"}`,
4166
},
4267
],
4368
};

src/tools/atlas/read/listClusters.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,37 @@ ${rows}`,
7979
}
8080
const rows = clusters.results
8181
.map((cluster) => {
82-
const connectionString = cluster.connectionStrings?.standard || "N/A";
82+
const connectionString =
83+
cluster.connectionStrings?.standardSrv || cluster.connectionStrings?.standard || "N/A";
8384
const mongoDBVersion = cluster.mongoDBVersion || "N/A";
84-
return `${cluster.name} | ${cluster.stateName} | ${mongoDBVersion} | ${connectionString}`;
85+
const regionConfigs = (cluster.replicationSpecs || [])
86+
.map(
87+
(replicationSpec) =>
88+
(replicationSpec.regionConfigs || []) as {
89+
providerName: string;
90+
electableSpecs?: {
91+
instanceSize: string;
92+
};
93+
readOnlySpecs?: {
94+
instanceSize: string;
95+
};
96+
}[]
97+
)
98+
.flat()
99+
.map((regionConfig) => {
100+
return {
101+
providerName: regionConfig.providerName,
102+
instanceSize:
103+
regionConfig.electableSpecs?.instanceSize || regionConfig.readOnlySpecs?.instanceSize,
104+
};
105+
});
106+
107+
const instanceSize =
108+
(regionConfigs.length <= 0 ? undefined : regionConfigs[0].instanceSize) || "UNKNOWN";
109+
110+
const clusterInstanceType = instanceSize == "M0" ? "FREE" : "DEDICATED";
111+
112+
return `${cluster.name} | ${clusterInstanceType} | ${clusterInstanceType == "DEDICATED" ? instanceSize : "N/A"} | ${cluster.stateName} | ${mongoDBVersion} | ${connectionString}`;
85113
})
86114
.join("\n");
87115
return {
@@ -92,8 +120,8 @@ ${rows}`,
92120
},
93121
{
94122
type: "text",
95-
text: `Cluster Name | State | MongoDB Version | Connection String
96-
----------------|----------------|----------------|----------------|----------------
123+
text: `Cluster Name | Cluster Type | Tier | State | MongoDB Version | Connection String
124+
----------------|----------------|----------------|----------------|----------------|----------------
97125
${rows}`,
98126
},
99127
],

0 commit comments

Comments
 (0)