Skip to content

Commit c95b9cb

Browse files
committed
Merge remote-tracking branch 'origin/main' into MCP-224
2 parents 91bffa8 + 91c99e5 commit c95b9cb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2533
-1430
lines changed

README.md

Lines changed: 25 additions & 23 deletions
Large diffs are not rendered by default.

knip.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"entry": [
3+
"src/index.ts!",
4+
"src/lib.ts!",
5+
"tests/**/*.ts",
6+
"scripts/**/*.ts",
7+
"eslint-rules/*.js"
8+
],
9+
"ignore": ["tests/integration/fixtures/curl.mjs", "tests/vitest.d.ts"],
10+
"ignoreExportsUsedInFile": true
11+
}

package-lock.json

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

package.json

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "mongodb-mcp-server",
33
"description": "MongoDB Model Context Protocol Server",
4-
"version": "1.0.0",
4+
"version": "1.0.1",
55
"type": "module",
66
"exports": {
77
".": {
@@ -44,8 +44,9 @@
4444
"build": "npm run build:clean && npm run build:esm && npm run build:cjs && npm run build:universal-package && npm run build:chmod",
4545
"inspect": "npm run build && mcp-inspector -- dist/esm/index.js",
4646
"prettier": "prettier",
47-
"check": "npm run build && npm run check:types && npm run check:lint && npm run check:format",
47+
"check": "npm run build && npm run check:types && npm run check:lint && npm run check:format && npm run check:dependencies",
4848
"check:lint": "eslint .",
49+
"check:dependencies": "knip --strict",
4950
"check:format": "prettier -c .",
5051
"check:types": "tsc --noEmit --project tsconfig.json",
5152
"fix": "npm run fix:lint && npm run reformat",
@@ -66,19 +67,20 @@
6667
"@mongodb-js/oidc-mock-provider": "^0.11.3",
6768
"@redocly/cli": "^2.0.8",
6869
"@types/express": "^5.0.3",
69-
"@types/http-proxy": "^1.17.16",
70-
"@types/node": "^24.3.0",
70+
"@types/node": "^24.5.2",
7171
"@types/proper-lockfile": "^4.1.4",
7272
"@types/semver": "^7.7.0",
73-
"@types/simple-oauth2": "^5.0.7",
7473
"@types/yargs-parser": "^21.0.3",
74+
"@typescript-eslint/parser": "^8.44.0",
7575
"@vitest/coverage-v8": "^3.2.4",
7676
"ai": "^4.3.17",
7777
"duplexpair": "^1.0.2",
7878
"eslint": "^9.34.0",
7979
"eslint-config-prettier": "^10.1.8",
8080
"eslint-plugin-prettier": "^5.5.4",
8181
"globals": "^16.3.0",
82+
"knip": "^5.63.1",
83+
"mongodb": "^6.19.0",
8284
"mongodb-runner": "^5.9.2",
8385
"ollama-ai-provider": "^1.2.0",
8486
"openapi-types": "^12.1.3",
@@ -90,22 +92,19 @@
9092
"tsx": "^4.20.5",
9193
"typescript": "^5.9.2",
9294
"typescript-eslint": "^8.41.0",
93-
"uuid": "^11.1.0",
94-
"vitest": "^3.2.4",
95-
"yaml": "^2.8.1"
95+
"@vitest/eslint-plugin": "^1.3.4",
96+
"uuid": "^13.0.0",
97+
"vitest": "^3.2.4"
9698
},
9799
"dependencies": {
98100
"@modelcontextprotocol/sdk": "^1.17.4",
99101
"@mongodb-js/device-id": "^0.3.1",
100-
"@mongodb-js/devtools-connect": "^3.9.3",
101-
"@mongodb-js/devtools-proxy-support": "^0.5.2",
102-
"@mongosh/arg-parser": "^3.14.0",
103-
"@mongosh/service-provider-node-driver": "~3.12.0",
104-
"@vitest/eslint-plugin": "^1.3.4",
102+
"@mongodb-js/devtools-proxy-support": "^0.5.3",
103+
"@mongosh/arg-parser": "^3.19.0",
104+
"@mongosh/service-provider-node-driver": "^3.17.0",
105105
"bson": "^6.10.4",
106106
"express": "^5.1.0",
107107
"lru-cache": "^11.1.0",
108-
"mongodb": "^6.19.0",
109108
"mongodb-connection-string-url": "^3.0.2",
110109
"mongodb-log-writer": "^2.4.1",
111110
"mongodb-redact": "^1.2.0",
@@ -115,7 +114,7 @@
115114
"oauth4webapi": "^3.8.0",
116115
"openapi-fetch": "^0.14.0",
117116
"ts-levenshtein": "^1.0.7",
118-
"yargs-parser": "^21.1.1",
117+
"yargs-parser": "^22.0.0",
119118
"zod": "^3.25.76"
120119
},
121120
"engines": {

scripts/accuracy/runAccuracyTests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export MDB_ACCURACY_RUN_ID=$(npx uuid v4)
1717
# specified in the command line. Such as:
1818
# npm run test:accuracy -- tests/accuracy/some-test.test.ts
1919
echo "Running accuracy tests with MDB_ACCURACY_RUN_ID '$MDB_ACCURACY_RUN_ID'"
20-
vitest --config vitest.config.ts --project=accuracy --coverage=false --run "$@"
20+
vitest --config vitest.config.ts --project=accuracy --coverage=false --no-file-parallelism --run "$@"
2121

2222
# Preserving the exit code from test run to correctly notify in the CI
2323
# environments when the tests fail.

src/common/config.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import levenshtein from "ts-levenshtein";
99

1010
// From: https://github.com/mongodb-js/mongosh/blob/main/packages/cli-repl/src/arg-parser.ts
1111
const OPTIONS = {
12+
number: ["maxDocumentsPerQuery", "maxBytesPerQuery"],
1213
string: [
1314
"apiBaseUrl",
1415
"apiClientId",
@@ -98,6 +99,7 @@ const OPTIONS = {
9899

99100
interface Options {
100101
string: string[];
102+
number: string[];
101103
boolean: string[];
102104
array: string[];
103105
alias: Record<string, string>;
@@ -106,6 +108,7 @@ interface Options {
106108

107109
export const ALL_CONFIG_KEYS = new Set(
108110
(OPTIONS.string as readonly string[])
111+
.concat(OPTIONS.number)
109112
.concat(OPTIONS.array)
110113
.concat(OPTIONS.boolean)
111114
.concat(Object.keys(OPTIONS.alias))
@@ -175,6 +178,8 @@ export interface UserConfig extends CliOptions {
175178
loggers: Array<"stderr" | "disk" | "mcp">;
176179
idleTimeoutMs: number;
177180
notificationTimeoutMs: number;
181+
maxDocumentsPerQuery: number;
182+
maxBytesPerQuery: number;
178183
atlasTemporaryDatabaseUserLifetimeMs: number;
179184
}
180185

@@ -202,6 +207,8 @@ export const defaultUserConfig: UserConfig = {
202207
idleTimeoutMs: 10 * 60 * 1000, // 10 minutes
203208
notificationTimeoutMs: 9 * 60 * 1000, // 9 minutes
204209
httpHeaders: {},
210+
maxDocumentsPerQuery: 100, // By default, we only fetch a maximum 100 documents per query / aggregation
211+
maxBytesPerQuery: 16 * 1024 * 1024, // By default, we only return ~16 mb of data per query / aggregation
205212
atlasTemporaryDatabaseUserLifetimeMs: 4 * 60 * 60 * 1000, // 4 hours
206213
};
207214

@@ -231,11 +238,6 @@ export const defaultDriverOptions: DriverOptions = {
231238
applyProxyToOIDC: true,
232239
};
233240

234-
export const driverOptions = setupDriverConfig({
235-
config,
236-
defaults: defaultDriverOptions,
237-
});
238-
239241
function getLogPath(): string {
240242
const logPath = path.join(getLocalDataPath(), "mongodb-mcp", ".app-logs");
241243
return logPath;

src/common/connectionManager.ts

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface ConnectionStateConnected extends ConnectionState {
3939

4040
export interface ConnectionStateConnecting extends ConnectionState {
4141
tag: "connecting";
42-
serviceProvider: NodeDriverServiceProvider;
42+
serviceProvider: Promise<NodeDriverServiceProvider>;
4343
oidcConnectionType: OIDCConnectionAuthType;
4444
oidcLoginUrl?: string;
4545
oidcUserCode?: string;
@@ -68,18 +68,6 @@ export interface ConnectionManagerEvents {
6868
"connection-error": [ConnectionStateErrored];
6969
}
7070

71-
/**
72-
* For a few tests, we need the changeState method to force a connection state
73-
* which is we have this type to typecast the actual ConnectionManager with
74-
* public changeState (only to make TS happy).
75-
*/
76-
export type TestConnectionManager = ConnectionManager & {
77-
changeState<Event extends keyof ConnectionManagerEvents, State extends ConnectionManagerEvents[Event][0]>(
78-
event: Event,
79-
newState: State
80-
): State;
81-
};
82-
8371
export abstract class ConnectionManager {
8472
protected clientName: string;
8573
protected readonly _events: EventEmitter<ConnectionManagerEvents>;
@@ -112,7 +100,6 @@ export abstract class ConnectionManager {
112100
}
113101

114102
abstract connect(settings: ConnectionSettings): Promise<AnyConnectionState>;
115-
116103
abstract disconnect(): Promise<ConnectionStateDisconnected | ConnectionStateErrored>;
117104
}
118105

@@ -130,6 +117,7 @@ export class MCPConnectionManager extends ConnectionManager {
130117
super();
131118
this.bus = bus ?? new EventEmitter();
132119
this.bus.on("mongodb-oidc-plugin:auth-failed", this.onOidcAuthFailed.bind(this));
120+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
133121
this.bus.on("mongodb-oidc-plugin:auth-succeeded", this.onOidcAuthSucceeded.bind(this));
134122
this.deviceId = deviceId;
135123
}
@@ -141,7 +129,7 @@ export class MCPConnectionManager extends ConnectionManager {
141129
await this.disconnect();
142130
}
143131

144-
let serviceProvider: NodeDriverServiceProvider;
132+
let serviceProvider: Promise<NodeDriverServiceProvider>;
145133
let connectionInfo: ConnectionInfo;
146134
let connectionStringAuthType: ConnectionStringAuthType = "scram";
147135

@@ -177,7 +165,7 @@ export class MCPConnectionManager extends ConnectionManager {
177165
connectionInfo
178166
);
179167

180-
serviceProvider = await NodeDriverServiceProvider.connect(
168+
serviceProvider = NodeDriverServiceProvider.connect(
181169
connectionInfo.connectionString,
182170
{
183171
productDocsLink: "https://github.com/mongodb-js/mongodb-mcp-server/",
@@ -200,23 +188,19 @@ export class MCPConnectionManager extends ConnectionManager {
200188

201189
try {
202190
if (connectionStringAuthType.startsWith("oidc")) {
203-
void this.pingAndForget(serviceProvider);
204-
205191
return this.changeState("connection-request", {
206192
tag: "connecting",
207-
connectedAtlasCluster: settings.atlas,
208193
serviceProvider,
194+
connectedAtlasCluster: settings.atlas,
209195
connectionStringAuthType,
210196
oidcConnectionType: connectionStringAuthType as OIDCConnectionAuthType,
211197
});
212198
}
213199

214-
await serviceProvider?.runCommand?.("admin", { hello: 1 });
215-
216200
return this.changeState("connection-success", {
217201
tag: "connected",
218202
connectedAtlasCluster: settings.atlas,
219-
serviceProvider,
203+
serviceProvider: await serviceProvider,
220204
connectionStringAuthType,
221205
});
222206
} catch (error: unknown) {
@@ -238,7 +222,13 @@ export class MCPConnectionManager extends ConnectionManager {
238222

239223
if (this.currentConnectionState.tag === "connected" || this.currentConnectionState.tag === "connecting") {
240224
try {
241-
await this.currentConnectionState.serviceProvider?.close(true);
225+
if (this.currentConnectionState.tag === "connected") {
226+
await this.currentConnectionState.serviceProvider?.close();
227+
}
228+
if (this.currentConnectionState.tag === "connecting") {
229+
const serviceProvider = await this.currentConnectionState.serviceProvider;
230+
await serviceProvider.close();
231+
}
242232
} finally {
243233
this.changeState("connection-close", {
244234
tag: "disconnected",
@@ -258,12 +248,16 @@ export class MCPConnectionManager extends ConnectionManager {
258248
}
259249
}
260250

261-
private onOidcAuthSucceeded(): void {
251+
private async onOidcAuthSucceeded(): Promise<void> {
262252
if (
263253
this.currentConnectionState.tag === "connecting" &&
264254
this.currentConnectionState.connectionStringAuthType?.startsWith("oidc")
265255
) {
266-
this.changeState("connection-success", { ...this.currentConnectionState, tag: "connected" });
256+
this.changeState("connection-success", {
257+
...this.currentConnectionState,
258+
tag: "connected",
259+
serviceProvider: await this.currentConnectionState.serviceProvider,
260+
});
267261
}
268262

269263
this.logger.info({
@@ -330,18 +324,6 @@ export class MCPConnectionManager extends ConnectionManager {
330324
}
331325
}
332326

333-
private async pingAndForget(serviceProvider: NodeDriverServiceProvider): Promise<void> {
334-
try {
335-
await serviceProvider?.runCommand?.("admin", { hello: 1 });
336-
} catch (error: unknown) {
337-
this.logger.warning({
338-
id: LogId.oidcFlow,
339-
context: "pingAndForget",
340-
message: String(error),
341-
});
342-
}
343-
}
344-
345327
private async disconnectOnOidcError(error: unknown): Promise<void> {
346328
try {
347329
await this.disconnect();

src/common/logger.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export const LogId = {
4444
mongodbConnectFailure: mongoLogId(1_004_001),
4545
mongodbDisconnectFailure: mongoLogId(1_004_002),
4646
mongodbConnectTry: mongoLogId(1_004_003),
47+
mongodbCursorCloseError: mongoLogId(1_004_004),
4748

4849
toolUpdateFailure: mongoLogId(1_005_001),
4950
resourceUpdateFailure: mongoLogId(1_005_002),
@@ -340,15 +341,3 @@ export class CompositeLogger extends LoggerBase {
340341
this.attributes[key] = value;
341342
}
342343
}
343-
344-
export class NullLogger extends LoggerBase {
345-
protected type?: LoggerType;
346-
347-
constructor() {
348-
super(undefined);
349-
}
350-
351-
protected logCore(): void {
352-
// No-op logger, does not log anything
353-
}
354-
}

src/common/packageInfo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// This file was generated by scripts/updatePackageVersion.ts - Do not edit it manually.
22
export const packageInfo = {
3-
version: "1.0.0",
3+
version: "1.0.1",
44
mcpServerName: "MongoDB MCP Server",
55
};

0 commit comments

Comments
 (0)