Skip to content
39 changes: 20 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,25 +323,26 @@ The MongoDB MCP Server can be configured using multiple methods, with the follow

### Configuration Options

| CLI Option | Environment Variable | Default | Description |
| ------------------------- | ------------------------------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apiClientId` | `MDB_MCP_API_CLIENT_ID` | <not set> | Atlas API client ID for authentication. Required for running Atlas tools. |
| `apiClientSecret` | `MDB_MCP_API_CLIENT_SECRET` | <not set> | Atlas API client secret for authentication. Required for running Atlas tools. |
| `connectionString` | `MDB_MCP_CONNECTION_STRING` | <not set> | MongoDB connection string for direct database connections. Optional, if not set, you'll need to call the `connect` tool before interacting with MongoDB data. |
| `loggers` | `MDB_MCP_LOGGERS` | disk,mcp | Comma separated values, possible values are `mcp`, `disk` and `stderr`. See [Logger Options](#logger-options) for details. |
| `logPath` | `MDB_MCP_LOG_PATH` | see note\* | Folder to store logs. |
| `disabledTools` | `MDB_MCP_DISABLED_TOOLS` | <not set> | An array of tool names, operation types, and/or categories of tools that will be disabled. |
| `readOnly` | `MDB_MCP_READ_ONLY` | false | When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations. |
| `indexCheck` | `MDB_MCP_INDEX_CHECK` | false | When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan. |
| `telemetry` | `MDB_MCP_TELEMETRY` | enabled | When set to disabled, disables telemetry collection. |
| `transport` | `MDB_MCP_TRANSPORT` | stdio | Either 'stdio' or 'http'. |
| `httpPort` | `MDB_MCP_HTTP_PORT` | 3000 | Port number. |
| `httpHost` | `MDB_MCP_HTTP_HOST` | 127.0.0.1 | Host to bind the http server. |
| `idleTimeoutMs` | `MDB_MCP_IDLE_TIMEOUT_MS` | 600000 | Idle timeout for a client to disconnect (only applies to http transport). |
| `notificationTimeoutMs` | `MDB_MCP_NOTIFICATION_TIMEOUT_MS` | 540000 | Notification timeout for a client to be aware of diconnect (only applies to http transport). |
| `exportsPath` | `MDB_MCP_EXPORTS_PATH` | see note\* | Folder to store exported data files. |
| `exportTimeoutMs` | `MDB_MCP_EXPORT_TIMEOUT_MS` | 300000 | Time in milliseconds after which an export is considered expired and eligible for cleanup. |
| `exportCleanupIntervalMs` | `MDB_MCP_EXPORT_CLEANUP_INTERVAL_MS` | 120000 | Time in milliseconds between export cleanup cycles that remove expired export files. |
| CLI Option | Environment Variable | Default | Description |
| -------------------------------------- | --------------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apiClientId` | `MDB_MCP_API_CLIENT_ID` | <not set> | Atlas API client ID for authentication. Required for running Atlas tools. |
| `apiClientSecret` | `MDB_MCP_API_CLIENT_SECRET` | <not set> | Atlas API client secret for authentication. Required for running Atlas tools. |
| `connectionString` | `MDB_MCP_CONNECTION_STRING` | <not set> | MongoDB connection string for direct database connections. Optional, if not set, you'll need to call the `connect` tool before interacting with MongoDB data. |
| `loggers` | `MDB_MCP_LOGGERS` | disk,mcp | Comma separated values, possible values are `mcp`, `disk` and `stderr`. See [Logger Options](#logger-options) for details. |
| `logPath` | `MDB_MCP_LOG_PATH` | see note\* | Folder to store logs. |
| `disabledTools` | `MDB_MCP_DISABLED_TOOLS` | <not set> | An array of tool names, operation types, and/or categories of tools that will be disabled. |
| `readOnly` | `MDB_MCP_READ_ONLY` | false | When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations. |
| `indexCheck` | `MDB_MCP_INDEX_CHECK` | false | When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan. |
| `telemetry` | `MDB_MCP_TELEMETRY` | enabled | When set to disabled, disables telemetry collection. |
| `transport` | `MDB_MCP_TRANSPORT` | stdio | Either 'stdio' or 'http'. |
| `httpPort` | `MDB_MCP_HTTP_PORT` | 3000 | Port number. |
| `httpHost` | `MDB_MCP_HTTP_HOST` | 127.0.0.1 | Host to bind the http server. |
| `idleTimeoutMs` | `MDB_MCP_IDLE_TIMEOUT_MS` | 600000 | Idle timeout for a client to disconnect (only applies to http transport). |
| `notificationTimeoutMs` | `MDB_MCP_NOTIFICATION_TIMEOUT_MS` | 540000 | Notification timeout for a client to be aware of diconnect (only applies to http transport). |
| `exportsPath` | `MDB_MCP_EXPORTS_PATH` | see note\* | Folder to store exported data files. |
| `exportTimeoutMs` | `MDB_MCP_EXPORT_TIMEOUT_MS` | 300000 | Time in milliseconds after which an export is considered expired and eligible for cleanup. |
| `exportCleanupIntervalMs` | `MDB_MCP_EXPORT_CLEANUP_INTERVAL_MS` | 120000 | Time in milliseconds between export cleanup cycles that remove expired export files. |
| `atlasTemporaryDatabaseUserLifetimeMs` | `MDB_MCP_ATLAS_TEMPORARY_DATABASE_USER_LIFETIME_MS` | 14400000 | Time in milliseconds that temporary database users created when connecting to MongoDB Atlas clusters will remain active before being automatically deleted. |

#### Logger Options

Expand Down
16 changes: 15 additions & 1 deletion src/common/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { Secret } from "./keychain.js";
import levenshtein from "ts-levenshtein";

// From: https://github.com/mongodb-js/mongosh/blob/main/packages/cli-repl/src/arg-parser.ts
const OPTIONS = {
const MONGOSH_OPTIONS = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is a problem. The options that you see here are not all MONGOSH options. They contain MCP related options as well.

I don't have strong opinion on fixing this right now but consider that this is only a partial solution. We still need to address it entirely, perhaps with https://jira.mongodb.org/browse/MCP-202

string: [
"apiBaseUrl",
"apiClientId",
Expand Down Expand Up @@ -92,6 +92,18 @@ const OPTIONS = {
},
} as const;

const MCP_SERVER_OPTIONS = {
string: ["atlasTemporaryDatabaseUserLifetimeMs"],
} as const;

const OPTIONS = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is fine. alternative idea for consideration but non-blocking:

function mergeOptions(...optionSources: Array<Record<string, any>>) {
    return {
        string: optionSources.flatMap(opts => opts.string ?? []),
        boolean: optionSources.flatMap(opts => opts.boolean ?? []),
        array: optionSources.flatMap(opts => opts.array ?? []),
        alias: Object.assign({}, ...optionSources.map(opts => opts.alias ?? {})),
        configuration: Object.assign({}, ...optionSources.map(opts => opts.configuration ?? {})),
    } as const;
}

const OPTIONS = mergeOptions(MONGOSH_OPTIONS, MCP_SERVER_OPTIONS);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have accepted your suggestion.

I had to introduce a new Options interface to make the linter happy.

string: [...MONGOSH_OPTIONS.string, ...MCP_SERVER_OPTIONS.string],
boolean: [...MONGOSH_OPTIONS.boolean],
array: [...MONGOSH_OPTIONS.array],
alias: { ...MONGOSH_OPTIONS.alias },
configuration: { ...MONGOSH_OPTIONS.configuration },
} as const;

const ALL_CONFIG_KEYS = new Set(
(OPTIONS.string as readonly string[])
.concat(OPTIONS.array)
Expand Down Expand Up @@ -161,6 +173,7 @@ export interface UserConfig extends CliOptions {
loggers: Array<"stderr" | "disk" | "mcp">;
idleTimeoutMs: number;
notificationTimeoutMs: number;
atlasTemporaryDatabaseUserLifetimeMs: number;
}

export const defaultUserConfig: UserConfig = {
Expand All @@ -180,6 +193,7 @@ export const defaultUserConfig: UserConfig = {
idleTimeoutMs: 600000, // 10 minutes
notificationTimeoutMs: 540000, // 9 minutes
httpHeaders: {},
atlasTemporaryDatabaseUserLifetimeMs: 14400000, // 4 hours
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When representing time, I find it easier to reason about the numbers if they're expressed as multiplication of units of time - i.e. 1000 * 60 * 60 * 4 rather than the result - it's much easier to spot mistakes than making the calculation in your head.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I chose to use the plain number format here to maintain consistency with the other time values already defined in this struct, which all follow the same pattern.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't mind changing the others to match as a drive-by as well

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've update the numbers

};

export const config = setupUserConfig({
Expand Down
3 changes: 1 addition & 2 deletions src/tools/atlas/connect/connectCluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { ensureCurrentIpInAccessList } from "../../../common/atlas/accessListUti
import type { AtlasClusterConnectionInfo } from "../../../common/connectionManager.js";
import { getDefaultRoleFromConfig } from "../../../common/atlas/roles.js";

const EXPIRY_MS = 1000 * 60 * 60 * 12; // 12 hours
const addedIpAccessListMessage =
"Note: Your current IP address has been added to the Atlas project's IP access list to enable secure connection.";

Expand Down Expand Up @@ -77,7 +76,7 @@ export class ConnectClusterTool extends AtlasToolBase {
const username = `mcpUser${Math.floor(Math.random() * 100000)}`;
const password = await generateSecurePassword();

const expiryDate = new Date(Date.now() + EXPIRY_MS);
const expiryDate = new Date(Date.now() + this.config.atlasTemporaryDatabaseUserLifetimeMs);
const role = getDefaultRoleFromConfig(this.config);

await this.session.apiClient.createDatabaseUser({
Expand Down
9 changes: 9 additions & 0 deletions tests/unit/common/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ describe("config", () => {
{ envVar: "MDB_MCP_HTTP_HOST", property: "httpHost", value: "localhost" },
{ envVar: "MDB_MCP_IDLE_TIMEOUT_MS", property: "idleTimeoutMs", value: 5000 },
{ envVar: "MDB_MCP_NOTIFICATION_TIMEOUT_MS", property: "notificationTimeoutMs", value: 5000 },
{
envVar: "MDB_MCP_ATLAS_TEMPORARY_DATABASE_USER_LIFETIME_MS",
property: "atlasTemporaryDatabaseUserLifetimeMs",
value: 12345,
},
] as const;

for (const { envVar, property, value } of testCases) {
Expand Down Expand Up @@ -129,6 +134,10 @@ describe("config", () => {
cli: ["--notificationTimeoutMs", "42"],
expected: { notificationTimeoutMs: "42" },
},
{
cli: ["--atlasTemporaryDatabaseUserLifetimeMs", "12345"],
expected: { atlasTemporaryDatabaseUserLifetimeMs: "12345" },
},
{
cli: ["--telemetry", "enabled"],
expected: { telemetry: "enabled" },
Expand Down
Loading