Skip to main content
Glama

MongoDB MCP Server

Official
by mongodb-js
createUserConfig.ts8.38 kB
import argv from "yargs-parser"; import { generateConnectionInfoFromCliArgs } from "@mongosh/arg-parser"; import { Keychain } from "../keychain.js"; import type { Secret } from "../keychain.js"; import { isConnectionSpecifier, matchingConfigKey } from "./configUtils.js"; import { OPTIONS } from "./argsParserOptions.js"; import { UserConfigSchema, type UserConfig } from "./userConfig.js"; export type CreateUserConfigHelpers = { onWarning: (message: string) => void; onError: (message: string) => void; closeProcess: (exitCode: number) => never; cliArguments: string[]; }; export const defaultUserConfigHelpers: CreateUserConfigHelpers = { onWarning(message) { console.warn(message); }, onError(message) { console.error(message); }, closeProcess(exitCode) { process.exit(exitCode); }, cliArguments: process.argv.slice(2), }; export function createUserConfig({ onWarning = defaultUserConfigHelpers.onWarning, onError = defaultUserConfigHelpers.onError, closeProcess = defaultUserConfigHelpers.closeProcess, cliArguments = defaultUserConfigHelpers.cliArguments, }: Partial<CreateUserConfigHelpers> = defaultUserConfigHelpers): UserConfig { const { unknownCliArgumentErrors, deprecatedCliArgumentWarning, userAndArgsParserConfig, connectionSpecifier } = parseUserConfigSources(cliArguments); if (unknownCliArgumentErrors.length) { const errorMessage = ` ${unknownCliArgumentErrors.join("\n")} - Refer to https://www.mongodb.com/docs/mcp-server/get-started/ for setting up the MCP Server. `; onError(errorMessage); return closeProcess(1); } if (deprecatedCliArgumentWarning) { const deprecatedMessages = ` ${deprecatedCliArgumentWarning} - Refer to https://www.mongodb.com/docs/mcp-server/get-started/ for setting up the MCP Server. `; onWarning(deprecatedMessages); } // If we have a connectionSpecifier, which can only appear as the positional // argument, then that has to be used on priority to construct the // connection string. In this case, if there is a connection string provided // by the env variable or config file, that will be overridden. if (connectionSpecifier) { const connectionInfo = generateConnectionInfoFromCliArgs({ ...userAndArgsParserConfig, connectionSpecifier }); userAndArgsParserConfig.connectionString = connectionInfo.connectionString; } const configParseResult = UserConfigSchema.safeParse(userAndArgsParserConfig); if (configParseResult.error) { onError( `Invalid configuration for the following fields:\n${configParseResult.error.issues.map((issue) => `${issue.path.join(".")} - ${issue.message}`).join("\n")}` ); return closeProcess(1); } // TODO: Separate correctly parsed user config from all other valid // arguments relevant to mongosh's args-parser. const userConfig: UserConfig = { ...userAndArgsParserConfig, ...configParseResult.data }; warnIfVectorSearchNotEnabledCorrectly(userConfig, onWarning); registerKnownSecretsInRootKeychain(userConfig); return userConfig; } function parseUserConfigSources(cliArguments: string[]): { unknownCliArgumentErrors: string[]; deprecatedCliArgumentWarning: string | undefined; userAndArgsParserConfig: Record<string, unknown>; connectionSpecifier: string | undefined; } { const { _: positionalAndUnknownArguments, // We don't make use of end of flag arguments but also don't want them to // end up alongside unknown arguments so we are extracting them and having a // no-op statement so ESLint does not complain. // eslint-disable-next-line @typescript-eslint/no-unused-vars "--": _endOfFlagArguments, ...parsedUserAndArgsParserConfig } = argv(cliArguments, { ...OPTIONS, // This helps parse the relevant environment variables. envPrefix: "MDB_MCP_", configuration: { ...OPTIONS.configuration, // Setting this to true will populate `_` variable which is // originally used for positional arguments, now with the unknown // arguments as well. The order of arguments are maintained. "unknown-options-as-args": true, // To avoid populating `_` with end-of-flag arguments we explicitly // populate `--` variable and altogether ignore them later. "populate--": true, }, }); // A connectionSpecifier can be one of: // - database name // - host name // - ip address // - replica set specifier // - complete connection string let connectionSpecifier: string | undefined = undefined; const [maybeConnectionSpecifier, ...unknownArguments] = positionalAndUnknownArguments; if (typeof maybeConnectionSpecifier === "string" && isConnectionSpecifier(maybeConnectionSpecifier)) { connectionSpecifier = maybeConnectionSpecifier; } else if (maybeConnectionSpecifier !== undefined) { // If the extracted connection specifier is not a connection specifier // indeed, then we push it back to the unknown arguments list. This might // happen for example when an unknown argument is provided without ever // specifying a positional argument. unknownArguments.unshift(maybeConnectionSpecifier); } return { unknownCliArgumentErrors: unknownArguments .filter((argument): argument is string => typeof argument === "string" && argument.startsWith("--")) .map((argument) => { const argumentKey = argument.replace(/^(--)/, ""); const matchingKey = matchingConfigKey(argumentKey); if (matchingKey) { return `Error: Invalid command line argument '${argument}'. Did you mean '--${matchingKey}'?`; } return `Error: Invalid command line argument '${argument}'.`; }), deprecatedCliArgumentWarning: cliArguments.find((argument) => argument.startsWith("--connectionString")) ? "Warning: The --connectionString argument is deprecated. Prefer using the MDB_MCP_CONNECTION_STRING environment variable or the first positional argument for the connection string." : undefined, userAndArgsParserConfig: parsedUserAndArgsParserConfig, connectionSpecifier, }; } function registerKnownSecretsInRootKeychain(userConfig: Partial<UserConfig>): void { const keychain = Keychain.root; const maybeRegister = (value: string | undefined, kind: Secret["kind"]): void => { if (value) { keychain.register(value, kind); } }; maybeRegister(userConfig.apiClientId, "user"); maybeRegister(userConfig.apiClientSecret, "password"); maybeRegister(userConfig.awsAccessKeyId, "password"); maybeRegister(userConfig.awsIamSessionToken, "password"); maybeRegister(userConfig.awsSecretAccessKey, "password"); maybeRegister(userConfig.awsSessionToken, "password"); maybeRegister(userConfig.password, "password"); maybeRegister(userConfig.tlsCAFile, "url"); maybeRegister(userConfig.tlsCRLFile, "url"); maybeRegister(userConfig.tlsCertificateKeyFile, "url"); maybeRegister(userConfig.tlsCertificateKeyFilePassword, "password"); maybeRegister(userConfig.username, "user"); } function warnIfVectorSearchNotEnabledCorrectly(config: UserConfig, warn: (message: string) => void): void { const vectorSearchEnabled = config.previewFeatures.includes("vectorSearch"); const embeddingsProviderConfigured = !!config.voyageApiKey; if (vectorSearchEnabled && !embeddingsProviderConfigured) { warn(`\ 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.\ `); } if (!vectorSearchEnabled && embeddingsProviderConfigured) { warn(`\ 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.\ `); } }

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