Skip to content

Commit 4b8fe45

Browse files
committed
chore: support schema overrides and parserOptions
1 parent cced0c7 commit 4b8fe45

File tree

5 files changed

+96
-37
lines changed

5 files changed

+96
-37
lines changed

MCP_SERVER_LIBRARY.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import {
4949
Session,
5050
UserConfig,
5151
UserConfigSchema,
52-
parseCliArgumentsAsUserConfig,
52+
parseUserConfig,
5353
StreamableHttpRunner,
5454
StdioRunner,
5555
TransportRunnerBase,
@@ -811,26 +811,25 @@ const customConfig = UserConfigSchema.parse({
811811

812812
This approach ensures you get all the default values without having to specify every configuration key manually.
813813

814-
### parseCliArgumentsAsUserConfig
814+
### parseUserConfig
815815

816816
Utility function to parse command-line arguments and environment variables into a UserConfig object, using the same parsing logic as the MongoDB MCP server CLI.
817817

818818
_Note: This is what MongoDB MCP server uses internally._
819819

820820
```typescript
821-
function parseCliArgumentsAsUserConfig(options?: {
821+
function parseUserConfig(options?: {
822822
args?: string[];
823-
helpers?: CreateUserConfigHelpers;
824823
}): UserConfig;
825824
```
826825

827826
**Example:**
828827

829828
```typescript
830-
import { parseCliArgumentsAsUserConfig, StdioRunner } from "mongodb-mcp-server";
829+
import { parseUserConfig, StdioRunner } from "mongodb-mcp-server";
831830

832831
// Parse config from process.argv and environment variables
833-
const config = parseCliArgumentsAsUserConfig();
832+
const config = parseUserConfig();
834833

835834
const runner = new StdioRunner({ userConfig: config });
836835
await runner.start();

src/common/config/createUserConfig.ts

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,52 @@ import type { Secret } from "../keychain.js";
44
import { matchingConfigKey } from "./configUtils.js";
55
import { UserConfigSchema, type UserConfig } from "./userConfig.js";
66
import {
7-
defaultParserOptions,
7+
defaultParserOptions as defaultArgParserOptions,
88
parseArgsWithCliOptions,
99
CliOptionsSchema,
1010
UnknownArgumentError,
1111
} from "@mongosh/arg-parser/arg-parser";
12-
import type { z as z4 } from "zod/v4";
13-
14-
export function createUserConfig({ args }: { args: string[] }): {
12+
import { z as z4 } from "zod/v4";
13+
import type yargsParser from "yargs-parser";
14+
15+
export type ParserOptions = Partial<yargsParser.Options>;
16+
17+
export const defaultParserOptions = {
18+
// This is the name of key that yargs-parser will look up in CLI
19+
// arguments (--config) and ENV variables (MDB_MCP_CONFIG) to load an
20+
// initial configuration from.
21+
config: "config",
22+
// This helps parse the relevant environment variables.
23+
envPrefix: "MDB_MCP_",
24+
configuration: {
25+
...defaultArgParserOptions.configuration,
26+
// To avoid populating `_` with end-of-flag arguments we explicitly
27+
// populate `--` variable and altogether ignore them later.
28+
"populate--": true,
29+
},
30+
} satisfies ParserOptions;
31+
32+
export function createUserConfig({
33+
args,
34+
overrides,
35+
parserOptions = defaultParserOptions,
36+
}: {
37+
args: string[];
38+
overrides?: z4.ZodRawShape;
39+
parserOptions?: ParserOptions;
40+
}): {
1541
warnings: string[];
1642
parsed: UserConfig | undefined;
1743
error: string | undefined;
1844
} {
19-
const { error: parseError, warnings, parsed } = parseUserConfigSources(args);
45+
const schema = overrides
46+
? z4.object({
47+
...UserConfigSchema.shape,
48+
...overrides,
49+
})
50+
: UserConfigSchema;
51+
52+
const { error: parseError, warnings, parsed } = parseUserConfigSources({ args, schema, parserOptions });
2053

2154
if (parseError) {
2255
return { error: parseError, warnings, parsed: undefined };
@@ -40,7 +73,7 @@ export function createUserConfig({ args }: { args: string[] }): {
4073
parsed.connectionString = connectionInfo.connectionString;
4174
}
4275

43-
const configParseResult = UserConfigSchema.safeParse(parsed);
76+
const configParseResult = schema.safeParse(parsed);
4477
const mongoshArguments = CliOptionsSchema.safeParse(parsed);
4578
const error = configParseResult.error || mongoshArguments.error;
4679
if (error) {
@@ -62,34 +95,29 @@ export function createUserConfig({ args }: { args: string[] }): {
6295
};
6396
}
6497

65-
function parseUserConfigSources(cliArguments: string[]): {
98+
function parseUserConfigSources<T extends typeof UserConfigSchema>({
99+
args,
100+
schema = UserConfigSchema as T,
101+
parserOptions,
102+
}: {
103+
args: string[];
104+
schema: T;
105+
parserOptions: ParserOptions;
106+
}): {
66107
error: string | undefined;
67108
warnings: string[];
68-
parsed: Partial<CliOptions & z4.infer<typeof UserConfigSchema>>;
109+
parsed: Partial<CliOptions & z4.infer<T>>;
69110
} {
70-
let parsed: Partial<CliOptions & z4.infer<typeof UserConfigSchema>>;
71-
let deprecated: Record<string, keyof UserConfig>;
111+
let parsed: Partial<CliOptions & z4.infer<T>>;
112+
let deprecated: Record<string, string>;
72113
try {
73114
const { parsed: parsedResult, deprecated: deprecatedResult } = parseArgsWithCliOptions({
74-
args: cliArguments,
75-
schema: UserConfigSchema,
76-
parserOptions: {
77-
// This is the name of key that yargs-parser will look up in CLI
78-
// arguments (--config) and ENV variables (MDB_MCP_CONFIG) to load an
79-
// initial configuration from.
80-
config: "config",
81-
// This helps parse the relevant environment variables.
82-
envPrefix: "MDB_MCP_",
83-
configuration: {
84-
...defaultParserOptions.configuration,
85-
// To avoid populating `_` with end-of-flag arguments we explicitly
86-
// populate `--` variable and altogether ignore them later.
87-
"populate--": true,
88-
},
89-
},
115+
args,
116+
schema,
117+
parserOptions,
90118
});
91119
parsed = parsedResult;
92-
deprecated = deprecatedResult;
120+
deprecated = deprecatedResult as Record<string, string>;
93121

94122
// Delete fileNames - this is a field populated by mongosh but not used by us.
95123
delete parsed.fileNames;
@@ -112,7 +140,7 @@ function parseUserConfigSources(cliArguments: string[]): {
112140
}
113141

114142
const deprecationWarnings = [
115-
...getWarnings(parsed, cliArguments),
143+
...getWarnings(parsed, args),
116144
...Object.entries(deprecated).map(([deprecated, replacement]) => {
117145
return `Warning: The --${deprecated} argument is deprecated. Use --${replacement} instead.`;
118146
}),

src/lib.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export { Server, type ServerOptions } from "./server.js";
22
export { Session, type SessionOptions } from "./common/session.js";
33
export { type UserConfig, UserConfigSchema } from "./common/config/userConfig.js";
4-
export { createUserConfig as parseCliArgumentsAsUserConfig } from "./common/config/createUserConfig.js";
4+
export { createUserConfig, defaultParserOptions, type ParserOptions } from "./common/config/createUserConfig.js";
55
export { LoggerBase, type LogPayload, type LoggerType, type LogLevel } from "./common/logger.js";
66
export { StreamableHttpRunner } from "./transports/streamableHttp.js";
77
export { StdioRunner } from "./transports/stdio.js";

src/transports/base.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export type TransportRunnerConfig = {
7575
*
7676
* To parse CLI arguments and environment variables in order to generate a
7777
* `UserConfig` object, you can use `createUserConfig` function, also
78-
* exported as `parseCliArgumentsAsUserConfig` through MCP server library
78+
* exported as `parseUserConfig` through MCP server library
7979
* exports.
8080
*
8181
* Optionally, you can also use `UserConfigSchema` (available through MCP

tests/unit/common/config.test.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { describe, it, expect, beforeEach, afterEach } from "vitest";
22
import { type UserConfig, UserConfigSchema } from "../../../src/common/config/userConfig.js";
3-
import { createUserConfig } from "../../../src/common/config/createUserConfig.js";
3+
import { createUserConfig, defaultParserOptions } from "../../../src/common/config/createUserConfig.js";
44
import {
55
getLogPath,
66
getExportsPath,
@@ -69,6 +69,24 @@ describe("config", () => {
6969
});
7070
});
7171

72+
it("can override defaults in the schema and those are populated instead", () => {
73+
expect(
74+
createUserConfig({
75+
args: [],
76+
overrides: {
77+
exportTimeoutMs: UserConfigSchema.shape.exportTimeoutMs.default(123),
78+
},
79+
})
80+
).toStrictEqual({
81+
parsed: {
82+
...expectedDefaults,
83+
exportTimeoutMs: 123,
84+
},
85+
warnings: [],
86+
error: undefined,
87+
});
88+
});
89+
7290
describe("env var parsing", () => {
7391
const { setVariable, clearVariables } = createEnvironment();
7492

@@ -143,6 +161,20 @@ describe("config", () => {
143161
});
144162
}
145163
});
164+
165+
it("works with custom prefixes through parserOptions", () => {
166+
setVariable("CUSTOM_MCP_DISABLED_TOOLS", "find,export");
167+
// Ensure our own ENV doesn't affect it
168+
setVariable("MDB_MCP_DISABLED_TOOLS", "explain");
169+
const { parsed: actual } = createUserConfig({
170+
args: [],
171+
parserOptions: {
172+
...defaultParserOptions,
173+
envPrefix: "CUSTOM_MCP_",
174+
},
175+
});
176+
expect(actual?.disabledTools).toEqual(["find", "export"]);
177+
});
146178
});
147179

148180
describe("cli parsing", () => {

0 commit comments

Comments
 (0)