Skip to main content
Glama
mongodb-js

MongoDB MCP Server

Official
by mongodb-js
base.ts13.5 kB
import type { UserConfig } from "../common/config/userConfig.js"; import { packageInfo } from "../common/packageInfo.js"; import { Server } from "../server.js"; import { Session } from "../common/session.js"; import { Telemetry } from "../telemetry/telemetry.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import type { LoggerBase } from "../common/logger.js"; import { CompositeLogger, ConsoleLogger, DiskLogger, McpLogger } from "../common/logger.js"; import { ExportsManager } from "../common/exportsManager.js"; import { DeviceId } from "../helpers/deviceId.js"; import { Keychain } from "../common/keychain.js"; import { createMCPConnectionManager, type ConnectionManagerFactoryFn } from "../common/connectionManager.js"; import { type ConnectionErrorHandler, connectionErrorHandler as defaultConnectionErrorHandler, } from "../common/connectionErrorHandler.js"; import type { CommonProperties } from "../telemetry/types.js"; import { Elicitation } from "../elicitation.js"; import type { AtlasLocalClientFactoryFn } from "../common/atlasLocal.js"; import { defaultCreateAtlasLocalClient } from "../common/atlasLocal.js"; import type { Client } from "@mongodb-js/atlas-local"; import { VectorSearchEmbeddingsManager } from "../common/search/vectorSearchEmbeddingsManager.js"; import type { ToolClass } from "../tools/tool.js"; import { applyConfigOverrides } from "../common/config/configOverrides.js"; export type RequestContext = { headers?: Record<string, string | string[] | undefined>; query?: Record<string, string | string[] | undefined>; }; /** * A function to dynamically generate `UserConfig` object, potentially unique to * each MCP client session. * * The function is passed a config context object containing: * 1. `userConfig`: The base `UserConfig` object that MongoDB MCP Server was * started with, either through parsed CLI arguments or a static * configuration injected through `TransportRunnerConfig` * 2. `request`: An optional, `RequestContext` object, available only when * MongoDB MCP server is running over HTTP transport, that contains headers * and query parameters received in MCP session initialization object. * * @see {@link UserConfig} to inspect the properties available on `userConfig` * object. * @see {@link RequestContext} to inspect the properties available on * `requestContext` object. */ type CreateSessionConfigFn = (context: { userConfig: UserConfig; request?: RequestContext; }) => Promise<UserConfig> | UserConfig; /** * Configuration options for customizing how transport runners are initialized. * This includes specifying the base user configuration, providing custom * connection management, and other advanced options. * * You may want to customize this configuration if you need to: * - Provide a custom user configuration for different environments or users. * - Override the default connection management to MongoDB deployments. * - Provide a specific list of tools to be registered with the MCP server. * * In most cases, just providing the `UserConfig` object is sufficient, but * advanced use-cases (such as embedding the MCP server in another application * or supporting custom authentication flows) may require customizing other * `TransportRunnerConfig` options as well. */ export type TransportRunnerConfig = { /** * Base user configuration for the server. * * Can be generated by parsing CLI arguments, environment variables or * written manually while conforming the interface requirements of * `UserConfig`. * * To parse CLI arguments and environment variables in order to generate a * `UserConfig` object, you can use `createUserConfig` function, also * exported as `parseCliArgumentsAsUserConfig` through MCP server library * exports. * * Optionally, you can also use `UserConfigSchema` (available through MCP * server library exports) to create a default configuration - * `UserConfigSchema.parse({})`. */ userConfig: UserConfig; /** * An optional factory function to generates an instance of * `ConnectionManager`. When not provided, MongoDB MCP Server uses an * internal implementation to manage connection to MongoDB deployments. * * Customize this only if the use-case involves handling the MongoDB * connections differently and outside of MongoDB MCP server. */ createConnectionManager?: ConnectionManagerFactoryFn; /** * An optional function to handle connection related errors. When not * provided, MongoDB MCP Server uses an internal implementation to handle * the errors raised by internal implementation of `ConnectionManager` * class. * * Customize this only if you need to handle the Connection errors different * from the internal implementation or if you have provided a different * implementation of `ConnectionManager` that might raise errors unknown to * default internal connection error handler. */ connectionErrorHandler?: ConnectionErrorHandler; /** * An optional factory function to create a client for working with Atlas * local deployments. When not provided, MongoDB MCP Server uses an internal * implementation to create the local Atlas client. */ createAtlasLocalClient?: AtlasLocalClientFactoryFn; /** * An optional list of loggers to be used in addition to the default logger * implementations. When not provided, MongoDB MCP Server will not utilize * any loggers other than the default that it works with. * * Customize this only if the default enabled loggers (disk/stderr/mcp) are * not covering your use-case. */ additionalLoggers?: LoggerBase[]; /** * An optional key value pair of telemetry properties that are reported to * the telemetry backend. Most, if not all, of the properties are captured * automatically. */ telemetryProperties?: Partial<CommonProperties>; /** * An optional list of tools constructors to be registered to the MongoDB * MCP Server. * * When not provided, MongoDB MCP Server will register all internal tools. * When specified, **only** the tools in this list will be registered. * * This allows you to: * - Register only custom tools (excluding all internal tools) * - Register a subset of internal tools alongside custom tools * - Register all internal tools plus custom tools * * To include internal tools, import them from `mongodb-mcp-server/tools`: * * ```typescript * import { AllTools, AggregateTool, FindTool } from "mongodb-mcp-server/tools"; * * // Register all internal tools plus custom tools * tools: [...AllTools, MyCustomTool] * * // Register only specific MongoDB tools plus custom tools * tools: [AggregateTool, FindTool, MyCustomTool] * * // Register all internal tools of mongodb category * tools: [AllTools.filter((tool) => tool.category === "mongodb")] * ``` * * Note: Ensure that each tool has unique names otherwise the server will * throw an error when initializing an MCP Client session. If you're using * only the internal tools, then you don't have to worry about it unless, * you've overridden the tool names. * * To ensure that you provide compliant tool implementations extend your * tool implementation using `ToolBase` class and ensure that they conform * to `ToolClass` type. * * @see {@link ToolClass} for the type that tool classes must conform to * @see {@link ToolBase} for base class for all the tools */ tools?: ToolClass[]; /** * An optional function to hook into session configuration lifecycle and * provide session specific configuration (`UserConfig`). * * The function is called before each session is created, allowing you to: * - Fetch configuration from external sources (secrets managers, APIs) * - Apply user-specific permissions and limits * - Modify connection strings dynamically * - Validate authentication credentials * * This function is called for each new MCP client connection. For stdio * transport, this is called once at server startup. For HTTP transport, * this is called for each new session. */ createSessionConfig?: CreateSessionConfigFn; }; export abstract class TransportRunnerBase { public logger: LoggerBase; public deviceId: DeviceId; protected readonly userConfig: UserConfig; private readonly createConnectionManager: ConnectionManagerFactoryFn; private readonly connectionErrorHandler: ConnectionErrorHandler; private readonly atlasLocalClient: Promise<Client | undefined>; private readonly telemetryProperties: Partial<CommonProperties>; private readonly tools?: ToolClass[]; private readonly createSessionConfig?: CreateSessionConfigFn; protected constructor({ userConfig, createConnectionManager = createMCPConnectionManager, connectionErrorHandler = defaultConnectionErrorHandler, createAtlasLocalClient = defaultCreateAtlasLocalClient, additionalLoggers = [], telemetryProperties = {}, tools, createSessionConfig, }: TransportRunnerConfig) { this.userConfig = userConfig; this.createConnectionManager = createConnectionManager; this.connectionErrorHandler = connectionErrorHandler; this.atlasLocalClient = createAtlasLocalClient(); this.telemetryProperties = telemetryProperties; this.tools = tools; this.createSessionConfig = createSessionConfig; const loggers: LoggerBase[] = [...additionalLoggers]; if (this.userConfig.loggers.includes("stderr")) { loggers.push(new ConsoleLogger(Keychain.root)); } if (this.userConfig.loggers.includes("disk")) { loggers.push( new DiskLogger( this.userConfig.logPath, (err) => { // If the disk logger fails to initialize, we log the error to stderr and exit console.error("Error initializing disk logger:", err); process.exit(1); }, Keychain.root ) ); } this.logger = new CompositeLogger(...loggers); this.deviceId = DeviceId.create(this.logger); } protected async setupServer(request?: RequestContext): Promise<Server> { let userConfig: UserConfig = this.userConfig; if (this.createSessionConfig) { userConfig = await this.createSessionConfig({ userConfig, request }); } else { userConfig = applyConfigOverrides({ baseConfig: this.userConfig, request }); } const mcpServer = new McpServer( { name: packageInfo.mcpServerName, version: packageInfo.version, }, { instructions: TransportRunnerBase.getInstructions(userConfig), } ); const logger = new CompositeLogger(this.logger); const exportsManager = ExportsManager.init(userConfig, logger); const connectionManager = await this.createConnectionManager({ logger, userConfig, deviceId: this.deviceId, }); const session = new Session({ userConfig, atlasLocalClient: await this.atlasLocalClient, logger, exportsManager, connectionManager, keychain: Keychain.root, vectorSearchEmbeddingsManager: new VectorSearchEmbeddingsManager(userConfig, connectionManager), }); const telemetry = Telemetry.create(session, userConfig, this.deviceId, { commonProperties: this.telemetryProperties, }); const elicitation = new Elicitation({ server: mcpServer.server }); const result = new Server({ mcpServer, session, telemetry, userConfig, connectionErrorHandler: this.connectionErrorHandler, elicitation, tools: this.tools, }); // We need to create the MCP logger after the server is constructed // because it needs the server instance if (userConfig.loggers.includes("mcp")) { logger.addLogger(new McpLogger(result, Keychain.root)); } return result; } abstract start(): Promise<void>; abstract closeTransport(): Promise<void>; async close(): Promise<void> { try { await this.closeTransport(); } finally { this.deviceId.close(); } } private static getInstructions(config: UserConfig): string { let instructions = ` This is the MongoDB MCP server. `; if (config.connectionString) { instructions += ` This MCP server was configured with a MongoDB connection string, and you can assume that you are connected to a MongoDB cluster. `; } if (config.apiClientId && config.apiClientSecret) { instructions += ` This MCP server was configured with MongoDB Atlas API credentials.`; } return instructions; } }

Latest Blog Posts

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