• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mongodb-js / mongodb-mcp-server / 16292877152

15 Jul 2025 12:10PM UTC coverage: 77.385% (+2.1%) from 75.27%
16292877152

push

github

web-flow
chore(tests): switch to vitest (#363)

498 of 687 branches covered (72.49%)

Branch coverage included in aggregate %.

0 of 27 new or added lines in 2 files covered. (0.0%)

293 existing lines in 26 files now uncovered.

2828 of 3611 relevant lines covered (78.32%)

28.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.35
/src/common/logger.ts
1
import fs from "fs/promises";
2✔
2
import { mongoLogId, MongoLogId, MongoLogManager, MongoLogWriter } from "mongodb-log-writer";
2✔
3
import redact from "mongodb-redact";
2✔
4
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
import { LoggingMessageNotification } from "@modelcontextprotocol/sdk/types.js";
6

7
export type LogLevel = LoggingMessageNotification["params"]["level"];
8

9
export const LogId = {
2✔
10
    serverStartFailure: mongoLogId(1_000_001),
2✔
11
    serverInitialized: mongoLogId(1_000_002),
2✔
12
    serverCloseRequested: mongoLogId(1_000_003),
2✔
13
    serverClosed: mongoLogId(1_000_004),
2✔
14
    serverCloseFailure: mongoLogId(1_000_005),
2✔
15

16
    atlasCheckCredentials: mongoLogId(1_001_001),
2✔
17
    atlasDeleteDatabaseUserFailure: mongoLogId(1_001_002),
2✔
18
    atlasConnectFailure: mongoLogId(1_001_003),
2✔
19
    atlasInspectFailure: mongoLogId(1_001_004),
2✔
20
    atlasConnectAttempt: mongoLogId(1_001_005),
2✔
21
    atlasConnectSucceeded: mongoLogId(1_001_006),
2✔
22
    atlasApiRevokeFailure: mongoLogId(1_001_007),
2✔
23

24
    telemetryDisabled: mongoLogId(1_002_001),
2✔
25
    telemetryEmitFailure: mongoLogId(1_002_002),
2✔
26
    telemetryEmitStart: mongoLogId(1_002_003),
2✔
27
    telemetryEmitSuccess: mongoLogId(1_002_004),
2✔
28
    telemetryMetadataError: mongoLogId(1_002_005),
2✔
29
    telemetryDeviceIdFailure: mongoLogId(1_002_006),
2✔
30
    telemetryDeviceIdTimeout: mongoLogId(1_002_007),
2✔
31

32
    toolExecute: mongoLogId(1_003_001),
2✔
33
    toolExecuteFailure: mongoLogId(1_003_002),
2✔
34
    toolDisabled: mongoLogId(1_003_003),
2✔
35

36
    mongodbConnectFailure: mongoLogId(1_004_001),
2✔
37
    mongodbDisconnectFailure: mongoLogId(1_004_002),
2✔
38

39
    toolUpdateFailure: mongoLogId(1_005_001),
2✔
40
} as const;
2✔
41

42
abstract class LoggerBase {
2✔
43
    abstract log(level: LogLevel, id: MongoLogId, context: string, message: string): void;
44

45
    info(id: MongoLogId, context: string, message: string): void {
2✔
46
        this.log("info", id, context, message);
138✔
47
    }
138✔
48

49
    error(id: MongoLogId, context: string, message: string): void {
2✔
50
        this.log("error", id, context, message);
38✔
51
    }
38✔
52
    debug(id: MongoLogId, context: string, message: string): void {
2✔
53
        this.log("debug", id, context, message);
293✔
54
    }
293✔
55

56
    notice(id: MongoLogId, context: string, message: string): void {
2✔
57
        this.log("notice", id, context, message);
×
UNCOV
58
    }
×
59

60
    warning(id: MongoLogId, context: string, message: string): void {
2✔
61
        this.log("warning", id, context, message);
×
UNCOV
62
    }
×
63

64
    critical(id: MongoLogId, context: string, message: string): void {
2✔
65
        this.log("critical", id, context, message);
×
UNCOV
66
    }
×
67

68
    alert(id: MongoLogId, context: string, message: string): void {
2✔
69
        this.log("alert", id, context, message);
×
UNCOV
70
    }
×
71

72
    emergency(id: MongoLogId, context: string, message: string): void {
2✔
73
        this.log("emergency", id, context, message);
×
UNCOV
74
    }
×
75
}
2✔
76

77
class ConsoleLogger extends LoggerBase {
2✔
78
    log(level: LogLevel, id: MongoLogId, context: string, message: string): void {
2✔
79
        message = redact(message);
10✔
80
        console.error(`[${level.toUpperCase()}] ${id.__value} - ${context}: ${message}`);
10✔
81
    }
10✔
82
}
2✔
83

84
class DiskLogger extends LoggerBase {
2✔
85
    private constructor(private logWriter: MongoLogWriter) {
2✔
86
        super();
34✔
87
    }
34✔
88

89
    static async fromPath(logPath: string): Promise<DiskLogger> {
2✔
90
        await fs.mkdir(logPath, { recursive: true });
34✔
91

92
        const manager = new MongoLogManager({
34✔
93
            directory: logPath,
34✔
94
            retentionDays: 30,
34✔
95
            onwarn: console.warn,
34✔
96
            onerror: console.error,
34✔
97
            gzip: false,
34✔
98
            retentionGB: 1,
34✔
99
        });
34✔
100

101
        await manager.cleanupOldLogFiles();
34✔
102

103
        const logWriter = await manager.createLogWriter();
34✔
104

105
        return new DiskLogger(logWriter);
34✔
106
    }
34✔
107

108
    log(level: LogLevel, id: MongoLogId, context: string, message: string): void {
2✔
109
        message = redact(message);
459✔
110
        const mongoDBLevel = this.mapToMongoDBLogLevel(level);
459✔
111

112
        this.logWriter[mongoDBLevel]("MONGODB-MCP", id, context, message);
459✔
113
    }
459✔
114

115
    private mapToMongoDBLogLevel(level: LogLevel): "info" | "warn" | "error" | "debug" | "fatal" {
2✔
116
        switch (level) {
459✔
117
            case "info":
459✔
118
                return "info";
136✔
119
            case "warning":
459!
120
                return "warn";
×
121
            case "error":
459✔
122
                return "error";
38✔
123
            case "notice":
459!
124
            case "debug":
459✔
125
                return "debug";
285✔
126
            case "critical":
459!
127
            case "alert":
459!
128
            case "emergency":
459!
129
                return "fatal";
×
130
            default:
459!
131
                return "info";
×
132
        }
459✔
133
    }
459✔
134
}
2✔
135

136
class McpLogger extends LoggerBase {
2✔
137
    constructor(private server: McpServer) {
2✔
138
        super();
34✔
139
    }
34✔
140

141
    log(level: LogLevel, _: MongoLogId, context: string, message: string): void {
2✔
142
        // Only log if the server is connected
143
        if (!this.server?.isConnected()) {
459✔
144
            return;
49✔
145
        }
49✔
146

147
        void this.server.server.sendLoggingMessage({
410✔
148
            level,
410✔
149
            data: `[${context}]: ${message}`,
410✔
150
        });
410✔
151
    }
459✔
152
}
2✔
153

154
class CompositeLogger extends LoggerBase {
2✔
155
    private loggers: LoggerBase[];
156

157
    constructor(...loggers: LoggerBase[]) {
2✔
158
        super();
38✔
159

160
        if (loggers.length === 0) {
38✔
161
            // default to ConsoleLogger
162
            this.loggers = [new ConsoleLogger()];
38✔
163
            return;
38✔
164
        }
38!
165

166
        this.loggers = [...loggers];
×
167
    }
38✔
168

169
    setLoggers(...loggers: LoggerBase[]): void {
2✔
170
        if (loggers.length === 0) {
34!
171
            throw new Error("At least one logger must be provided");
×
UNCOV
172
        }
×
173
        this.loggers = [...loggers];
34✔
174
    }
34✔
175

176
    log(level: LogLevel, id: MongoLogId, context: string, message: string): void {
2✔
177
        for (const logger of this.loggers) {
469✔
178
            logger.log(level, id, context, message);
928✔
179
        }
928✔
180
    }
469✔
181
}
2✔
182

183
const logger = new CompositeLogger();
2✔
184
export default logger;
2✔
185

186
export async function setStdioPreset(server: McpServer, logPath: string): Promise<void> {
34✔
187
    const diskLogger = await DiskLogger.fromPath(logPath);
34✔
188
    const mcpLogger = new McpLogger(server);
34✔
189

190
    logger.setLoggers(mcpLogger, diskLogger);
34✔
191
}
34✔
192

193
export function setContainerPreset(server: McpServer): void {
2✔
194
    const mcpLogger = new McpLogger(server);
×
195
    const consoleLogger = new ConsoleLogger();
×
196

197
    logger.setLoggers(mcpLogger, consoleLogger);
×
UNCOV
198
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc