Skip to content

Commit ed59914

Browse files
committed
refactor: move configuration to be passed
1 parent 9ba243d commit ed59914

File tree

12 files changed

+62
-94
lines changed

12 files changed

+62
-94
lines changed

src/common/atlas/apiClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import config from "../../config.js";
1+
import version from "../../version.js";
22
import createClient, { Client, FetchOptions, Middleware } from "openapi-fetch";
33
import { AccessToken, ClientCredentials } from "simple-oauth2";
44
import { ApiClientError } from "./apiClientError.js";
@@ -67,7 +67,7 @@ export class ApiClient {
6767
baseUrl: options?.baseUrl || "https://cloud.mongodb.com/",
6868
userAgent:
6969
options?.userAgent ||
70-
`AtlasMCP/${config.version} (${process.platform}; ${process.arch}; ${process.env.HOSTNAME || "unknown"})`,
70+
`AtlasMCP/${version} (${process.platform}; ${process.arch}; ${process.env.HOSTNAME || "unknown"})`,
7171
};
7272

7373
this.client = createClient<paths>({

src/config.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ import path from "path";
22
import os from "os";
33
import argv from "yargs-parser";
44

5-
import packageJson from "../package.json" with { type: "json" };
65
import { ReadConcernLevel, ReadPreferenceMode, W } from "mongodb";
76

87
// If we decide to support non-string config options, we'll need to extend the mechanism for parsing
98
// env variables.
10-
interface UserConfig {
9+
export interface UserConfig {
1110
apiBaseUrl?: string;
1211
apiClientId?: string;
1312
apiClientSecret?: string;
@@ -33,17 +32,12 @@ const defaults: UserConfig = {
3332
disabledTools: [],
3433
};
3534

36-
const mergedUserConfig = {
35+
export const config = {
3736
...defaults,
3837
...getEnvConfig(),
3938
...getCliConfig(),
4039
};
4140

42-
const config = {
43-
...mergedUserConfig,
44-
version: packageJson.version,
45-
};
46-
4741
export default config;
4842

4943
function getLogPath(): string {

src/index.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,11 @@
33
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
44
import logger from "./logger.js";
55
import { mongoLogId } from "mongodb-log-writer";
6-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7-
import config from "./config.js";
8-
import { Session } from "./session.js";
96
import { Server } from "./server.js";
7+
import config from "./config.js";
108

119
try {
12-
const session = new Session();
13-
const mcpServer = new McpServer({
14-
name: "MongoDB Atlas",
15-
version: config.version,
16-
});
17-
18-
const server = new Server({
19-
mcpServer,
20-
session,
21-
});
10+
const server = new Server(config);
2211

2312
const transport = new StdioServerTransport();
2413

src/logger.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import fs from "fs/promises";
22
import { MongoLogId, MongoLogManager, MongoLogWriter } from "mongodb-log-writer";
3-
import config from "./config.js";
43
import redact from "mongodb-redact";
54
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
65
import { LoggingMessageNotification } from "@modelcontextprotocol/sdk/types.js";
@@ -98,11 +97,11 @@ class ProxyingLogger extends LoggerBase {
9897
const logger = new ProxyingLogger();
9998
export default logger;
10099

101-
export async function initializeLogger(server: McpServer): Promise<void> {
102-
await fs.mkdir(config.logPath, { recursive: true });
100+
export async function initializeLogger(server: McpServer, logPath: string): Promise<void> {
101+
await fs.mkdir(logPath, { recursive: true });
103102

104103
const manager = new MongoLogManager({
105-
directory: config.logPath,
104+
directory: logPath,
106105
retentionDays: 30,
107106
onwarn: console.warn,
108107
onerror: console.error,

src/server.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,22 @@ import { AtlasTools } from "./tools/atlas/tools.js";
55
import { MongoDbTools } from "./tools/mongodb/tools.js";
66
import logger, { initializeLogger } from "./logger.js";
77
import { mongoLogId } from "mongodb-log-writer";
8-
import config from "./config.js";
8+
import { UserConfig } from "./config.js";
9+
import version from "./version.js";
910

1011
export class Server {
1112
public readonly session: Session;
12-
private readonly mcpServer: McpServer;
13+
private readonly mcpServer: McpServer = new McpServer({
14+
name: "MongoDB Atlas",
15+
version,
16+
});
1317

14-
constructor({ mcpServer, session }: { mcpServer: McpServer; session: Session }) {
15-
this.mcpServer = mcpServer;
16-
this.session = session;
18+
constructor(private readonly config: UserConfig) {
19+
this.session = new Session({
20+
apiBaseUrl: config.apiBaseUrl,
21+
apiClientId: config.apiClientId,
22+
apiClientSecret: config.apiClientSecret,
23+
});
1724
}
1825

1926
async connect(transport: Transport) {
@@ -22,7 +29,7 @@ export class Server {
2229
this.registerTools();
2330
this.registerResources();
2431

25-
await initializeLogger(this.mcpServer);
32+
await initializeLogger(this.mcpServer, this.config.logPath);
2633

2734
await this.mcpServer.connect(transport);
2835

@@ -36,12 +43,12 @@ export class Server {
3643

3744
private registerTools() {
3845
for (const tool of [...AtlasTools, ...MongoDbTools]) {
39-
new tool(this.session).register(this.mcpServer);
46+
new tool(this.session, this.config).register(this.mcpServer);
4047
}
4148
}
4249

4350
private registerResources() {
44-
if (config.connectionString) {
51+
if (this.config.connectionString) {
4552
this.mcpServer.resource(
4653
"connection-string",
4754
"config://connection-string",
@@ -52,7 +59,7 @@ export class Server {
5259
return {
5360
contents: [
5461
{
55-
text: `Preconfigured connection string: ${config.connectionString}`,
62+
text: `Preconfigured connection string: ${this.config.connectionString}`,
5663
uri: uri.href,
5764
},
5865
],

src/session.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver";
22
import { ApiClient, ApiClientCredentials } from "./common/atlas/apiClient.js";
3-
import config from "./config.js";
3+
4+
export interface SessionOptions {
5+
apiBaseUrl?: string;
6+
apiClientId?: string;
7+
apiClientSecret?: string;
8+
}
49

510
export class Session {
611
serviceProvider?: NodeDriverServiceProvider;
712
apiClient: ApiClient;
813

9-
constructor() {
14+
constructor(options?: SessionOptions) {
1015
const credentials: ApiClientCredentials | undefined =
11-
config.apiClientId && config.apiClientSecret
16+
options?.apiClientId && options?.apiClientSecret
1217
? {
13-
clientId: config.apiClientId,
14-
clientSecret: config.apiClientSecret,
18+
clientId: options?.apiClientId,
19+
clientSecret: options?.apiClientSecret,
1520
}
1621
: undefined;
1722

1823
this.apiClient = new ApiClient({
19-
baseUrl: config.apiBaseUrl,
24+
baseUrl: options?.apiBaseUrl,
2025
credentials,
2126
});
2227
}

src/tools/atlas/atlasTool.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
import { ToolBase, ToolCategory } from "../tool.js";
2-
import { Session } from "../../session.js";
3-
import config from "../../config.js";
42

53
export abstract class AtlasToolBase extends ToolBase {
6-
constructor(protected readonly session: Session) {
7-
super(session);
8-
}
9-
104
protected category: ToolCategory = "atlas";
115

126
protected verifyAllowed(): boolean {
13-
if (!config.apiClientId || !config.apiClientSecret) {
7+
if (!this.config.apiClientId || !this.config.apiClientSecret) {
148
return false;
159
}
1610
return super.verifyAllowed();

src/tools/mongodb/metadata/connect.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { z } from "zod";
22
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
33
import { MongoDBToolBase } from "../mongodbTool.js";
44
import { ToolArgs, OperationType } from "../../tool.js";
5-
import config from "../../../config.js";
65
import { MongoError as DriverError } from "mongodb";
76

87
export class ConnectTool extends MongoDBToolBase {
@@ -35,7 +34,7 @@ export class ConnectTool extends MongoDBToolBase {
3534
protected async execute({ options: optionsArr }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
3635
const options = optionsArr?.[0];
3736
let connectionString: string;
38-
if (!options && !config.connectionString) {
37+
if (!options && !this.config.connectionString) {
3938
return {
4039
content: [
4140
{ type: "text", text: "No connection details provided." },
@@ -46,7 +45,7 @@ export class ConnectTool extends MongoDBToolBase {
4645

4746
if (!options) {
4847
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
49-
connectionString = config.connectionString!;
48+
connectionString = this.config.connectionString!;
5049
} else if ("connectionString" in options) {
5150
connectionString = options.connectionString;
5251
} else {
@@ -72,17 +71,17 @@ export class ConnectTool extends MongoDBToolBase {
7271
// Sometimes the model will supply an incorrect connection string. If the user has configured
7372
// a different one as environment variable or a cli argument, suggest using that one instead.
7473
if (
75-
config.connectionString &&
74+
this.config.connectionString &&
7675
error instanceof DriverError &&
77-
config.connectionString !== connectionString
76+
this.config.connectionString !== connectionString
7877
) {
7978
return {
8079
content: [
8180
{
8281
type: "text",
8382
text:
8483
`Failed to connect to MongoDB at '${connectionString}' due to error: '${error.message}.` +
85-
`Your config lists a different connection string: '${config.connectionString}' - do you want to try connecting to it instead?`,
84+
`Your config lists a different connection string: '${this.config.connectionString}' - do you want to try connecting to it instead?`,
8685
},
8786
],
8887
};

src/tools/mongodb/mongodbTool.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,20 @@
11
import { z } from "zod";
22
import { ToolBase, ToolCategory } from "../tool.js";
3-
import { Session } from "../../session.js";
43
import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver";
54
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
65
import { ErrorCodes, MongoDBError } from "../../errors.js";
7-
import config from "../../config.js";
86

97
export const DbOperationArgs = {
108
database: z.string().describe("Database name"),
119
collection: z.string().describe("Collection name"),
1210
};
1311

1412
export abstract class MongoDBToolBase extends ToolBase {
15-
constructor(session: Session) {
16-
super(session);
17-
}
18-
1913
protected category: ToolCategory = "mongodb";
2014

2115
protected async ensureConnected(): Promise<NodeDriverServiceProvider> {
22-
if (!this.session.serviceProvider && config.connectionString) {
23-
await this.connectToMongoDB(config.connectionString);
16+
if (!this.session.serviceProvider && this.config.connectionString) {
17+
await this.connectToMongoDB(this.config.connectionString);
2418
}
2519

2620
if (!this.session.serviceProvider) {
@@ -55,13 +49,13 @@ export abstract class MongoDBToolBase extends ToolBase {
5549
productDocsLink: "https://docs.mongodb.com/todo-mcp",
5650
productName: "MongoDB MCP",
5751
readConcern: {
58-
level: config.connectOptions.readConcern,
52+
level: this.config.connectOptions.readConcern,
5953
},
60-
readPreference: config.connectOptions.readPreference,
54+
readPreference: this.config.connectOptions.readPreference,
6155
writeConcern: {
62-
w: config.connectOptions.writeConcern,
56+
w: this.config.connectOptions.writeConcern,
6357
},
64-
timeoutMS: config.connectOptions.timeoutMS,
58+
timeoutMS: this.config.connectOptions.timeoutMS,
6559
});
6660

6761
this.session.serviceProvider = provider;

src/tools/tool.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
44
import { Session } from "../session.js";
55
import logger from "../logger.js";
66
import { mongoLogId } from "mongodb-log-writer";
7-
import config from "../config.js";
7+
import { UserConfig } from "../config.js";
88

99
export type ToolArgs<Args extends ZodRawShape> = z.objectOutputType<Args, ZodNever>;
1010

@@ -24,7 +24,10 @@ export abstract class ToolBase {
2424

2525
protected abstract execute(...args: Parameters<ToolCallback<typeof this.argsShape>>): Promise<CallToolResult>;
2626

27-
protected constructor(protected session: Session) {}
27+
constructor(
28+
protected readonly session: Session,
29+
protected readonly config: UserConfig
30+
) {}
2831

2932
public register(server: McpServer): void {
3033
if (!this.verifyAllowed()) {
@@ -54,11 +57,11 @@ export abstract class ToolBase {
5457
// Checks if a tool is allowed to run based on the config
5558
protected verifyAllowed(): boolean {
5659
let errorClarification: string | undefined;
57-
if (config.disabledTools.includes(this.category)) {
60+
if (this.config.disabledTools.includes(this.category)) {
5861
errorClarification = `its category, \`${this.category}\`,`;
59-
} else if (config.disabledTools.includes(this.operationType)) {
62+
} else if (this.config.disabledTools.includes(this.operationType)) {
6063
errorClarification = `its operation type, \`${this.operationType}\`,`;
61-
} else if (config.disabledTools.includes(this.name)) {
64+
} else if (this.config.disabledTools.includes(this.name)) {
6265
errorClarification = `it`;
6366
}
6467

0 commit comments

Comments
 (0)