From 676ca276dc34a99d8a2990b20a702a16b997e4da Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Fri, 19 Sep 2025 13:45:09 +0100 Subject: [PATCH 1/5] chore: validate apiBaseUrl --- src/server.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/server.ts b/src/server.ts index 2e6ac2c46..c72638443 100644 --- a/src/server.ts +++ b/src/server.ts @@ -239,6 +239,13 @@ export class Server { // Validate API client credentials if (this.userConfig.apiClientId && this.userConfig.apiClientSecret) { try { + if (!this.userConfig.apiBaseUrl.startsWith("https://")) { + const message = + "Failed to validate MongoDB Atlas the credentials from the config: API URL must be HTTPS"; + console.error(message); + throw new Error(message); + } + await this.session.apiClient.validateAccessToken(); } catch (error) { if (this.userConfig.connectionString === undefined) { From acf048c0ccd89a9a16ff61db4fb4bfc466610431 Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Fri, 19 Sep 2025 14:28:05 +0100 Subject: [PATCH 2/5] address comment --- src/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server.ts b/src/server.ts index c72638443..7d4a10b16 100644 --- a/src/server.ts +++ b/src/server.ts @@ -241,7 +241,7 @@ export class Server { try { if (!this.userConfig.apiBaseUrl.startsWith("https://")) { const message = - "Failed to validate MongoDB Atlas the credentials from the config: API URL must be HTTPS"; + "Failed to validate MongoDB Atlas the credentials from config: apiBaseUrl must start with https://"; console.error(message); throw new Error(message); } From 67923d2c5700a5e3b754e5f6ec344710562cf55e Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 25 Sep 2025 13:11:16 +0100 Subject: [PATCH 3/5] chore: improve descriptions about connection - MCP-224 --- src/common/logger.ts | 1 + src/server.ts | 48 ++++++++++++++++++++-------- src/tools/mongodb/connect/connect.ts | 36 ++++++++++++++------- 3 files changed, 61 insertions(+), 24 deletions(-) diff --git a/src/common/logger.ts b/src/common/logger.ts index 7a3ebd99c..e6e8a598c 100644 --- a/src/common/logger.ts +++ b/src/common/logger.ts @@ -47,6 +47,7 @@ export const LogId = { toolUpdateFailure: mongoLogId(1_005_001), resourceUpdateFailure: mongoLogId(1_005_002), + updateToolMetadata: mongoLogId(1_005_003), streamableHttpTransportStarted: mongoLogId(1_006_001), streamableHttpTransportSessionCloseFailure: mongoLogId(1_006_002), diff --git a/src/server.ts b/src/server.ts index 7d4a10b16..63e2404ad 100644 --- a/src/server.ts +++ b/src/server.ts @@ -62,12 +62,15 @@ export class Server { } async connect(transport: Transport): Promise { - // Resources are now reactive, so we register them ASAP so they can listen to events like + await this.validateConfig(); + // Register resources after the server is initialized so they can listen to events like // connection events. this.registerResources(); - await this.validateConfig(); - - this.mcpServer.server.registerCapabilities({ logging: {}, resources: { listChanged: true, subscribe: true } }); + this.mcpServer.server.registerCapabilities({ + logging: {}, + resources: { listChanged: true, subscribe: true }, + instructions: this.getInstructions(), + }); // TODO: Eventually we might want to make tools reactive too instead of relying on custom logic. this.registerTools(); @@ -134,17 +137,17 @@ export class Server { message: `Server with version ${packageInfo.version} started with transport ${transport.constructor.name} and agent runner ${JSON.stringify(this.session.mcpClient)}`, }); - this.emitServerEvent("start", Date.now() - this.startTime); + this.emitServerTelemetryEvent("start", Date.now() - this.startTime); }; this.mcpServer.server.onclose = (): void => { const closeTime = Date.now(); - this.emitServerEvent("stop", Date.now() - closeTime); + this.emitServerTelemetryEvent("stop", Date.now() - closeTime); }; this.mcpServer.server.onerror = (error: Error): void => { const closeTime = Date.now(); - this.emitServerEvent("stop", Date.now() - closeTime, error); + this.emitServerTelemetryEvent("stop", Date.now() - closeTime, error); }; await this.mcpServer.connect(transport); @@ -161,17 +164,18 @@ export class Server { } public sendResourceUpdated(uri: string): void { + this.session.logger.info({ + id: LogId.serverInitialized, + context: "resources", + message: `Resource updated: ${uri}`, + }); + if (this.subscriptions.has(uri)) { void this.mcpServer.server.sendResourceUpdated({ uri }); } } - /** - * Emits a server event - * @param command - The server command (e.g., "start", "stop", "register", "deregister") - * @param additionalProperties - Additional properties specific to the event - */ - private emitServerEvent(command: ServerCommand, commandDuration: number, error?: Error): void { + private emitServerTelemetryEvent(command: ServerCommand, commandDuration: number, error?: Error): void { const event: ServerEvent = { timestamp: new Date().toISOString(), source: "mdbmcp", @@ -262,6 +266,24 @@ export class Server { } } + private getInstructions(): string { + let instructions = ` + This is the MongoDB MCP server. + `; + if (this.userConfig.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 (this.userConfig.apiClientId && this.userConfig.apiClientSecret) { + instructions = ` + This MCP server was configured with MongoDB Atlas API credentials.`; + } + + return instructions; + } + private async connectToConfigConnectionString(): Promise { if (this.userConfig.connectionString) { try { diff --git a/src/tools/mongodb/connect/connect.ts b/src/tools/mongodb/connect/connect.ts index d7ed16d26..4fb035ecd 100644 --- a/src/tools/mongodb/connect/connect.ts +++ b/src/tools/mongodb/connect/connect.ts @@ -4,6 +4,7 @@ import { MongoDBToolBase } from "../mongodbTool.js"; import type { ToolArgs, OperationType, ToolConstructorParams } from "../../tool.js"; import assert from "assert"; import type { Server } from "../../../server.js"; +import { LogId } from "../../../common/logger.js"; const disconnectedSchema = z .object({ @@ -27,7 +28,8 @@ const disconnectedName = "connect" as const; const connectedDescription = "Switch to a different MongoDB connection. If the user has configured a connection string or has previously called the connect tool, a connection is already established and there's no need to call this tool unless the user has explicitly requested to switch to a new instance."; -const disconnectedDescription = "Connect to a MongoDB instance"; +const disconnectedDescription = + "Connect to a MongoDB instance. The config resource captures if the server is already connected to a MongoDB cluster. If the user has configured a connection string or has previously called the connect tool, a connection is already established and there's no need to call this tool unless the user has explicitly requested to switch to a new MongoDB cluster."; export class ConnectTool extends MongoDBToolBase { public name: typeof connectedName | typeof disconnectedName = disconnectedName; @@ -84,18 +86,30 @@ export class ConnectTool extends MongoDBToolBase { } private updateMetadata(): void { + let name: string; + let description: string; + let inputSchema: z.ZodObject; + if (this.session.isConnectedToMongoDB) { - this.update?.({ - name: connectedName, - description: connectedDescription, - inputSchema: connectedSchema, - }); + name = connectedName; + description = connectedDescription; + inputSchema = connectedSchema; } else { - this.update?.({ - name: disconnectedName, - description: disconnectedDescription, - inputSchema: disconnectedSchema, - }); + name = disconnectedName; + description = disconnectedDescription; + inputSchema = disconnectedSchema; } + + this.session.logger.info({ + id: LogId.updateToolMetadata, + context: "tool", + message: `Updating tool metadata to ${name}`, + }); + + this.update?.({ + name: name, + description: description, + inputSchema: inputSchema, + }); } } From 91bffa85d28eb2b7b2ad79d27c5d70678a3f3d61 Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 25 Sep 2025 13:17:10 +0100 Subject: [PATCH 4/5] fix test --- .../tools/mongodb/connect/connect.test.ts | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/integration/tools/mongodb/connect/connect.test.ts b/tests/integration/tools/mongodb/connect/connect.test.ts index 26d65ba49..7e56f845d 100644 --- a/tests/integration/tools/mongodb/connect/connect.test.ts +++ b/tests/integration/tools/mongodb/connect/connect.test.ts @@ -91,14 +91,19 @@ describeWithMongoDB( describeWithMongoDB( "Connect tool", (integration) => { - validateToolMetadata(integration, "connect", "Connect to a MongoDB instance", [ - { - name: "connectionString", - description: "MongoDB connection string (in the mongodb:// or mongodb+srv:// format)", - type: "string", - required: true, - }, - ]); + validateToolMetadata( + integration, + "connect", + "Connect to a MongoDB instance. The config resource captures if the server is already connected to a MongoDB cluster. If the user has configured a connection string or has previously called the connect tool, a connection is already established and there's no need to call this tool unless the user has explicitly requested to switch to a new MongoDB cluster.", + [ + { + name: "connectionString", + description: "MongoDB connection string (in the mongodb:// or mongodb+srv:// format)", + type: "string", + required: true, + }, + ] + ); validateThrowsForInvalidArguments(integration, "connect", [{}, { connectionString: 123 }]); From d53e39fb3391132b37b42f6809284c97a63c9314 Mon Sep 17 00:00:00 2001 From: Bianca Lisle Date: Thu, 25 Sep 2025 14:44:24 +0100 Subject: [PATCH 5/5] address copilot comments --- src/server.ts | 6 +++--- src/tools/mongodb/connect/connect.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/server.ts b/src/server.ts index 63e2404ad..458bcd28b 100644 --- a/src/server.ts +++ b/src/server.ts @@ -165,7 +165,7 @@ export class Server { public sendResourceUpdated(uri: string): void { this.session.logger.info({ - id: LogId.serverInitialized, + id: LogId.resourceUpdateFailure, context: "resources", message: `Resource updated: ${uri}`, }); @@ -271,13 +271,13 @@ export class Server { This is the MongoDB MCP server. `; if (this.userConfig.connectionString) { - instructions = ` + instructions += ` This MCP server was configured with a MongoDB connection string, and you can assume that you are connected to a MongoDB cluster. `; } if (this.userConfig.apiClientId && this.userConfig.apiClientSecret) { - instructions = ` + instructions += ` This MCP server was configured with MongoDB Atlas API credentials.`; } diff --git a/src/tools/mongodb/connect/connect.ts b/src/tools/mongodb/connect/connect.ts index 4fb035ecd..601fcb368 100644 --- a/src/tools/mongodb/connect/connect.ts +++ b/src/tools/mongodb/connect/connect.ts @@ -107,9 +107,9 @@ export class ConnectTool extends MongoDBToolBase { }); this.update?.({ - name: name, - description: description, - inputSchema: inputSchema, + name, + description, + inputSchema, }); } }