Skip to content

Commit e77b1f3

Browse files
chore: adds vscode specific connection error handler MCP-132 (#1113)
1 parent 5e6e677 commit e77b1f3

File tree

6 files changed

+177
-13
lines changed

6 files changed

+177
-13
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,7 @@
13961396
"@babel/core": "^7.25.8",
13971397
"@babel/parser": "^7.25.8",
13981398
"@babel/traverse": "^7.25.7",
1399-
"@himanshusinghs/mongodb-mcp-server": "^0.3.1",
1399+
"@himanshusinghs/mongodb-mcp-server": "^0.3.5",
14001400
"@mongodb-js/compass-components": "^1.38.1",
14011401
"@mongodb-js/connection-form": "^1.52.3",
14021402
"@mongodb-js/connection-info": "^0.17.1",
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import {
2+
ErrorCodes,
3+
type ConnectionErrorHandler,
4+
} from '@himanshusinghs/mongodb-mcp-server';
5+
import type ConnectionController from '../connectionController';
6+
7+
export const createMCPConnectionErrorHandler = (
8+
connectionController: Pick<
9+
ConnectionController,
10+
'getSavedConnections' | 'getActiveConnectionName'
11+
>,
12+
): ConnectionErrorHandler => {
13+
return (error) => {
14+
const activeConnectionName = connectionController.getActiveConnectionName();
15+
const availableConnections = connectionController
16+
.getSavedConnections()
17+
.map(({ name }) => ({ name }));
18+
19+
const connectionGuidance: string[] = availableConnections.length
20+
? [
21+
`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.`,
22+
'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',
23+
]
24+
: [
25+
'The user has no connections saved in their MongoDB Extension sidebar.',
26+
'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.',
27+
];
28+
29+
switch (error.code) {
30+
case ErrorCodes.NotConnectedToMongoDB:
31+
return {
32+
errorHandled: true,
33+
result: {
34+
content: [
35+
{
36+
type: 'text',
37+
text: 'You need to connect to a MongoDB instance before you can access its data.',
38+
},
39+
...connectionGuidance.map<{ type: 'text'; text: string }>(
40+
(text) => ({ type: 'text', text }),
41+
),
42+
],
43+
},
44+
};
45+
case ErrorCodes.MisconfiguredConnectionString: {
46+
const resolutionGuidance: string[] = [
47+
'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',
48+
...connectionGuidance,
49+
];
50+
return {
51+
errorHandled: true,
52+
result: {
53+
content: [
54+
{
55+
type: 'text',
56+
text: `MCP server is having trouble connecting to ${activeConnectionName ? activeConnectionName : 'the selected connection in the MongoDB VSCode extension'}.`,
57+
},
58+
...resolutionGuidance.map<{ type: 'text'; text: string }>(
59+
(text) => ({ type: 'text', text }),
60+
),
61+
],
62+
},
63+
};
64+
}
65+
default:
66+
return {
67+
errorHandled: false,
68+
};
69+
}
70+
};
71+
};

src/mcp/mcpConnectionManager.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,9 @@ export class MCPConnectionManager extends ConnectionManager {
3131
connect(): Promise<AnyConnectionState> {
3232
return Promise.reject(
3333
new Error(
34-
[
35-
'MongoDB MCP Server in MongoDB VSCode extension makes use of the connection that the MongoDB VSCode extension is connected to.',
36-
"To connect, choose a connection from MongoDB VSCode extensions's sidepanel - https://www.mongodb.com/docs/mongodb-vscode/connect/#connect-to-your-mongodb-deployment",
37-
].join(' '),
34+
// eslint-disable-next-line no-multi-str
35+
"MongoDB MCP Server in MongoDB VSCode extension makes use of the connection that the MongoDB VSCode extension is connected to. \
36+
To connect, choose a connection from MongoDB VSCode extensions's sidepanel - https://www.mongodb.com/docs/mongodb-vscode/connect/#connect-to-your-mongodb-deployment",
3837
),
3938
);
4039
}

src/mcp/mcpController.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type ConnectionController from '../connectionController';
1515
import { createLogger } from '../logging';
1616
import type { MCPConnectParams } from './mcpConnectionManager';
1717
import { MCPConnectionManager } from './mcpConnectionManager';
18+
import { createMCPConnectionErrorHandler } from './mcpConnectionErrorHandler';
1819

1920
type mcpServerStartupConfig = 'ask' | 'enabled' | 'disabled';
2021

@@ -90,11 +91,14 @@ export class MCPController {
9091
return connectionManager;
9192
};
9293

93-
const runner = new StreamableHttpRunner(
94-
mcpConfig,
94+
const runner = new StreamableHttpRunner({
95+
userConfig: mcpConfig,
9596
createConnectionManager,
96-
[new VSCodeMCPLogger()],
97-
);
97+
connectionErrorHandler: createMCPConnectionErrorHandler(
98+
this.connectionController,
99+
),
100+
additionalLoggers: [new VSCodeMCPLogger()],
101+
});
98102
await runner.start();
99103

100104
this.server = {
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { expect } from 'chai';
2+
import { beforeEach } from 'mocha';
3+
import { createMCPConnectionErrorHandler } from '../../../mcp/mcpConnectionErrorHandler';
4+
import ConnectionController from '../../../connectionController';
5+
import { ExtensionContextStub } from '../stubs';
6+
import { StorageController } from '../../../storage';
7+
import { TelemetryService } from '../../../telemetry';
8+
import { StatusView } from '../../../views';
9+
import type {
10+
ConnectionErrorHandled,
11+
ConnectionErrorHandlerContext,
12+
} from '@himanshusinghs/mongodb-mcp-server';
13+
import { ErrorCodes } from '@himanshusinghs/mongodb-mcp-server';
14+
15+
class MongoDBError extends Error {
16+
constructor(
17+
public code:
18+
| ErrorCodes.NotConnectedToMongoDB
19+
| ErrorCodes.MisconfiguredConnectionString,
20+
message: string,
21+
) {
22+
super(message);
23+
}
24+
}
25+
26+
suite('mcpConnectionErrorHandler suite', () => {
27+
let connectionController: ConnectionController;
28+
beforeEach(() => {
29+
const extensionContext = new ExtensionContextStub();
30+
const testStorageController = new StorageController(extensionContext);
31+
const testTelemetryService = new TelemetryService(
32+
testStorageController,
33+
extensionContext,
34+
);
35+
connectionController = new ConnectionController({
36+
statusView: new StatusView(extensionContext),
37+
storageController: testStorageController,
38+
telemetryService: testTelemetryService,
39+
});
40+
});
41+
42+
test('should handle NotConnectedToMongoDB error', () => {
43+
const handler = createMCPConnectionErrorHandler(connectionController);
44+
const result = handler(
45+
new MongoDBError(
46+
ErrorCodes.NotConnectedToMongoDB,
47+
'Not connected to MongoDB',
48+
),
49+
{} as ConnectionErrorHandlerContext,
50+
) as ConnectionErrorHandled;
51+
52+
expect(result.errorHandled).to.be.true;
53+
expect(result.result.content).to.deep.contain({
54+
type: 'text',
55+
text: 'You need to connect to a MongoDB instance before you can access its data.',
56+
});
57+
});
58+
59+
test('should handle MisconfiguredConnectionString error', () => {
60+
const handler = createMCPConnectionErrorHandler(connectionController);
61+
const result = handler(
62+
new MongoDBError(
63+
ErrorCodes.MisconfiguredConnectionString,
64+
'Misconfigured MongoDB string',
65+
),
66+
{} as ConnectionErrorHandlerContext,
67+
) as ConnectionErrorHandled;
68+
69+
expect(result.errorHandled).to.be.true;
70+
expect(result.result.content).to.deep.contain({
71+
type: 'text',
72+
text: 'MCP server is having trouble connecting to the selected connection in the MongoDB VSCode extension.',
73+
});
74+
});
75+
76+
test('should not handle any other errors', () => {
77+
const handler = createMCPConnectionErrorHandler(connectionController);
78+
expect(
79+
handler(
80+
new MongoDBError(ErrorCodes.ForbiddenCollscan as any, 'Some error'),
81+
{} as any,
82+
),
83+
).to.deep.equal({
84+
errorHandled: false,
85+
});
86+
expect(handler(new Error('Some error') as any, {} as any)).to.deep.equal({
87+
errorHandled: false,
88+
});
89+
});
90+
});

0 commit comments

Comments
 (0)