Skip to content

Commit 74a2f0f

Browse files
authored
Add config option for connection string (#56)
1 parent f278e4f commit 74a2f0f

22 files changed

+96
-42
lines changed

src/config.ts

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,34 @@ import argv from "yargs-parser";
44

55
import packageJson from "../package.json" with { type: "json" };
66
import fs from "fs";
7+
import { ReadConcernLevel, ReadPreferenceMode, W } from "mongodb";
78
const { localDataPath, configPath } = getLocalDataPath();
89

910
// If we decide to support non-string config options, we'll need to extend the mechanism for parsing
1011
// env variables.
11-
interface UserConfig extends Record<string, string | undefined> {
12+
interface UserConfig {
1213
apiBaseUrl: string;
1314
clientId: string;
1415
stateFile: string;
1516
connectionString?: string;
17+
connectOptions: {
18+
readConcern: ReadConcernLevel;
19+
readPreference: ReadPreferenceMode;
20+
writeConcern: W;
21+
timeoutMS: number;
22+
};
1623
}
1724

1825
const defaults: UserConfig = {
1926
apiBaseUrl: "https://cloud.mongodb.com/",
2027
clientId: "0oabtxactgS3gHIR0297",
2128
stateFile: path.join(localDataPath, "state.json"),
29+
connectOptions: {
30+
readConcern: "local",
31+
readPreference: "secondaryPreferred",
32+
writeConcern: "majority",
33+
timeoutMS: 30_000,
34+
},
2235
};
2336

2437
const mergedUserConfig = {
@@ -66,21 +79,52 @@ function getLocalDataPath(): { localDataPath: string; configPath: string } {
6679
// are prefixed with `MDB_MCP_` and the keys match the UserConfig keys, but are converted
6780
// to SNAKE_UPPER_CASE.
6881
function getEnvConfig(): Partial<UserConfig> {
69-
const camelCaseToSNAKE_UPPER_CASE = (str: string): string => {
70-
return str.replace(/([a-z])([A-Z])/g, "$1_$2").toUpperCase();
71-
};
82+
function setValue(obj: Record<string, unknown>, path: string[], value: string): void {
83+
const currentField = path.shift()!;
84+
if (path.length === 0) {
85+
const numberValue = Number(value);
86+
if (!isNaN(numberValue)) {
87+
obj[currentField] = numberValue;
88+
return;
89+
}
90+
91+
const booleanValue = value.toLocaleLowerCase();
92+
if (booleanValue === "true" || booleanValue === "false") {
93+
obj[currentField] = booleanValue === "true";
94+
return;
95+
}
96+
97+
obj[currentField] = value;
98+
return;
99+
}
72100

73-
const result: Partial<UserConfig> = {};
74-
for (const key of Object.keys(defaults)) {
75-
const envVarName = `MDB_MCP_${camelCaseToSNAKE_UPPER_CASE(key)}`;
76-
if (process.env[envVarName]) {
77-
result[key] = process.env[envVarName];
101+
if (!obj[currentField]) {
102+
obj[currentField] = {};
78103
}
104+
105+
setValue(obj[currentField] as Record<string, unknown>, path, value);
106+
}
107+
108+
const result: Record<string, unknown> = {};
109+
const mcpVariables = Object.entries(process.env).filter(
110+
([key, value]) => value !== undefined && key.startsWith("MDB_MCP_")
111+
) as [string, string][];
112+
for (const [key, value] of mcpVariables) {
113+
const fieldPath = key
114+
.replace("MDB_MCP_", "")
115+
.split(".")
116+
.map((part) => SNAKE_CASE_toCamelCase(part));
117+
118+
setValue(result, fieldPath, value);
79119
}
80120

81121
return result;
82122
}
83123

124+
function SNAKE_CASE_toCamelCase(str: string): string {
125+
return str.toLowerCase().replace(/([-_][a-z])/g, (group) => group.toUpperCase().replace("_", ""));
126+
}
127+
84128
// Gets the config supplied by the user as a JSON file. The file is expected to be located in the local data path
85129
// and named `config.json`.
86130
function getFileConfig(): Partial<UserConfig> {

src/tools/mongodb/collectionIndexes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export class CollectionIndexesTool extends MongoDBToolBase {
99
protected operationType: DbOperationType = "read";
1010

1111
protected async execute({ database, collection }: ToolArgs<typeof DbOperationArgs>): Promise<CallToolResult> {
12-
const provider = this.ensureConnected();
12+
const provider = await this.ensureConnected();
1313
const indexes = await provider.getIndexes(database, collection);
1414

1515
return {

src/tools/mongodb/connect.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { z } from "zod";
22
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3-
import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver";
43
import { DbOperationType, MongoDBToolBase } from "./mongodbTool.js";
54
import { ToolArgs } from "../tool.js";
65
import { ErrorCodes, MongoDBError } from "../../errors.js";
@@ -58,21 +57,10 @@ export class ConnectTool extends MongoDBToolBase {
5857
throw new MongoDBError(ErrorCodes.InvalidParams, "Invalid connection options");
5958
}
6059

61-
await this.connect(connectionString);
60+
await this.connectToMongoDB(connectionString, this.state);
6261

6362
return {
6463
content: [{ type: "text", text: `Successfully connected to ${connectionString}.` }],
6564
};
6665
}
67-
68-
private async connect(connectionString: string): Promise<void> {
69-
const provider = await NodeDriverServiceProvider.connect(connectionString, {
70-
productDocsLink: "https://docs.mongodb.com/todo-mcp",
71-
productName: "MongoDB MCP",
72-
});
73-
74-
this.state.serviceProvider = provider;
75-
this.state.credentials.connectionString = connectionString;
76-
await this.state.persistCredentials();
77-
}
7866
}

src/tools/mongodb/create/insertMany.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class InsertManyTool extends MongoDBToolBase {
2121
collection,
2222
documents,
2323
}: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
24-
const provider = this.ensureConnected();
24+
const provider = await this.ensureConnected();
2525
const result = await provider.insertMany(database, collection, documents);
2626

2727
return {

src/tools/mongodb/create/insertOne.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class InsertOneTool extends MongoDBToolBase {
2323
collection,
2424
document,
2525
}: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
26-
const provider = this.ensureConnected();
26+
const provider = await this.ensureConnected();
2727
const result = await provider.insertOne(database, collection, document);
2828

2929
return {

src/tools/mongodb/createIndex.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export class CreateIndexTool extends MongoDBToolBase {
1515
protected operationType: DbOperationType = "create";
1616

1717
protected async execute({ database, collection, keys }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
18-
const provider = this.ensureConnected();
18+
const provider = await this.ensureConnected();
1919
const indexes = await provider.createIndexes(database, collection, [
2020
{
2121
key: keys,

src/tools/mongodb/delete/deleteMany.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class DeleteManyTool extends MongoDBToolBase {
2323
collection,
2424
filter,
2525
}: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
26-
const provider = this.ensureConnected();
26+
const provider = await this.ensureConnected();
2727
const result = await provider.deleteMany(database, collection, filter);
2828

2929
return {

src/tools/mongodb/delete/deleteOne.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class DeleteOneTool extends MongoDBToolBase {
2323
collection,
2424
filter,
2525
}: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
26-
const provider = this.ensureConnected();
26+
const provider = await this.ensureConnected();
2727
const result = await provider.deleteOne(database, collection, filter);
2828

2929
return {

src/tools/mongodb/delete/dropCollection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export class DropCollectionTool extends MongoDBToolBase {
1212
protected operationType: DbOperationType = "delete";
1313

1414
protected async execute({ database, collection }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
15-
const provider = this.ensureConnected();
15+
const provider = await this.ensureConnected();
1616
const result = await provider.dropCollection(database, collection);
1717

1818
return {

src/tools/mongodb/delete/dropDatabase.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export class DropDatabaseTool extends MongoDBToolBase {
1111
protected operationType: DbOperationType = "delete";
1212

1313
protected async execute({ database }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
14-
const provider = this.ensureConnected();
14+
const provider = await this.ensureConnected();
1515
const result = await provider.dropDatabase(database);
1616

1717
return {

0 commit comments

Comments
 (0)