@@ -5,6 +5,7 @@ import type { CliOptions, ConnectionInfo } from "@mongosh/arg-parser";
5
5
import { generateConnectionInfoFromCliArgs } from "@mongosh/arg-parser" ;
6
6
import { Keychain } from "./keychain.js" ;
7
7
import type { Secret } from "./keychain.js" ;
8
+ import levenshtein from "ts-levenshtein" ;
8
9
9
10
// From: https://github.com/mongodb-js/mongosh/blob/main/packages/cli-repl/src/arg-parser.ts
10
11
const OPTIONS = {
@@ -91,6 +92,44 @@ const OPTIONS = {
91
92
} ,
92
93
} as const ;
93
94
95
+ const ALL_CONFIG_KEYS = new Set (
96
+ ( OPTIONS . string as readonly string [ ] )
97
+ . concat ( OPTIONS . array )
98
+ . concat ( OPTIONS . boolean )
99
+ . concat ( Object . keys ( OPTIONS . alias ) )
100
+ ) ;
101
+
102
+ export function validateConfigKey ( key : string ) : { valid : boolean ; suggestion ?: string } {
103
+ if ( ALL_CONFIG_KEYS . has ( key ) ) {
104
+ return { valid : true } ;
105
+ }
106
+
107
+ let minLev = Number . MAX_VALUE ;
108
+ let suggestion = "" ;
109
+
110
+ // find the closest match for a suggestion
111
+ for ( const validKey of ALL_CONFIG_KEYS ) {
112
+ // check if there is an exact case-insensitive match
113
+ if ( validKey . toLowerCase ( ) === key . toLowerCase ( ) ) {
114
+ return { valid : false , suggestion : validKey } ;
115
+ }
116
+
117
+ // else, infer something using levenshtein so we suggest a valid key
118
+ const lev = levenshtein . get ( key , validKey ) ;
119
+ if ( lev < minLev ) {
120
+ minLev = lev ;
121
+ suggestion = validKey ;
122
+ }
123
+ }
124
+
125
+ if ( minLev <= 2 ) {
126
+ // accept up to 2 typos
127
+ return { valid : false , suggestion } ;
128
+ }
129
+
130
+ return { valid : false } ;
131
+ }
132
+
94
133
function isConnectionSpecifier ( arg : string | undefined ) : boolean {
95
134
return (
96
135
arg !== undefined &&
@@ -267,7 +306,13 @@ function parseCliConfig(args: string[]): CliOptions {
267
306
// so we don't have a logger. For stdio, the warning will be received as a string in
268
307
// the client and IDEs like VSCode do show the message in the log window. For HTTP,
269
308
// it will be in the stdout of the process.
270
- warnAboutDeprecatedCliArgs ( { ...parsed , _ : positionalArguments } , console . warn ) ;
309
+ warnAboutDeprecatedOrUnknownCliArgs (
310
+ { ...parsed , _ : positionalArguments } ,
311
+ {
312
+ warn : ( msg ) => console . warn ( msg ) ,
313
+ exit : ( status ) => process . exit ( status ) ,
314
+ }
315
+ ) ;
271
316
272
317
// if we have a positional argument that matches a connection string
273
318
// store it as the connection specifier and remove it from the argument
@@ -280,26 +325,47 @@ function parseCliConfig(args: string[]): CliOptions {
280
325
return parsed ;
281
326
}
282
327
283
- export function warnAboutDeprecatedCliArgs (
284
- args : CliOptions &
285
- UserConfig & {
286
- _ ?: string [ ] ;
287
- } ,
288
- warn : ( msg : string ) => void
328
+ export function warnAboutDeprecatedOrUnknownCliArgs (
329
+ args : Record < string , unknown > ,
330
+ { warn, exit } : { warn : ( msg : string ) => void ; exit : ( status : number ) => void | never }
289
331
) : void {
290
332
let usedDeprecatedArgument = false ;
333
+ let usedInvalidArgument = false ;
334
+
335
+ const knownArgs = args as unknown as UserConfig & CliOptions ;
291
336
// the first position argument should be used
292
337
// instead of --connectionString, as it's how the mongosh works.
293
- if ( args . connectionString ) {
338
+ if ( knownArgs . connectionString ) {
294
339
usedDeprecatedArgument = true ;
295
340
warn (
296
341
"The --connectionString argument is deprecated. Prefer using the first positional argument for the connection string or the MDB_MCP_CONNECTION_STRING environment variable."
297
342
) ;
298
343
}
299
344
300
- if ( usedDeprecatedArgument ) {
345
+ for ( const providedKey of Object . keys ( args ) ) {
346
+ if ( providedKey === "_" ) {
347
+ // positional argument
348
+ continue ;
349
+ }
350
+
351
+ const { valid, suggestion } = validateConfigKey ( providedKey ) ;
352
+ if ( ! valid ) {
353
+ usedInvalidArgument = true ;
354
+ if ( suggestion ) {
355
+ warn ( `Invalid command line argument '${ providedKey } '. Did you mean '${ suggestion } '?` ) ;
356
+ } else {
357
+ warn ( `Invalid command line argument '${ providedKey } '.` ) ;
358
+ }
359
+ }
360
+ }
361
+
362
+ if ( usedInvalidArgument || usedDeprecatedArgument ) {
301
363
warn ( "Refer to https://www.mongodb.com/docs/mcp-server/get-started/ for setting up the MCP Server." ) ;
302
364
}
365
+
366
+ if ( usedInvalidArgument ) {
367
+ exit ( 1 ) ;
368
+ }
303
369
}
304
370
305
371
function commaSeparatedToArray < T extends string [ ] > ( str : string | string [ ] | undefined ) : T {
0 commit comments