Skip to content

Commit 607c250

Browse files
feat: allow reading config from a file
1 parent 8acd47b commit 607c250

File tree

4 files changed

+117
-14
lines changed

4 files changed

+117
-14
lines changed

src/common/config/createUserConfig.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ function parseUserConfigSources(cliArguments: string[]): {
9595
...OPTIONS,
9696
// This helps parse the relevant environment variables.
9797
envPrefix: "MDB_MCP_",
98+
// This is the name of key that yargs-parser will look up in CLI
99+
// arguments (--config) and ENV variables (MDB_MCP_CONFIG) to load an
100+
// initial configuration from.
101+
config: "config",
98102
configuration: {
99103
...OPTIONS.configuration,
100104
// Setting this to true will populate `_` variable which is
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"connectionString": "mongodb://invalid-value-json-localhost:1000",
3+
"loggers": "stderr,stderr"
4+
}

tests/fixtures/valid-config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"connectionString": "mongodb://valid-json-localhost:1000",
3+
"loggers": "stderr"
4+
}

tests/unit/common/config.test.ts

Lines changed: 105 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import path from "path";
12
import { describe, it, expect, vi, beforeEach, afterEach, type MockedFunction } from "vitest";
23
import { type UserConfig, UserConfigSchema } from "../../../src/common/config/userConfig.js";
34
import { type CreateUserConfigHelpers, createUserConfig } from "../../../src/common/config/createUserConfig.js";
@@ -25,6 +26,11 @@ function createEnvironment(): {
2526
};
2627
}
2728

29+
const CONFIG_FIXTURES = {
30+
VALID: path.resolve(import.meta.dirname, "..", "..", "fixtures", "valid-config.json"),
31+
WITH_INVALID_VALUE: path.resolve(import.meta.dirname, "..", "..", "fixtures", "config-with-invalid-value.json"),
32+
};
33+
2834
describe("config", () => {
2935
it("should generate defaults from UserConfigSchema that match expected values", () => {
3036
// Expected hardcoded values (what we had before)
@@ -489,6 +495,87 @@ describe("config", () => {
489495
});
490496
});
491497

498+
describe("loading a config file", () => {
499+
let warn: MockedFunction<CreateUserConfigHelpers["onWarning"]>;
500+
let error: MockedFunction<CreateUserConfigHelpers["onError"]>;
501+
let exit: MockedFunction<CreateUserConfigHelpers["closeProcess"]>;
502+
503+
beforeEach(() => {
504+
warn = vi.fn();
505+
error = vi.fn();
506+
exit = vi.fn();
507+
});
508+
509+
describe("through env variable MDB_MCP_CONFIG", () => {
510+
const { setVariable, clearVariables } = createEnvironment();
511+
afterEach(() => {
512+
clearVariables();
513+
});
514+
515+
it("should load a valid config file without troubles", () => {
516+
setVariable("MDB_MCP_CONFIG", CONFIG_FIXTURES.VALID);
517+
const config = createUserConfig({
518+
onWarning: warn,
519+
onError: error,
520+
closeProcess: exit,
521+
});
522+
expect(warn).not.toBeCalled();
523+
expect(error).not.toBeCalled();
524+
expect(exit).not.toBeCalled();
525+
526+
expect(config.connectionString).toBe("mongodb://valid-json-localhost:1000");
527+
expect(config.loggers).toStrictEqual(["stderr"]);
528+
});
529+
530+
it("should attempt loading config file with wrong value and exit", () => {
531+
setVariable("MDB_MCP_CONFIG", CONFIG_FIXTURES.WITH_INVALID_VALUE);
532+
createUserConfig({
533+
onWarning: warn,
534+
onError: error,
535+
closeProcess: exit,
536+
});
537+
expect(warn).not.toBeCalled();
538+
expect(error).toBeCalledWith(
539+
expect.stringContaining("Invalid configuration for the following fields:")
540+
);
541+
expect(error).toBeCalledWith(expect.stringContaining("loggers - Duplicate loggers found in config"));
542+
expect(exit).toBeCalledWith(1);
543+
});
544+
});
545+
546+
describe("through cli argument --config", () => {
547+
it("should load a valid config file without troubles", () => {
548+
const config = createUserConfig({
549+
onWarning: warn,
550+
onError: error,
551+
closeProcess: exit,
552+
cliArguments: ["--config", CONFIG_FIXTURES.VALID],
553+
});
554+
expect(warn).not.toBeCalled();
555+
expect(error).not.toBeCalled();
556+
expect(exit).not.toBeCalled();
557+
558+
expect(config.connectionString).toBe("mongodb://valid-json-localhost:1000");
559+
expect(config.loggers).toStrictEqual(["stderr"]);
560+
});
561+
562+
it("should attempt loading config file with wrong value and exit", () => {
563+
createUserConfig({
564+
onWarning: warn,
565+
onError: error,
566+
closeProcess: exit,
567+
cliArguments: ["--config", CONFIG_FIXTURES.WITH_INVALID_VALUE],
568+
});
569+
expect(warn).not.toBeCalled();
570+
expect(error).toBeCalledWith(
571+
expect.stringContaining("Invalid configuration for the following fields:")
572+
);
573+
expect(error).toBeCalledWith(expect.stringContaining("loggers - Duplicate loggers found in config"));
574+
expect(exit).toBeCalledWith(1);
575+
});
576+
});
577+
});
578+
492579
describe("precedence rules", () => {
493580
const { setVariable, clearVariables } = createEnvironment();
494581

@@ -499,30 +586,34 @@ describe("config", () => {
499586
it("positional argument takes precedence over all", () => {
500587
setVariable("MDB_MCP_CONNECTION_STRING", "mongodb://crazyhost1");
501588
const actual = createUserConfig({
502-
cliArguments: ["mongodb://crazyhost2", "--connectionString", "mongodb://localhost"],
589+
cliArguments: [
590+
"mongodb://crazyhost2",
591+
"--config",
592+
CONFIG_FIXTURES.VALID,
593+
"--connectionString",
594+
"mongodb://localhost",
595+
],
503596
});
504597
expect(actual.connectionString).toBe("mongodb://crazyhost2/?directConnection=true");
505598
});
506599

507-
it("cli arguments take precedence over env vars", () => {
508-
setVariable("MDB_MCP_CONNECTION_STRING", "mongodb://crazyhost");
600+
it("any cli argument takes precedence over env vars, config and defaults", () => {
601+
setVariable("MDB_MCP_CONNECTION_STRING", "mongodb://dummyhost");
509602
const actual = createUserConfig({
510-
cliArguments: ["--connectionString", "mongodb://localhost"],
603+
cliArguments: ["--config", CONFIG_FIXTURES.VALID, "--connectionString", "mongodb://host-from-cli"],
511604
});
512-
expect(actual.connectionString).toBe("mongodb://localhost");
605+
expect(actual.connectionString).toBe("mongodb://host-from-cli");
513606
});
514607

515-
it("any cli argument takes precedence over defaults", () => {
516-
const actual = createUserConfig({
517-
cliArguments: ["--connectionString", "mongodb://localhost"],
518-
});
519-
expect(actual.connectionString).toBe("mongodb://localhost");
608+
it("any env var takes precedence over config and defaults", () => {
609+
setVariable("MDB_MCP_CONNECTION_STRING", "mongodb://dummyhost");
610+
const actual = createUserConfig({ cliArguments: ["--config", CONFIG_FIXTURES.VALID] });
611+
expect(actual.connectionString).toBe("mongodb://dummyhost");
520612
});
521613

522-
it("any env var takes precedence over defaults", () => {
523-
setVariable("MDB_MCP_CONNECTION_STRING", "mongodb://localhost");
524-
const actual = createUserConfig();
525-
expect(actual.connectionString).toBe("mongodb://localhost");
614+
it("config file takes precendence over defaults", () => {
615+
const actual = createUserConfig({ cliArguments: ["--config", CONFIG_FIXTURES.VALID] });
616+
expect(actual.connectionString).toBe("mongodb://valid-json-localhost:1000");
526617
});
527618
});
528619

0 commit comments

Comments
 (0)