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

mongodb-js / mongodb-mcp-server / 16876636630

11 Aug 2025 09:51AM UTC coverage: 81.999% (+0.6%) from 81.362%
16876636630

Pull #424

github

web-flow
Merge 602f1c199 into 7572ec5d6
Pull Request #424: feat: adds an export tool and exported-data resource MCP-16

784 of 1003 branches covered (78.17%)

Branch coverage included in aggregate %.

592 of 659 new or added lines in 13 files covered. (89.83%)

18 existing lines in 3 files now uncovered.

4072 of 4919 relevant lines covered (82.78%)

66.27 hits per line

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

80.36
/src/common/config.ts
1
import path from "path";
2✔
2
import os from "os";
2✔
3
import argv from "yargs-parser";
2✔
4

5
import { ReadConcernLevel, ReadPreferenceMode, W } from "mongodb";
6

7
export interface ConnectOptions {
8
    readConcern: ReadConcernLevel;
9
    readPreference: ReadPreferenceMode;
10
    writeConcern: W;
11
    timeoutMS: number;
12
}
13

14
// If we decide to support non-string config options, we'll need to extend the mechanism for parsing
15
// env variables.
16
export interface UserConfig {
17
    apiBaseUrl: string;
18
    apiClientId?: string;
19
    apiClientSecret?: string;
20
    telemetry: "enabled" | "disabled";
21
    logPath: string;
22
    exportsPath: string;
23
    exportTimeoutMs: number;
24
    exportCleanupIntervalMs: number;
25
    connectionString?: string;
26
    connectOptions: ConnectOptions;
27
    disabledTools: Array<string>;
28
    readOnly?: boolean;
29
    indexCheck?: boolean;
30
    transport: "stdio" | "http";
31
    httpPort: number;
32
    httpHost: string;
33
    loggers: Array<"stderr" | "disk" | "mcp">;
34
    idleTimeoutMs: number;
35
    notificationTimeoutMs: number;
36
}
37

38
const defaults: UserConfig = {
2✔
39
    apiBaseUrl: "https://cloud.mongodb.com/",
2✔
40
    logPath: getLogPath(),
2✔
41
    exportsPath: getExportsPath(),
2✔
42
    exportTimeoutMs: 300000, // 5 minutes
2✔
43
    exportCleanupIntervalMs: 120000, // 2 minutes
2✔
44
    connectOptions: {
2✔
45
        readConcern: "local",
2✔
46
        readPreference: "secondaryPreferred",
2✔
47
        writeConcern: "majority",
2✔
48
        timeoutMS: 30_000,
2✔
49
    },
2✔
50
    disabledTools: [],
2✔
51
    telemetry: "enabled",
2✔
52
    readOnly: false,
2✔
53
    indexCheck: false,
2✔
54
    transport: "stdio",
2✔
55
    httpPort: 3000,
2✔
56
    httpHost: "127.0.0.1",
2✔
57
    loggers: ["disk", "mcp"],
2✔
58
    idleTimeoutMs: 600000, // 10 minutes
2✔
59
    notificationTimeoutMs: 540000, // 9 minutes
2✔
60
};
2✔
61

62
export const config = {
2✔
63
    ...defaults,
2✔
64
    ...getEnvConfig(),
2✔
65
    ...getCliConfig(),
2✔
66
};
2✔
67

68
function getLocalDataPath(): string {
152✔
69
    return process.platform === "win32"
152!
NEW
70
        ? path.join(process.env.LOCALAPPDATA || process.env.APPDATA || os.homedir(), "mongodb")
×
71
        : path.join(os.homedir(), ".mongodb");
152✔
72
}
152✔
73

74
function getLogPath(): string {
76✔
75
    const logPath = path.join(getLocalDataPath(), "mongodb-mcp", ".app-logs");
76✔
76
    return logPath;
76✔
77
}
76✔
78

79
function getExportsPath(): string {
76✔
80
    return path.join(getLocalDataPath(), "mongodb-mcp", "exports");
76✔
81
}
76✔
82

83
// Gets the config supplied by the user as environment variables. The variable names
84
// are prefixed with `MDB_MCP_` and the keys match the UserConfig keys, but are converted
85
// to SNAKE_UPPER_CASE.
86
function getEnvConfig(): Partial<UserConfig> {
76✔
87
    function setValue(obj: Record<string, unknown>, path: string[], value: string): void {
76✔
88
        const currentField = path.shift();
114✔
89
        if (!currentField) {
114!
90
            return;
×
91
        }
×
92
        if (path.length === 0) {
114✔
93
            const numberValue = Number(value);
114✔
94
            if (!isNaN(numberValue)) {
114!
95
                obj[currentField] = numberValue;
×
96
                return;
×
97
            }
×
98

99
            const booleanValue = value.toLocaleLowerCase();
114✔
100
            if (booleanValue === "true" || booleanValue === "false") {
114!
101
                obj[currentField] = booleanValue === "true";
×
102
                return;
×
103
            }
×
104

105
            // Try to parse an array of values
106
            if (value.indexOf(",") !== -1) {
114!
107
                obj[currentField] = value.split(",").map((v) => v.trim());
×
108
                return;
×
109
            }
×
110

111
            obj[currentField] = value;
114✔
112
            return;
114✔
113
        }
114!
114

115
        if (!obj[currentField]) {
×
116
            obj[currentField] = {};
×
117
        }
×
118

119
        setValue(obj[currentField] as Record<string, unknown>, path, value);
×
120
    }
114✔
121

122
    const result: Record<string, unknown> = {};
76✔
123
    const mcpVariables = Object.entries(process.env).filter(
76✔
124
        ([key, value]) => value !== undefined && key.startsWith("MDB_MCP_")
76✔
125
    ) as [string, string][];
76✔
126
    for (const [key, value] of mcpVariables) {
76✔
127
        const fieldPath = key
114✔
128
            .replace("MDB_MCP_", "")
114✔
129
            .split(".")
114✔
130
            .map((part) => SNAKE_CASE_toCamelCase(part));
114✔
131

132
        setValue(result, fieldPath, value);
114✔
133
    }
114✔
134

135
    return result;
76✔
136
}
76✔
137

138
function SNAKE_CASE_toCamelCase(str: string): string {
114✔
139
    return str.toLowerCase().replace(/([-_][a-z])/g, (group) => group.toUpperCase().replace("_", ""));
114✔
140
}
114✔
141

142
// Reads the cli args and parses them into a UserConfig object.
143
function getCliConfig(): Partial<UserConfig> {
76✔
144
    return argv(process.argv.slice(2), {
76✔
145
        array: ["disabledTools", "loggers"],
76✔
146
    }) as unknown as Partial<UserConfig>;
76✔
147
}
76✔
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