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

mongodb-js / mongodb-mcp-server / 19908707554

03 Dec 2025 09:01PM UTC coverage: 79.893% (-0.7%) from 80.607%
19908707554

Pull #777

github

web-flow
Merge 0d8d017b1 into e12068a03
Pull Request #777: chore: adopt strict validation for all command line arguments MCP-298

1447 of 1887 branches covered (76.68%)

Branch coverage included in aggregate %.

80 of 114 new or added lines in 6 files covered. (70.18%)

31 existing lines in 3 files now uncovered.

6603 of 8189 relevant lines covered (80.63%)

77.09 hits per line

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

79.59
/src/common/config/createUserConfig.ts
1
import { type CliOptions, generateConnectionInfoFromCliArgs } from "@mongosh/arg-parser";
1!
2
import { Keychain } from "../keychain.js";
1✔
3
import type { Secret } from "../keychain.js";
4
import { matchingConfigKey } from "./configUtils.js";
1✔
5
import { UserConfigSchema, type UserConfig } from "./userConfig.js";
1✔
6
import {
1✔
7
    defaultParserOptions,
8
    parseArgsWithCliOptions,
9
    CliOptionsSchema,
10
    UnknownArgumentError,
11
} from "@mongosh/arg-parser/arg-parser";
12
import type { z as z4 } from "zod/v4";
13

14
export function createUserConfig({ args }: { args: string[] }): {
1✔
15
    warnings: string[];
16
    parsed: UserConfig | undefined;
17
    error: string | undefined;
18
} {
136✔
19
    const { error: parseError, warnings, parsed } = parseUserConfigSources(args);
136✔
20

21
    if (parseError) {
136!
NEW
22
        return { error: parseError, warnings, parsed: undefined };
×
UNCOV
23
    }
×
24

25
    // If we have a connectionSpecifier, which can only appear as the positional
26
    // argument, then that has to be used on priority to construct the
27
    // connection string. In this case, if there is a connection string provided
28
    // by the env variable or config file, that will be overridden.
29
    const { connectionSpecifier } = parsed;
136✔
30
    if (connectionSpecifier) {
136✔
31
        const connectionInfo = generateConnectionInfoFromCliArgs({ ...parsed, connectionSpecifier });
9✔
32
        parsed.connectionString = connectionInfo.connectionString;
9✔
33
    }
9✔
34

35
    const configParseResult = UserConfigSchema.safeParse(parsed);
136✔
36
    const mongoshArguments = CliOptionsSchema.safeParse(parsed);
136✔
37
    const error = configParseResult.error || mongoshArguments.error;
136✔
38
    if (error) {
136✔
39
        return {
11✔
40
            error: `Invalid configuration for the following fields:\n${error.issues.map((issue) => `${issue.path.join(".")} - ${issue.message}`).join("\n")}`,
11✔
41
            warnings,
11✔
42
            parsed: undefined,
11✔
43
        };
11✔
44
    }
11✔
45

46
    // TODO: Separate correctly parsed user config from all other valid
47
    // arguments relevant to mongosh's args-parser.
48
    const userConfig: UserConfig = { ...parsed, ...configParseResult.data };
125✔
49
    registerKnownSecretsInRootKeychain(userConfig);
125✔
50
    return {
125✔
51
        parsed: userConfig,
125✔
52
        warnings,
125✔
53
        error: undefined,
125✔
54
    };
125✔
55
}
125✔
56

57
function parseUserConfigSources(cliArguments: string[]): {
136✔
58
    error: string | undefined;
59
    warnings: string[];
60
    parsed: Partial<CliOptions & z4.infer<typeof UserConfigSchema>>;
61
} {
136✔
62
    let parsed: Partial<CliOptions & z4.infer<typeof UserConfigSchema>>;
136✔
63
    let deprecated: Record<string, keyof UserConfig>;
136✔
64
    try {
136✔
65
        const { parsed: parsedResult, deprecated: deprecatedResult } = parseArgsWithCliOptions({
136✔
66
            args: cliArguments,
136✔
67
            schema: UserConfigSchema,
136✔
68
            parserOptions: {
136✔
69
                // This helps parse the relevant environment variables.
70
                envPrefix: "MDB_MCP_",
136✔
71
                configuration: {
136✔
72
                    ...defaultParserOptions.configuration,
136✔
73
                    // To avoid populating `_` with end-of-flag arguments we explicitly
74
                    // populate `--` variable and altogether ignore them later.
75
                    "populate--": true,
136✔
76
                },
136✔
77
            },
136✔
78
        });
136✔
79
        parsed = parsedResult;
136✔
80
        deprecated = deprecatedResult;
136✔
81

82
        // Delete fileNames - this is a field populated by mongosh but not used by us.
83
        delete parsed.fileNames;
136✔
84
    } catch (error) {
136!
NEW
85
        let errorMessage: string | undefined;
×
NEW
86
        if (error instanceof UnknownArgumentError) {
×
NEW
87
            const matchingKey = matchingConfigKey(error.argument.replace(/^(--)/, ""));
×
NEW
88
            if (matchingKey) {
×
NEW
89
                errorMessage = `Error: Invalid command line argument '${error.argument}'. Did you mean '--${matchingKey}'?`;
×
NEW
90
            } else {
×
NEW
91
                errorMessage = `Error: Invalid command line argument '${error.argument}'.`;
×
NEW
92
            }
×
NEW
93
        }
×
94

NEW
95
        return {
×
NEW
96
            error: errorMessage,
×
NEW
97
            warnings: [],
×
NEW
98
            parsed: {},
×
NEW
99
        };
×
UNCOV
100
    }
×
101

102
    const deprecationWarnings = [
136✔
103
        ...getWarnings(parsed, cliArguments),
136✔
104
        ...Object.entries(deprecated).map(([deprecated, replacement]) => {
136✔
105
            return `Warning: The --${deprecated} argument is deprecated. Use --${replacement} instead.`;
9✔
106
        }),
136✔
107
    ];
136✔
108

109
    return {
136✔
110
        error: undefined,
136✔
111
        warnings: deprecationWarnings,
136✔
112
        parsed,
136✔
113
    };
136✔
114
}
136✔
115

116
function registerKnownSecretsInRootKeychain(userConfig: Partial<UserConfig>): void {
125✔
117
    const keychain = Keychain.root;
125✔
118

119
    const maybeRegister = (value: string | undefined, kind: Secret["kind"]): void => {
125✔
120
        if (value) {
1,500✔
121
            keychain.register(value, kind);
24✔
122
        }
24✔
123
    };
1,500✔
124

125
    maybeRegister(userConfig.apiClientId, "user");
125✔
126
    maybeRegister(userConfig.apiClientSecret, "password");
125✔
127
    maybeRegister(userConfig.awsAccessKeyId, "password");
125✔
128
    maybeRegister(userConfig.awsIamSessionToken, "password");
125✔
129
    maybeRegister(userConfig.awsSecretAccessKey, "password");
125✔
130
    maybeRegister(userConfig.awsSessionToken, "password");
125✔
131
    maybeRegister(userConfig.password, "password");
125✔
132
    maybeRegister(userConfig.tlsCAFile, "url");
125✔
133
    maybeRegister(userConfig.tlsCRLFile, "url");
125✔
134
    maybeRegister(userConfig.tlsCertificateKeyFile, "url");
125✔
135
    maybeRegister(userConfig.tlsCertificateKeyFilePassword, "password");
125✔
136
    maybeRegister(userConfig.username, "user");
125✔
137
}
125✔
138

139
function getWarnings(config: Partial<UserConfig>, cliArguments: string[]): string[] {
136✔
140
    const warnings = [];
136✔
141

142
    if (cliArguments.find((argument: string) => argument.startsWith("--connectionString"))) {
136✔
143
        warnings.push(
6✔
144
            "Warning: The --connectionString argument is deprecated. Prefer using the MDB_MCP_CONNECTION_STRING environment variable or the first positional argument for the connection string."
6✔
145
        );
6✔
146
    }
6✔
147

148
    if (config.nodb) {
136✔
149
        warnings.push(
1✔
150
            "Warning: The nodb option is deprecated and will be removed in a future version. Please remove it from your configuration."
1✔
151
        );
1✔
152
    }
1✔
153

154
    const searchEnabled = config.previewFeatures?.includes("search");
136!
155
    const embeddingsProviderConfigured = !!config.voyageApiKey;
136✔
156
    if (searchEnabled && !embeddingsProviderConfigured) {
136!
NEW
157
        warnings.push(`\
×
158
Warning: Vector search is enabled but no embeddings provider is configured.
159
- Set an embeddings provider configuration option to enable auto-embeddings during document insertion and text-based queries with $vectorSearch.\
UNCOV
160
`);
×
UNCOV
161
    }
×
162

163
    if (!searchEnabled && embeddingsProviderConfigured) {
136!
NEW
164
        warnings.push(`\
×
165
Warning: An embeddings provider is configured but the 'search' preview feature is not enabled.
166
- Enable vector search by adding 'search' to the 'previewFeatures' configuration option, or remove the embeddings provider configuration if not needed.\
UNCOV
167
`);
×
UNCOV
168
    }
×
169
    return warnings;
136✔
170
}
136✔
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

© 2026 Coveralls, Inc