@@ -4,21 +4,34 @@ import argv from "yargs-parser";
4
4
5
5
import packageJson from "../package.json" with { type : "json" } ;
6
6
import fs from "fs" ;
7
+ import { ReadConcernLevel , ReadPreferenceMode , W } from "mongodb" ;
7
8
const { localDataPath, configPath } = getLocalDataPath ( ) ;
8
9
9
10
// If we decide to support non-string config options, we'll need to extend the mechanism for parsing
10
11
// env variables.
11
- interface UserConfig extends Record < string , string | undefined > {
12
+ interface UserConfig extends Record < string , unknown > {
12
13
apiBaseUrl : string ;
13
14
clientId : string ;
14
15
stateFile : string ;
15
16
connectionString ?: string ;
17
+ connectOptions : {
18
+ readConcern : ReadConcernLevel ;
19
+ readPreference : ReadPreferenceMode ;
20
+ writeConcern : W ;
21
+ timeoutMS : number ;
22
+ } ;
16
23
}
17
24
18
25
const defaults : UserConfig = {
19
26
apiBaseUrl : "https://cloud.mongodb.com/" ,
20
27
clientId : "0oabtxactgS3gHIR0297" ,
21
28
stateFile : path . join ( localDataPath , "state.json" ) ,
29
+ connectOptions : {
30
+ readConcern : "local" ,
31
+ readPreference : "secondaryPreferred" ,
32
+ writeConcern : "majority" ,
33
+ timeoutMS : 30_000 ,
34
+ } ,
22
35
} ;
23
36
24
37
const mergedUserConfig = {
@@ -66,21 +79,51 @@ function getLocalDataPath(): { localDataPath: string; configPath: string } {
66
79
// are prefixed with `MDB_MCP_` and the keys match the UserConfig keys, but are converted
67
80
// to SNAKE_UPPER_CASE.
68
81
function getEnvConfig ( ) : Partial < UserConfig > {
69
- const camelCaseToSNAKE_UPPER_CASE = ( str : string ) : string => {
70
- return str . replace ( / ( [ a - z ] ) ( [ A - Z ] ) / g, "$1_$2" ) . toUpperCase ( ) ;
71
- } ;
82
+ function setValue ( obj : Record < string , unknown > , path : string [ ] , value : string ) : void {
83
+ const currentField = path . shift ( ) ! ;
84
+ if ( path . length === 0 ) {
85
+ const numberValue = Number ( value ) ;
86
+ if ( ! isNaN ( numberValue ) ) {
87
+ obj [ currentField ] = numberValue ;
88
+ return ;
89
+ }
90
+
91
+ const booleanValue = value . toLocaleLowerCase ( ) ;
92
+ if ( booleanValue === "true" || booleanValue === "false" ) {
93
+ obj [ currentField ] = booleanValue === "true" ;
94
+ return ;
95
+ }
96
+
97
+ obj [ currentField ] = value ;
98
+ return ;
99
+ }
72
100
73
- const result : Partial < UserConfig > = { } ;
74
- for ( const key of Object . keys ( defaults ) ) {
75
- const envVarName = `MDB_MCP_${ camelCaseToSNAKE_UPPER_CASE ( key ) } ` ;
76
- if ( process . env [ envVarName ] ) {
77
- result [ key ] = process . env [ envVarName ] ;
101
+ if ( ! obj [ currentField ] ) {
102
+ obj [ currentField ] = { } ;
78
103
}
104
+
105
+ setValue ( obj [ currentField ] as Record < string , unknown > , path , value ) ;
106
+ }
107
+
108
+ const result : Record < string , unknown > = { } ;
109
+ for ( const [ key , value ] of Object . entries ( process . env ) . filter (
110
+ ( [ key , value ] ) => value !== undefined && key . startsWith ( "MDB_MCP_" )
111
+ ) ) {
112
+ const fieldPath = key
113
+ . replace ( "MDB_MCP_" , "" )
114
+ . split ( "." )
115
+ . map ( ( part ) => SNAKE_CASE_toCamelCase ( part ) ) ;
116
+
117
+ setValue ( result , fieldPath , value ! ) ;
79
118
}
80
119
81
120
return result ;
82
121
}
83
122
123
+ function SNAKE_CASE_toCamelCase ( str : string ) : string {
124
+ return str . toLowerCase ( ) . replace ( / ( [ - _ ] [ a - z ] ) / g, ( group ) => group . toUpperCase ( ) . replace ( "_" , "" ) ) ;
125
+ }
126
+
84
127
// Gets the config supplied by the user as a JSON file. The file is expected to be located in the local data path
85
128
// and named `config.json`.
86
129
function getFileConfig ( ) : Partial < UserConfig > {
0 commit comments