From 84989079390587811a0919b46b5fdf78f3284db4 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 13 Nov 2025 11:34:38 +0100 Subject: [PATCH 1/6] chore: move config related code to common folder --- scripts/generateArguments.ts | 2 +- src/common/config.ts | 4 ++-- src/common/{ => config}/argsParserOptions.ts | 0 src/common/{ => config}/configUtils.ts | 0 tests/unit/common/config.test.ts | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename src/common/{ => config}/argsParserOptions.ts (100%) rename src/common/{ => config}/configUtils.ts (100%) diff --git a/scripts/generateArguments.ts b/scripts/generateArguments.ts index ee3695c4..69d10bc4 100644 --- a/scripts/generateArguments.ts +++ b/scripts/generateArguments.ts @@ -14,7 +14,7 @@ import { fileURLToPath } from "url"; import { UserConfigSchema, configRegistry } from "../src/common/config.js"; import assert from "assert"; import { execSync } from "child_process"; -import { OPTIONS } from "../src/common/argsParserOptions.js"; +import { OPTIONS } from "../src/common/config/argsParserOptions.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); diff --git a/src/common/config.ts b/src/common/config.ts index 6e404b86..ff5e2fec 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -11,8 +11,8 @@ import { getLogPath, isConnectionSpecifier, validateConfigKey, -} from "./configUtils.js"; -import { OPTIONS } from "./argsParserOptions.js"; +} from "./config/configUtils.js"; +import { OPTIONS } from "./config/argsParserOptions.js"; import { similarityValues, previewFeatureValues } from "./schemas.js"; export const configRegistry = z4.registry(); diff --git a/src/common/argsParserOptions.ts b/src/common/config/argsParserOptions.ts similarity index 100% rename from src/common/argsParserOptions.ts rename to src/common/config/argsParserOptions.ts diff --git a/src/common/configUtils.ts b/src/common/config/configUtils.ts similarity index 100% rename from src/common/configUtils.ts rename to src/common/config/configUtils.ts diff --git a/tests/unit/common/config.test.ts b/tests/unit/common/config.test.ts index ebd4d0bb..827a5d6b 100644 --- a/tests/unit/common/config.test.ts +++ b/tests/unit/common/config.test.ts @@ -7,7 +7,7 @@ import { UserConfigSchema, warnIfVectorSearchNotEnabledCorrectly, } from "../../../src/common/config.js"; -import { getLogPath, getExportsPath } from "../../../src/common/configUtils.js"; +import { getLogPath, getExportsPath } from "../../../src/common/config/configUtils.js"; import type { CliOptions } from "@mongosh/arg-parser"; import { Keychain } from "../../../src/common/keychain.js"; import type { Secret } from "../../../src/common/keychain.js"; From f2dce249ff6c1dcd3c4bffd10af4fbf17e3ab284 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 13 Nov 2025 12:12:41 +0100 Subject: [PATCH 2/6] chore: untangle driverOptions from config --- src/common/config.ts | 30 +------------------ src/common/config/driverOptions.ts | 27 +++++++++++++++++ src/common/connectionManager.ts | 8 ++--- src/resources/common/config.ts | 4 +-- .../common/connectionManager.oidc.test.ts | 8 ++--- tests/integration/helpers.ts | 13 ++------ .../tools/mongodb/mongodbHelpers.ts | 3 +- .../tools/mongodb/mongodbTool.test.ts | 3 +- 8 files changed, 42 insertions(+), 54 deletions(-) create mode 100644 src/common/config/driverOptions.ts diff --git a/src/common/config.ts b/src/common/config.ts index ff5e2fec..35b4616c 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -1,5 +1,5 @@ import argv from "yargs-parser"; -import type { CliOptions, ConnectionInfo } from "@mongosh/arg-parser"; +import type { CliOptions } from "@mongosh/arg-parser"; import { generateConnectionInfoFromCliArgs } from "@mongosh/arg-parser"; import { Keychain } from "./keychain.js"; import type { Secret } from "./keychain.js"; @@ -183,20 +183,6 @@ export const config = setupUserConfig({ env: process.env, }); -export type DriverOptions = ConnectionInfo["driverOptions"]; -export const defaultDriverOptions: DriverOptions = { - readConcern: { - level: "local", - }, - readPreference: "secondaryPreferred", - writeConcern: { - w: "majority", - }, - timeoutMS: 30_000, - proxy: { useEnvironmentVariableProxies: true }, - applyProxyToOIDC: true, -}; - // Gets the config supplied by the user as environment variables. The variable names // are prefixed with `MDB_MCP_` and the keys match the UserConfig keys, but are converted // to SNAKE_UPPER_CASE. @@ -414,17 +400,3 @@ export function setupUserConfig({ cli, env }: { cli: string[]; env: Record; -}): DriverOptions { - const { driverOptions } = generateConnectionInfoFromCliArgs(config); - return { - ...defaults, - ...driverOptions, - }; -} diff --git a/src/common/config/driverOptions.ts b/src/common/config/driverOptions.ts new file mode 100644 index 00000000..1a9a0a6d --- /dev/null +++ b/src/common/config/driverOptions.ts @@ -0,0 +1,27 @@ +import { generateConnectionInfoFromCliArgs, type ConnectionInfo } from "@mongosh/arg-parser"; +import type { UserConfig } from "../config.js"; + +export type DriverOptions = ConnectionInfo["driverOptions"]; +export const defaultDriverOptions: DriverOptions = { + readConcern: { + level: "local", + }, + readPreference: "secondaryPreferred", + writeConcern: { + w: "majority", + }, + timeoutMS: 30_000, + proxy: { useEnvironmentVariableProxies: true }, + applyProxyToOIDC: true, +}; + +export function createDriverOptions( + config: UserConfig, + defaults: Partial = defaultDriverOptions +): DriverOptions { + const { driverOptions } = generateConnectionInfoFromCliArgs(config); + return { + ...defaults, + ...driverOptions, + }; +} diff --git a/src/common/connectionManager.ts b/src/common/connectionManager.ts index bb8002d3..1f0b94e0 100644 --- a/src/common/connectionManager.ts +++ b/src/common/connectionManager.ts @@ -4,7 +4,8 @@ import { ConnectionString } from "mongodb-connection-string-url"; import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver"; import { type ConnectionInfo, generateConnectionInfoFromCliArgs } from "@mongosh/arg-parser"; import type { DeviceId } from "../helpers/deviceId.js"; -import { defaultDriverOptions, setupDriverConfig, type DriverOptions, type UserConfig } from "./config.js"; +import { createDriverOptions, type DriverOptions } from "./config/driverOptions.js"; +import { type UserConfig } from "./config.js"; import { MongoDBError, ErrorCodes } from "./errors.js"; import { type LoggerBase, LogId } from "./logger.js"; import { packageInfo } from "./packageInfo.js"; @@ -394,10 +395,7 @@ export type ConnectionManagerFactoryFn = (createParams: { }) => Promise; export const createMCPConnectionManager: ConnectionManagerFactoryFn = ({ logger, deviceId, userConfig }) => { - const driverOptions = setupDriverConfig({ - config: userConfig, - defaults: defaultDriverOptions, - }); + const driverOptions = createDriverOptions(userConfig); return Promise.resolve(new MCPConnectionManager(userConfig, driverOptions, logger, deviceId)); }; diff --git a/src/resources/common/config.ts b/src/resources/common/config.ts index d67b0400..7949bd90 100644 --- a/src/resources/common/config.ts +++ b/src/resources/common/config.ts @@ -1,5 +1,5 @@ import { ReactiveResource } from "../resource.js"; -import { defaultDriverOptions } from "../../common/config.js"; +import { createDriverOptions } from "../../common/config/driverOptions.js"; import type { UserConfig } from "../../common/config.js"; import type { Telemetry } from "../../telemetry/telemetry.js"; import type { Session } from "../../lib.js"; @@ -38,7 +38,7 @@ export class ConfigResource extends ReactiveResource { connectionString: this.current.connectionString ? "set; access to MongoDB tools are currently available to use" : "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'.", - connectOptions: defaultDriverOptions, + connectOptions: createDriverOptions(this.config), atlas: this.current.apiClientId && this.current.apiClientSecret ? "set; MongoDB Atlas tools are currently available to use" diff --git a/tests/integration/common/connectionManager.oidc.test.ts b/tests/integration/common/connectionManager.oidc.test.ts index 595239ce..401f91fd 100644 --- a/tests/integration/common/connectionManager.oidc.test.ts +++ b/tests/integration/common/connectionManager.oidc.test.ts @@ -7,7 +7,7 @@ import { describeWithMongoDB, isCommunityServer, getServerVersion } from "../too import { defaultTestConfig, responseAsText, timeout, waitUntil } from "../helpers.js"; import type { ConnectionStateConnected, ConnectionStateConnecting } from "../../../src/common/connectionManager.js"; import type { UserConfig } from "../../../src/common/config.js"; -import { setupDriverConfig } from "../../../src/common/config.js"; +import { createDriverOptions } from "../../../src/common/config/driverOptions.js"; import path from "path"; import type { OIDCMockProviderConfig } from "@mongodb-js/oidc-mock-provider"; import { OIDCMockProvider } from "@mongodb-js/oidc-mock-provider"; @@ -142,11 +142,7 @@ describe.skipIf(process.platform !== "linux")("ConnectionManager OIDC Tests", as }, { getUserConfig: () => oidcConfig, - getDriverOptions: () => - setupDriverConfig({ - config: oidcConfig, - defaults: {}, - }), + getDriverOptions: () => createDriverOptions(oidcConfig), downloadOptions: { runner: true, downloadOptions: { enterprise: true, version: mongodbVersion }, diff --git a/tests/integration/helpers.ts b/tests/integration/helpers.ts index 78560f52..182ac457 100644 --- a/tests/integration/helpers.ts +++ b/tests/integration/helpers.ts @@ -6,13 +6,9 @@ import { Telemetry } from "../../src/telemetry/telemetry.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { InMemoryTransport } from "./inMemoryTransport.js"; -import type { UserConfig, DriverOptions } from "../../src/common/config.js"; +import { type UserConfig, config } from "../../src/common/config.js"; +import { type DriverOptions, createDriverOptions } from "../../src/common/config/driverOptions.js"; import { McpError, ResourceUpdatedNotificationSchema } from "@modelcontextprotocol/sdk/types.js"; -import { - config, - setupDriverConfig, - defaultDriverOptions as defaultDriverOptionsFromConfig, -} from "../../src/common/config.js"; import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest"; import type { ConnectionManager, ConnectionState } from "../../src/common/connectionManager.js"; import { MCPConnectionManager } from "../../src/common/connectionManager.js"; @@ -24,10 +20,7 @@ import type { MockClientCapabilities, createMockElicitInput } from "../utils/eli import { VectorSearchEmbeddingsManager } from "../../src/common/search/vectorSearchEmbeddingsManager.js"; import { defaultCreateAtlasLocalClient } from "../../src/common/atlasLocal.js"; -export const driverOptions = setupDriverConfig({ - config, - defaults: defaultDriverOptionsFromConfig, -}); +export const driverOptions = createDriverOptions(config); export const defaultDriverOptions: DriverOptions = { ...driverOptions }; diff --git a/tests/integration/tools/mongodb/mongodbHelpers.ts b/tests/integration/tools/mongodb/mongodbHelpers.ts index d53c97df..be654100 100644 --- a/tests/integration/tools/mongodb/mongodbHelpers.ts +++ b/tests/integration/tools/mongodb/mongodbHelpers.ts @@ -11,7 +11,8 @@ import { defaultDriverOptions, getDataFromUntrustedContent, } from "../../helpers.js"; -import type { UserConfig, DriverOptions } from "../../../../src/common/config.js"; +import type { UserConfig } from "../../../../src/common/config.js"; +import type { DriverOptions } from "../../../../src/common/config/driverOptions.js"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { EJSON } from "bson"; import { MongoDBClusterProcess } from "./mongodbClusterProcess.js"; diff --git a/tests/integration/tools/mongodb/mongodbTool.test.ts b/tests/integration/tools/mongodb/mongodbTool.test.ts index de538292..80c8939d 100644 --- a/tests/integration/tools/mongodb/mongodbTool.test.ts +++ b/tests/integration/tools/mongodb/mongodbTool.test.ts @@ -4,7 +4,8 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { MongoDBToolBase } from "../../../../src/tools/mongodb/mongodbTool.js"; import { type ToolBase, type ToolConstructorParams, type OperationType } from "../../../../src/tools/tool.js"; -import { defaultDriverOptions, type UserConfig } from "../../../../src/common/config.js"; +import { type UserConfig } from "../../../../src/common/config.js"; +import { defaultDriverOptions } from "../../../../src/common/config/driverOptions.js"; import { MCPConnectionManager } from "../../../../src/common/connectionManager.js"; import { Session } from "../../../../src/common/session.js"; import { CompositeLogger } from "../../../../src/common/logger.js"; From abf5054d840a51fc9b0e559f8021bf5b5214b5b2 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Thu, 13 Nov 2025 12:20:08 +0100 Subject: [PATCH 3/6] chore: remove duplicate driverOptions test object --- tests/integration/helpers.ts | 6 ++---- tests/integration/telemetry.test.ts | 4 ++-- tests/unit/common/session.test.ts | 4 ++-- tests/unit/resources/common/debug.test.ts | 4 ++-- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/integration/helpers.ts b/tests/integration/helpers.ts index 182ac457..86573fd6 100644 --- a/tests/integration/helpers.ts +++ b/tests/integration/helpers.ts @@ -20,10 +20,6 @@ import type { MockClientCapabilities, createMockElicitInput } from "../utils/eli import { VectorSearchEmbeddingsManager } from "../../src/common/search/vectorSearchEmbeddingsManager.js"; import { defaultCreateAtlasLocalClient } from "../../src/common/atlasLocal.js"; -export const driverOptions = createDriverOptions(config); - -export const defaultDriverOptions: DriverOptions = { ...driverOptions }; - interface Parameter { name: string; description: string; @@ -52,6 +48,8 @@ export const defaultTestConfig: UserConfig = { loggers: ["stderr"], }; +export const defaultDriverOptions: DriverOptions = createDriverOptions(defaultTestConfig); + export const DEFAULT_LONG_RUNNING_TEST_WAIT_TIMEOUT_MS = 1_200_000; export function setupIntegrationTest( diff --git a/tests/integration/telemetry.test.ts b/tests/integration/telemetry.test.ts index 28e4c3b4..ef741d37 100644 --- a/tests/integration/telemetry.test.ts +++ b/tests/integration/telemetry.test.ts @@ -1,7 +1,7 @@ import { Telemetry } from "../../src/telemetry/telemetry.js"; import { Session } from "../../src/common/session.js"; import { config } from "../../src/common/config.js"; -import { driverOptions } from "./helpers.js"; +import { defaultDriverOptions } from "./helpers.js"; import { DeviceId } from "../../src/helpers/deviceId.js"; import { describe, expect, it } from "vitest"; import { CompositeLogger } from "../../src/common/logger.js"; @@ -16,7 +16,7 @@ describe("Telemetry", () => { const deviceId = DeviceId.create(logger); const actualDeviceId = await deviceId.get(); - const connectionManager = new MCPConnectionManager(config, driverOptions, logger, deviceId); + const connectionManager = new MCPConnectionManager(config, defaultDriverOptions, logger, deviceId); const telemetry = Telemetry.create( new Session({ diff --git a/tests/unit/common/session.test.ts b/tests/unit/common/session.test.ts index ed465f22..6e4d9331 100644 --- a/tests/unit/common/session.test.ts +++ b/tests/unit/common/session.test.ts @@ -3,7 +3,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver"; import { Session } from "../../../src/common/session.js"; import { config } from "../../../src/common/config.js"; -import { driverOptions } from "../../integration/helpers.js"; +import { defaultDriverOptions } from "../../integration/helpers.js"; import { CompositeLogger } from "../../../src/common/logger.js"; import { MCPConnectionManager } from "../../../src/common/connectionManager.js"; import { ExportsManager } from "../../../src/common/exportsManager.js"; @@ -25,7 +25,7 @@ describe("Session", () => { const logger = new CompositeLogger(); mockDeviceId = MockDeviceId; - const connectionManager = new MCPConnectionManager(config, driverOptions, logger, mockDeviceId); + const connectionManager = new MCPConnectionManager(config, defaultDriverOptions, logger, mockDeviceId); session = new Session({ apiClientId: "test-client-id", diff --git a/tests/unit/resources/common/debug.test.ts b/tests/unit/resources/common/debug.test.ts index 6758ebeb..e00ce4f2 100644 --- a/tests/unit/resources/common/debug.test.ts +++ b/tests/unit/resources/common/debug.test.ts @@ -3,7 +3,7 @@ import { DebugResource } from "../../../../src/resources/common/debug.js"; import { Session } from "../../../../src/common/session.js"; import { Telemetry } from "../../../../src/telemetry/telemetry.js"; import { config } from "../../../../src/common/config.js"; -import { driverOptions } from "../../../integration/helpers.js"; +import { defaultDriverOptions } from "../../../integration/helpers.js"; import { CompositeLogger } from "../../../../src/common/logger.js"; import { MCPConnectionManager } from "../../../../src/common/connectionManager.js"; import { ExportsManager } from "../../../../src/common/exportsManager.js"; @@ -14,7 +14,7 @@ import { VectorSearchEmbeddingsManager } from "../../../../src/common/search/vec describe("debug resource", () => { const logger = new CompositeLogger(); const deviceId = DeviceId.create(logger); - const connectionManager = new MCPConnectionManager(config, driverOptions, logger, deviceId); + const connectionManager = new MCPConnectionManager(config, defaultDriverOptions, logger, deviceId); const session = vi.mocked( new Session({ From ef7450153bc99b761782020b000f66e644ff8fb6 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Mon, 17 Nov 2025 12:07:41 +0100 Subject: [PATCH 4/6] fix: don't use config opts for further connections This commit adds a test to assert that we don't use the driver options derived from the CLI arguments -> userConfig for further connections (other than the first connection) such as switch-connection tool. The problem earlier was that MCPConnectionManager was accepting a driverOptions object which it was then using in conjunction with userConfig to construct a fresh set of driver options for all the connections established by the MCP server. Now this was particularly problematic because the driver options for the configured connection might not be compatible with the new connection attempts being made in the MCP server. Take for example - MCP server configured to connect with an OIDC enabled MongoDB server and later switch-connection tool using the same driver options to connect to a locally running mongodb server without any auth. To fix that we've removed DriverOptions object from the interface of MCPConnectionManager and instead put it on the connect method. It is the responsibility of the caller to provide a correct ConnectionInfo object. For pre-configured connections server constructs the ConnectionInfo object using user config and passes it down to the MCPConnectionManager.connect and for the rest usage, they simply pass the connection string that they want to connect to. --- package-lock.json | 23 ------- src/common/connectionManager.ts | 22 +++--- src/resources/common/config.ts | 7 +- src/server.ts | 7 +- .../common/connectionManager.oidc.test.ts | 2 - tests/integration/helpers.ts | 7 +- tests/integration/telemetry.test.ts | 3 +- .../tools/atlas-local/atlasLocalHelpers.ts | 12 +--- tests/integration/tools/atlas/atlasHelpers.ts | 17 ++--- .../tools/atlas/performanceAdvisor.test.ts | 16 ++--- .../tools/mongodb/connect/connect.test.ts | 69 ++++++++++++++++++- .../tools/mongodb/mongodbHelpers.ts | 9 +-- .../tools/mongodb/mongodbTool.test.ts | 4 +- tests/unit/common/session.test.ts | 3 +- tests/unit/resources/common/debug.test.ts | 3 +- 15 files changed, 107 insertions(+), 97 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3373cb35..bc8fc231 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1639,7 +1639,6 @@ "resolved": "https://registry.npmjs.org/@mongodb-js/oidc-plugin/-/oidc-plugin-2.0.4.tgz", "integrity": "sha512-mB7kEK80+DD2QrB01GmtFKm02ItJpIO9j7OARMHI4RL+rVQD3Ey9giluf3xQtuSdcmg7a+bf5fkJgQZCWMvRPg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "express": "^5.1.0", "node-fetch": "^3.3.2", @@ -1893,7 +1892,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -4035,7 +4033,6 @@ "integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.14.0" } @@ -5001,7 +4998,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5064,7 +5060,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -5781,7 +5776,6 @@ "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=16.20.1" } @@ -7288,7 +7282,6 @@ "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -7350,7 +7343,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -7664,7 +7656,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", @@ -9941,7 +9932,6 @@ "integrity": "sha512-UczzB+0nnwGotYSgllfARAqWCJ5e/skuV2K/l+Zyck/H6pJIhLXuBnz+6vn2i211o7DtbE78HQtsYEKICHGI+g==", "dev": true, "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/mobx" @@ -10004,7 +9994,6 @@ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.20.0.tgz", "integrity": "sha512-Tl6MEIU3K4Rq3TSHd+sZQqRBoGlFsOgNrH5ltAcFBV62Re3Fd+FcaVf8uSEQFOJ51SDowDVttBTONMfoYWrWlQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@mongodb-js/saslprep": "^1.3.0", "bson": "^6.10.4", @@ -10154,7 +10143,6 @@ "resolved": "https://registry.npmjs.org/mongodb-log-writer/-/mongodb-log-writer-2.4.2.tgz", "integrity": "sha512-jXKSNG/z3sBgD42p2puOoBHKcxKHJhiIVfvGhSlwNezJIr7aL74kpKowQ3kG8Oq+nljhjfDNru8Meeq24Em3lg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "heap-js": "^2.3.0" }, @@ -11230,7 +11218,6 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -11515,7 +11502,6 @@ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -11529,7 +11515,6 @@ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -13135,7 +13120,6 @@ "integrity": "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@emotion/is-prop-valid": "1.2.2", "@emotion/unitless": "0.8.1", @@ -13748,7 +13732,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13937,7 +13920,6 @@ "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" @@ -14091,7 +14073,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14364,7 +14345,6 @@ "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -14481,7 +14461,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -14524,7 +14503,6 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -15132,7 +15110,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/common/connectionManager.ts b/src/common/connectionManager.ts index 1f0b94e0..5d583c6d 100644 --- a/src/common/connectionManager.ts +++ b/src/common/connectionManager.ts @@ -2,9 +2,8 @@ import { EventEmitter } from "events"; import type { MongoClientOptions } from "mongodb"; import { ConnectionString } from "mongodb-connection-string-url"; import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver"; -import { type ConnectionInfo, generateConnectionInfoFromCliArgs } from "@mongosh/arg-parser"; +import { type ConnectionInfo } from "@mongosh/arg-parser"; import type { DeviceId } from "../helpers/deviceId.js"; -import { createDriverOptions, type DriverOptions } from "./config/driverOptions.js"; import { type UserConfig } from "./config.js"; import { MongoDBError, ErrorCodes } from "./errors.js"; import { type LoggerBase, LogId } from "./logger.js"; @@ -18,8 +17,8 @@ export interface AtlasClusterConnectionInfo { expiryDate: Date; } -export interface ConnectionSettings { - connectionString: string; +export interface ConnectionSettings extends Omit { + driverOptions?: ConnectionInfo["driverOptions"]; atlas?: AtlasClusterConnectionInfo; } @@ -137,7 +136,6 @@ export class MCPConnectionManager extends ConnectionManager { constructor( private userConfig: UserConfig, - private driverOptions: DriverOptions, private logger: LoggerBase, deviceId: DeviceId, bus?: EventEmitter @@ -158,7 +156,6 @@ export class MCPConnectionManager extends ConnectionManager { } let serviceProvider: Promise; - let connectionInfo: ConnectionInfo; let connectionStringAuthType: ConnectionStringAuthType = "scram"; try { @@ -174,11 +171,10 @@ export class MCPConnectionManager extends ConnectionManager { components: appNameComponents, }); - connectionInfo = generateConnectionInfoFromCliArgs({ - ...this.userConfig, - ...this.driverOptions, - connectionSpecifier: settings.connectionString, - }); + const connectionInfo = { + connectionString: settings.connectionString, + driverOptions: settings.driverOptions ?? {}, + }; if (connectionInfo.driverOptions.oidc) { connectionInfo.driverOptions.oidc.allowedFlows ??= ["auth-code"]; @@ -395,7 +391,5 @@ export type ConnectionManagerFactoryFn = (createParams: { }) => Promise; export const createMCPConnectionManager: ConnectionManagerFactoryFn = ({ logger, deviceId, userConfig }) => { - const driverOptions = createDriverOptions(userConfig); - - return Promise.resolve(new MCPConnectionManager(userConfig, driverOptions, logger, deviceId)); + return Promise.resolve(new MCPConnectionManager(userConfig, logger, deviceId)); }; diff --git a/src/resources/common/config.ts b/src/resources/common/config.ts index 7949bd90..684c03f3 100644 --- a/src/resources/common/config.ts +++ b/src/resources/common/config.ts @@ -1,8 +1,8 @@ import { ReactiveResource } from "../resource.js"; -import { createDriverOptions } from "../../common/config/driverOptions.js"; import type { UserConfig } from "../../common/config.js"; import type { Telemetry } from "../../telemetry/telemetry.js"; import type { Session } from "../../lib.js"; +import { generateConnectionInfoFromCliArgs } from "@mongosh/arg-parser"; export class ConfigResource extends ReactiveResource { constructor(session: Session, config: UserConfig, telemetry: Telemetry) { @@ -32,13 +32,14 @@ export class ConfigResource extends ReactiveResource { } toOutput(): string { + const connectionInfo = generateConnectionInfoFromCliArgs(this.current); const result = { telemetry: this.current.telemetry, logPath: this.current.logPath, - connectionString: this.current.connectionString + connectionString: connectionInfo.connectionString ? "set; access to MongoDB tools are currently available to use" : "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'.", - connectOptions: createDriverOptions(this.config), + connectOptions: connectionInfo.driverOptions, atlas: this.current.apiClientId && this.current.apiClientSecret ? "set; MongoDB Atlas tools are currently available to use" diff --git a/src/server.ts b/src/server.ts index 8c164358..8201d249 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,3 +1,4 @@ +import { generateConnectionInfoFromCliArgs } from "@mongosh/arg-parser"; import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import type { Session } from "./common/session.js"; import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js"; @@ -308,9 +309,11 @@ export class Server { context: "server", message: `Detected a MongoDB connection string in the configuration, trying to connect...`, }); - await this.session.connectToMongoDB({ - connectionString: this.userConfig.connectionString, + const connectionInfo = generateConnectionInfoFromCliArgs({ + ...this.userConfig, + connectionSpecifier: this.userConfig.connectionString, }); + await this.session.connectToMongoDB(connectionInfo); } catch (error) { // We don't throw an error here because we want to allow the server to start even if the connection string is invalid. this.session.logger.error({ diff --git a/tests/integration/common/connectionManager.oidc.test.ts b/tests/integration/common/connectionManager.oidc.test.ts index 401f91fd..729c5012 100644 --- a/tests/integration/common/connectionManager.oidc.test.ts +++ b/tests/integration/common/connectionManager.oidc.test.ts @@ -7,7 +7,6 @@ import { describeWithMongoDB, isCommunityServer, getServerVersion } from "../too import { defaultTestConfig, responseAsText, timeout, waitUntil } from "../helpers.js"; import type { ConnectionStateConnected, ConnectionStateConnecting } from "../../../src/common/connectionManager.js"; import type { UserConfig } from "../../../src/common/config.js"; -import { createDriverOptions } from "../../../src/common/config/driverOptions.js"; import path from "path"; import type { OIDCMockProviderConfig } from "@mongodb-js/oidc-mock-provider"; import { OIDCMockProvider } from "@mongodb-js/oidc-mock-provider"; @@ -142,7 +141,6 @@ describe.skipIf(process.platform !== "linux")("ConnectionManager OIDC Tests", as }, { getUserConfig: () => oidcConfig, - getDriverOptions: () => createDriverOptions(oidcConfig), downloadOptions: { runner: true, downloadOptions: { enterprise: true, version: mongodbVersion }, diff --git a/tests/integration/helpers.ts b/tests/integration/helpers.ts index 86573fd6..bfa5dc1a 100644 --- a/tests/integration/helpers.ts +++ b/tests/integration/helpers.ts @@ -7,7 +7,6 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { InMemoryTransport } from "./inMemoryTransport.js"; import { type UserConfig, config } from "../../src/common/config.js"; -import { type DriverOptions, createDriverOptions } from "../../src/common/config/driverOptions.js"; import { McpError, ResourceUpdatedNotificationSchema } from "@modelcontextprotocol/sdk/types.js"; import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest"; import type { ConnectionManager, ConnectionState } from "../../src/common/connectionManager.js"; @@ -48,13 +47,10 @@ export const defaultTestConfig: UserConfig = { loggers: ["stderr"], }; -export const defaultDriverOptions: DriverOptions = createDriverOptions(defaultTestConfig); - export const DEFAULT_LONG_RUNNING_TEST_WAIT_TIMEOUT_MS = 1_200_000; export function setupIntegrationTest( getUserConfig: () => UserConfig, - getDriverOptions: () => DriverOptions, { elicitInput, getClientCapabilities, @@ -69,7 +65,6 @@ export function setupIntegrationTest( beforeAll(async () => { const userConfig = getUserConfig(); - const driverOptions = getDriverOptions(); const clientCapabilities = getClientCapabilities?.() ?? (elicitInput ? { elicitation: {} } : {}); const clientTransport = new InMemoryTransport(); @@ -95,7 +90,7 @@ export function setupIntegrationTest( const exportsManager = ExportsManager.init(userConfig, logger); deviceId = DeviceId.create(logger); - const connectionManager = new MCPConnectionManager(userConfig, driverOptions, logger, deviceId); + const connectionManager = new MCPConnectionManager(userConfig, logger, deviceId); const session = new Session({ apiBaseUrl: userConfig.apiBaseUrl, diff --git a/tests/integration/telemetry.test.ts b/tests/integration/telemetry.test.ts index ef741d37..2a3f18b4 100644 --- a/tests/integration/telemetry.test.ts +++ b/tests/integration/telemetry.test.ts @@ -1,7 +1,6 @@ import { Telemetry } from "../../src/telemetry/telemetry.js"; import { Session } from "../../src/common/session.js"; import { config } from "../../src/common/config.js"; -import { defaultDriverOptions } from "./helpers.js"; import { DeviceId } from "../../src/helpers/deviceId.js"; import { describe, expect, it } from "vitest"; import { CompositeLogger } from "../../src/common/logger.js"; @@ -16,7 +15,7 @@ describe("Telemetry", () => { const deviceId = DeviceId.create(logger); const actualDeviceId = await deviceId.get(); - const connectionManager = new MCPConnectionManager(config, defaultDriverOptions, logger, deviceId); + const connectionManager = new MCPConnectionManager(config, logger, deviceId); const telemetry = Telemetry.create( new Session({ diff --git a/tests/integration/tools/atlas-local/atlasLocalHelpers.ts b/tests/integration/tools/atlas-local/atlasLocalHelpers.ts index 3d3c09a6..4daf37ef 100644 --- a/tests/integration/tools/atlas-local/atlasLocalHelpers.ts +++ b/tests/integration/tools/atlas-local/atlasLocalHelpers.ts @@ -1,4 +1,4 @@ -import { defaultDriverOptions, defaultTestConfig, setupIntegrationTest, type IntegrationTest } from "../../helpers.js"; +import { defaultTestConfig, setupIntegrationTest, type IntegrationTest } from "../../helpers.js"; import { describe } from "vitest"; const isMacOSInGitHubActions = process.platform === "darwin" && process.env.GITHUB_ACTIONS === "true"; @@ -11,10 +11,7 @@ export type IntegrationTestFunction = (integration: IntegrationTest) => void; */ export function describeWithAtlasLocal(name: string, fn: IntegrationTestFunction): void { describe.skipIf(isMacOSInGitHubActions)(name, () => { - const integration = setupIntegrationTest( - () => defaultTestConfig, - () => defaultDriverOptions - ); + const integration = setupIntegrationTest(() => defaultTestConfig); fn(integration); }); } @@ -25,10 +22,7 @@ export function describeWithAtlasLocal(name: string, fn: IntegrationTestFunction */ export function describeWithAtlasLocalDisabled(name: string, fn: IntegrationTestFunction): void { describe.skipIf(!isMacOSInGitHubActions)(name, () => { - const integration = setupIntegrationTest( - () => defaultTestConfig, - () => defaultDriverOptions - ); + const integration = setupIntegrationTest(() => defaultTestConfig); fn(integration); }); } diff --git a/tests/integration/tools/atlas/atlasHelpers.ts b/tests/integration/tools/atlas/atlasHelpers.ts index 308fdc06..7871b47a 100644 --- a/tests/integration/tools/atlas/atlasHelpers.ts +++ b/tests/integration/tools/atlas/atlasHelpers.ts @@ -2,7 +2,7 @@ import { ObjectId } from "mongodb"; import type { ClusterDescription20240805, Group } from "../../../../src/common/atlas/openapi.js"; import type { ApiClient } from "../../../../src/common/atlas/apiClient.js"; import type { IntegrationTest } from "../../helpers.js"; -import { setupIntegrationTest, defaultTestConfig, defaultDriverOptions } from "../../helpers.js"; +import { setupIntegrationTest, defaultTestConfig } from "../../helpers.js"; import type { SuiteCollector } from "vitest"; import { afterAll, beforeAll, describe } from "vitest"; import type { Session } from "../../../../src/common/session.js"; @@ -15,15 +15,12 @@ export function describeWithAtlas(name: string, fn: IntegrationTestFunction): vo ? describe.skip : describe; describeFn(name, () => { - const integration = setupIntegrationTest( - () => ({ - ...defaultTestConfig, - apiClientId: process.env.MDB_MCP_API_CLIENT_ID || "test-client", - apiClientSecret: process.env.MDB_MCP_API_CLIENT_SECRET || "test-secret", - apiBaseUrl: process.env.MDB_MCP_API_BASE_URL ?? "https://cloud-dev.mongodb.com", - }), - () => defaultDriverOptions - ); + const integration = setupIntegrationTest(() => ({ + ...defaultTestConfig, + apiClientId: process.env.MDB_MCP_API_CLIENT_ID || "test-client", + apiClientSecret: process.env.MDB_MCP_API_CLIENT_SECRET || "test-secret", + apiBaseUrl: process.env.MDB_MCP_API_BASE_URL ?? "https://cloud-dev.mongodb.com", + })); fn(integration); }); } diff --git a/tests/integration/tools/atlas/performanceAdvisor.test.ts b/tests/integration/tools/atlas/performanceAdvisor.test.ts index f8b5ec24..70816b18 100644 --- a/tests/integration/tools/atlas/performanceAdvisor.test.ts +++ b/tests/integration/tools/atlas/performanceAdvisor.test.ts @@ -5,7 +5,6 @@ import { ObjectId } from "bson"; import type { Session } from "../../../../src/common/session.js"; import { DEFAULT_LONG_RUNNING_TEST_WAIT_TIMEOUT_MS, - defaultDriverOptions, defaultTestConfig, expectDefined, getResponseElements, @@ -132,15 +131,12 @@ describeWithAtlas("performanceAdvisor", (integration) => { }); describe("mocked atlas-get-performance-advisor", () => { - const integration = setupIntegrationTest( - () => ({ - ...defaultTestConfig, - apiClientId: process.env.MDB_MCP_API_CLIENT_ID || "test-client", - apiClientSecret: process.env.MDB_MCP_API_CLIENT_SECRET || "test-secret", - apiBaseUrl: process.env.MDB_MCP_API_BASE_URL ?? "https://cloud-dev.mongodb.com", - }), - () => defaultDriverOptions - ); + const integration = setupIntegrationTest(() => ({ + ...defaultTestConfig, + apiClientId: process.env.MDB_MCP_API_CLIENT_ID || "test-client", + apiClientSecret: process.env.MDB_MCP_API_CLIENT_SECRET || "test-secret", + apiBaseUrl: process.env.MDB_MCP_API_BASE_URL ?? "https://cloud-dev.mongodb.com", + })); let mockEmitEvents: MockInstance<(events: BaseEvent[]) => void>; let projectId: string; diff --git a/tests/integration/tools/mongodb/connect/connect.test.ts b/tests/integration/tools/mongodb/connect/connect.test.ts index 132e0fd9..a995d3d4 100644 --- a/tests/integration/tools/mongodb/connect/connect.test.ts +++ b/tests/integration/tools/mongodb/connect/connect.test.ts @@ -6,7 +6,8 @@ import { validateToolMetadata, } from "../../../helpers.js"; import { defaultTestConfig } from "../../../helpers.js"; -import { beforeEach, describe, expect, it } from "vitest"; +import { beforeEach, describe, expect, it, type MockInstance, vi } from "vitest"; +import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver"; describeWithMongoDB( "SwitchConnection tool", @@ -88,6 +89,72 @@ describeWithMongoDB( } ); +describeWithMongoDB( + "SwitchConnection tool when server is configured to connect with complex connection", + (integration) => { + let connectFnSpy: MockInstance; + beforeEach(async () => { + connectFnSpy = vi.spyOn(NodeDriverServiceProvider, "connect"); + await integration.mcpServer().session.connectToMongoDB({ + connectionString: integration.connectionString(), + }); + }); + + it("should be able to connect to next connection and not use the connect options of the connection setup during server boot", async () => { + const newConnectionString = `${integration.connectionString()}`; + // Note: The connect function is called with OIDC options for the + // configured string + expect(connectFnSpy).toHaveBeenNthCalledWith( + 1, + expect.stringContaining(`${integration.connectionString()}/?directConnection=true`), + expect.objectContaining({ + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + oidc: expect.objectContaining({ openBrowser: { command: "not-a-browser" } }), + }), + undefined, + expect.anything() + ); + const response = await integration.mcpClient().callTool({ + name: "switch-connection", + arguments: { + connectionString: newConnectionString, + }, + }); + + const content = getResponseContent(response.content); + // The connection will still be connected because the --browser + // option only sets the command to be used when opening the browser + // for OIDC handling. + expect(content).toContain("Successfully connected"); + + // Now that we're connected lets verify the config + // Note: The connect function is called with OIDC options for the + // configured string + expect(connectFnSpy).toHaveBeenNthCalledWith( + 2, + expect.stringContaining(`${integration.connectionString()}`), + expect.not.objectContaining({ + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + oidc: expect.objectContaining({ openBrowser: { command: "not-a-browser" } }), + }), + undefined, + expect.anything() + ); + }); + }, + { + getUserConfig: (mdbIntegration) => ({ + ...defaultTestConfig, + // Setting browser in config is the same as passing `--browser` CLI + // argument to the MCP server CLI entry point. We expect that the + // further connection attempts stay detached from the connection + // options passed during server boot, in this case browser. + browser: "not-a-browser", + connectionString: `${mdbIntegration.connectionString()}/?directConnection=true`, + }), + } +); + describeWithMongoDB("Connect tool", (integration) => { validateToolMetadata( integration, diff --git a/tests/integration/tools/mongodb/mongodbHelpers.ts b/tests/integration/tools/mongodb/mongodbHelpers.ts index be654100..850dd7d5 100644 --- a/tests/integration/tools/mongodb/mongodbHelpers.ts +++ b/tests/integration/tools/mongodb/mongodbHelpers.ts @@ -8,11 +8,9 @@ import { getResponseContent, setupIntegrationTest, defaultTestConfig, - defaultDriverOptions, getDataFromUntrustedContent, } from "../../helpers.js"; import type { UserConfig } from "../../../../src/common/config.js"; -import type { DriverOptions } from "../../../../src/common/config/driverOptions.js"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { EJSON } from "bson"; import { MongoDBClusterProcess } from "./mongodbClusterProcess.js"; @@ -73,7 +71,6 @@ export type MongoSearchConfiguration = { search: true; image?: string }; export type TestSuiteConfig = { getUserConfig: (mdbIntegration: MongoDBIntegrationTest) => UserConfig; - getDriverOptions: (mdbIntegration: MongoDBIntegrationTest) => DriverOptions; downloadOptions: MongoClusterConfiguration; getMockElicitationInput?: () => ReturnType; getClientCapabilities?: () => MockClientCapabilities; @@ -81,7 +78,6 @@ export type TestSuiteConfig = { export const defaultTestSuiteConfig: TestSuiteConfig = { getUserConfig: () => defaultTestConfig, - getDriverOptions: () => defaultDriverOptions, downloadOptions: DEFAULT_MONGODB_PROCESS_OPTIONS, }; @@ -90,7 +86,7 @@ export function describeWithMongoDB( fn: (integration: MongoDBIntegrationTestCase) => void, partialTestSuiteConfig?: Partial ): void { - const { getUserConfig, getDriverOptions, downloadOptions, getMockElicitationInput, getClientCapabilities } = { + const { getUserConfig, downloadOptions, getMockElicitationInput, getClientCapabilities } = { ...defaultTestSuiteConfig, ...partialTestSuiteConfig, }; @@ -101,9 +97,6 @@ export function describeWithMongoDB( () => ({ ...getUserConfig(mdbIntegration), }), - () => ({ - ...getDriverOptions(mdbIntegration), - }), { elicitInput: mockElicitInput, getClientCapabilities } ); diff --git a/tests/integration/tools/mongodb/mongodbTool.test.ts b/tests/integration/tools/mongodb/mongodbTool.test.ts index 80c8939d..20e53c24 100644 --- a/tests/integration/tools/mongodb/mongodbTool.test.ts +++ b/tests/integration/tools/mongodb/mongodbTool.test.ts @@ -5,7 +5,6 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { MongoDBToolBase } from "../../../../src/tools/mongodb/mongodbTool.js"; import { type ToolBase, type ToolConstructorParams, type OperationType } from "../../../../src/tools/tool.js"; import { type UserConfig } from "../../../../src/common/config.js"; -import { defaultDriverOptions } from "../../../../src/common/config/driverOptions.js"; import { MCPConnectionManager } from "../../../../src/common/connectionManager.js"; import { Session } from "../../../../src/common/session.js"; import { CompositeLogger } from "../../../../src/common/logger.js"; @@ -95,11 +94,10 @@ describe("MongoDBTool implementations", () => { ): Promise { await cleanup(); const userConfig: UserConfig = { ...defaultTestConfig, telemetry: "disabled", ...config }; - const driverOptions = defaultDriverOptions; const logger = new CompositeLogger(); const exportsManager = ExportsManager.init(userConfig, logger); deviceId = DeviceId.create(logger); - const connectionManager = new MCPConnectionManager(userConfig, driverOptions, logger, deviceId); + const connectionManager = new MCPConnectionManager(userConfig, logger, deviceId); const session = new Session({ apiBaseUrl: userConfig.apiBaseUrl, apiClientId: userConfig.apiClientId, diff --git a/tests/unit/common/session.test.ts b/tests/unit/common/session.test.ts index 6e4d9331..c4a1c370 100644 --- a/tests/unit/common/session.test.ts +++ b/tests/unit/common/session.test.ts @@ -3,7 +3,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver"; import { Session } from "../../../src/common/session.js"; import { config } from "../../../src/common/config.js"; -import { defaultDriverOptions } from "../../integration/helpers.js"; import { CompositeLogger } from "../../../src/common/logger.js"; import { MCPConnectionManager } from "../../../src/common/connectionManager.js"; import { ExportsManager } from "../../../src/common/exportsManager.js"; @@ -25,7 +24,7 @@ describe("Session", () => { const logger = new CompositeLogger(); mockDeviceId = MockDeviceId; - const connectionManager = new MCPConnectionManager(config, defaultDriverOptions, logger, mockDeviceId); + const connectionManager = new MCPConnectionManager(config, logger, mockDeviceId); session = new Session({ apiClientId: "test-client-id", diff --git a/tests/unit/resources/common/debug.test.ts b/tests/unit/resources/common/debug.test.ts index e00ce4f2..db4024fd 100644 --- a/tests/unit/resources/common/debug.test.ts +++ b/tests/unit/resources/common/debug.test.ts @@ -3,7 +3,6 @@ import { DebugResource } from "../../../../src/resources/common/debug.js"; import { Session } from "../../../../src/common/session.js"; import { Telemetry } from "../../../../src/telemetry/telemetry.js"; import { config } from "../../../../src/common/config.js"; -import { defaultDriverOptions } from "../../../integration/helpers.js"; import { CompositeLogger } from "../../../../src/common/logger.js"; import { MCPConnectionManager } from "../../../../src/common/connectionManager.js"; import { ExportsManager } from "../../../../src/common/exportsManager.js"; @@ -14,7 +13,7 @@ import { VectorSearchEmbeddingsManager } from "../../../../src/common/search/vec describe("debug resource", () => { const logger = new CompositeLogger(); const deviceId = DeviceId.create(logger); - const connectionManager = new MCPConnectionManager(config, defaultDriverOptions, logger, deviceId); + const connectionManager = new MCPConnectionManager(config, logger, deviceId); const session = vi.mocked( new Session({ From 408620f1f544b2a951ae0a80fac7f3dc39c260ea Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Mon, 17 Nov 2025 12:16:55 +0100 Subject: [PATCH 5/6] chore: remove driverOptions related code --- src/common/config/driverOptions.ts | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 src/common/config/driverOptions.ts diff --git a/src/common/config/driverOptions.ts b/src/common/config/driverOptions.ts deleted file mode 100644 index 1a9a0a6d..00000000 --- a/src/common/config/driverOptions.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { generateConnectionInfoFromCliArgs, type ConnectionInfo } from "@mongosh/arg-parser"; -import type { UserConfig } from "../config.js"; - -export type DriverOptions = ConnectionInfo["driverOptions"]; -export const defaultDriverOptions: DriverOptions = { - readConcern: { - level: "local", - }, - readPreference: "secondaryPreferred", - writeConcern: { - w: "majority", - }, - timeoutMS: 30_000, - proxy: { useEnvironmentVariableProxies: true }, - applyProxyToOIDC: true, -}; - -export function createDriverOptions( - config: UserConfig, - defaults: Partial = defaultDriverOptions -): DriverOptions { - const { driverOptions } = generateConnectionInfoFromCliArgs(config); - return { - ...defaults, - ...driverOptions, - }; -} From 12363667365a4e38fd4b7169b9263884560ab1f5 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Mon, 17 Nov 2025 14:22:54 +0100 Subject: [PATCH 6/6] chore: fix OIDC tests --- .../common/connectionManager.oidc.test.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/integration/common/connectionManager.oidc.test.ts b/tests/integration/common/connectionManager.oidc.test.ts index 729c5012..f6fd9fee 100644 --- a/tests/integration/common/connectionManager.oidc.test.ts +++ b/tests/integration/common/connectionManager.oidc.test.ts @@ -1,3 +1,4 @@ +import { generateConnectionInfoFromCliArgs } from "@mongosh/arg-parser"; import type { TestContext } from "vitest"; import { describe, beforeEach, afterAll, it, expect, vi } from "vitest"; import semver from "semver"; @@ -134,7 +135,19 @@ describe.skipIf(process.platform !== "linux")("ConnectionManager OIDC Tests", as // state of the connection manager connectionManager.changeState("connection-close", { tag: "disconnected" }); - await integration.connectMcpClient(); + // Note: Instead of using `integration.connectMcpClient`, + // we're connecting straight using Session because + // `integration.connectMcpClient` uses `connect` tool which + // does not work the same way as connect on server start up. + // So to mimic the same functionality as that of server + // startup we call the connectToMongoDB the same way as the + // `Server.connectToConfigConnectionString` does. + await integration.mcpServer().session.connectToMongoDB( + generateConnectionInfoFromCliArgs({ + ...oidcConfig, + connectionSpecifier: integration.connectionString(), + }) + ); }, DEFAULT_TIMEOUT); addCb?.(oidcIt);