Skip to content

Commit 8f1d6ba

Browse files
committed
provide a better hint when the connection string is misconfigured
1 parent 409e01f commit 8f1d6ba

File tree

8 files changed

+75
-43
lines changed

8 files changed

+75
-43
lines changed

src/common/atlas/apiClient.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import { AccessToken, ClientCredentials } from "simple-oauth2";
44
import { ApiClientError } from "./apiClientError.js";
55
import { paths, operations } from "./openapi.js";
66
import { BaseEvent } from "../../telemetry/types.js";
7-
import { mongoLogId } from "mongodb-log-writer";
8-
import logger from "../../logger.js";
7+
import logger, { LogId } from "../../logger.js";
98
import { packageInfo } from "../../packageInfo.js";
109

1110
const ATLAS_API_VERSION = "2025-03-12";
@@ -99,7 +98,7 @@ export class ApiClient {
9998

10099
public hasCredentials(): boolean {
101100
logger.info(
102-
mongoLogId(1_000_000),
101+
LogId.atlasCheckCredentials,
103102
"api-client",
104103
`Checking if API client has credentials: ${!!(this.oauth2Client && this.accessToken)}`
105104
);

src/errors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export enum ErrorCodes {
22
NotConnectedToMongoDB = 1_000_000,
3-
InvalidParams = 1_000_001,
3+
MisconfiguredConnectionString = 1_000_001,
44
}
55

66
export class MongoDBError extends Error {

src/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
#!/usr/bin/env node
22

33
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4-
import logger from "./logger.js";
5-
import { mongoLogId } from "mongodb-log-writer";
4+
import logger, { LogId } from "./logger.js";
65
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
76
import { config } from "./config.js";
87
import { Session } from "./session.js";
@@ -29,6 +28,6 @@ try {
2928

3029
await server.connect(transport);
3130
} catch (error: unknown) {
32-
logger.emergency(mongoLogId(1_000_004), "server", `Fatal error running server: ${error as string}`);
31+
logger.emergency(LogId.serverStartFailure, "server", `Fatal error running server: ${error as string}`);
3332
process.exit(1);
3433
}

src/logger.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,29 @@
11
import fs from "fs/promises";
2-
import { MongoLogId, MongoLogManager, MongoLogWriter } from "mongodb-log-writer";
2+
import { mongoLogId, MongoLogId, MongoLogManager, MongoLogWriter } from "mongodb-log-writer";
33
import redact from "mongodb-redact";
44
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
55
import { LoggingMessageNotification } from "@modelcontextprotocol/sdk/types.js";
66

77
export type LogLevel = LoggingMessageNotification["params"]["level"];
88

9+
export const LogId = {
10+
serverStartFailure: mongoLogId(1_000_001),
11+
serverInitialized: mongoLogId(1_000_002),
12+
13+
atlasCheckCredentials: mongoLogId(1_001_001),
14+
15+
telemetryDisabled: mongoLogId(1_002_001),
16+
telemetryEmitFailure: mongoLogId(1_002_002),
17+
telemetryEmitStart: mongoLogId(1_002_003),
18+
telemetryEmitSuccess: mongoLogId(1_002_004),
19+
20+
toolExecute: mongoLogId(1_003_001),
21+
toolExecuteFailure: mongoLogId(1_003_002),
22+
toolDisabled: mongoLogId(1_003_003),
23+
24+
mongodbConnectFailure: mongoLogId(1_004_001),
25+
} as const;
26+
927
abstract class LoggerBase {
1028
abstract log(level: LogLevel, id: MongoLogId, context: string, message: string): void;
1129
info(id: MongoLogId, context: string, message: string): void {

src/server.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import { Session } from "./session.js";
33
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
44
import { AtlasTools } from "./tools/atlas/tools.js";
55
import { MongoDbTools } from "./tools/mongodb/tools.js";
6-
import logger, { initializeLogger } from "./logger.js";
7-
import { mongoLogId } from "mongodb-log-writer";
6+
import logger, { initializeLogger, LogId } from "./logger.js";
87
import { ObjectId } from "mongodb";
98
import { Telemetry } from "./telemetry/telemetry.js";
109
import { UserConfig } from "./config.js";
@@ -67,7 +66,7 @@ export class Server {
6766
this.session.sessionId = new ObjectId().toString();
6867

6968
logger.info(
70-
mongoLogId(1_000_004),
69+
LogId.serverInitialized,
7170
"server",
7271
`Server started with transport ${transport.constructor.name} and agent runner ${this.session.agentRunner?.name}`
7372
);

src/telemetry/telemetry.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { Session } from "../session.js";
22
import { BaseEvent } from "./types.js";
33
import { config } from "../config.js";
4-
import logger from "../logger.js";
5-
import { mongoLogId } from "mongodb-log-writer";
4+
import logger, { LogId } from "../logger.js";
65
import { ApiClient } from "../common/atlas/apiClient.js";
76
import { MACHINE_METADATA } from "./constants.js";
87
import { EventCache } from "./eventCache.js";
@@ -69,13 +68,13 @@ export class Telemetry {
6968
public async emitEvents(events: BaseEvent[]): Promise<void> {
7069
try {
7170
if (!Telemetry.isTelemetryEnabled()) {
72-
logger.debug(mongoLogId(1_000_000), "telemetry", "Telemetry is disabled, skipping events.");
71+
logger.debug(LogId.telemetryDisabled, "telemetry", "Telemetry is disabled, skipping events.");
7372
return;
7473
}
7574

7675
await this.emit(events);
7776
} catch {
78-
logger.debug(mongoLogId(1_000_002), "telemetry", `Error emitting telemetry events.`);
77+
logger.debug(LogId.telemetryEmitFailure, "telemetry", `Error emitting telemetry events.`);
7978
}
8079
}
8180

@@ -101,20 +100,20 @@ export class Telemetry {
101100
const allEvents = [...cachedEvents, ...events];
102101

103102
logger.debug(
104-
mongoLogId(1_000_003),
103+
LogId.telemetryEmitStart,
105104
"telemetry",
106105
`Attempting to send ${allEvents.length} events (${cachedEvents.length} cached)`
107106
);
108107

109108
const result = await this.sendEvents(this.session.apiClient, allEvents);
110109
if (result.success) {
111110
this.eventCache.clearEvents();
112-
logger.debug(mongoLogId(1_000_004), "telemetry", `Sent ${allEvents.length} events successfully`);
111+
logger.debug(LogId.telemetryEmitSuccess, "telemetry", `Sent ${allEvents.length} events successfully`);
113112
return;
114113
}
115114

116-
logger.warning(
117-
mongoLogId(1_000_005),
115+
logger.debug(
116+
LogId.telemetryEmitFailure,
118117
"telemetry",
119118
`Error sending event to client: ${result.error instanceof Error ? result.error.message : String(result.error)}`
120119
);

src/tools/mongodb/mongodbTool.ts

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ToolArgs, ToolBase, ToolCategory } from "../tool.js";
33
import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver";
44
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
55
import { ErrorCodes, MongoDBError } from "../../errors.js";
6+
import logger, { LogId } from "../../logger.js";
67

78
export const DbOperationArgs = {
89
database: z.string().describe("Database name"),
@@ -14,7 +15,16 @@ export abstract class MongoDBToolBase extends ToolBase {
1415

1516
protected async ensureConnected(): Promise<NodeDriverServiceProvider> {
1617
if (!this.session.serviceProvider && this.config.connectionString) {
17-
await this.connectToMongoDB(this.config.connectionString);
18+
try {
19+
await this.connectToMongoDB(this.config.connectionString);
20+
} catch (error) {
21+
logger.error(
22+
LogId.mongodbConnectFailure,
23+
"mongodbTool",
24+
`Failed to connect to MongoDB instance using the connection string from the config: ${error as string}`
25+
);
26+
throw new MongoDBError(ErrorCodes.MisconfiguredConnectionString, "Not connected to MongoDB.");
27+
}
1828
}
1929

2030
if (!this.session.serviceProvider) {
@@ -28,20 +38,33 @@ export abstract class MongoDBToolBase extends ToolBase {
2838
error: unknown,
2939
args: ToolArgs<typeof this.argsShape>
3040
): Promise<CallToolResult> | CallToolResult {
31-
if (error instanceof MongoDBError && error.code === ErrorCodes.NotConnectedToMongoDB) {
32-
return {
33-
content: [
34-
{
35-
type: "text",
36-
text: "You need to connect to a MongoDB instance before you can access its data.",
37-
},
38-
{
39-
type: "text",
40-
text: "Please use the 'connect' tool to connect to a MongoDB instance.",
41-
},
42-
],
43-
isError: true,
44-
};
41+
if (error instanceof MongoDBError) {
42+
switch (error.code) {
43+
case ErrorCodes.NotConnectedToMongoDB:
44+
return {
45+
content: [
46+
{
47+
type: "text",
48+
text: "You need to connect to a MongoDB instance before you can access its data.",
49+
},
50+
{
51+
type: "text",
52+
text: "Please use the 'connect' or 'switch-connection' tool to connect to a MongoDB instance.",
53+
},
54+
],
55+
isError: true,
56+
};
57+
case ErrorCodes.MisconfiguredConnectionString:
58+
return {
59+
content: [
60+
{
61+
type: "text",
62+
text: "The configured connection string is not valid. Please check the connection string and confirm it points to a valid MongoDB instance. Alternatively, use the 'switch-connection' tool to connect to a different instance.",
63+
},
64+
],
65+
isError: true,
66+
};
67+
}
4568
}
4669

4770
return super.handleError(error, args);

src/tools/tool.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { z, type ZodRawShape, type ZodNever, AnyZodObject } from "zod";
22
import type { McpServer, RegisteredTool, ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js";
33
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
44
import { Session } from "../session.js";
5-
import logger from "../logger.js";
6-
import { mongoLogId } from "mongodb-log-writer";
5+
import logger, { LogId } from "../logger.js";
76
import { Telemetry } from "../telemetry/telemetry.js";
87
import { type ToolEvent } from "../telemetry/types.js";
98
import { UserConfig } from "../config.js";
@@ -63,17 +62,13 @@ export abstract class ToolBase {
6362
const callback: ToolCallback<typeof this.argsShape> = async (...args) => {
6463
const startTime = Date.now();
6564
try {
66-
logger.debug(
67-
mongoLogId(1_000_006),
68-
"tool",
69-
`Executing ${this.name} with args: ${JSON.stringify(args)}`
70-
);
65+
logger.debug(LogId.toolExecute, "tool", `Executing ${this.name} with args: ${JSON.stringify(args)}`);
7166

7267
const result = await this.execute(...args);
7368
await this.emitToolEvent(startTime, result);
7469
return result;
7570
} catch (error: unknown) {
76-
logger.error(mongoLogId(1_000_000), "tool", `Error executing ${this.name}: ${error as string}`);
71+
logger.error(LogId.toolExecuteFailure, "tool", `Error executing ${this.name}: ${error as string}`);
7772
const toolResult = await this.handleError(error, args[0] as ToolArgs<typeof this.argsShape>);
7873
await this.emitToolEvent(startTime, toolResult).catch(() => {});
7974
return toolResult;
@@ -124,7 +119,7 @@ export abstract class ToolBase {
124119

125120
if (errorClarification) {
126121
logger.debug(
127-
mongoLogId(1_000_010),
122+
LogId.toolDisabled,
128123
"tool",
129124
`Prevented registration of ${this.name} because ${errorClarification} is disabled in the config`
130125
);

0 commit comments

Comments
 (0)