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

mongodb-js / mongodb-mcp-server / 19928292758

04 Dec 2025 12:03PM UTC coverage: 80.172% (-0.4%) from 80.581%
19928292758

Pull #777

github

web-flow
Merge 305c35330 into 18ff7cc01
Pull Request #777: chore: adopt strict validation for all command line arguments MCP-298

1451 of 1892 branches covered (76.69%)

Branch coverage included in aggregate %.

82 of 121 new or added lines in 8 files covered. (67.77%)

18 existing lines in 2 files now uncovered.

6640 of 8200 relevant lines covered (80.98%)

79.9 hits per line

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

84.66
/src/common/config/configUtils.ts
1
import path from "path";
3✔
2
import os from "os";
3✔
3
import { ALL_CONFIG_KEYS } from "./userConfig.js";
3✔
4
import * as levenshteinModule from "ts-levenshtein";
3✔
5
const levenshtein = levenshteinModule.default;
3✔
6

7
/// Custom logic function to apply the override value.
8
/// Returns the value to use (which may be transformed from newValue).
9
/// Should throw an error if the override cannot be applied.
10
export type CustomOverrideLogic = (oldValue: unknown, newValue: unknown) => unknown;
11

12
/**
13
 * Defines how a config field can be overridden via HTTP headers or query parameters.
14
 */
15
export type OverrideBehavior =
16
    /// Cannot be overridden via request
17
    | "not-allowed"
18
    /// Can be completely replaced
19
    | "override"
20
    /// Values are merged (for arrays)
21
    | "merge"
22
    | CustomOverrideLogic;
23

24
/**
25
 * Metadata for config schema fields.
26
 */
27
export type ConfigFieldMeta = {
28
    /**
29
     * Custom description for the default value, used when generating documentation.
30
     */
31
    defaultValueDescription?: string;
32
    /**
33
     * Marks the field as containing sensitive/secret information, used for MCP Registry.
34
     * Secret fields will be marked as secret in environment variable definitions.
35
     */
36
    isSecret?: boolean;
37
    /**
38
     * Defines how this config field can be overridden via HTTP headers or query parameters.
39
     * Defaults to "not-allowed" for security.
40
     */
41
    overrideBehavior?: OverrideBehavior;
42
    [key: string]: unknown;
43
};
44

45
export function matchingConfigKey(key: string): string | undefined {
3✔
UNCOV
46
    let minLev = Number.MAX_VALUE;
×
UNCOV
47
    let suggestion = undefined;
×
UNCOV
48
    for (const validKey of ALL_CONFIG_KEYS) {
×
UNCOV
49
        const lev = levenshtein.get(key, validKey);
×
50
        // Accepting upto 2 typos and should be better than whatever previous
51
        // suggestion was.
UNCOV
52
        if (lev <= 2 && lev < minLev) {
×
UNCOV
53
            minLev = lev;
×
UNCOV
54
            suggestion = validKey;
×
UNCOV
55
        }
×
UNCOV
56
    }
×
57

UNCOV
58
    return suggestion;
×
UNCOV
59
}
×
60

61
export function getLocalDataPath(): string {
3✔
62
    return process.platform === "win32"
110!
63
        ? path.join(process.env.LOCALAPPDATA || process.env.APPDATA || os.homedir(), "mongodb")
×
64
        : path.join(os.homedir(), ".mongodb");
110✔
65
}
110✔
66

67
export function getLogPath(): string {
3✔
68
    const logPath = path.join(getLocalDataPath(), "mongodb-mcp", ".app-logs");
55✔
69
    return logPath;
55✔
70
}
55✔
71

72
export function getExportsPath(): string {
3✔
73
    return path.join(getLocalDataPath(), "mongodb-mcp", "exports");
55✔
74
}
55✔
75

76
export function commaSeparatedToArray<T extends string[]>(str: string | string[] | undefined): T | undefined {
3✔
77
    if (str === undefined) {
24!
78
        return undefined;
×
79
    }
×
80

81
    if (typeof str === "string") {
24✔
82
        return str
14✔
83
            .split(",")
14✔
84
            .map((e) => e.trim())
14✔
85
            .filter((e) => e.length > 0) as T;
14✔
86
    }
14✔
87

88
    if (str.length === 1) {
19✔
89
        return str[0]
9✔
90
            ?.split(",")
9✔
91
            .map((e) => e.trim())
9✔
92
            .filter((e) => e.length > 0) as T;
9✔
93
    }
9✔
94

95
    return str as T;
1✔
96
}
1✔
97

98
/**
99
 * Preprocessor for boolean values that handles string "false"/"0" correctly.
100
 * Zod's coerce.boolean() treats any non-empty string as true, which is not what we want.
101
 */
102
export function parseBoolean(val: unknown): unknown {
3✔
103
    if (val === undefined) {
50!
104
        return undefined;
×
105
    }
×
106
    if (typeof val === "string") {
50✔
107
        if (val === "false") {
28✔
108
            return false;
5✔
109
        }
5✔
110
        if (val === "true") {
27✔
111
            return true;
16✔
112
        }
16✔
113
        throw new Error(`Invalid boolean value: ${val}`);
7✔
114
    }
7✔
115
    if (typeof val === "boolean") {
22✔
116
        return val;
22✔
117
    }
22!
118
    if (typeof val === "number") {
×
119
        return val !== 0;
×
120
    }
×
121
    return !!val;
×
122
}
×
123

124
/** Allow overriding only to the allowed value */
125
export function oneWayOverride<T>(allowedValue: T): CustomOverrideLogic {
3✔
126
    return (oldValue, newValue) => {
162✔
127
        // Only allow override if setting to allowed value or current value
128
        if (newValue === oldValue) {
18✔
129
            return newValue;
2✔
130
        }
2✔
131
        if (newValue === allowedValue) {
18✔
132
            return newValue;
12✔
133
        }
12✔
134
        throw new Error(`Can only set to ${String(allowedValue)}`);
4✔
135
    };
18✔
136
}
162✔
137

138
/** Allow overriding only to a value lower than the specified value */
139
export function onlyLowerThanBaseValueOverride(): CustomOverrideLogic {
3✔
140
    return (oldValue, newValue) => {
221✔
141
        if (typeof oldValue !== "number") {
13✔
142
            throw new Error(`Unsupported type for base value for override: ${typeof oldValue}`);
1✔
143
        }
1✔
144
        if (typeof newValue !== "number") {
13✔
145
            throw new Error(`Unsupported type for new value for override: ${typeof newValue}`);
1✔
146
        }
1✔
147
        if (newValue >= oldValue) {
11✔
148
            throw new Error(`Can only set to a value lower than the base value`);
4✔
149
        }
4✔
150
        return newValue;
7✔
151
    };
13✔
152
}
221✔
153

154
/** Allow overriding only to a subset of an array but not a superset */
155
export function onlySubsetOfBaseValueOverride(): CustomOverrideLogic {
3✔
156
    return (oldValue, newValue) => {
63✔
157
        if (!Array.isArray(oldValue)) {
12✔
158
            throw new Error(`Unsupported type for base value for override: ${typeof oldValue}`);
1✔
159
        }
1✔
160
        if (!Array.isArray(newValue)) {
12✔
161
            throw new Error(`Unsupported type for new value for override: ${typeof newValue}`);
1✔
162
        }
1✔
163
        if (newValue.length > oldValue.length) {
12✔
164
            throw new Error(`Can only override to a subset of the base value`);
3✔
165
        }
3✔
166
        if (!newValue.every((value) => oldValue.includes(value))) {
12✔
167
            throw new Error(`Can only override to a subset of the base value`);
1✔
168
        }
1✔
169
        return newValue as unknown;
6✔
170
    };
12✔
171
}
63✔
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