Skip to main content
Glama

MongoDB MCP Server

Official
by mongodb-js
config.test.tsโ€ข33.9 kB
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import type { UserConfig } from "../../../src/common/config.js"; import { setupUserConfig, registerKnownSecretsInRootKeychain, warnAboutDeprecatedOrUnknownCliArgs, UserConfigSchema, warnIfVectorSearchNotEnabledCorrectly, } from "../../../src/common/config.js"; import { getLogPath, getExportsPath } from "../../../src/common/configUtils.js"; import type { CliOptions } from "@mongosh/arg-parser"; import { Keychain } from "../../../src/common/keychain.js"; import type { Secret } from "../../../src/common/keychain.js"; import { defaultTestConfig } from "../../integration/helpers.js"; describe("config", () => { it("should generate defaults from UserConfigSchema that match expected values", () => { // Expected hardcoded values (what we had before) const expectedDefaults = { apiBaseUrl: "https://cloud.mongodb.com/", logPath: getLogPath(), exportsPath: getExportsPath(), exportTimeoutMs: 5 * 60 * 1000, // 5 minutes exportCleanupIntervalMs: 2 * 60 * 1000, // 2 minutes disabledTools: [], telemetry: "enabled", readOnly: false, indexCheck: false, confirmationRequiredTools: [ "atlas-create-access-list", "atlas-create-db-user", "drop-database", "drop-collection", "delete-many", "drop-index", ], transport: "stdio", httpPort: 3000, httpHost: "127.0.0.1", loggers: ["disk", "mcp"], idleTimeoutMs: 10 * 60 * 1000, // 10 minutes notificationTimeoutMs: 9 * 60 * 1000, // 9 minutes httpHeaders: {}, maxDocumentsPerQuery: 100, maxBytesPerQuery: 16 * 1024 * 1024, // ~16 mb atlasTemporaryDatabaseUserLifetimeMs: 4 * 60 * 60 * 1000, // 4 hours voyageApiKey: "", vectorSearchDimensions: 1024, vectorSearchSimilarityFunction: "euclidean", disableEmbeddingsValidation: false, previewFeatures: [], }; expect(UserConfigSchema.parse({})).toStrictEqual(expectedDefaults); }); describe("env var parsing", () => { describe("mongodb urls", () => { it("should not try to parse a multiple-host urls", () => { const actual = setupUserConfig({ env: { MDB_MCP_CONNECTION_STRING: "mongodb://user:password@host1,host2,host3/", }, cli: [], }); expect(actual.connectionString).toEqual("mongodb://user:password@host1,host2,host3/"); }); }); describe("string cases", () => { const testCases = [ { envVar: "MDB_MCP_API_BASE_URL", property: "apiBaseUrl", value: "http://test.com" }, { envVar: "MDB_MCP_API_CLIENT_ID", property: "apiClientId", value: "ClientIdLol" }, { envVar: "MDB_MCP_API_CLIENT_SECRET", property: "apiClientSecret", value: "SuperClientSecret" }, { envVar: "MDB_MCP_TELEMETRY", property: "telemetry", value: "enabled" }, { envVar: "MDB_MCP_LOG_PATH", property: "logPath", value: "/var/log" }, { envVar: "MDB_MCP_CONNECTION_STRING", property: "connectionString", value: "mongodb://localhost" }, { envVar: "MDB_MCP_READ_ONLY", property: "readOnly", value: true }, { envVar: "MDB_MCP_INDEX_CHECK", property: "indexCheck", value: true }, { envVar: "MDB_MCP_TRANSPORT", property: "transport", value: "http" }, { envVar: "MDB_MCP_HTTP_PORT", property: "httpPort", value: 8080 }, { envVar: "MDB_MCP_HTTP_HOST", property: "httpHost", value: "localhost" }, { envVar: "MDB_MCP_IDLE_TIMEOUT_MS", property: "idleTimeoutMs", value: 5000 }, { envVar: "MDB_MCP_NOTIFICATION_TIMEOUT_MS", property: "notificationTimeoutMs", value: 5000 }, { envVar: "MDB_MCP_ATLAS_TEMPORARY_DATABASE_USER_LIFETIME_MS", property: "atlasTemporaryDatabaseUserLifetimeMs", value: 12345, }, ] as const; for (const { envVar, property, value } of testCases) { it(`should map ${envVar} to ${property} with value "${value}"`, () => { const actual = setupUserConfig({ cli: [], env: { [envVar]: String(value), }, }); expect(actual[property]).toBe(value); }); } }); describe("array cases", () => { const testCases = { MDB_MCP_DISABLED_TOOLS: "disabledTools", MDB_MCP_LOGGERS: "loggers", } as const; for (const [envVar, config] of Object.entries(testCases)) { it(`should map ${envVar} to ${config}`, () => { const actual = setupUserConfig({ cli: [], env: { [envVar]: "disk,mcp", }, }); expect(actual[config]).toEqual(["disk", "mcp"]); }); } }); }); describe("cli parsing", () => { it("should not try to parse a multiple-host urls", () => { const actual = setupUserConfig({ cli: ["myself", "--", "--connectionString", "mongodb://user:password@host1,host2,host3/"], env: {}, }); expect(actual.connectionString).toEqual("mongodb://user:password@host1,host2,host3/"); }); describe("string use cases", () => { const testCases = [ { cli: ["--apiBaseUrl", "http://some-url.com"], expected: { apiBaseUrl: "http://some-url.com" }, }, { cli: ["--apiClientId", "OmgSoIdYeah"], expected: { apiClientId: "OmgSoIdYeah" }, }, { cli: ["--apiClientSecret", "OmgSoSecretYeah"], expected: { apiClientSecret: "OmgSoSecretYeah" }, }, { cli: ["--connectionString", "mongodb://localhost"], expected: { connectionString: "mongodb://localhost" }, }, { cli: ["--httpHost", "mongodb://localhost"], expected: { httpHost: "mongodb://localhost" }, }, { cli: ["--httpPort", "8080"], expected: { httpPort: 8080 }, }, { cli: ["--idleTimeoutMs", "42"], expected: { idleTimeoutMs: 42 }, }, { cli: ["--logPath", "/var/"], expected: { logPath: "/var/" }, }, { cli: ["--notificationTimeoutMs", "42"], expected: { notificationTimeoutMs: 42 }, }, { cli: ["--atlasTemporaryDatabaseUserLifetimeMs", "12345"], expected: { atlasTemporaryDatabaseUserLifetimeMs: 12345 }, }, { cli: ["--telemetry", "enabled"], expected: { telemetry: "enabled" }, }, { cli: ["--transport", "stdio"], expected: { transport: "stdio" }, }, { cli: ["--apiVersion", "1"], expected: { apiVersion: "1" }, }, { cli: ["--authenticationDatabase", "admin"], expected: { authenticationDatabase: "admin" }, }, { cli: ["--authenticationMechanism", "PLAIN"], expected: { authenticationMechanism: "PLAIN" }, }, { cli: ["--browser", "firefox"], expected: { browser: "firefox" }, }, { cli: ["--db", "test"], expected: { db: "test" }, }, { cli: ["--gssapiHostName", "localhost"], expected: { gssapiHostName: "localhost" }, }, { cli: ["--gssapiServiceName", "SERVICE"], expected: { gssapiServiceName: "SERVICE" }, }, { cli: ["--host", "localhost"], expected: { host: "localhost" }, }, { cli: ["--oidcFlows", "device"], expected: { oidcFlows: "device" }, }, { cli: ["--oidcRedirectUri", "https://oidc"], expected: { oidcRedirectUri: "https://oidc", oidcRedirectUrl: "https://oidc" }, }, { cli: ["--oidcRedirectUrl", "https://oidc"], expected: { oidcRedirectUrl: "https://oidc", oidcRedirectUri: "https://oidc" }, }, { cli: ["--password", "123456"], expected: { password: "123456", p: "123456" }, }, { cli: ["-p", "123456"], expected: { password: "123456", p: "123456" }, }, { cli: ["--port", "27017"], expected: { port: "27017" }, }, { cli: ["--sslCAFile", "/var/file"], expected: { sslCAFile: "/var/file" }, }, { cli: ["--sslCRLFile", "/var/file"], expected: { sslCRLFile: "/var/file" }, }, { cli: ["--sslCertificateSelector", "pem=pom"], expected: { sslCertificateSelector: "pem=pom" }, }, { cli: ["--sslDisabledProtocols", "tls1"], expected: { sslDisabledProtocols: "tls1" }, }, { cli: ["--sslPEMKeyFile", "/var/pem"], expected: { sslPEMKeyFile: "/var/pem" }, }, { cli: ["--sslPEMKeyPassword", "654321"], expected: { sslPEMKeyPassword: "654321" }, }, { cli: ["--sspiHostnameCanonicalization", "true"], expected: { sspiHostnameCanonicalization: "true" }, }, { cli: ["--sspiRealmOverride", "OVER9000!"], expected: { sspiRealmOverride: "OVER9000!" }, }, { cli: ["--tlsCAFile", "/var/file"], expected: { tlsCAFile: "/var/file" }, }, { cli: ["--tlsCRLFile", "/var/file"], expected: { tlsCRLFile: "/var/file" }, }, { cli: ["--tlsCertificateKeyFile", "/var/file"], expected: { tlsCertificateKeyFile: "/var/file" }, }, { cli: ["--tlsCertificateKeyFilePassword", "4242"], expected: { tlsCertificateKeyFilePassword: "4242" }, }, { cli: ["--tlsCertificateSelector", "pom=pum"], expected: { tlsCertificateSelector: "pom=pum" }, }, { cli: ["--tlsDisabledProtocols", "tls1"], expected: { tlsDisabledProtocols: "tls1" }, }, { cli: ["--username", "admin"], expected: { username: "admin", u: "admin" }, }, { cli: ["-u", "admin"], expected: { username: "admin", u: "admin" }, }, ] as { cli: string[]; expected: Partial<UserConfig> }[]; for (const { cli, expected } of testCases) { it(`should parse '${cli.join(" ")}' to ${JSON.stringify(expected)}`, () => { const actual = setupUserConfig({ cli: ["myself", "--", ...cli], env: {}, }); expect(actual).toStrictEqual({ ...UserConfigSchema.parse({}), ...expected, }); }); } }); describe("boolean use cases", () => { const testCases = [ { cli: ["--apiDeprecationErrors"], expected: { apiDeprecationErrors: true }, }, { cli: ["--apiStrict"], expected: { apiStrict: true }, }, { cli: ["--help"], expected: { help: true }, }, { cli: ["--indexCheck"], expected: { indexCheck: true }, }, { cli: ["--ipv6"], expected: { ipv6: true }, }, { cli: ["--nodb"], expected: { nodb: true }, }, { cli: ["--oidcIdTokenAsAccessToken"], expected: { oidcIdTokenAsAccessToken: true }, }, { cli: ["--oidcNoNonce"], expected: { oidcNoNonce: true }, }, { cli: ["--oidcTrustedEndpoint"], expected: { oidcTrustedEndpoint: true }, }, { cli: ["--readOnly"], expected: { readOnly: true }, }, { cli: ["--retryWrites"], expected: { retryWrites: true }, }, { cli: ["--ssl"], expected: { ssl: true }, }, { cli: ["--sslAllowInvalidCertificates"], expected: { sslAllowInvalidCertificates: true }, }, { cli: ["--sslAllowInvalidHostnames"], expected: { sslAllowInvalidHostnames: true }, }, { cli: ["--sslFIPSMode"], expected: { sslFIPSMode: true }, }, { cli: ["--tls"], expected: { tls: true }, }, { cli: ["--tlsAllowInvalidCertificates"], expected: { tlsAllowInvalidCertificates: true }, }, { cli: ["--tlsAllowInvalidHostnames"], expected: { tlsAllowInvalidHostnames: true }, }, { cli: ["--tlsFIPSMode"], expected: { tlsFIPSMode: true }, }, { cli: ["--version"], expected: { version: true }, }, ] as { cli: string[]; expected: Partial<UserConfig> }[]; for (const { cli, expected } of testCases) { it(`should parse '${cli.join(" ")}' to ${JSON.stringify(expected)}`, () => { const actual = setupUserConfig({ cli: ["myself", "--", ...cli], env: {}, }); for (const [key, value] of Object.entries(expected)) { expect(actual[key as keyof UserConfig]).toBe(value); } }); } }); describe("array use cases", () => { const testCases = [ { cli: ["--disabledTools", "some,tool"], expected: { disabledTools: ["some", "tool"] }, }, { cli: ["--loggers", "disk,mcp"], expected: { loggers: ["disk", "mcp"] }, }, ] as { cli: string[]; expected: Partial<UserConfig> }[]; for (const { cli, expected } of testCases) { it(`should parse '${cli.join(" ")}' to ${JSON.stringify(expected)}`, () => { const actual = setupUserConfig({ cli: ["myself", "--", ...cli], env: {}, }); for (const [key, value] of Object.entries(expected)) { expect(actual[key as keyof UserConfig]).toEqual(value); } }); } }); }); describe("precedence rules", () => { it("cli arguments take precedence over env vars", () => { const actual = setupUserConfig({ cli: ["myself", "--", "--connectionString", "mongodb://localhost"], env: { MDB_MCP_CONNECTION_STRING: "mongodb://crazyhost" }, }); expect(actual.connectionString).toBe("mongodb://localhost"); }); it("any cli argument takes precedence over defaults", () => { const actual = setupUserConfig({ cli: ["myself", "--", "--connectionString", "mongodb://localhost"], env: {}, }); expect(actual.connectionString).toBe("mongodb://localhost"); }); it("any env var takes precedence over defaults", () => { const actual = setupUserConfig({ cli: [], env: { MDB_MCP_CONNECTION_STRING: "mongodb://localhost" }, }); expect(actual.connectionString).toBe("mongodb://localhost"); }); }); describe("consolidation", () => { it("positional argument for url has precedence over --connectionString", () => { const actual = setupUserConfig({ cli: ["myself", "--", "mongodb://localhost", "--connectionString", "toRemove"], env: {}, }); // the shell specifies directConnection=true and serverSelectionTimeoutMS=2000 by default expect(actual.connectionString).toBe( "mongodb://localhost/?directConnection=true&serverSelectionTimeoutMS=2000" ); expect(actual.connectionSpecifier).toBe("mongodb://localhost"); }); }); describe("validation", () => { describe("transport", () => { it("should support http", () => { const actual = setupUserConfig({ cli: ["myself", "--", "--transport", "http"], env: {}, }); expect(actual.transport).toEqual("http"); }); it("should support stdio", () => { const actual = setupUserConfig({ cli: ["myself", "--", "--transport", "stdio"], env: {}, }); expect(actual.transport).toEqual("stdio"); }); it("should not support sse", () => { expect(() => setupUserConfig({ cli: ["myself", "--", "--transport", "sse"], env: {}, }) ).toThrowError( 'Invalid configuration for the following fields:\ntransport - Invalid option: expected one of "stdio"|"http"' ); }); it("should not support arbitrary values", () => { const value = Math.random() + "transport"; expect(() => setupUserConfig({ cli: ["myself", "--", "--transport", value], env: {}, }) ).toThrowError( `Invalid configuration for the following fields:\ntransport - Invalid option: expected one of "stdio"|"http"` ); }); }); describe("telemetry", () => { it("can be enabled", () => { const actual = setupUserConfig({ cli: ["myself", "--", "--telemetry", "enabled"], env: {}, }); expect(actual.telemetry).toEqual("enabled"); }); it("can be disabled", () => { const actual = setupUserConfig({ cli: ["myself", "--", "--telemetry", "disabled"], env: {}, }); expect(actual.telemetry).toEqual("disabled"); }); it("should not support the boolean true value", () => { expect(() => setupUserConfig({ cli: ["myself", "--", "--telemetry", "true"], env: {}, }) ).toThrowError( 'Invalid configuration for the following fields:\ntelemetry - Invalid option: expected one of "enabled"|"disabled"' ); }); it("should not support the boolean false value", () => { expect(() => setupUserConfig({ cli: ["myself", "--", "--telemetry", "false"], env: {}, }) ).toThrowError( 'Invalid configuration for the following fields:\ntelemetry - Invalid option: expected one of "enabled"|"disabled"' ); }); it("should not support arbitrary values", () => { const value = Math.random() + "telemetry"; expect(() => setupUserConfig({ cli: ["myself", "--", "--telemetry", value], env: {}, }) ).toThrowError( `Invalid configuration for the following fields:\ntelemetry - Invalid option: expected one of "enabled"|"disabled"` ); }); }); describe("httpPort", () => { it("must be above 1", () => { expect(() => setupUserConfig({ cli: ["myself", "--", "--httpPort", "0"], env: {}, }) ).toThrowError( "Invalid configuration for the following fields:\nhttpPort - Invalid httpPort: must be at least 1" ); }); it("must be below 65535 (OS limit)", () => { expect(() => setupUserConfig({ cli: ["myself", "--", "--httpPort", "89527345"], env: {}, }) ).toThrowError( "Invalid configuration for the following fields:\nhttpPort - Invalid httpPort: must be at most 65535" ); }); it("should not support non numeric values", () => { expect(() => setupUserConfig({ cli: ["myself", "--", "--httpPort", "portAventura"], env: {}, }) ).toThrowError( "Invalid configuration for the following fields:\nhttpPort - Invalid input: expected number, received NaN" ); }); it("should support numeric values", () => { const actual = setupUserConfig({ cli: ["myself", "--", "--httpPort", "8888"], env: {}, }); expect(actual.httpPort).toEqual(8888); }); }); describe("loggers", () => { it("must not be empty", () => { expect(() => setupUserConfig({ cli: ["myself", "--", "--loggers", ""], env: {}, }) ).toThrowError("Invalid configuration for the following fields:\nloggers - Cannot be an empty array"); }); it("must not allow duplicates", () => { expect(() => setupUserConfig({ cli: ["myself", "--", "--loggers", "disk,disk,disk"], env: {}, }) ).toThrowError( "Invalid configuration for the following fields:\nloggers - Duplicate loggers found in config" ); }); it("allows mcp logger", () => { const actual = setupUserConfig({ cli: ["myself", "--", "--loggers", "mcp"], env: {}, }); expect(actual.loggers).toEqual(["mcp"]); }); it("allows disk logger", () => { const actual = setupUserConfig({ cli: ["myself", "--", "--loggers", "disk"], env: {}, }); expect(actual.loggers).toEqual(["disk"]); }); it("allows stderr logger", () => { const actual = setupUserConfig({ cli: ["myself", "--", "--loggers", "stderr"], env: {}, }); expect(actual.loggers).toEqual(["stderr"]); }); }); }); }); describe("CLI arguments", () => { const referDocMessage = "- Refer to https://www.mongodb.com/docs/mcp-server/get-started/ for setting up the MCP Server."; type TestCase = { readonly cliArg: keyof (CliOptions & UserConfig); readonly warning: string }; const testCases = [ { cliArg: "connectionString", warning: "Warning: The --connectionString argument is deprecated. Prefer using the MDB_MCP_CONNECTION_STRING environment variable or the first positional argument for the connection string.", }, ] as TestCase[]; for (const { cliArg, warning } of testCases) { describe(`deprecation behaviour of ${cliArg}`, () => { let cliArgs: CliOptions & UserConfig & { _?: string[] }; let warn: (msg: string) => void; let exit: (status: number) => void | never; beforeEach(() => { cliArgs = { [cliArg]: "RandomString" } as unknown as CliOptions & UserConfig & { _?: string[] }; warn = vi.fn(); exit = vi.fn(); warnAboutDeprecatedOrUnknownCliArgs(cliArgs as unknown as Record<string, unknown>, { warn, exit }); }); it(`warns the usage of ${cliArg} as it is deprecated`, () => { expect(warn).toHaveBeenCalledWith(warning); }); it(`shows the reference message when ${cliArg} was passed`, () => { expect(warn).toHaveBeenCalledWith(referDocMessage); }); it(`should not exit the process`, () => { expect(exit).not.toHaveBeenCalled(); }); }); } describe("invalid arguments", () => { let warn: (msg: string) => void; let exit: (status: number) => void | never; beforeEach(() => { warn = vi.fn(); exit = vi.fn(); }); it("should show a warning when an argument is not known", () => { warnAboutDeprecatedOrUnknownCliArgs( { wakanda: "", }, { warn, exit } ); expect(warn).toHaveBeenCalledWith("Warning: Invalid command line argument 'wakanda'."); expect(warn).toHaveBeenCalledWith( "- Refer to https://www.mongodb.com/docs/mcp-server/get-started/ for setting up the MCP Server." ); }); it("should exit the process on unknown cli args", () => { warnAboutDeprecatedOrUnknownCliArgs( { wakanda: "", }, { warn, exit } ); expect(exit).toHaveBeenCalledWith(1); }); it("should show a suggestion when is a simple typo", () => { warnAboutDeprecatedOrUnknownCliArgs( { readonli: "", }, { warn, exit } ); expect(warn).toHaveBeenCalledWith( "Warning: Invalid command line argument 'readonli'. Did you mean 'readOnly'?" ); expect(warn).toHaveBeenCalledWith( "- Refer to https://www.mongodb.com/docs/mcp-server/get-started/ for setting up the MCP Server." ); }); it("should show a suggestion when the only change is on the case", () => { warnAboutDeprecatedOrUnknownCliArgs( { readonly: "", }, { warn, exit } ); expect(warn).toHaveBeenCalledWith( "Warning: Invalid command line argument 'readonly'. Did you mean 'readOnly'?" ); expect(warn).toHaveBeenCalledWith( "- Refer to https://www.mongodb.com/docs/mcp-server/get-started/ for setting up the MCP Server." ); }); }); describe("warnIfVectorSearchNotEnabledCorrectly", () => { it("should warn if vectorSearch is enabled but embeddings provider is not configured", () => { const warnStub = vi.fn(); warnIfVectorSearchNotEnabledCorrectly( { ...defaultTestConfig, previewFeatures: ["vectorSearch"], }, warnStub ); expect(warnStub).toBeCalledWith(`\ Warning: Vector search is enabled but no embeddings provider is configured. - Set an embeddings provider configuration option to enable auto-embeddings during document insertion and text-based queries with $vectorSearch.\ `); }); it("should warn if vectorSearch is not enabled but embeddings provider is configured", () => { const warnStub = vi.fn(); warnIfVectorSearchNotEnabledCorrectly( { ...defaultTestConfig, voyageApiKey: "random-key", }, warnStub ); expect(warnStub).toBeCalledWith(`\ Warning: An embeddings provider is configured but the 'vectorSearch' preview feature is not enabled. - Enable vector search by adding 'vectorSearch' to the 'previewFeatures' configuration option, or remove the embeddings provider configuration if not needed.\ `); }); it("should not warn if vectorSearch is enabled correctly", () => { const warnStub = vi.fn(); warnIfVectorSearchNotEnabledCorrectly( { ...defaultTestConfig, voyageApiKey: "random-key", previewFeatures: ["vectorSearch"], }, warnStub ); expect(warnStub).not.toBeCalled(); }); }); describe("keychain management", () => { type TestCase = { readonly cliArg: keyof UserConfig; secretKind: Secret["kind"] }; const testCases = [ { cliArg: "apiClientId", secretKind: "user" }, { cliArg: "apiClientSecret", secretKind: "password" }, { cliArg: "awsAccessKeyId", secretKind: "password" }, { cliArg: "awsIamSessionToken", secretKind: "password" }, { cliArg: "awsSecretAccessKey", secretKind: "password" }, { cliArg: "awsSessionToken", secretKind: "password" }, { cliArg: "password", secretKind: "password" }, { cliArg: "tlsCAFile", secretKind: "url" }, { cliArg: "tlsCRLFile", secretKind: "url" }, { cliArg: "tlsCertificateKeyFile", secretKind: "url" }, { cliArg: "tlsCertificateKeyFilePassword", secretKind: "password" }, { cliArg: "username", secretKind: "user" }, ] as TestCase[]; let keychain: Keychain; beforeEach(() => { keychain = Keychain.root; keychain.clearAllSecrets(); }); afterEach(() => { keychain.clearAllSecrets(); }); for (const { cliArg, secretKind } of testCases) { it(`should register ${cliArg} as a secret of kind ${secretKind} in the root keychain`, () => { registerKnownSecretsInRootKeychain({ [cliArg]: cliArg }); expect(keychain.allSecrets).toEqual([{ value: cliArg, kind: secretKind }]); }); } }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mongodb-js/mongodb-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server