From 40c2293b5333dbb4b63614997d6fe4fd704add19 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 2 Sep 2025 17:30:02 +0200 Subject: [PATCH 1/4] chore: adds vscode specific connection error handler --- src/mcp/mcpConnectionErrorHandler.ts | 71 ++++++++++++++++++++++++++++ src/mcp/mcpController.ts | 12 +++-- 2 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 src/mcp/mcpConnectionErrorHandler.ts diff --git a/src/mcp/mcpConnectionErrorHandler.ts b/src/mcp/mcpConnectionErrorHandler.ts new file mode 100644 index 000000000..d9989283b --- /dev/null +++ b/src/mcp/mcpConnectionErrorHandler.ts @@ -0,0 +1,71 @@ +import { + ErrorCodes, + type ConnectionErrorHandler, +} from '@himanshusinghs/mongodb-mcp-server'; +import type ConnectionController from '../connectionController'; + +export const createMCPConnectionErrorHandler = ( + connectionController: Pick< + ConnectionController, + 'getSavedConnections' | 'getActiveConnectionName' + >, +): ConnectionErrorHandler => { + return (error) => { + const activeConnectionName = connectionController.getActiveConnectionName(); + const availableConnections = connectionController + .getSavedConnections() + .map(({ name }) => ({ name })); + + const connectionGuidance: string[] = availableConnections.length + ? [ + `Following connections are available in the Sidebar for the user to connect to: ${JSON.stringify(availableConnections)}. Note to LLM: Provide user with the list of connections available and ask them to select a connection in the Sidebar.`, + 'Note to LLM: Alternatively, if the user wish to establish a new MongoDB connection, then ask them to follow our official guide on the following link: https://www.mongodb.com/docs/mongodb-vscode/connect/#create-a-connection', + ] + : [ + 'The user has no connections saved in their MongoDB Extension sidebar.', + 'Note to LLM: Ask the user to follow our official guide on the following link: https://www.mongodb.com/docs/mongodb-vscode/connect/#create-a-connection to connect to a MongoDB cluster.', + ]; + + switch (error.code) { + case ErrorCodes.NotConnectedToMongoDB: + return { + errorHandled: true, + result: { + content: [ + { + type: 'text', + text: 'You need to connect to a MongoDB instance before you can access its data.', + }, + ...connectionGuidance.map<{ type: 'text'; text: string }>( + (text) => ({ type: 'text', text }), + ), + ], + }, + }; + case ErrorCodes.MisconfiguredConnectionString: { + const resolutionGuidance: string[] = [ + 'Note to LLM: Ask the user to reconnect to the desired connection. If the problem persist even after that then advice them to raise an issue on the VSCode project board - https://github.com/mongodb-js/vscode/issues', + ...connectionGuidance, + ]; + return { + errorHandled: true, + result: { + content: [ + { + type: 'text', + text: `MCP server is having trouble connecting to the ${activeConnectionName ?? 'selected connection in the MongoDB VSCode extension'}.`, + }, + ...resolutionGuidance.map<{ type: 'text'; text: string }>( + (text) => ({ type: 'text', text }), + ), + ], + }, + }; + } + default: + return { + errorHandled: false, + }; + } + }; +}; diff --git a/src/mcp/mcpController.ts b/src/mcp/mcpController.ts index c75994f72..0ca90a856 100644 --- a/src/mcp/mcpController.ts +++ b/src/mcp/mcpController.ts @@ -15,6 +15,7 @@ import type ConnectionController from '../connectionController'; import { createLogger } from '../logging'; import type { MCPConnectParams } from './mcpConnectionManager'; import { MCPConnectionManager } from './mcpConnectionManager'; +import { createMCPConnectionErrorHandler } from './mcpConnectionErrorHandler'; type mcpServerStartupConfig = 'ask' | 'enabled' | 'disabled'; @@ -90,11 +91,14 @@ export class MCPController { return connectionManager; }; - const runner = new StreamableHttpRunner( - mcpConfig, + const runner = new StreamableHttpRunner({ + userConfig: mcpConfig, createConnectionManager, - [new VSCodeMCPLogger()], - ); + connectionErrorHandler: createMCPConnectionErrorHandler( + this.connectionController, + ), + additionalLoggers: [new VSCodeMCPLogger()], + }); await runner.start(); this.server = { From 0d62a1dd07e1a0fff86508da8030209843df39e5 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Tue, 2 Sep 2025 21:43:11 +0200 Subject: [PATCH 2/4] chore: tests for connection error handler --- src/mcp/mcpConnectionErrorHandler.ts | 2 +- src/mcp/mcpConnectionManager.ts | 8 +- .../mcp/mcpConnectionErrorHandler.test.ts | 97 +++++++++++++++++++ 3 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 src/test/suite/mcp/mcpConnectionErrorHandler.test.ts diff --git a/src/mcp/mcpConnectionErrorHandler.ts b/src/mcp/mcpConnectionErrorHandler.ts index d9989283b..f61e959f4 100644 --- a/src/mcp/mcpConnectionErrorHandler.ts +++ b/src/mcp/mcpConnectionErrorHandler.ts @@ -53,7 +53,7 @@ export const createMCPConnectionErrorHandler = ( content: [ { type: 'text', - text: `MCP server is having trouble connecting to the ${activeConnectionName ?? 'selected connection in the MongoDB VSCode extension'}.`, + text: `MCP server is having trouble connecting to ${activeConnectionName ? activeConnectionName : 'the selected connection in the MongoDB VSCode extension'}.`, }, ...resolutionGuidance.map<{ type: 'text'; text: string }>( (text) => ({ type: 'text', text }), diff --git a/src/mcp/mcpConnectionManager.ts b/src/mcp/mcpConnectionManager.ts index 4057bd2e9..142601390 100644 --- a/src/mcp/mcpConnectionManager.ts +++ b/src/mcp/mcpConnectionManager.ts @@ -31,10 +31,10 @@ export class MCPConnectionManager extends ConnectionManager { connect(): Promise { return Promise.reject( new Error( - [ - 'MongoDB MCP Server in MongoDB VSCode extension makes use of the connection that the MongoDB VSCode extension is connected to.', - "To connect, choose a connection from MongoDB VSCode extensions's sidepanel - https://www.mongodb.com/docs/mongodb-vscode/connect/#connect-to-your-mongodb-deployment", - ].join(' '), + // MCP runs in node process + // eslint-disable-next-line no-multi-str + "MongoDB MCP Server in MongoDB VSCode extension makes use of the connection that the MongoDB VSCode extension is connected to.\ + To connect, choose a connection from MongoDB VSCode extensions's sidepanel - https://www.mongodb.com/docs/mongodb-vscode/connect/#connect-to-your-mongodb-deployment", ), ); } diff --git a/src/test/suite/mcp/mcpConnectionErrorHandler.test.ts b/src/test/suite/mcp/mcpConnectionErrorHandler.test.ts new file mode 100644 index 000000000..c6aff2ad8 --- /dev/null +++ b/src/test/suite/mcp/mcpConnectionErrorHandler.test.ts @@ -0,0 +1,97 @@ +import sinon from 'sinon'; +import { expect } from 'chai'; +import { afterEach, beforeEach } from 'mocha'; +import { createMCPConnectionErrorHandler } from '../../../mcp/mcpConnectionErrorHandler'; +import ConnectionController from '../../../connectionController'; +import { ExtensionContextStub } from '../stubs'; +import { StorageController } from '../../../storage'; +import { TelemetryService } from '../../../telemetry'; +import { StatusView } from '../../../views'; +import type { + ConnectionErrorHandled, + ConnectionErrorHandlerContext, +} from '@himanshusinghs/mongodb-mcp-server'; +import { ErrorCodes } from '@himanshusinghs/mongodb-mcp-server'; + +class MongoDBError extends Error { + constructor( + public code: + | ErrorCodes.NotConnectedToMongoDB + | ErrorCodes.MisconfiguredConnectionString, + message: string, + ) { + super(message); + } +} + +const sandbox = sinon.createSandbox(); +suite('mcpConnectionErrorHandler suite', () => { + let connectionController: ConnectionController; + beforeEach(() => { + const extensionContext = new ExtensionContextStub(); + const testStorageController = new StorageController(extensionContext); + const testTelemetryService = new TelemetryService( + testStorageController, + extensionContext, + ); + connectionController = new ConnectionController({ + statusView: new StatusView(extensionContext), + storageController: testStorageController, + telemetryService: testTelemetryService, + }); + }); + + afterEach(() => { + sandbox.reset(); + sandbox.restore(); + }); + + test('should handle NotConnectedToMongoDB error', () => { + const handler = createMCPConnectionErrorHandler(connectionController); + const result = handler( + new MongoDBError( + ErrorCodes.NotConnectedToMongoDB, + 'Not connected to MongoDB', + ), + {} as ConnectionErrorHandlerContext, + ) as ConnectionErrorHandled; + + expect(result.errorHandled).to.be.true; + expect(result.result.content).to.deep.contain({ + type: 'text', + text: 'You need to connect to a MongoDB instance before you can access its data.', + }); + }); + + test('should handle MisconfiguredConnectionString error', () => { + const handler = createMCPConnectionErrorHandler(connectionController); + const result = handler( + new MongoDBError( + ErrorCodes.MisconfiguredConnectionString, + 'Misconfigured MongoDB string', + ), + {} as ConnectionErrorHandlerContext, + ) as ConnectionErrorHandled; + + expect(result.errorHandled).to.be.true; + expect(result.result.content).to.deep.contain({ + type: 'text', + text: 'MCP server is having trouble connecting to the selected connection in the MongoDB VSCode extension.', + }); + }); + + test('should not handle any other errors', () => { + const handler = createMCPConnectionErrorHandler(connectionController); + expect( + handler( + new MongoDBError(ErrorCodes.ForbiddenCollscan as any, 'Some error'), + {} as any, + ), + ).to.deep.equal({ + errorHandled: false, + }); + expect(handler(new Error('Some error') as any, {} as any)).to.deep.equal({ + errorHandled: false, + }); + }); +}); From f82a04bca29ab09dd68bafa50888aba62511f2ea Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 3 Sep 2025 12:30:39 +0200 Subject: [PATCH 3/4] chore: PR feedback --- src/mcp/mcpConnectionManager.ts | 5 ++--- src/test/suite/mcp/mcpConnectionErrorHandler.test.ts | 9 +-------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/mcp/mcpConnectionManager.ts b/src/mcp/mcpConnectionManager.ts index 142601390..a1e9edd61 100644 --- a/src/mcp/mcpConnectionManager.ts +++ b/src/mcp/mcpConnectionManager.ts @@ -31,10 +31,9 @@ export class MCPConnectionManager extends ConnectionManager { connect(): Promise { return Promise.reject( new Error( - // MCP runs in node process // eslint-disable-next-line no-multi-str - "MongoDB MCP Server in MongoDB VSCode extension makes use of the connection that the MongoDB VSCode extension is connected to.\ - To connect, choose a connection from MongoDB VSCode extensions's sidepanel - https://www.mongodb.com/docs/mongodb-vscode/connect/#connect-to-your-mongodb-deployment", + "MongoDB MCP Server in MongoDB VSCode extension makes use of the connection that the MongoDB VSCode extension is connected to. \ +To connect, choose a connection from MongoDB VSCode extensions's sidepanel - https://www.mongodb.com/docs/mongodb-vscode/connect/#connect-to-your-mongodb-deployment", ), ); } diff --git a/src/test/suite/mcp/mcpConnectionErrorHandler.test.ts b/src/test/suite/mcp/mcpConnectionErrorHandler.test.ts index c6aff2ad8..c1db22f5c 100644 --- a/src/test/suite/mcp/mcpConnectionErrorHandler.test.ts +++ b/src/test/suite/mcp/mcpConnectionErrorHandler.test.ts @@ -1,6 +1,5 @@ -import sinon from 'sinon'; import { expect } from 'chai'; -import { afterEach, beforeEach } from 'mocha'; +import { beforeEach } from 'mocha'; import { createMCPConnectionErrorHandler } from '../../../mcp/mcpConnectionErrorHandler'; import ConnectionController from '../../../connectionController'; import { ExtensionContextStub } from '../stubs'; @@ -24,7 +23,6 @@ class MongoDBError extends Error { } } -const sandbox = sinon.createSandbox(); suite('mcpConnectionErrorHandler suite', () => { let connectionController: ConnectionController; beforeEach(() => { @@ -41,11 +39,6 @@ suite('mcpConnectionErrorHandler suite', () => { }); }); - afterEach(() => { - sandbox.reset(); - sandbox.restore(); - }); - test('should handle NotConnectedToMongoDB error', () => { const handler = createMCPConnectionErrorHandler(connectionController); const result = handler( From 5ef220bd08599d4f07e4f58d0ff453c8c01d9a5f Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 3 Sep 2025 12:35:28 +0200 Subject: [PATCH 4/4] chore: update mcp-server with updated main --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a60b03a40..591c7640c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@babel/core": "^7.25.8", "@babel/parser": "^7.25.8", "@babel/traverse": "^7.25.7", - "@himanshusinghs/mongodb-mcp-server": "^0.3.1", + "@himanshusinghs/mongodb-mcp-server": "^0.3.5", "@mongodb-js/compass-components": "^1.38.1", "@mongodb-js/connection-form": "^1.52.3", "@mongodb-js/connection-info": "^0.17.1", @@ -5686,9 +5686,9 @@ "license": "MIT" }, "node_modules/@himanshusinghs/mongodb-mcp-server": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@himanshusinghs/mongodb-mcp-server/-/mongodb-mcp-server-0.3.1.tgz", - "integrity": "sha512-H/QfueuEg7/qiUH8EI8NDP//7RsBy/iP6EwSemrz5fymovQSUnxsJnwiKlPM267HGpSDwT5QrJpo6Td6jfGA7A==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@himanshusinghs/mongodb-mcp-server/-/mongodb-mcp-server-0.3.5.tgz", + "integrity": "sha512-Pm7+vAz7S4o6o94BJ3g3WkFxoUx9TVe3iBFfEElt6WfG+L/lUCBbxsPVWYhkNHcHqqOhhu6HAChFngHeyAb3YA==", "license": "Apache-2.0", "dependencies": { "@modelcontextprotocol/sdk": "^1.17.4", diff --git a/package.json b/package.json index d528f0dc5..17a361a14 100644 --- a/package.json +++ b/package.json @@ -1396,7 +1396,7 @@ "@babel/core": "^7.25.8", "@babel/parser": "^7.25.8", "@babel/traverse": "^7.25.7", - "@himanshusinghs/mongodb-mcp-server": "^0.3.1", + "@himanshusinghs/mongodb-mcp-server": "^0.3.5", "@mongodb-js/compass-components": "^1.38.1", "@mongodb-js/connection-form": "^1.52.3", "@mongodb-js/connection-info": "^0.17.1",