From 70077eff935b6f2c592dcf05f6b12e5fe5db4121 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Thu, 10 Apr 2025 21:32:05 +0200 Subject: [PATCH 1/4] feat: add connection config --- src/config.ts | 61 ++++++++++++++++++++++++++++++------ src/tools/mongodb/connect.ts | 6 ++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/config.ts b/src/config.ts index 63bba69d..8de09234 100644 --- a/src/config.ts +++ b/src/config.ts @@ -4,21 +4,34 @@ import argv from "yargs-parser"; import packageJson from "../package.json" with { type: "json" }; import fs from "fs"; +import { ReadConcernLevel, ReadPreferenceMode, W } from "mongodb"; const { localDataPath, configPath } = getLocalDataPath(); // If we decide to support non-string config options, we'll need to extend the mechanism for parsing // env variables. -interface UserConfig extends Record { +interface UserConfig extends Record { apiBaseUrl: string; clientId: string; stateFile: string; connectionString?: string; + connectOptions: { + readConcern: ReadConcernLevel; + readPreference: ReadPreferenceMode; + writeConcern: W; + timeoutMS: number; + }; } const defaults: UserConfig = { apiBaseUrl: "https://cloud.mongodb.com/", clientId: "0oabtxactgS3gHIR0297", stateFile: path.join(localDataPath, "state.json"), + connectOptions: { + readConcern: "local", + readPreference: "secondaryPreferred", + writeConcern: "majority", + timeoutMS: 30_000, + }, }; const mergedUserConfig = { @@ -66,21 +79,51 @@ function getLocalDataPath(): { localDataPath: string; configPath: string } { // are prefixed with `MDB_MCP_` and the keys match the UserConfig keys, but are converted // to SNAKE_UPPER_CASE. function getEnvConfig(): Partial { - const camelCaseToSNAKE_UPPER_CASE = (str: string): string => { - return str.replace(/([a-z])([A-Z])/g, "$1_$2").toUpperCase(); - }; + function setValue(obj: Record, path: string[], value: string): void { + const currentField = path.shift()!; + if (path.length === 0) { + const numberValue = Number(value); + if (!isNaN(numberValue)) { + obj[currentField] = numberValue; + return; + } + + const booleanValue = value.toLocaleLowerCase(); + if (booleanValue === "true" || booleanValue === "false") { + obj[currentField] = booleanValue === "true"; + return; + } + + obj[currentField] = value; + return; + } - const result: Partial = {}; - for (const key of Object.keys(defaults)) { - const envVarName = `MDB_MCP_${camelCaseToSNAKE_UPPER_CASE(key)}`; - if (process.env[envVarName]) { - result[key] = process.env[envVarName]; + if (!obj[currentField]) { + obj[currentField] = {}; } + + setValue(obj[currentField] as Record, path, value); + } + + const result: Record = {}; + for (const [key, value] of Object.entries(process.env).filter( + ([key, value]) => value !== undefined && key.startsWith("MDB_MCP_") + )) { + const fieldPath = key + .replace("MDB_MCP_", "") + .split(".") + .map((part) => SNAKE_CASE_toCamelCase(part)); + + setValue(result, fieldPath, value!); } return result; } +function SNAKE_CASE_toCamelCase(str: string): string { + return str.toLowerCase().replace(/([-_][a-z])/g, (group) => group.toUpperCase().replace("_", "")); +} + // Gets the config supplied by the user as a JSON file. The file is expected to be located in the local data path // and named `config.json`. function getFileConfig(): Partial { diff --git a/src/tools/mongodb/connect.ts b/src/tools/mongodb/connect.ts index 6055311b..fc7113ef 100644 --- a/src/tools/mongodb/connect.ts +++ b/src/tools/mongodb/connect.ts @@ -69,6 +69,12 @@ export class ConnectTool extends MongoDBToolBase { const provider = await NodeDriverServiceProvider.connect(connectionString, { productDocsLink: "https://docs.mongodb.com/todo-mcp", productName: "MongoDB MCP", + readConcern: config.connectOptions.readConcern, + readPreference: config.connectOptions.readPreference, + writeConcern: { + w: config.connectOptions.writeConcern, + }, + timeoutMS: config.connectOptions.timeoutMS, }); this.state.serviceProvider = provider; From 95f3b1eb18f08a6b33a7c11ab52120d3b4645a1a Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Thu, 10 Apr 2025 22:03:49 +0200 Subject: [PATCH 2/4] automatically connect if config connection string is provided --- src/common/mongodb/connect.ts | 20 ++++++++++++++++++++ src/tools/mongodb/connect.ts | 20 ++------------------ src/tools/mongodb/mongodbTool.ts | 8 +++++++- 3 files changed, 29 insertions(+), 19 deletions(-) create mode 100644 src/common/mongodb/connect.ts diff --git a/src/common/mongodb/connect.ts b/src/common/mongodb/connect.ts new file mode 100644 index 00000000..9230ec8c --- /dev/null +++ b/src/common/mongodb/connect.ts @@ -0,0 +1,20 @@ +import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver"; +import { State } from "../../state.js"; +import config from "../../config.js"; + +export async function connectToMongoDB(connectionString: string, state: State): Promise { + const provider = await NodeDriverServiceProvider.connect(connectionString, { + productDocsLink: "https://docs.mongodb.com/todo-mcp", + productName: "MongoDB MCP", + readConcern: config.connectOptions.readConcern, + readPreference: config.connectOptions.readPreference, + writeConcern: { + w: config.connectOptions.writeConcern, + }, + timeoutMS: config.connectOptions.timeoutMS, + }); + + state.serviceProvider = provider; + state.credentials.connectionString = connectionString; + await state.persistCredentials(); +} diff --git a/src/tools/mongodb/connect.ts b/src/tools/mongodb/connect.ts index fc7113ef..cf4e77e3 100644 --- a/src/tools/mongodb/connect.ts +++ b/src/tools/mongodb/connect.ts @@ -5,6 +5,7 @@ import { DbOperationType, MongoDBToolBase } from "./mongodbTool.js"; import { ToolArgs } from "../tool.js"; import { ErrorCodes, MongoDBError } from "../../errors.js"; import config from "../../config.js"; +import { connectToMongoDB } from "../../common/mongodb/connect.js"; export class ConnectTool extends MongoDBToolBase { protected name = "connect"; @@ -58,27 +59,10 @@ export class ConnectTool extends MongoDBToolBase { throw new MongoDBError(ErrorCodes.InvalidParams, "Invalid connection options"); } - await this.connect(connectionString); + await connectToMongoDB(connectionString, this.state); return { content: [{ type: "text", text: `Successfully connected to ${connectionString}.` }], }; } - - private async connect(connectionString: string): Promise { - const provider = await NodeDriverServiceProvider.connect(connectionString, { - productDocsLink: "https://docs.mongodb.com/todo-mcp", - productName: "MongoDB MCP", - readConcern: config.connectOptions.readConcern, - readPreference: config.connectOptions.readPreference, - writeConcern: { - w: config.connectOptions.writeConcern, - }, - timeoutMS: config.connectOptions.timeoutMS, - }); - - this.state.serviceProvider = provider; - this.state.credentials.connectionString = connectionString; - await this.state.persistCredentials(); - } } diff --git a/src/tools/mongodb/mongodbTool.ts b/src/tools/mongodb/mongodbTool.ts index 2031fe29..4d6e7664 100644 --- a/src/tools/mongodb/mongodbTool.ts +++ b/src/tools/mongodb/mongodbTool.ts @@ -4,6 +4,8 @@ import { State } from "../../state.js"; import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver"; import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { ErrorCodes, MongoDBError } from "../../errors.js"; +import config from "../../config.js"; +import { connectToMongoDB } from "../../common/mongodb/connect.js"; export const DbOperationArgs = { database: z.string().describe("Database name"), @@ -19,8 +21,12 @@ export abstract class MongoDBToolBase extends ToolBase { protected abstract operationType: DbOperationType; - protected ensureConnected(): NodeDriverServiceProvider { + protected async ensureConnected(): Promise { const provider = this.state.serviceProvider; + if (!provider && config.connectionString) { + await connectToMongoDB(config.connectionString, this.state); + } + if (!provider) { throw new MongoDBError(ErrorCodes.NotConnectedToMongoDB, "Not connected to MongoDB"); } From 8e18b975e904d262819f8b4108db01b1d53f11d9 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Thu, 10 Apr 2025 22:07:09 +0200 Subject: [PATCH 3/4] add awaits --- src/tools/mongodb/collectionIndexes.ts | 2 +- src/tools/mongodb/connect.ts | 1 - src/tools/mongodb/create/insertMany.ts | 2 +- src/tools/mongodb/create/insertOne.ts | 2 +- src/tools/mongodb/createIndex.ts | 2 +- src/tools/mongodb/delete/deleteMany.ts | 2 +- src/tools/mongodb/delete/deleteOne.ts | 2 +- src/tools/mongodb/delete/dropCollection.ts | 2 +- src/tools/mongodb/delete/dropDatabase.ts | 2 +- src/tools/mongodb/metadata/collectionSchema.ts | 2 +- src/tools/mongodb/metadata/collectionStorageSize.ts | 2 +- src/tools/mongodb/metadata/dbStats.ts | 2 +- src/tools/mongodb/metadata/listCollections.ts | 2 +- src/tools/mongodb/metadata/listDatabases.ts | 2 +- src/tools/mongodb/read/aggregate.ts | 2 +- src/tools/mongodb/read/count.ts | 2 +- src/tools/mongodb/read/find.ts | 2 +- src/tools/mongodb/update/renameCollection.ts | 2 +- src/tools/mongodb/update/updateMany.ts | 2 +- src/tools/mongodb/update/updateOne.ts | 2 +- 20 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/tools/mongodb/collectionIndexes.ts b/src/tools/mongodb/collectionIndexes.ts index 9fa1b46b..4d8cae90 100644 --- a/src/tools/mongodb/collectionIndexes.ts +++ b/src/tools/mongodb/collectionIndexes.ts @@ -9,7 +9,7 @@ export class CollectionIndexesTool extends MongoDBToolBase { protected operationType: DbOperationType = "read"; protected async execute({ database, collection }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const indexes = await provider.getIndexes(database, collection); return { diff --git a/src/tools/mongodb/connect.ts b/src/tools/mongodb/connect.ts index cf4e77e3..ed80f652 100644 --- a/src/tools/mongodb/connect.ts +++ b/src/tools/mongodb/connect.ts @@ -1,6 +1,5 @@ import { z } from "zod"; import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; -import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver"; import { DbOperationType, MongoDBToolBase } from "./mongodbTool.js"; import { ToolArgs } from "../tool.js"; import { ErrorCodes, MongoDBError } from "../../errors.js"; diff --git a/src/tools/mongodb/create/insertMany.ts b/src/tools/mongodb/create/insertMany.ts index d22be0db..fdf1dcbc 100644 --- a/src/tools/mongodb/create/insertMany.ts +++ b/src/tools/mongodb/create/insertMany.ts @@ -21,7 +21,7 @@ export class InsertManyTool extends MongoDBToolBase { collection, documents, }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const result = await provider.insertMany(database, collection, documents); return { diff --git a/src/tools/mongodb/create/insertOne.ts b/src/tools/mongodb/create/insertOne.ts index f55d3089..b490efd4 100644 --- a/src/tools/mongodb/create/insertOne.ts +++ b/src/tools/mongodb/create/insertOne.ts @@ -23,7 +23,7 @@ export class InsertOneTool extends MongoDBToolBase { collection, document, }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const result = await provider.insertOne(database, collection, document); return { diff --git a/src/tools/mongodb/createIndex.ts b/src/tools/mongodb/createIndex.ts index 52bd1abc..30bc17af 100644 --- a/src/tools/mongodb/createIndex.ts +++ b/src/tools/mongodb/createIndex.ts @@ -15,7 +15,7 @@ export class CreateIndexTool extends MongoDBToolBase { protected operationType: DbOperationType = "create"; protected async execute({ database, collection, keys }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const indexes = await provider.createIndexes(database, collection, [ { key: keys, diff --git a/src/tools/mongodb/delete/deleteMany.ts b/src/tools/mongodb/delete/deleteMany.ts index 4c433ed3..5702b54a 100644 --- a/src/tools/mongodb/delete/deleteMany.ts +++ b/src/tools/mongodb/delete/deleteMany.ts @@ -23,7 +23,7 @@ export class DeleteManyTool extends MongoDBToolBase { collection, filter, }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const result = await provider.deleteMany(database, collection, filter); return { diff --git a/src/tools/mongodb/delete/deleteOne.ts b/src/tools/mongodb/delete/deleteOne.ts index 1d7a047c..3c9a2e57 100644 --- a/src/tools/mongodb/delete/deleteOne.ts +++ b/src/tools/mongodb/delete/deleteOne.ts @@ -23,7 +23,7 @@ export class DeleteOneTool extends MongoDBToolBase { collection, filter, }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const result = await provider.deleteOne(database, collection, filter); return { diff --git a/src/tools/mongodb/delete/dropCollection.ts b/src/tools/mongodb/delete/dropCollection.ts index d5c2a550..b6444da6 100644 --- a/src/tools/mongodb/delete/dropCollection.ts +++ b/src/tools/mongodb/delete/dropCollection.ts @@ -12,7 +12,7 @@ export class DropCollectionTool extends MongoDBToolBase { protected operationType: DbOperationType = "delete"; protected async execute({ database, collection }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const result = await provider.dropCollection(database, collection); return { diff --git a/src/tools/mongodb/delete/dropDatabase.ts b/src/tools/mongodb/delete/dropDatabase.ts index 8fb45464..4b126b2c 100644 --- a/src/tools/mongodb/delete/dropDatabase.ts +++ b/src/tools/mongodb/delete/dropDatabase.ts @@ -11,7 +11,7 @@ export class DropDatabaseTool extends MongoDBToolBase { protected operationType: DbOperationType = "delete"; protected async execute({ database }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const result = await provider.dropDatabase(database); return { diff --git a/src/tools/mongodb/metadata/collectionSchema.ts b/src/tools/mongodb/metadata/collectionSchema.ts index d15d4121..f780252d 100644 --- a/src/tools/mongodb/metadata/collectionSchema.ts +++ b/src/tools/mongodb/metadata/collectionSchema.ts @@ -11,7 +11,7 @@ export class CollectionSchemaTool extends MongoDBToolBase { protected operationType: DbOperationType = "metadata"; protected async execute({ database, collection }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const documents = await provider.find(database, collection, {}, { limit: 5 }).toArray(); const schema = await parseSchema(documents); diff --git a/src/tools/mongodb/metadata/collectionStorageSize.ts b/src/tools/mongodb/metadata/collectionStorageSize.ts index 93c91fb5..ab41261d 100644 --- a/src/tools/mongodb/metadata/collectionStorageSize.ts +++ b/src/tools/mongodb/metadata/collectionStorageSize.ts @@ -10,7 +10,7 @@ export class CollectionStorageSizeTool extends MongoDBToolBase { protected operationType: DbOperationType = "metadata"; protected async execute({ database, collection }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const [{ value }] = await provider .aggregate(database, collection, [ { $collStats: { storageStats: {} } }, diff --git a/src/tools/mongodb/metadata/dbStats.ts b/src/tools/mongodb/metadata/dbStats.ts index 03d9a6d6..1223b25b 100644 --- a/src/tools/mongodb/metadata/dbStats.ts +++ b/src/tools/mongodb/metadata/dbStats.ts @@ -12,7 +12,7 @@ export class DbStatsTool extends MongoDBToolBase { protected operationType: DbOperationType = "metadata"; protected async execute({ database }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const result = await provider.runCommandWithCheck(database, { dbStats: 1, scale: 1, diff --git a/src/tools/mongodb/metadata/listCollections.ts b/src/tools/mongodb/metadata/listCollections.ts index 15ef084f..2fc95d3d 100644 --- a/src/tools/mongodb/metadata/listCollections.ts +++ b/src/tools/mongodb/metadata/listCollections.ts @@ -12,7 +12,7 @@ export class ListCollectionsTool extends MongoDBToolBase { protected operationType: DbOperationType = "metadata"; protected async execute({ database }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const collections = await provider.listCollections(database); return { diff --git a/src/tools/mongodb/metadata/listDatabases.ts b/src/tools/mongodb/metadata/listDatabases.ts index 1eca8f7a..7a89d09c 100644 --- a/src/tools/mongodb/metadata/listDatabases.ts +++ b/src/tools/mongodb/metadata/listDatabases.ts @@ -10,7 +10,7 @@ export class ListDatabasesTool extends MongoDBToolBase { protected operationType: DbOperationType = "metadata"; protected async execute(): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const dbs = (await provider.listDatabases("")).databases as { name: string; sizeOnDisk: bson.Long }[]; return { diff --git a/src/tools/mongodb/read/aggregate.ts b/src/tools/mongodb/read/aggregate.ts index f6acb18f..66bc1edb 100644 --- a/src/tools/mongodb/read/aggregate.ts +++ b/src/tools/mongodb/read/aggregate.ts @@ -19,7 +19,7 @@ export class AggregateTool extends MongoDBToolBase { collection, pipeline, }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const documents = await provider.aggregate(database, collection, pipeline).toArray(); const content: Array<{ text: string; type: "text" }> = [ diff --git a/src/tools/mongodb/read/count.ts b/src/tools/mongodb/read/count.ts index 956e160c..8c5f446d 100644 --- a/src/tools/mongodb/read/count.ts +++ b/src/tools/mongodb/read/count.ts @@ -20,7 +20,7 @@ export class CountTool extends MongoDBToolBase { protected operationType: DbOperationType = "metadata"; protected async execute({ database, collection, query }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const count = await provider.count(database, collection, query); return { diff --git a/src/tools/mongodb/read/find.ts b/src/tools/mongodb/read/find.ts index 04392139..54edce8e 100644 --- a/src/tools/mongodb/read/find.ts +++ b/src/tools/mongodb/read/find.ts @@ -38,7 +38,7 @@ export class FindTool extends MongoDBToolBase { limit, sort, }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const documents = await provider.find(database, collection, filter, { projection, limit, sort }).toArray(); const content: Array<{ text: string; type: "text" }> = [ diff --git a/src/tools/mongodb/update/renameCollection.ts b/src/tools/mongodb/update/renameCollection.ts index 967b8ee7..e0c83875 100644 --- a/src/tools/mongodb/update/renameCollection.ts +++ b/src/tools/mongodb/update/renameCollection.ts @@ -20,7 +20,7 @@ export class RenameCollectionTool extends MongoDBToolBase { newName, dropTarget, }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const result = await provider.renameCollection(database, collection, newName, { dropTarget, }); diff --git a/src/tools/mongodb/update/updateMany.ts b/src/tools/mongodb/update/updateMany.ts index 159399cd..e692c36b 100644 --- a/src/tools/mongodb/update/updateMany.ts +++ b/src/tools/mongodb/update/updateMany.ts @@ -35,7 +35,7 @@ export class UpdateManyTool extends MongoDBToolBase { update, upsert, }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const result = await provider.updateMany(database, collection, filter, update, { upsert, }); diff --git a/src/tools/mongodb/update/updateOne.ts b/src/tools/mongodb/update/updateOne.ts index bd9df030..b1a604c6 100644 --- a/src/tools/mongodb/update/updateOne.ts +++ b/src/tools/mongodb/update/updateOne.ts @@ -35,7 +35,7 @@ export class UpdateOneTool extends MongoDBToolBase { update, upsert, }: ToolArgs): Promise { - const provider = this.ensureConnected(); + const provider = await this.ensureConnected(); const result = await provider.updateOne(database, collection, filter, update, { upsert, }); From 92c0e8875c7c20eae8074701938634f679c47fb1 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Fri, 11 Apr 2025 12:03:48 +0200 Subject: [PATCH 4/4] address PR feedback --- src/common/mongodb/connect.ts | 20 -------------------- src/config.ts | 9 +++++---- src/tools/mongodb/connect.ts | 3 +-- src/tools/mongodb/mongodbTool.ts | 20 ++++++++++++++++++-- 4 files changed, 24 insertions(+), 28 deletions(-) delete mode 100644 src/common/mongodb/connect.ts diff --git a/src/common/mongodb/connect.ts b/src/common/mongodb/connect.ts deleted file mode 100644 index 9230ec8c..00000000 --- a/src/common/mongodb/connect.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver"; -import { State } from "../../state.js"; -import config from "../../config.js"; - -export async function connectToMongoDB(connectionString: string, state: State): Promise { - const provider = await NodeDriverServiceProvider.connect(connectionString, { - productDocsLink: "https://docs.mongodb.com/todo-mcp", - productName: "MongoDB MCP", - readConcern: config.connectOptions.readConcern, - readPreference: config.connectOptions.readPreference, - writeConcern: { - w: config.connectOptions.writeConcern, - }, - timeoutMS: config.connectOptions.timeoutMS, - }); - - state.serviceProvider = provider; - state.credentials.connectionString = connectionString; - await state.persistCredentials(); -} diff --git a/src/config.ts b/src/config.ts index 8de09234..f4d437a6 100644 --- a/src/config.ts +++ b/src/config.ts @@ -9,7 +9,7 @@ const { localDataPath, configPath } = getLocalDataPath(); // If we decide to support non-string config options, we'll need to extend the mechanism for parsing // env variables. -interface UserConfig extends Record { +interface UserConfig { apiBaseUrl: string; clientId: string; stateFile: string; @@ -106,15 +106,16 @@ function getEnvConfig(): Partial { } const result: Record = {}; - for (const [key, value] of Object.entries(process.env).filter( + const mcpVariables = Object.entries(process.env).filter( ([key, value]) => value !== undefined && key.startsWith("MDB_MCP_") - )) { + ) as [string, string][]; + for (const [key, value] of mcpVariables) { const fieldPath = key .replace("MDB_MCP_", "") .split(".") .map((part) => SNAKE_CASE_toCamelCase(part)); - setValue(result, fieldPath, value!); + setValue(result, fieldPath, value); } return result; diff --git a/src/tools/mongodb/connect.ts b/src/tools/mongodb/connect.ts index ed80f652..3ed18fcd 100644 --- a/src/tools/mongodb/connect.ts +++ b/src/tools/mongodb/connect.ts @@ -4,7 +4,6 @@ import { DbOperationType, MongoDBToolBase } from "./mongodbTool.js"; import { ToolArgs } from "../tool.js"; import { ErrorCodes, MongoDBError } from "../../errors.js"; import config from "../../config.js"; -import { connectToMongoDB } from "../../common/mongodb/connect.js"; export class ConnectTool extends MongoDBToolBase { protected name = "connect"; @@ -58,7 +57,7 @@ export class ConnectTool extends MongoDBToolBase { throw new MongoDBError(ErrorCodes.InvalidParams, "Invalid connection options"); } - await connectToMongoDB(connectionString, this.state); + await this.connectToMongoDB(connectionString, this.state); return { content: [{ type: "text", text: `Successfully connected to ${connectionString}.` }], diff --git a/src/tools/mongodb/mongodbTool.ts b/src/tools/mongodb/mongodbTool.ts index 4d6e7664..5ca8a1c5 100644 --- a/src/tools/mongodb/mongodbTool.ts +++ b/src/tools/mongodb/mongodbTool.ts @@ -5,7 +5,6 @@ import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { ErrorCodes, MongoDBError } from "../../errors.js"; import config from "../../config.js"; -import { connectToMongoDB } from "../../common/mongodb/connect.js"; export const DbOperationArgs = { database: z.string().describe("Database name"), @@ -24,7 +23,7 @@ export abstract class MongoDBToolBase extends ToolBase { protected async ensureConnected(): Promise { const provider = this.state.serviceProvider; if (!provider && config.connectionString) { - await connectToMongoDB(config.connectionString, this.state); + await this.connectToMongoDB(config.connectionString, this.state); } if (!provider) { @@ -52,4 +51,21 @@ export abstract class MongoDBToolBase extends ToolBase { return undefined; } + + protected async connectToMongoDB(connectionString: string, state: State): Promise { + const provider = await NodeDriverServiceProvider.connect(connectionString, { + productDocsLink: "https://docs.mongodb.com/todo-mcp", + productName: "MongoDB MCP", + readConcern: config.connectOptions.readConcern, + readPreference: config.connectOptions.readPreference, + writeConcern: { + w: config.connectOptions.writeConcern, + }, + timeoutMS: config.connectOptions.timeoutMS, + }); + + state.serviceProvider = provider; + state.credentials.connectionString = connectionString; + await state.persistCredentials(); + } }