From cebb0ba24794faeadf8ca7070dba8910beb81369 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 14:34:06 +0200 Subject: [PATCH 01/18] chore: add server.json file the MCP registry --- .github/workflows/publish.yml | 17 + Dockerfile | 1 + package.json | 4 +- scripts/generateArguments.ts | 289 +++++++++++++++ server.json | 670 ++++++++++++++++++++++++++++++++++ src/common/config.ts | 150 ++++++-- 6 files changed, 1096 insertions(+), 35 deletions(-) create mode 100644 scripts/generateArguments.ts create mode 100644 server.json diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 978198b87..6e98de542 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -75,6 +75,7 @@ jobs: environment: Production permissions: contents: write + id-token: write # Required for OIDC authentication with MCP Registry needs: - check if: needs.check.outputs.VERSION_EXISTS == 'false' @@ -95,6 +96,22 @@ jobs: run: npm publish --tag ${{ needs.check.outputs.RELEASE_CHANNEL }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Update server.json version and arguments + run: | + VERSION="${{ needs.check.outputs.VERSION }}" + VERSION="${VERSION#v}" + npm run generate:arguments + + - name: Install MCP Publisher + run: brew install mcp-publisher + + - name: Login to MCP Registry + run: mcp-publisher login github-oidc + + - name: Publish to MCP Registry + run: mcp-publisher publish + - name: Publish git release env: GH_TOKEN: ${{ github.token }} diff --git a/Dockerfile b/Dockerfile index 6d692a4dd..6c206d524 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,3 +9,4 @@ ENTRYPOINT ["mongodb-mcp-server"] LABEL maintainer="MongoDB Inc " LABEL description="MongoDB MCP Server" LABEL version=${VERSION} +LABEL io.modelcontextprotocol.server.name="io.github.mongodb-js/mongodb-mcp-server" diff --git a/package.json b/package.json index 309cb643f..608277e2c 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "description": "MongoDB Model Context Protocol Server", "version": "1.1.0", "type": "module", + "mcpName": "io.github.mongodb-js/mongodb-mcp-server", "exports": { ".": { "import": { @@ -51,7 +52,8 @@ "fix": "npm run fix:lint && npm run reformat", "fix:lint": "eslint . --fix", "reformat": "prettier --write .", - "generate": "./scripts/generate.sh", + "generate": "./scripts/generate.sh && npm run generate:arguments", + "generate:args": "tsx scripts/generateArguments.ts", "test": "vitest --project eslint-rules --project unit-and-integration --coverage", "pretest:accuracy": "npm run build", "test:accuracy": "sh ./scripts/accuracy/runAccuracyTests.sh", diff --git a/scripts/generateArguments.ts b/scripts/generateArguments.ts new file mode 100644 index 000000000..1090aec58 --- /dev/null +++ b/scripts/generateArguments.ts @@ -0,0 +1,289 @@ +#!/usr/bin/env tsx + +/** + * This script generates environment variable definitions and updates: + * - server.json environmentVariables arrays + * - TODO: README.md configuration table + * + * It uses the Zod schema and OPTIONS defined in src/common/config.ts + */ + +import { readFileSync, writeFileSync } from "fs"; +import { join, dirname } from "path"; +import { fileURLToPath } from "url"; +import { UserConfigSchema } from "../src/common/config.js"; +import type { ZodObject, ZodRawShape } from "zod"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +function camelCaseToSnakeCase(str: string): string { + return str.replace(/[A-Z]/g, (letter) => `_${letter}`).toUpperCase(); +} + +// List of configuration keys that contain sensitive/secret information +// These should be redacted in logs and marked as secret in environment variable definitions +const SECRET_CONFIG_KEYS = new Set([ + "connectionString", + "username", + "password", + "apiClientId", + "apiClientSecret", + "tlsCAFile", + "tlsCertificateKeyFile", + "tlsCertificateKeyFilePassword", + "tlsCRLFile", + "sslCAFile", + "sslPEMKeyFile", + "sslPEMKeyPassword", + "sslCRLFile", + "voyageApiKey", +]); + +interface ParsedOptions { + string: string[]; + number: string[]; + boolean: string[]; + array: string[]; + alias: Record; +} + +interface EnvironmentVariable { + name: string; + description: string; + isRequired: boolean; + format: string; + isSecret: boolean; + configKey: string; + defaultValue?: unknown; +} + +interface ConfigMetadata { + description: string; + defaultValue?: unknown; +} + +function extractZodDescriptions(): Record { + const result: Record = {}; + + // Get the shape of the Zod schema + const shape = (UserConfigSchema as ZodObject).shape; + + for (const [key, fieldSchema] of Object.entries(shape)) { + const schema = fieldSchema; + // Extract description from Zod schema + const description = schema.description || `Configuration option: ${key}`; + + // Extract default value if present + let defaultValue: unknown = undefined; + if (schema._def && "defaultValue" in schema._def) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access + defaultValue = schema._def.defaultValue() as unknown; + } + + result[key] = { + description, + defaultValue, + }; + } + + return result; +} + +function parseOptionsFromConfig(): ParsedOptions { + const configPath = join(__dirname, "..", "src", "common", "config.ts"); + const configContent = readFileSync(configPath, "utf-8"); + + // Extract the OPTIONS object using regex + const optionsMatch = configContent.match(/const OPTIONS = \{([\s\S]*?)\} as Readonly;/); + + if (!optionsMatch) { + throw new Error("Could not find OPTIONS object in config.ts"); + } + + const optionsContent = optionsMatch[1]; + + // Parse each array type + const parseArray = (type: string): string[] => { + const regex = new RegExp(`${type}:\\s*\\[(.*?)\\]`, "s"); + const match = optionsContent?.match(regex); + if (!match) return []; + + // Extract quoted strings from the array + const arrayContent = match[1]; + if (!arrayContent) return []; + const items = arrayContent.match(/"([^"]+)"/g); + return items ? items.map((item) => item.replace(/"/g, "")) : []; + }; + + // Parse alias object + const parseAlias = (): Record => { + const aliasMatch = optionsContent?.match(/alias:\s*\{([\s\S]*?)\}/); + if (!aliasMatch) return {}; + + const aliasContent = aliasMatch[1]; + if (!aliasContent) return {}; + const entries = aliasContent.matchAll(/(\w+):\s*"([^"]+)"/g); + const result: Record = {}; + + for (const match of entries) { + if (match && match[1] && match[2]) { + result[match[1]] = match[2]; + } + } + + return result; + }; + + return { + string: parseArray("string"), + number: parseArray("number"), + boolean: parseArray("boolean"), + array: parseArray("array"), + alias: parseAlias(), + }; +} + +function generateEnvironmentVariables( + options: ParsedOptions, + zodMetadata: Record +): EnvironmentVariable[] { + const envVars: EnvironmentVariable[] = []; + const processedKeys = new Set(); + + // Helper to add env var + const addEnvVar = (key: string, type: "string" | "number" | "boolean" | "array"): void => { + if (processedKeys.has(key)) return; + processedKeys.add(key); + + const envVarName = `MDB_MCP_${camelCaseToSnakeCase(key)}`; + + // Get description and default value from Zod metadata + const metadata = zodMetadata[key] || { + description: `Configuration option: ${key}`, + }; + + // Determine format based on type + let format = type; + if (type === "array") { + format = "string"; // Arrays are passed as comma-separated strings + } + + envVars.push({ + name: envVarName, + description: metadata.description, + isRequired: false, + format: format, + isSecret: SECRET_CONFIG_KEYS.has(key), + configKey: key, + defaultValue: metadata.defaultValue, + }); + }; + + // Process all string options + for (const key of options.string) { + addEnvVar(key, "string"); + } + + // Process all number options + for (const key of options.number) { + addEnvVar(key, "number"); + } + + // Process all boolean options + for (const key of options.boolean) { + addEnvVar(key, "boolean"); + } + + // Process all array options + for (const key of options.array) { + addEnvVar(key, "array"); + } + + // Sort by name for consistent output + return envVars.sort((a, b) => a.name.localeCompare(b.name)); +} + +function generatePackageArguments(envVars: EnvironmentVariable[]): unknown[] { + const packageArguments: unknown[] = []; + + // Generate positional arguments from the same config options (only documented ones) + const documentedVars = envVars.filter((v) => !v.description.startsWith("Configuration option:")); + + for (const envVar of documentedVars) { + const arg: Record = { + type: "positional", + valueHint: envVar.configKey, + description: envVar.description, + isRequired: envVar.isRequired, + }; + + // Add format if it's not string (string is the default) + if (envVar.format !== "string") { + arg.format = envVar.format; + } + + packageArguments.push(arg); + } + + return packageArguments; +} + +function updateServerJsonEnvVars(envVars: EnvironmentVariable[]): void { + const serverJsonPath = join(__dirname, "..", "server.json"); + const packageJsonPath = join(__dirname, "..", "package.json"); + + const content = readFileSync(serverJsonPath, "utf-8"); + const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as { version: string }; + const serverJson = JSON.parse(content) as { + version?: string; + packages: { environmentVariables: EnvironmentVariable[]; packageArguments?: unknown[]; version?: string }[]; + }; + + // Get version from package.json + const version = packageJson.version; + + // Generate environment variables array (only documented ones) + const documentedVars = envVars.filter((v) => !v.description.startsWith("Configuration option:")); + const envVarsArray = documentedVars.map((v) => ({ + name: v.name, + description: v.description, + isRequired: v.isRequired, + format: v.format, + isSecret: v.isSecret, + })); + + // Generate package arguments (positional arguments in camelCase) + const packageArguments = generatePackageArguments(envVars); + + // Update version at root level + serverJson.version = process.env.VERSION || version; + + // Update environmentVariables, packageArguments, and version for all packages + if (serverJson.packages && Array.isArray(serverJson.packages)) { + for (const pkg of serverJson.packages) { + pkg.environmentVariables = envVarsArray as EnvironmentVariable[]; + pkg.packageArguments = packageArguments; + pkg.version = version; + + // Update OCI identifier version tag if this is an OCI package + if (pkg.registryType === "oci" && pkg.identifier) { + // Replace the version tag in the OCI identifier (e.g., docker.io/mongodb/mongodb-mcp-server:1.0.0) + pkg.identifier = pkg.identifier.replace(/:[^:]+$/, `:${version}`); + } + } + } + + writeFileSync(serverJsonPath, JSON.stringify(serverJson, null, 2) + "\n", "utf-8"); + console.log(`✓ Updated server.json (version ${version})`); +} + +function main(): void { + const zodMetadata = extractZodDescriptions(); + const options = parseOptionsFromConfig(); + + const envVars = generateEnvironmentVariables(options, zodMetadata); + updateServerJsonEnvVars(envVars); +} + +main(); diff --git a/server.json b/server.json new file mode 100644 index 000000000..e877d868b --- /dev/null +++ b/server.json @@ -0,0 +1,670 @@ +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-10-17/server.schema.json", + "name": "io.github.mongodb-js/mongodb-mcp-server", + "description": "MongoDB Model Context Protocol Server", + "repository": { + "url": "https://github.com/mongodb-js/mongodb-mcp-server", + "source": "github" + }, + "version": "1.1.0", + "packages": [ + { + "registryType": "npm", + "identifier": "mongodb-mcp-server", + "version": "1.1.0", + "transport": { + "type": "stdio" + }, + "environmentVariables": [ + { + "name": "MDB_MCP_API_BASE_URL", + "description": "Base URL for MongoDB Atlas API", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_API_CLIENT_ID", + "description": "Atlas API client ID for authentication. Required for running Atlas tools.", + "isRequired": false, + "format": "string", + "isSecret": true + }, + { + "name": "MDB_MCP_API_CLIENT_SECRET", + "description": "Atlas API client secret for authentication. Required for running Atlas tools.", + "isRequired": false, + "format": "string", + "isSecret": true + }, + { + "name": "MDB_MCP_ATLAS_TEMPORARY_DATABASE_USER_LIFETIME_MS", + "description": "Time in milliseconds that temporary database users created when connecting to MongoDB Atlas clusters will remain active before being automatically deleted.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_CONFIRMATION_REQUIRED_TOOLS", + "description": "An array of tool names that require user confirmation before execution. Requires the client to support elicitation.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_CONNECTION_STRING", + "description": "MongoDB connection string for direct database connections. Optional, if not set, you'll need to call the connect tool before interacting with MongoDB data.", + "isRequired": false, + "format": "string", + "isSecret": true + }, + { + "name": "MDB_MCP_DISABLE_EMBEDDINGS_VALIDATION", + "description": "When set to true, disables validation of embeddings dimensions.", + "isRequired": false, + "format": "boolean", + "isSecret": false + }, + { + "name": "MDB_MCP_DISABLED_TOOLS", + "description": "An array of tool names, operation types, and/or categories of tools that will be disabled.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_EXPORT_CLEANUP_INTERVAL_MS", + "description": "Time in milliseconds between export cleanup cycles that remove expired export files.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_EXPORT_TIMEOUT_MS", + "description": "Time in milliseconds after which an export is considered expired and eligible for cleanup.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_EXPORTS_PATH", + "description": "Folder to store exported data files.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_HTTP_HOST", + "description": "Host to bind the http server.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_HTTP_PORT", + "description": "Port number.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_IDLE_TIMEOUT_MS", + "description": "Idle timeout for a client to disconnect (only applies to http transport).", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_INDEX_CHECK", + "description": "When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan.", + "isRequired": false, + "format": "boolean", + "isSecret": false + }, + { + "name": "MDB_MCP_LOG_PATH", + "description": "Folder to store logs.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_LOGGERS", + "description": "Comma separated values, possible values are 'mcp', 'disk' and 'stderr'.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_MAX_BYTES_PER_QUERY", + "description": "The maximum size in bytes for results from a find or aggregate tool call. This serves as an upper bound for the responseBytesLimit parameter in those tools.", + "isRequired": false, + "format": "number", + "isSecret": false + }, + { + "name": "MDB_MCP_MAX_DOCUMENTS_PER_QUERY", + "description": "The maximum number of documents that can be returned by a find or aggregate tool call. For the find tool, the effective limit will be the smaller of this value and the tool's limit parameter.", + "isRequired": false, + "format": "number", + "isSecret": false + }, + { + "name": "MDB_MCP_NOTIFICATION_TIMEOUT_MS", + "description": "Notification timeout for a client to be aware of disconnect (only applies to http transport).", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_READ_ONLY", + "description": "When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations.", + "isRequired": false, + "format": "boolean", + "isSecret": false + }, + { + "name": "MDB_MCP_TELEMETRY", + "description": "When set to disabled, disables telemetry collection.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_TRANSPORT", + "description": "Either 'stdio' or 'http'.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_VOYAGE_API_KEY", + "description": "API key for Voyage AI embeddings service (required for vector search operations with text-to-embedding conversion).", + "isRequired": false, + "format": "string", + "isSecret": true + } + ], + "packageArguments": [ + { + "type": "positional", + "valueHint": "apiBaseUrl", + "description": "Base URL for MongoDB Atlas API", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "apiClientId", + "description": "Atlas API client ID for authentication. Required for running Atlas tools.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "apiClientSecret", + "description": "Atlas API client secret for authentication. Required for running Atlas tools.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "atlasTemporaryDatabaseUserLifetimeMs", + "description": "Time in milliseconds that temporary database users created when connecting to MongoDB Atlas clusters will remain active before being automatically deleted.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "confirmationRequiredTools", + "description": "An array of tool names that require user confirmation before execution. Requires the client to support elicitation.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "connectionString", + "description": "MongoDB connection string for direct database connections. Optional, if not set, you'll need to call the connect tool before interacting with MongoDB data.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "disableEmbeddingsValidation", + "description": "When set to true, disables validation of embeddings dimensions.", + "isRequired": false, + "format": "boolean" + }, + { + "type": "positional", + "valueHint": "disabledTools", + "description": "An array of tool names, operation types, and/or categories of tools that will be disabled.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "exportCleanupIntervalMs", + "description": "Time in milliseconds between export cleanup cycles that remove expired export files.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "exportTimeoutMs", + "description": "Time in milliseconds after which an export is considered expired and eligible for cleanup.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "exportsPath", + "description": "Folder to store exported data files.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "httpHost", + "description": "Host to bind the http server.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "httpPort", + "description": "Port number.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "idleTimeoutMs", + "description": "Idle timeout for a client to disconnect (only applies to http transport).", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "indexCheck", + "description": "When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan.", + "isRequired": false, + "format": "boolean" + }, + { + "type": "positional", + "valueHint": "logPath", + "description": "Folder to store logs.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "loggers", + "description": "Comma separated values, possible values are 'mcp', 'disk' and 'stderr'.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "maxBytesPerQuery", + "description": "The maximum size in bytes for results from a find or aggregate tool call. This serves as an upper bound for the responseBytesLimit parameter in those tools.", + "isRequired": false, + "format": "number" + }, + { + "type": "positional", + "valueHint": "maxDocumentsPerQuery", + "description": "The maximum number of documents that can be returned by a find or aggregate tool call. For the find tool, the effective limit will be the smaller of this value and the tool's limit parameter.", + "isRequired": false, + "format": "number" + }, + { + "type": "positional", + "valueHint": "notificationTimeoutMs", + "description": "Notification timeout for a client to be aware of disconnect (only applies to http transport).", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "readOnly", + "description": "When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations.", + "isRequired": false, + "format": "boolean" + }, + { + "type": "positional", + "valueHint": "telemetry", + "description": "When set to disabled, disables telemetry collection.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "transport", + "description": "Either 'stdio' or 'http'.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "voyageApiKey", + "description": "API key for Voyage AI embeddings service (required for vector search operations with text-to-embedding conversion).", + "isRequired": false + } + ] + }, + { + "registryType": "oci", + "identifier": "docker.io/mongodb/mongodb-mcp-server:1.1.0", + "transport": { + "type": "stdio" + }, + "environmentVariables": [ + { + "name": "MDB_MCP_API_BASE_URL", + "description": "Base URL for MongoDB Atlas API", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_API_CLIENT_ID", + "description": "Atlas API client ID for authentication. Required for running Atlas tools.", + "isRequired": false, + "format": "string", + "isSecret": true + }, + { + "name": "MDB_MCP_API_CLIENT_SECRET", + "description": "Atlas API client secret for authentication. Required for running Atlas tools.", + "isRequired": false, + "format": "string", + "isSecret": true + }, + { + "name": "MDB_MCP_ATLAS_TEMPORARY_DATABASE_USER_LIFETIME_MS", + "description": "Time in milliseconds that temporary database users created when connecting to MongoDB Atlas clusters will remain active before being automatically deleted.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_CONFIRMATION_REQUIRED_TOOLS", + "description": "An array of tool names that require user confirmation before execution. Requires the client to support elicitation.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_CONNECTION_STRING", + "description": "MongoDB connection string for direct database connections. Optional, if not set, you'll need to call the connect tool before interacting with MongoDB data.", + "isRequired": false, + "format": "string", + "isSecret": true + }, + { + "name": "MDB_MCP_DISABLE_EMBEDDINGS_VALIDATION", + "description": "When set to true, disables validation of embeddings dimensions.", + "isRequired": false, + "format": "boolean", + "isSecret": false + }, + { + "name": "MDB_MCP_DISABLED_TOOLS", + "description": "An array of tool names, operation types, and/or categories of tools that will be disabled.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_EXPORT_CLEANUP_INTERVAL_MS", + "description": "Time in milliseconds between export cleanup cycles that remove expired export files.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_EXPORT_TIMEOUT_MS", + "description": "Time in milliseconds after which an export is considered expired and eligible for cleanup.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_EXPORTS_PATH", + "description": "Folder to store exported data files.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_HTTP_HOST", + "description": "Host to bind the http server.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_HTTP_PORT", + "description": "Port number.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_IDLE_TIMEOUT_MS", + "description": "Idle timeout for a client to disconnect (only applies to http transport).", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_INDEX_CHECK", + "description": "When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan.", + "isRequired": false, + "format": "boolean", + "isSecret": false + }, + { + "name": "MDB_MCP_LOG_PATH", + "description": "Folder to store logs.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_LOGGERS", + "description": "Comma separated values, possible values are 'mcp', 'disk' and 'stderr'.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_MAX_BYTES_PER_QUERY", + "description": "The maximum size in bytes for results from a find or aggregate tool call. This serves as an upper bound for the responseBytesLimit parameter in those tools.", + "isRequired": false, + "format": "number", + "isSecret": false + }, + { + "name": "MDB_MCP_MAX_DOCUMENTS_PER_QUERY", + "description": "The maximum number of documents that can be returned by a find or aggregate tool call. For the find tool, the effective limit will be the smaller of this value and the tool's limit parameter.", + "isRequired": false, + "format": "number", + "isSecret": false + }, + { + "name": "MDB_MCP_NOTIFICATION_TIMEOUT_MS", + "description": "Notification timeout for a client to be aware of disconnect (only applies to http transport).", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_READ_ONLY", + "description": "When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations.", + "isRequired": false, + "format": "boolean", + "isSecret": false + }, + { + "name": "MDB_MCP_TELEMETRY", + "description": "When set to disabled, disables telemetry collection.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_TRANSPORT", + "description": "Either 'stdio' or 'http'.", + "isRequired": false, + "format": "string", + "isSecret": false + }, + { + "name": "MDB_MCP_VOYAGE_API_KEY", + "description": "API key for Voyage AI embeddings service (required for vector search operations with text-to-embedding conversion).", + "isRequired": false, + "format": "string", + "isSecret": true + } + ], + "packageArguments": [ + { + "type": "positional", + "valueHint": "apiBaseUrl", + "description": "Base URL for MongoDB Atlas API", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "apiClientId", + "description": "Atlas API client ID for authentication. Required for running Atlas tools.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "apiClientSecret", + "description": "Atlas API client secret for authentication. Required for running Atlas tools.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "atlasTemporaryDatabaseUserLifetimeMs", + "description": "Time in milliseconds that temporary database users created when connecting to MongoDB Atlas clusters will remain active before being automatically deleted.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "confirmationRequiredTools", + "description": "An array of tool names that require user confirmation before execution. Requires the client to support elicitation.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "connectionString", + "description": "MongoDB connection string for direct database connections. Optional, if not set, you'll need to call the connect tool before interacting with MongoDB data.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "disableEmbeddingsValidation", + "description": "When set to true, disables validation of embeddings dimensions.", + "isRequired": false, + "format": "boolean" + }, + { + "type": "positional", + "valueHint": "disabledTools", + "description": "An array of tool names, operation types, and/or categories of tools that will be disabled.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "exportCleanupIntervalMs", + "description": "Time in milliseconds between export cleanup cycles that remove expired export files.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "exportTimeoutMs", + "description": "Time in milliseconds after which an export is considered expired and eligible for cleanup.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "exportsPath", + "description": "Folder to store exported data files.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "httpHost", + "description": "Host to bind the http server.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "httpPort", + "description": "Port number.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "idleTimeoutMs", + "description": "Idle timeout for a client to disconnect (only applies to http transport).", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "indexCheck", + "description": "When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan.", + "isRequired": false, + "format": "boolean" + }, + { + "type": "positional", + "valueHint": "logPath", + "description": "Folder to store logs.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "loggers", + "description": "Comma separated values, possible values are 'mcp', 'disk' and 'stderr'.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "maxBytesPerQuery", + "description": "The maximum size in bytes for results from a find or aggregate tool call. This serves as an upper bound for the responseBytesLimit parameter in those tools.", + "isRequired": false, + "format": "number" + }, + { + "type": "positional", + "valueHint": "maxDocumentsPerQuery", + "description": "The maximum number of documents that can be returned by a find or aggregate tool call. For the find tool, the effective limit will be the smaller of this value and the tool's limit parameter.", + "isRequired": false, + "format": "number" + }, + { + "type": "positional", + "valueHint": "notificationTimeoutMs", + "description": "Notification timeout for a client to be aware of disconnect (only applies to http transport).", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "readOnly", + "description": "When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations.", + "isRequired": false, + "format": "boolean" + }, + { + "type": "positional", + "valueHint": "telemetry", + "description": "When set to disabled, disables telemetry collection.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "transport", + "description": "Either 'stdio' or 'http'.", + "isRequired": false + }, + { + "type": "positional", + "valueHint": "voyageApiKey", + "description": "API key for Voyage AI embeddings service (required for vector search operations with text-to-embedding conversion).", + "isRequired": false + } + ], + "version": "1.1.0" + } + ] +} diff --git a/src/common/config.ts b/src/common/config.ts index 68c6ebc17..0ff58c150 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -5,11 +5,13 @@ import type { CliOptions, ConnectionInfo } from "@mongosh/arg-parser"; import { generateConnectionInfoFromCliArgs } from "@mongosh/arg-parser"; import { Keychain } from "./keychain.js"; import type { Secret } from "./keychain.js"; -import levenshtein from "ts-levenshtein"; +import * as levenshteinModule from "ts-levenshtein"; import type { Similarity } from "./search/vectorSearchEmbeddingsManager.js"; +import { z } from "zod"; +const levenshtein = levenshteinModule.default; // From: https://github.com/mongodb-js/mongosh/blob/main/packages/cli-repl/src/arg-parser.ts -const OPTIONS = { +export const OPTIONS = { number: ["maxDocumentsPerQuery", "maxBytesPerQuery"], string: [ "apiBaseUrl", @@ -157,38 +159,118 @@ function isConnectionSpecifier(arg: string | undefined): boolean { ); } -// If we decide to support non-string config options, we'll need to extend the mechanism for parsing -// env variables. -export interface UserConfig extends CliOptions { - apiBaseUrl: string; - apiClientId?: string; - apiClientSecret?: string; - telemetry: "enabled" | "disabled"; - logPath: string; - exportsPath: string; - exportTimeoutMs: number; - exportCleanupIntervalMs: number; - connectionString?: string; - // TODO: Use a type tracking all tool names. - disabledTools: Array; - confirmationRequiredTools: Array; - readOnly?: boolean; - indexCheck?: boolean; - transport: "stdio" | "http"; - httpPort: number; - httpHost: string; - httpHeaders: Record; - loggers: Array<"stderr" | "disk" | "mcp">; - idleTimeoutMs: number; - notificationTimeoutMs: number; - maxDocumentsPerQuery: number; - maxBytesPerQuery: number; - atlasTemporaryDatabaseUserLifetimeMs: number; - voyageApiKey: string; - disableEmbeddingsValidation: boolean; - vectorSearchDimensions: number; - vectorSearchSimilarityFunction: Similarity; -} +// Zod schema for UserConfig with descriptions +export const UserConfigSchema = z.object({ + // Atlas API Options + apiBaseUrl: z.string().describe("Base URL for MongoDB Atlas API"), + apiClientId: z + .string() + .optional() + .describe("Atlas API client ID for authentication. Required for running Atlas tools."), + apiClientSecret: z + .string() + .optional() + .describe("Atlas API client secret for authentication. Required for running Atlas tools."), + connectionString: z + .string() + .optional() + .describe( + "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: z + .array(z.enum(["stderr", "disk", "mcp"])) + .default(["disk", "mcp"]) + .describe("Comma separated values, possible values are 'mcp', 'disk' and 'stderr'."), + logPath: z.string().describe("Folder to store logs."), + disabledTools: z + .array(z.string()) + .describe("An array of tool names, operation types, and/or categories of tools that will be disabled."), + confirmationRequiredTools: z + .array(z.string()) + .default([ + "atlas-create-access-list", + "atlas-create-db-user", + "drop-database", + "drop-collection", + "delete-many", + "drop-index", + ]) + .describe( + "An array of tool names that require user confirmation before execution. Requires the client to support elicitation." + ), + readOnly: z + .boolean() + .default(false) + .optional() + .describe( + "When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations." + ), + indexCheck: z + .boolean() + .default(false) + .optional() + .describe( + "When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan." + ), + telemetry: z + .enum(["enabled", "disabled"]) + .default("enabled") + .describe("When set to disabled, disables telemetry collection."), + transport: z.enum(["stdio", "http"]).default("stdio").describe("Either 'stdio' or 'http'."), + httpPort: z.number().default(3000).describe("Port number."), + httpHost: z.string().default("127.0.0.1").describe("Host to bind the http server."), + httpHeaders: z.record(z.string()).describe("HTTP headers for the server."), + idleTimeoutMs: z + .number() + .default(600_000) + .describe("Idle timeout for a client to disconnect (only applies to http transport)."), + notificationTimeoutMs: z + .number() + .default(540_000) + .describe("Notification timeout for a client to be aware of disconnect (only applies to http transport)."), + maxBytesPerQuery: z + .number() + .default(16_777_216) + .describe( + "The maximum size in bytes for results from a find or aggregate tool call. This serves as an upper bound for the responseBytesLimit parameter in those tools." + ), + maxDocumentsPerQuery: z + .number() + .default(100) + .describe( + "The maximum number of documents that can be returned by a find or aggregate tool call. For the find tool, the effective limit will be the smaller of this value and the tool's limit parameter." + ), + exportsPath: z.string().describe("Folder to store exported data files."), + exportTimeoutMs: z + .number() + .default(300_000) + .describe("Time in milliseconds after which an export is considered expired and eligible for cleanup."), + exportCleanupIntervalMs: z + .number() + .default(120_000) + .describe("Time in milliseconds between export cleanup cycles that remove expired export files."), + atlasTemporaryDatabaseUserLifetimeMs: z + .number() + .default(14_400_000) + .describe( + "Time in milliseconds that temporary database users created when connecting to MongoDB Atlas clusters will remain active before being automatically deleted." + ), + voyageApiKey: z + .string() + .describe( + "API key for Voyage AI embeddings service (required for vector search operations with text-to-embedding conversion)." + ), + disableEmbeddingsValidation: z + .boolean() + .describe("When set to true, disables validation of embeddings dimensions."), + vectorSearchDimensions: z.number().describe("Default number of dimensions for vector search embeddings."), + vectorSearchSimilarityFunction: z + .custom() + .describe("Default similarity function for vector search: 'euclidean', 'cosine', or 'dotProduct'."), +}); + +// Export UserConfig type derived from the Zod schema +export type UserConfig = z.infer & CliOptions; export const defaultUserConfig: UserConfig = { apiBaseUrl: "https://cloud.mongodb.com/", From df9654466e680c20123834776c3052031bc1076b Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 14:37:51 +0200 Subject: [PATCH 02/18] chore: fix name --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 608277e2c..9ce335d40 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "fix:lint": "eslint . --fix", "reformat": "prettier --write .", "generate": "./scripts/generate.sh && npm run generate:arguments", - "generate:args": "tsx scripts/generateArguments.ts", + "generate:arguments": "tsx scripts/generateArguments.ts", "test": "vitest --project eslint-rules --project unit-and-integration --coverage", "pretest:accuracy": "npm run build", "test:accuracy": "sh ./scripts/accuracy/runAccuracyTests.sh", From 9724f9550212a3f7f9f65e9566f6305a9974e3ab Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 14:40:39 +0200 Subject: [PATCH 03/18] chore: import options --- scripts/generateArguments.ts | 72 ++++++++---------------------------- 1 file changed, 15 insertions(+), 57 deletions(-) diff --git a/scripts/generateArguments.ts b/scripts/generateArguments.ts index 1090aec58..bfc6b31ee 100644 --- a/scripts/generateArguments.ts +++ b/scripts/generateArguments.ts @@ -11,7 +11,7 @@ import { readFileSync, writeFileSync } from "fs"; import { join, dirname } from "path"; import { fileURLToPath } from "url"; -import { UserConfigSchema } from "../src/common/config.js"; +import { OPTIONS, UserConfigSchema } from "../src/common/config.js"; import type { ZodObject, ZodRawShape } from "zod"; const __filename = fileURLToPath(import.meta.url); @@ -90,60 +90,6 @@ function extractZodDescriptions(): Record { return result; } -function parseOptionsFromConfig(): ParsedOptions { - const configPath = join(__dirname, "..", "src", "common", "config.ts"); - const configContent = readFileSync(configPath, "utf-8"); - - // Extract the OPTIONS object using regex - const optionsMatch = configContent.match(/const OPTIONS = \{([\s\S]*?)\} as Readonly;/); - - if (!optionsMatch) { - throw new Error("Could not find OPTIONS object in config.ts"); - } - - const optionsContent = optionsMatch[1]; - - // Parse each array type - const parseArray = (type: string): string[] => { - const regex = new RegExp(`${type}:\\s*\\[(.*?)\\]`, "s"); - const match = optionsContent?.match(regex); - if (!match) return []; - - // Extract quoted strings from the array - const arrayContent = match[1]; - if (!arrayContent) return []; - const items = arrayContent.match(/"([^"]+)"/g); - return items ? items.map((item) => item.replace(/"/g, "")) : []; - }; - - // Parse alias object - const parseAlias = (): Record => { - const aliasMatch = optionsContent?.match(/alias:\s*\{([\s\S]*?)\}/); - if (!aliasMatch) return {}; - - const aliasContent = aliasMatch[1]; - if (!aliasContent) return {}; - const entries = aliasContent.matchAll(/(\w+):\s*"([^"]+)"/g); - const result: Record = {}; - - for (const match of entries) { - if (match && match[1] && match[2]) { - result[match[1]] = match[2]; - } - } - - return result; - }; - - return { - string: parseArray("string"), - number: parseArray("number"), - boolean: parseArray("boolean"), - array: parseArray("array"), - alias: parseAlias(), - }; -} - function generateEnvironmentVariables( options: ParsedOptions, zodMetadata: Record @@ -237,7 +183,13 @@ function updateServerJsonEnvVars(envVars: EnvironmentVariable[]): void { const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as { version: string }; const serverJson = JSON.parse(content) as { version?: string; - packages: { environmentVariables: EnvironmentVariable[]; packageArguments?: unknown[]; version?: string }[]; + packages: { + registryType?: string; + identifier?: string; + environmentVariables: EnvironmentVariable[]; + packageArguments?: unknown[]; + version?: string; + }[]; }; // Get version from package.json @@ -280,7 +232,13 @@ function updateServerJsonEnvVars(envVars: EnvironmentVariable[]): void { function main(): void { const zodMetadata = extractZodDescriptions(); - const options = parseOptionsFromConfig(); + const options = { + string: Array.from(OPTIONS.string), + number: Array.from(OPTIONS.number), + boolean: Array.from(OPTIONS.boolean), + array: Array.from(OPTIONS.array), + alias: { ...OPTIONS.alias }, + }; const envVars = generateEnvironmentVariables(options, zodMetadata); updateServerJsonEnvVars(envVars); From 9b4b8d251d7dd3ddc2150ca062805017b932af92 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 14:42:51 +0200 Subject: [PATCH 04/18] chore: docs --- scripts/generateArguments.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/generateArguments.ts b/scripts/generateArguments.ts index bfc6b31ee..c2fc728dd 100644 --- a/scripts/generateArguments.ts +++ b/scripts/generateArguments.ts @@ -1,8 +1,8 @@ #!/usr/bin/env tsx /** - * This script generates environment variable definitions and updates: - * - server.json environmentVariables arrays + * This script generates argument definitions and updates: + * - server.json arrays * - TODO: README.md configuration table * * It uses the Zod schema and OPTIONS defined in src/common/config.ts From ed38888ec83a43d0867c01a7a37c753edfb2c424 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 14:44:27 +0200 Subject: [PATCH 05/18] chore: cleanup --- src/common/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/config.ts b/src/common/config.ts index 0ff58c150..b5f0993a4 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -159,7 +159,6 @@ function isConnectionSpecifier(arg: string | undefined): boolean { ); } -// Zod schema for UserConfig with descriptions export const UserConfigSchema = z.object({ // Atlas API Options apiBaseUrl: z.string().describe("Base URL for MongoDB Atlas API"), From 39d7918411f00e8474f93d3217885060fdecb79b Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 14:46:24 +0200 Subject: [PATCH 06/18] chore: more cleanup --- scripts/generateArguments.ts | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/scripts/generateArguments.ts b/scripts/generateArguments.ts index c2fc728dd..d133c60f2 100644 --- a/scripts/generateArguments.ts +++ b/scripts/generateArguments.ts @@ -40,14 +40,6 @@ const SECRET_CONFIG_KEYS = new Set([ "voyageApiKey", ]); -interface ParsedOptions { - string: string[]; - number: string[]; - boolean: string[]; - array: string[]; - alias: Record; -} - interface EnvironmentVariable { name: string; description: string; @@ -91,7 +83,7 @@ function extractZodDescriptions(): Record { } function generateEnvironmentVariables( - options: ParsedOptions, + options: typeof OPTIONS, zodMetadata: Record ): EnvironmentVariable[] { const envVars: EnvironmentVariable[] = []; @@ -232,15 +224,8 @@ function updateServerJsonEnvVars(envVars: EnvironmentVariable[]): void { function main(): void { const zodMetadata = extractZodDescriptions(); - const options = { - string: Array.from(OPTIONS.string), - number: Array.from(OPTIONS.number), - boolean: Array.from(OPTIONS.boolean), - array: Array.from(OPTIONS.array), - alias: { ...OPTIONS.alias }, - }; - const envVars = generateEnvironmentVariables(options, zodMetadata); + const envVars = generateEnvironmentVariables(OPTIONS, zodMetadata); updateServerJsonEnvVars(envVars); } From 18e6d27308cc6d2ec00e954f6433592b5f2c8497 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 15:14:17 +0200 Subject: [PATCH 07/18] chore: use binary, use named not positional arguments --- .github/workflows/publish.yml | 7 +- scripts/generateArguments.ts | 17 +-- server.json | 210 +++++++++++++++------------------- src/common/config.ts | 4 +- 4 files changed, 107 insertions(+), 131 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6e98de542..9dfd3bd95 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -104,13 +104,14 @@ jobs: npm run generate:arguments - name: Install MCP Publisher - run: brew install mcp-publisher + run: | + curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher - name: Login to MCP Registry - run: mcp-publisher login github-oidc + run: ./mcp-publisher login github-oidc - name: Publish to MCP Registry - run: mcp-publisher publish + run: ./mcp-publisher publish - name: Publish git release env: diff --git a/scripts/generateArguments.ts b/scripts/generateArguments.ts index d133c60f2..2079df82a 100644 --- a/scripts/generateArguments.ts +++ b/scripts/generateArguments.ts @@ -148,17 +148,18 @@ function generatePackageArguments(envVars: EnvironmentVariable[]): unknown[] { // Generate positional arguments from the same config options (only documented ones) const documentedVars = envVars.filter((v) => !v.description.startsWith("Configuration option:")); - for (const envVar of documentedVars) { + // Generate named arguments from the same config options + for (const argument of documentedVars) { const arg: Record = { - type: "positional", - valueHint: envVar.configKey, - description: envVar.description, - isRequired: envVar.isRequired, + type: "named", + name: "--" + argument.configKey, + description: argument.description, + isRequired: argument.isRequired, }; // Add format if it's not string (string is the default) - if (envVar.format !== "string") { - arg.format = envVar.format; + if (argument.format !== "string") { + arg.format = argument.format; } packageArguments.push(arg); @@ -197,7 +198,7 @@ function updateServerJsonEnvVars(envVars: EnvironmentVariable[]): void { isSecret: v.isSecret, })); - // Generate package arguments (positional arguments in camelCase) + // Generate package arguments (named arguments in camelCase) const packageArguments = generatePackageArguments(envVars); // Update version at root level diff --git a/server.json b/server.json index e877d868b..7ac3f9f2c 100644 --- a/server.json +++ b/server.json @@ -16,13 +16,6 @@ "type": "stdio" }, "environmentVariables": [ - { - "name": "MDB_MCP_API_BASE_URL", - "description": "Base URL for MongoDB Atlas API", - "isRequired": false, - "format": "string", - "isSecret": false - }, { "name": "MDB_MCP_API_CLIENT_ID", "description": "Atlas API client ID for authentication. Required for running Atlas tools.", @@ -187,151 +180,145 @@ ], "packageArguments": [ { - "type": "positional", - "valueHint": "apiBaseUrl", - "description": "Base URL for MongoDB Atlas API", - "isRequired": false - }, - { - "type": "positional", - "valueHint": "apiClientId", + "type": "named", + "name": "--apiClientId", "description": "Atlas API client ID for authentication. Required for running Atlas tools.", "isRequired": false }, { - "type": "positional", - "valueHint": "apiClientSecret", + "type": "named", + "name": "--apiClientSecret", "description": "Atlas API client secret for authentication. Required for running Atlas tools.", "isRequired": false }, { - "type": "positional", - "valueHint": "atlasTemporaryDatabaseUserLifetimeMs", + "type": "named", + "name": "--atlasTemporaryDatabaseUserLifetimeMs", "description": "Time in milliseconds that temporary database users created when connecting to MongoDB Atlas clusters will remain active before being automatically deleted.", "isRequired": false }, { - "type": "positional", - "valueHint": "confirmationRequiredTools", + "type": "named", + "name": "--confirmationRequiredTools", "description": "An array of tool names that require user confirmation before execution. Requires the client to support elicitation.", "isRequired": false }, { - "type": "positional", - "valueHint": "connectionString", + "type": "named", + "name": "--connectionString", "description": "MongoDB connection string for direct database connections. Optional, if not set, you'll need to call the connect tool before interacting with MongoDB data.", "isRequired": false }, { - "type": "positional", - "valueHint": "disableEmbeddingsValidation", + "type": "named", + "name": "--disableEmbeddingsValidation", "description": "When set to true, disables validation of embeddings dimensions.", "isRequired": false, "format": "boolean" }, { - "type": "positional", - "valueHint": "disabledTools", + "type": "named", + "name": "--disabledTools", "description": "An array of tool names, operation types, and/or categories of tools that will be disabled.", "isRequired": false }, { - "type": "positional", - "valueHint": "exportCleanupIntervalMs", + "type": "named", + "name": "--exportCleanupIntervalMs", "description": "Time in milliseconds between export cleanup cycles that remove expired export files.", "isRequired": false }, { - "type": "positional", - "valueHint": "exportTimeoutMs", + "type": "named", + "name": "--exportTimeoutMs", "description": "Time in milliseconds after which an export is considered expired and eligible for cleanup.", "isRequired": false }, { - "type": "positional", - "valueHint": "exportsPath", + "type": "named", + "name": "--exportsPath", "description": "Folder to store exported data files.", "isRequired": false }, { - "type": "positional", - "valueHint": "httpHost", + "type": "named", + "name": "--httpHost", "description": "Host to bind the http server.", "isRequired": false }, { - "type": "positional", - "valueHint": "httpPort", + "type": "named", + "name": "--httpPort", "description": "Port number.", "isRequired": false }, { - "type": "positional", - "valueHint": "idleTimeoutMs", + "type": "named", + "name": "--idleTimeoutMs", "description": "Idle timeout for a client to disconnect (only applies to http transport).", "isRequired": false }, { - "type": "positional", - "valueHint": "indexCheck", + "type": "named", + "name": "--indexCheck", "description": "When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan.", "isRequired": false, "format": "boolean" }, { - "type": "positional", - "valueHint": "logPath", + "type": "named", + "name": "--logPath", "description": "Folder to store logs.", "isRequired": false }, { - "type": "positional", - "valueHint": "loggers", + "type": "named", + "name": "--loggers", "description": "Comma separated values, possible values are 'mcp', 'disk' and 'stderr'.", "isRequired": false }, { - "type": "positional", - "valueHint": "maxBytesPerQuery", + "type": "named", + "name": "--maxBytesPerQuery", "description": "The maximum size in bytes for results from a find or aggregate tool call. This serves as an upper bound for the responseBytesLimit parameter in those tools.", "isRequired": false, "format": "number" }, { - "type": "positional", - "valueHint": "maxDocumentsPerQuery", + "type": "named", + "name": "--maxDocumentsPerQuery", "description": "The maximum number of documents that can be returned by a find or aggregate tool call. For the find tool, the effective limit will be the smaller of this value and the tool's limit parameter.", "isRequired": false, "format": "number" }, { - "type": "positional", - "valueHint": "notificationTimeoutMs", + "type": "named", + "name": "--notificationTimeoutMs", "description": "Notification timeout for a client to be aware of disconnect (only applies to http transport).", "isRequired": false }, { - "type": "positional", - "valueHint": "readOnly", + "type": "named", + "name": "--readOnly", "description": "When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations.", "isRequired": false, "format": "boolean" }, { - "type": "positional", - "valueHint": "telemetry", + "type": "named", + "name": "--telemetry", "description": "When set to disabled, disables telemetry collection.", "isRequired": false }, { - "type": "positional", - "valueHint": "transport", + "type": "named", + "name": "--transport", "description": "Either 'stdio' or 'http'.", "isRequired": false }, { - "type": "positional", - "valueHint": "voyageApiKey", + "type": "named", + "name": "--voyageApiKey", "description": "API key for Voyage AI embeddings service (required for vector search operations with text-to-embedding conversion).", "isRequired": false } @@ -344,13 +331,6 @@ "type": "stdio" }, "environmentVariables": [ - { - "name": "MDB_MCP_API_BASE_URL", - "description": "Base URL for MongoDB Atlas API", - "isRequired": false, - "format": "string", - "isSecret": false - }, { "name": "MDB_MCP_API_CLIENT_ID", "description": "Atlas API client ID for authentication. Required for running Atlas tools.", @@ -515,151 +495,145 @@ ], "packageArguments": [ { - "type": "positional", - "valueHint": "apiBaseUrl", - "description": "Base URL for MongoDB Atlas API", - "isRequired": false - }, - { - "type": "positional", - "valueHint": "apiClientId", + "type": "named", + "name": "--apiClientId", "description": "Atlas API client ID for authentication. Required for running Atlas tools.", "isRequired": false }, { - "type": "positional", - "valueHint": "apiClientSecret", + "type": "named", + "name": "--apiClientSecret", "description": "Atlas API client secret for authentication. Required for running Atlas tools.", "isRequired": false }, { - "type": "positional", - "valueHint": "atlasTemporaryDatabaseUserLifetimeMs", + "type": "named", + "name": "--atlasTemporaryDatabaseUserLifetimeMs", "description": "Time in milliseconds that temporary database users created when connecting to MongoDB Atlas clusters will remain active before being automatically deleted.", "isRequired": false }, { - "type": "positional", - "valueHint": "confirmationRequiredTools", + "type": "named", + "name": "--confirmationRequiredTools", "description": "An array of tool names that require user confirmation before execution. Requires the client to support elicitation.", "isRequired": false }, { - "type": "positional", - "valueHint": "connectionString", + "type": "named", + "name": "--connectionString", "description": "MongoDB connection string for direct database connections. Optional, if not set, you'll need to call the connect tool before interacting with MongoDB data.", "isRequired": false }, { - "type": "positional", - "valueHint": "disableEmbeddingsValidation", + "type": "named", + "name": "--disableEmbeddingsValidation", "description": "When set to true, disables validation of embeddings dimensions.", "isRequired": false, "format": "boolean" }, { - "type": "positional", - "valueHint": "disabledTools", + "type": "named", + "name": "--disabledTools", "description": "An array of tool names, operation types, and/or categories of tools that will be disabled.", "isRequired": false }, { - "type": "positional", - "valueHint": "exportCleanupIntervalMs", + "type": "named", + "name": "--exportCleanupIntervalMs", "description": "Time in milliseconds between export cleanup cycles that remove expired export files.", "isRequired": false }, { - "type": "positional", - "valueHint": "exportTimeoutMs", + "type": "named", + "name": "--exportTimeoutMs", "description": "Time in milliseconds after which an export is considered expired and eligible for cleanup.", "isRequired": false }, { - "type": "positional", - "valueHint": "exportsPath", + "type": "named", + "name": "--exportsPath", "description": "Folder to store exported data files.", "isRequired": false }, { - "type": "positional", - "valueHint": "httpHost", + "type": "named", + "name": "--httpHost", "description": "Host to bind the http server.", "isRequired": false }, { - "type": "positional", - "valueHint": "httpPort", + "type": "named", + "name": "--httpPort", "description": "Port number.", "isRequired": false }, { - "type": "positional", - "valueHint": "idleTimeoutMs", + "type": "named", + "name": "--idleTimeoutMs", "description": "Idle timeout for a client to disconnect (only applies to http transport).", "isRequired": false }, { - "type": "positional", - "valueHint": "indexCheck", + "type": "named", + "name": "--indexCheck", "description": "When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan.", "isRequired": false, "format": "boolean" }, { - "type": "positional", - "valueHint": "logPath", + "type": "named", + "name": "--logPath", "description": "Folder to store logs.", "isRequired": false }, { - "type": "positional", - "valueHint": "loggers", + "type": "named", + "name": "--loggers", "description": "Comma separated values, possible values are 'mcp', 'disk' and 'stderr'.", "isRequired": false }, { - "type": "positional", - "valueHint": "maxBytesPerQuery", + "type": "named", + "name": "--maxBytesPerQuery", "description": "The maximum size in bytes for results from a find or aggregate tool call. This serves as an upper bound for the responseBytesLimit parameter in those tools.", "isRequired": false, "format": "number" }, { - "type": "positional", - "valueHint": "maxDocumentsPerQuery", + "type": "named", + "name": "--maxDocumentsPerQuery", "description": "The maximum number of documents that can be returned by a find or aggregate tool call. For the find tool, the effective limit will be the smaller of this value and the tool's limit parameter.", "isRequired": false, "format": "number" }, { - "type": "positional", - "valueHint": "notificationTimeoutMs", + "type": "named", + "name": "--notificationTimeoutMs", "description": "Notification timeout for a client to be aware of disconnect (only applies to http transport).", "isRequired": false }, { - "type": "positional", - "valueHint": "readOnly", + "type": "named", + "name": "--readOnly", "description": "When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations.", "isRequired": false, "format": "boolean" }, { - "type": "positional", - "valueHint": "telemetry", + "type": "named", + "name": "--telemetry", "description": "When set to disabled, disables telemetry collection.", "isRequired": false }, { - "type": "positional", - "valueHint": "transport", + "type": "named", + "name": "--transport", "description": "Either 'stdio' or 'http'.", "isRequired": false }, { - "type": "positional", - "valueHint": "voyageApiKey", + "type": "named", + "name": "--voyageApiKey", "description": "API key for Voyage AI embeddings service (required for vector search operations with text-to-embedding conversion).", "isRequired": false } diff --git a/src/common/config.ts b/src/common/config.ts index b5f0993a4..202a0c7db 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -161,7 +161,7 @@ function isConnectionSpecifier(arg: string | undefined): boolean { export const UserConfigSchema = z.object({ // Atlas API Options - apiBaseUrl: z.string().describe("Base URL for MongoDB Atlas API"), + apiBaseUrl: z.string(), apiClientId: z .string() .optional() @@ -218,7 +218,7 @@ export const UserConfigSchema = z.object({ transport: z.enum(["stdio", "http"]).default("stdio").describe("Either 'stdio' or 'http'."), httpPort: z.number().default(3000).describe("Port number."), httpHost: z.string().default("127.0.0.1").describe("Host to bind the http server."), - httpHeaders: z.record(z.string()).describe("HTTP headers for the server."), + httpHeaders: z.record(z.string()).describe("HTTP headers to pass to the http server."), idleTimeoutMs: z .number() .default(600_000) From ac1e69642e55f0243977288ec4c0b23556bdef22 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 15:19:20 +0200 Subject: [PATCH 08/18] chore: format --- .github/workflows/publish.yml | 2 +- scripts/generateArguments.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9dfd3bd95..eb7a17d71 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -75,7 +75,7 @@ jobs: environment: Production permissions: contents: write - id-token: write # Required for OIDC authentication with MCP Registry + id-token: write # Required for OIDC authentication with MCP Registry needs: - check if: needs.check.outputs.VERSION_EXISTS == 'false' diff --git a/scripts/generateArguments.ts b/scripts/generateArguments.ts index 2079df82a..a5a4c64d7 100644 --- a/scripts/generateArguments.ts +++ b/scripts/generateArguments.ts @@ -69,7 +69,7 @@ function extractZodDescriptions(): Record { // Extract default value if present let defaultValue: unknown = undefined; if (schema._def && "defaultValue" in schema._def) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access defaultValue = schema._def.defaultValue() as unknown; } From ce2d6cf22527c4d80fd206cdfd57c8f024f31022 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 15:24:01 +0200 Subject: [PATCH 09/18] chore: use app-token publishing --- .github/workflows/publish.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index eb7a17d71..9694732c5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,6 +15,11 @@ jobs: RELEASE_CHANNEL: ${{ steps.npm-tag.outputs.RELEASE_CHANNEL }} steps: - uses: GitHubSecurityLab/actions-permissions/monitor@v1 + - uses: mongodb-js/devtools-shared/actions/setup-bot-token@main + id: app-token + with: + app-id: ${{ vars.DEVTOOLS_BOT_APP_ID }} + private-key: ${{ secrets.DEVTOOLS_BOT_PRIVATE_KEY }} - uses: actions/checkout@v5 with: fetch-depth: 0 @@ -108,7 +113,9 @@ jobs: curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher - name: Login to MCP Registry - run: ./mcp-publisher login github-oidc + run: ./mcp-publisher login github --token $GITHUB_TOKEN + env: + GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} - name: Publish to MCP Registry run: ./mcp-publisher publish From e42a4481571820f5f5d2c88195541884c71e1151 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 15:24:22 +0200 Subject: [PATCH 10/18] chore: use token publishing --- .github/workflows/publish.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9694732c5..79981f323 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -113,9 +113,7 @@ jobs: curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher - name: Login to MCP Registry - run: ./mcp-publisher login github --token $GITHUB_TOKEN - env: - GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} + run: ./mcp-publisher login github --token ${{ steps.app-token.outputs.token }} - name: Publish to MCP Registry run: ./mcp-publisher publish From 2ad52a6f936fda0752205c97a410dd566bc12e77 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 15:55:45 +0200 Subject: [PATCH 11/18] chore: add clarifications --- src/common/config.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/common/config.ts b/src/common/config.ts index 202a0c7db..c9a235233 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -216,9 +216,19 @@ export const UserConfigSchema = z.object({ .default("enabled") .describe("When set to disabled, disables telemetry collection."), transport: z.enum(["stdio", "http"]).default("stdio").describe("Either 'stdio' or 'http'."), - httpPort: z.number().default(3000).describe("Port number."), - httpHost: z.string().default("127.0.0.1").describe("Host to bind the http server."), - httpHeaders: z.record(z.string()).describe("HTTP headers to pass to the http server."), + httpPort: z + .number() + .default(3000) + .describe("Port number for the HTTP server (only used when transport is 'http')."), + httpHost: z + .string() + .default("127.0.0.1") + .describe("Host address to bind the HTTP server to (only used when transport is 'http')."), + httpHeaders: z + .record(z.string()) + .describe( + "Custom HTTP headers to include in responses from the HTTP server (only used when transport is 'http'). Useful for adding CORS headers, authentication tokens, or other custom headers required by your client application." + ), idleTimeoutMs: z .number() .default(600_000) @@ -268,7 +278,6 @@ export const UserConfigSchema = z.object({ .describe("Default similarity function for vector search: 'euclidean', 'cosine', or 'dotProduct'."), }); -// Export UserConfig type derived from the Zod schema export type UserConfig = z.infer & CliOptions; export const defaultUserConfig: UserConfig = { From 106e28aca0912818b765e7ce0ce4adf0af9b1d28 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 15:57:53 +0200 Subject: [PATCH 12/18] chore: make args optional --- src/common/config.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/common/config.ts b/src/common/config.ts index c9a235233..f17aa0b49 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -160,8 +160,7 @@ function isConnectionSpecifier(arg: string | undefined): boolean { } export const UserConfigSchema = z.object({ - // Atlas API Options - apiBaseUrl: z.string(), + apiBaseUrl: z.string().optional(), apiClientId: z .string() .optional() @@ -183,6 +182,7 @@ export const UserConfigSchema = z.object({ logPath: z.string().describe("Folder to store logs."), disabledTools: z .array(z.string()) + .optional() .describe("An array of tool names, operation types, and/or categories of tools that will be disabled."), confirmationRequiredTools: z .array(z.string()) @@ -200,14 +200,12 @@ export const UserConfigSchema = z.object({ readOnly: z .boolean() .default(false) - .optional() .describe( "When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations." ), indexCheck: z .boolean() .default(false) - .optional() .describe( "When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan." ), @@ -226,6 +224,7 @@ export const UserConfigSchema = z.object({ .describe("Host address to bind the HTTP server to (only used when transport is 'http')."), httpHeaders: z .record(z.string()) + .optional() .describe( "Custom HTTP headers to include in responses from the HTTP server (only used when transport is 'http'). Useful for adding CORS headers, authentication tokens, or other custom headers required by your client application." ), @@ -266,15 +265,21 @@ export const UserConfigSchema = z.object({ ), voyageApiKey: z .string() + .optional() .describe( "API key for Voyage AI embeddings service (required for vector search operations with text-to-embedding conversion)." ), disableEmbeddingsValidation: z .boolean() + .optional() .describe("When set to true, disables validation of embeddings dimensions."), - vectorSearchDimensions: z.number().describe("Default number of dimensions for vector search embeddings."), + vectorSearchDimensions: z + .number() + .optional() + .describe("Default number of dimensions for vector search embeddings."), vectorSearchSimilarityFunction: z .custom() + .optional() .describe("Default similarity function for vector search: 'euclidean', 'cosine', or 'dotProduct'."), }); From 54563a5e7ad33f4b74d4076cf4e3ad6ab8ab6dad Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 16:00:37 +0200 Subject: [PATCH 13/18] chore: remove id-token, move publish step --- .github/workflows/publish.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 79981f323..765b8c60a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -80,7 +80,6 @@ jobs: environment: Production permissions: contents: write - id-token: write # Required for OIDC authentication with MCP Registry needs: - check if: needs.check.outputs.VERSION_EXISTS == 'false' @@ -102,6 +101,12 @@ jobs: env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Publish git release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create ${{ needs.check.outputs.VERSION }} --title "${{ needs.check.outputs.VERSION }}" --generate-notes --target ${{ github.sha }} ${{ (needs.check.outputs.RELEASE_CHANNEL != 'latest' && '--prerelease') || ''}} + - name: Update server.json version and arguments run: | VERSION="${{ needs.check.outputs.VERSION }}" @@ -116,10 +121,4 @@ jobs: run: ./mcp-publisher login github --token ${{ steps.app-token.outputs.token }} - name: Publish to MCP Registry - run: ./mcp-publisher publish - - - name: Publish git release - env: - GH_TOKEN: ${{ github.token }} - run: | - gh release create ${{ needs.check.outputs.VERSION }} --title "${{ needs.check.outputs.VERSION }}" --generate-notes --target ${{ github.sha }} ${{ (needs.check.outputs.RELEASE_CHANNEL != 'latest' && '--prerelease') || ''}} + run: ./mcp-publisher publish \ No newline at end of file From f7cd64a8a8aa4b37dd69914a75c35b7a8e7f54ec Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 16:03:10 +0200 Subject: [PATCH 14/18] chore: use defaults --- src/common/config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/config.ts b/src/common/config.ts index f17aa0b49..aed46a405 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -160,7 +160,7 @@ function isConnectionSpecifier(arg: string | undefined): boolean { } export const UserConfigSchema = z.object({ - apiBaseUrl: z.string().optional(), + apiBaseUrl: z.string().default("https://cloud.mongodb.com/"), apiClientId: z .string() .optional() @@ -182,7 +182,7 @@ export const UserConfigSchema = z.object({ logPath: z.string().describe("Folder to store logs."), disabledTools: z .array(z.string()) - .optional() + .default([]) .describe("An array of tool names, operation types, and/or categories of tools that will be disabled."), confirmationRequiredTools: z .array(z.string()) From 8ff4eefddc12c0a78c51b8d7f4f8ffc269bf2985 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 16:11:45 +0200 Subject: [PATCH 15/18] chore: add default to vector and headers, format --- .github/workflows/publish.yml | 2 +- src/common/config.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 765b8c60a..391c41421 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -121,4 +121,4 @@ jobs: run: ./mcp-publisher login github --token ${{ steps.app-token.outputs.token }} - name: Publish to MCP Registry - run: ./mcp-publisher publish \ No newline at end of file + run: ./mcp-publisher publish diff --git a/src/common/config.ts b/src/common/config.ts index aed46a405..58967bc85 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -224,7 +224,7 @@ export const UserConfigSchema = z.object({ .describe("Host address to bind the HTTP server to (only used when transport is 'http')."), httpHeaders: z .record(z.string()) - .optional() + .default({}) .describe( "Custom HTTP headers to include in responses from the HTTP server (only used when transport is 'http'). Useful for adding CORS headers, authentication tokens, or other custom headers required by your client application." ), @@ -275,11 +275,12 @@ export const UserConfigSchema = z.object({ .describe("When set to true, disables validation of embeddings dimensions."), vectorSearchDimensions: z .number() - .optional() + .default(1024) .describe("Default number of dimensions for vector search embeddings."), vectorSearchSimilarityFunction: z .custom() .optional() + .default("euclidean") .describe("Default similarity function for vector search: 'euclidean', 'cosine', or 'dotProduct'."), }); From a01db620104dd1f87d38a8ceb2a5021789f5e7a3 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 16:39:38 +0200 Subject: [PATCH 16/18] chore: add voyage api key default --- src/common/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/config.ts b/src/common/config.ts index 58967bc85..adf8bc2b6 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -265,7 +265,7 @@ export const UserConfigSchema = z.object({ ), voyageApiKey: z .string() - .optional() + .default("") .describe( "API key for Voyage AI embeddings service (required for vector search operations with text-to-embedding conversion)." ), From 97c758580811f59ba7166f5fa99c2d4be5d6744a Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 17:01:55 +0200 Subject: [PATCH 17/18] chore: move argument generation to prepare-release --- .github/workflows/prepare-release.yml | 5 +++++ .github/workflows/publish.yml | 6 ------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index ca63cfae1..25439dfe1 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -35,6 +35,11 @@ jobs: run: | echo "NEW_VERSION=$(npm version ${{ inputs.version }} --no-git-tag-version)" >> $GITHUB_OUTPUT npm run build:update-package-version + + - name: Update server.json version and arguments + run: | + npm run generate:arguments + - name: Create release PR uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # 7.0.8 id: create-pr diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 391c41421..14f6cf14a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -107,12 +107,6 @@ jobs: run: | gh release create ${{ needs.check.outputs.VERSION }} --title "${{ needs.check.outputs.VERSION }}" --generate-notes --target ${{ github.sha }} ${{ (needs.check.outputs.RELEASE_CHANNEL != 'latest' && '--prerelease') || ''}} - - name: Update server.json version and arguments - run: | - VERSION="${{ needs.check.outputs.VERSION }}" - VERSION="${VERSION#v}" - npm run generate:arguments - - name: Install MCP Publisher run: | curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher From d3b80f5021981dce0605567df825dc9c2d0bcb28 Mon Sep 17 00:00:00 2001 From: gagik Date: Thu, 23 Oct 2025 18:08:17 +0200 Subject: [PATCH 18/18] chore: move to publish job, fix description --- .github/workflows/publish.yml | 10 +++++----- src/common/config.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 14f6cf14a..8cbbda6f0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,11 +15,6 @@ jobs: RELEASE_CHANNEL: ${{ steps.npm-tag.outputs.RELEASE_CHANNEL }} steps: - uses: GitHubSecurityLab/actions-permissions/monitor@v1 - - uses: mongodb-js/devtools-shared/actions/setup-bot-token@main - id: app-token - with: - app-id: ${{ vars.DEVTOOLS_BOT_APP_ID }} - private-key: ${{ secrets.DEVTOOLS_BOT_PRIVATE_KEY }} - uses: actions/checkout@v5 with: fetch-depth: 0 @@ -85,6 +80,11 @@ jobs: if: needs.check.outputs.VERSION_EXISTS == 'false' steps: - uses: GitHubSecurityLab/actions-permissions/monitor@v1 + - uses: mongodb-js/devtools-shared/actions/setup-bot-token@main + id: app-token + with: + app-id: ${{ vars.DEVTOOLS_BOT_APP_ID }} + private-key: ${{ secrets.DEVTOOLS_BOT_PRIVATE_KEY }} - uses: actions/checkout@v5 - uses: actions/setup-node@v6 with: diff --git a/src/common/config.ts b/src/common/config.ts index adf8bc2b6..9565e1d07 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -226,7 +226,7 @@ export const UserConfigSchema = z.object({ .record(z.string()) .default({}) .describe( - "Custom HTTP headers to include in responses from the HTTP server (only used when transport is 'http'). Useful for adding CORS headers, authentication tokens, or other custom headers required by your client application." + "Header that the HTTP server will validate when making requests (only used when transport is 'http')." ), idleTimeoutMs: z .number()