diff --git a/.prettierignore b/.prettierignore index ffb0dcd0..52be6ef1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,3 +2,4 @@ dist coverage package-lock.json tests/tmp +src/common/atlas/openapi.d.ts diff --git a/.prettierrc.json b/.prettierrc.json index 076027c3..a8d4dcc3 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -5,6 +5,13 @@ "singleQuote": false, "printWidth": 120, "overrides": [ + { + "files": "*.ts", + "options": { + "insertPragma": false, + "proseWrap": "preserve" + } + }, { "files": "*.json", "options": { diff --git a/eslint.config.js b/eslint.config.js index e93a22bf..18f564c7 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -4,10 +4,31 @@ import globals from "globals"; import tseslint from "typescript-eslint"; import eslintConfigPrettier from "eslint-config-prettier/flat"; +const files = ["src/**/*.ts", "scripts/**/*.ts", "tests/**/*.test.ts", "eslint.config.js", "jest.config.js"]; + export default defineConfig([ - { files: ["src/**/*.ts"], plugins: { js }, extends: ["js/recommended"] }, - { files: ["src/**/*.ts"], languageOptions: { globals: globals.node } }, - tseslint.configs.recommended, + { files, plugins: { js }, extends: ["js/recommended"] }, + { files, languageOptions: { globals: globals.node } }, + tseslint.configs.recommendedTypeChecked, + { + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + { + files, + rules: { + "@typescript-eslint/switch-exhaustiveness-check": "error", + }, + }, + // Ignore features specific to TypeScript resolved rules + tseslint.config({ + // TODO: Configure tests and scripts to work with this. + ignores: ["eslint.config.js", "jest.config.js", "tests/**/*.ts", "scripts/**/*.ts"], + }), + globalIgnores(["node_modules", "dist", "src/common/atlas/openapi.d.ts"]), eslintConfigPrettier, - globalIgnores(["node_modules", "dist"]), ]); diff --git a/package-lock.json b/package-lock.json index 0ec360e2..db3e8841 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "dependencies": { "@mongodb-js/devtools-connect": "^3.7.2", "@mongosh/service-provider-node-driver": "^3.6.0", - "@types/express": "^5.0.1", "bson": "^6.10.3", "mongodb": "^6.15.0", "mongodb-log-writer": "^2.4.1", @@ -31,6 +30,7 @@ "@modelcontextprotocol/inspector": "^0.8.2", "@modelcontextprotocol/sdk": "^1.8.0", "@redocly/cli": "^1.34.2", + "@types/express": "^5.0.1", "@types/jest": "^29.5.14", "@types/node": "^22.14.0", "@types/simple-oauth2": "^5.0.7", @@ -5844,6 +5844,7 @@ "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, "license": "MIT", "dependencies": { "@types/connect": "*", @@ -5854,6 +5855,7 @@ "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -5870,6 +5872,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.1.tgz", "integrity": "sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/body-parser": "*", @@ -5881,6 +5884,7 @@ "version": "5.0.6", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -5903,6 +5907,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-coverage": { @@ -5954,12 +5959,14 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, "license": "MIT" }, "node_modules/@types/node": { "version": "22.14.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -5976,18 +5983,21 @@ "version": "6.9.18", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", + "dev": true, "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, "license": "MIT" }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, "license": "MIT", "dependencies": { "@types/mime": "^1", @@ -5998,6 +6008,7 @@ "version": "1.15.7", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, "license": "MIT", "dependencies": { "@types/http-errors": "*", @@ -14582,6 +14593,7 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, "license": "MIT" }, "node_modules/unpipe": { diff --git a/package.json b/package.json index 80c2b88d..3d334144 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,8 @@ "prepare": "npm run build", "build:clean": "rm -rf dist", "build:compile": "tsc", - "build:addshebang": "echo '#!/usr/bin/env node' > dist/index2.js && cat dist/index.js >> dist/index2.js && mv dist/index2.js dist/index.js", "build:chmod": "chmod +x dist/index.js", - "build": "npm run build:clean && npm run build:compile && npm run build:addshebang && npm run build:chmod", + "build": "npm run build:clean && npm run build:compile && npm run build:chmod", "inspect": "npm run build && mcp-inspector -- dist/index.js", "prettier": "prettier", "check": "npm run build && npm run check:lint && npm run check:format", @@ -38,6 +37,7 @@ "@modelcontextprotocol/inspector": "^0.8.2", "@modelcontextprotocol/sdk": "^1.8.0", "@redocly/cli": "^1.34.2", + "@types/express": "^5.0.1", "@types/jest": "^29.5.14", "@types/node": "^22.14.0", "@types/simple-oauth2": "^5.0.7", @@ -60,7 +60,6 @@ "dependencies": { "@mongodb-js/devtools-connect": "^3.7.2", "@mongosh/service-provider-node-driver": "^3.6.0", - "@types/express": "^5.0.1", "bson": "^6.10.3", "mongodb": "^6.15.0", "mongodb-log-writer": "^2.4.1", diff --git a/src/common/atlas/apiClient.ts b/src/common/atlas/apiClient.ts index 3198ea70..39957b7d 100644 --- a/src/common/atlas/apiClient.ts +++ b/src/common/atlas/apiClient.ts @@ -112,7 +112,9 @@ export class ApiClient { this.client.use(this.errorMiddleware()); } - async getIpInfo() { + public async getIpInfo(): Promise<{ + currentIpv4Address: string; + }> { const accessToken = await this.getAccessToken(); const endpoint = "api/private/ipinfo"; @@ -130,10 +132,9 @@ export class ApiClient { throw await ApiClientError.fromResponse(response); } - const responseBody = await response.json(); - return responseBody as { + return (await response.json()) as Promise<{ currentIpv4Address: string; - }; + }>; } async listProjects(options?: FetchOptions) { diff --git a/src/common/atlas/openapi.d.ts b/src/common/atlas/openapi.d.ts index 8ff7878c..c55f53ae 100644 --- a/src/common/atlas/openapi.d.ts +++ b/src/common/atlas/openapi.d.ts @@ -241,13 +241,7 @@ export interface components { * @enum {string} */ providerName: "AWS"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "AWS"; - }; + } ; AWSCloudProviderSettings: Omit & { autoScaling?: components["schemas"]["CloudProviderAWSAutoScaling"]; /** @@ -346,13 +340,7 @@ export interface components { * @enum {string} */ providerName: "AWS"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "AWS"; - }; + } ; /** * AWS * @description Collection of settings that configures how a cluster might scale its cluster tier and whether the cluster can scale down. Cluster tier auto-scaling is unavailable for clusters using Low CPU or NVME storage classes. @@ -643,13 +631,7 @@ export interface components { * @enum {string} */ providerName: "AWS"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "AWS"; - }; + } ; /** * AWS Regional Replication Specifications * @description Details that explain how MongoDB Cloud replicates data in one region on the specified MongoDB database. @@ -665,13 +647,7 @@ export interface components { * @enum {string} */ providerName: "AWS"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "AWS"; - }; + } ; /** * Automatic Scaling Settings * @description Options that determine how this cluster handles resource scaling. @@ -919,13 +895,7 @@ export interface components { * @enum {string} */ providerName: "AZURE"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "AZURE"; - }; + } ; AzureCloudProviderSettings: Omit & { autoScaling?: components["schemas"]["CloudProviderAzureAutoScaling"]; /** @@ -1022,13 +992,7 @@ export interface components { * @enum {string} */ providerName: "AZURE"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "AZURE"; - }; + } ; /** * Azure * @description Collection of settings that configures how a cluster might scale its cluster tier and whether the cluster can scale down. Cluster tier auto-scaling is unavailable for clusters using Low CPU or NVME storage classes. @@ -1246,13 +1210,7 @@ export interface components { * @enum {string} */ providerName: "AZURE"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "AZURE"; - }; + } ; /** * Azure Regional Replication Specifications * @description Details that explain how MongoDB Cloud replicates data in one region on the specified MongoDB database. @@ -1268,13 +1226,7 @@ export interface components { * @enum {string} */ providerName: "AZURE"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "AZURE"; - }; + } ; /** @description Bad request detail. */ BadRequestDetail: { /** @description Describes all violations in a client request. */ @@ -1310,49 +1262,49 @@ export interface components { | "M400_NVME" ) | ( - | "M10" - | "M20" - | "M30" - | "M40" - | "M50" - | "M60" - | "M80" + + + + + + + | "M90" - | "M200" - | "R40" - | "R50" - | "R60" - | "R80" - | "R200" - | "R300" - | "R400" - | "M60_NVME" - | "M80_NVME" - | "M200_NVME" + + + + + + + + + + + | "M300_NVME" - | "M400_NVME" + | "M600_NVME" ) | ( - | "M10" - | "M20" - | "M30" - | "M40" - | "M50" - | "M60" - | "M80" - | "M140" - | "M200" + + + + + + + + + | "M250" - | "M300" + | "M400" - | "R40" - | "R50" - | "R60" - | "R80" - | "R200" - | "R300" - | "R400" + + + + + + + | "R600" ); BasicDBObject: { @@ -1832,13 +1784,7 @@ export interface components { * @enum {string} */ providerName: "GCP"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "GCP"; - }; + } ; /** @description Range of instance sizes to which your cluster can scale. */ CloudProviderAWSAutoScaling: { compute?: components["schemas"]["AWSComputeAutoScaling"]; @@ -2258,14 +2204,14 @@ export interface components { | ( | "US_CENTRAL" | "US_EAST" - | "US_EAST_2" + | "US_NORTH_CENTRAL" | "US_WEST" | "US_SOUTH_CENTRAL" | "EUROPE_NORTH" | "EUROPE_WEST" | "US_WEST_CENTRAL" - | "US_WEST_2" + | "US_WEST_3" | "CANADA_EAST" | "CANADA_CENTRAL" @@ -2313,9 +2259,9 @@ export interface components { | "US_EAST_4_AW" | "US_EAST_5" | "US_EAST_5_AW" - | "US_WEST_2" + | "US_WEST_2_AW" - | "US_WEST_3" + | "US_WEST_3_AW" | "US_WEST_4" | "US_WEST_4_AW" @@ -2426,14 +2372,14 @@ export interface components { | ( | "US_CENTRAL" | "US_EAST" - | "US_EAST_2" + | "US_NORTH_CENTRAL" | "US_WEST" | "US_SOUTH_CENTRAL" | "EUROPE_NORTH" | "EUROPE_WEST" | "US_WEST_CENTRAL" - | "US_WEST_2" + | "US_WEST_3" | "CANADA_EAST" | "CANADA_CENTRAL" @@ -2481,9 +2427,9 @@ export interface components { | "US_EAST_4_AW" | "US_EAST_5" | "US_EAST_5_AW" - | "US_WEST_2" + | "US_WEST_2_AW" - | "US_WEST_3" + | "US_WEST_3_AW" | "US_WEST_4" | "US_WEST_4_AW" @@ -2756,13 +2702,7 @@ export interface components { * @enum {string} */ providerName: "FLEX"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "FLEX"; - }; + } ; /** @description Range of instance sizes to which your cluster can scale. */ ClusterFreeAutoScaling: { compute?: components["schemas"]["FreeComputeAutoScalingRules"]; @@ -2795,13 +2735,7 @@ export interface components { * @enum {string} */ providerName: "TENANT"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "TENANT"; - }; + } ; /** * Cloud Service Provider Settings for a Cluster * @description Group of cloud provider settings that configure the provisioned MongoDB hosts. @@ -3007,13 +2941,7 @@ export interface components { * @enum {string} */ type: "DAILY"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - type: "DAILY"; - }; + } ; DataLakeAtlasStoreInstance: Omit & { /** @description Human-readable label of the MongoDB Cloud cluster on which the store is based. */ clusterName?: string; @@ -3027,13 +2955,7 @@ export interface components { * @enum {string} */ provider: "atlas"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - provider: "atlas"; - }; + } ; /** @description MongoDB Cloud cluster read concern, which determines the consistency and isolation properties of the data read from an Atlas cluster. */ DataLakeAtlasStoreReadConcern: { /** @@ -3140,13 +3062,7 @@ export interface components { * @enum {string} */ provider: "azure"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - provider: "azure"; - }; + } ; DataLakeDLSAWSStore: Omit & { /** * AWS Regions @@ -3194,13 +3110,7 @@ export interface components { * @enum {string} */ provider: "dls:aws"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - provider: "dls:aws"; - }; + } ; DataLakeDLSAzureStore: Omit & { /** * Azure Regions @@ -3263,13 +3173,7 @@ export interface components { * @enum {string} */ provider: "dls:azure"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - provider: "dls:azure"; - }; + } ; DataLakeDLSGCPStore: Omit & { /** * GCP Regions @@ -3319,13 +3223,7 @@ export interface components { * @enum {string} */ provider: "dls:gcp"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - provider: "dls:gcp"; - }; + } ; DataLakeGoogleCloudStorageStore: Omit & { /** @description Human-readable label that identifies the Google Cloud Storage bucket. */ bucket?: string; @@ -3388,13 +3286,7 @@ export interface components { * @enum {string} */ provider: "gcs"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - provider: "gcs"; - }; + } ; DataLakeHTTPStore: Omit & { /** * @description Flag that validates the scheme in the specified URLs. If `true`, allows insecure `HTTP` scheme, doesn't verify the server's certificate chain and hostname, and accepts any certificate with any hostname presented by the server. If `false`, allows secure `HTTPS` scheme only. @@ -3411,13 +3303,7 @@ export interface components { * @enum {string} */ provider: "http"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - provider: "http"; - }; + } ; /** * Partition Field * @description Partition Field in the Data Lake Storage provider for a Data Lake Pipeline. @@ -3497,13 +3383,7 @@ export interface components { * @enum {string} */ provider: "s3"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - provider: "s3"; - }; + } ; /** @description Group of settings that define where the data is stored. */ DataLakeStoreSettings: { /** @description Human-readable label that identifies the data store. The **databases.[n].collections.[n].dataSources.[n].storeName** field references this values as part of the mapping configuration. To use MongoDB Cloud as a data store, the data lake requires a serverless instance or an `M10` or higher cluster. */ @@ -3626,13 +3506,7 @@ export interface components { * @enum {string} */ type: "DEFAULT"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - type: "DEFAULT"; - }; + } ; DiskBackupSnapshotAWSExportBucketRequest: Omit< WithRequired, "cloudProvider" @@ -3886,13 +3760,7 @@ export interface components { * @enum {string} */ providerName: "GCP"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "GCP"; - }; + } ; /** * GCP * @description Collection of settings that configures how a cluster might scale its cluster tier and whether the cluster can scale down. Cluster tier auto-scaling is unavailable for clusters using Low CPU or NVME storage classes. @@ -4075,13 +3943,7 @@ export interface components { * @enum {string} */ providerName: "GCP"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "GCP"; - }; + } ; /** * GCP Regional Replication Specifications * @description Details that explain how MongoDB Cloud replicates data in one region on the specified MongoDB database. @@ -4097,13 +3959,7 @@ export interface components { * @enum {string} */ providerName: "GCP"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "GCP"; - }; + } ; Group: { /** * Format: int64 @@ -4191,13 +4047,7 @@ export interface components { * @enum {string} */ orgMembershipStatus: "ACTIVE"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - orgMembershipStatus: "ACTIVE"; - }; + } ; GroupPendingUserResponse: Omit< WithRequired< components["schemas"]["GroupUserResponse"], @@ -4226,13 +4076,7 @@ export interface components { * @enum {string} */ orgMembershipStatus: "PENDING"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - orgMembershipStatus: "PENDING"; - }; + } ; GroupRoleAssignment: { /** * @description Unique 24-hexadecimal digit string that identifies the project to which these roles belong. @@ -4871,13 +4715,7 @@ export interface components { * @enum {string} */ type: "MONTHLY"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - type: "MONTHLY"; - }; + } ; NetworkPermissionEntry: { /** @description Unique string of the Amazon Web Services (AWS) security group that you want to add to the project's IP access list. Your IP access list entry can be one **awsSecurityGroup**, one **cidrBlock**, or one **ipAddress**. You must configure Virtual Private Connection (VPC) peering for your project before you can add an AWS security group to an IP access list. You cannot set AWS security groups as temporary access list entries. Don't set this parameter if you set **cidrBlock** or **ipAddress**. */ awsSecurityGroup?: string; @@ -4976,13 +4814,7 @@ export interface components { * @enum {string} */ orgMembershipStatus: "ACTIVE"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - orgMembershipStatus: "ACTIVE"; - }; + } ; OrgGroup: { /** @description Settings that describe the clusters in each project that the API key is authorized to view. */ readonly clusters?: components["schemas"]["CloudCluster"][]; @@ -5024,13 +4856,7 @@ export interface components { * @enum {string} */ orgMembershipStatus: "PENDING"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - orgMembershipStatus: "PENDING"; - }; + } ; OrgUserResponse: { /** * @description Unique 24-hexadecimal digit string that identifies the MongoDB Cloud user. @@ -5605,13 +5431,7 @@ export interface components { * @enum {string} */ type: "AWSLambda"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - type: "AWSLambda"; - }; + } ; StreamsClusterConnection: Omit & { /** @description Name of the cluster configured for this connection. */ clusterName?: string; @@ -5622,13 +5442,7 @@ export interface components { * @enum {string} */ type: "Cluster"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - type: "Cluster"; - }; + } ; /** @description Settings that define a connection to an external data store. */ StreamsConnection: { /** @description List of one or more Uniform Resource Locators (URLs) that point to API sub-resources, related API resources, or both. RFC 5988 outlines these relationships. */ @@ -5661,13 +5475,7 @@ export interface components { * @enum {string} */ type: "Https"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - type: "Https"; - }; + } ; /** @description User credentials required to connect to a Kafka Cluster. Includes the authentication type, as well as the parameters for that authentication mode. */ StreamsKafkaAuthentication: { /** @description List of one or more Uniform Resource Locators (URLs) that point to API sub-resources, related API resources, or both. RFC 5988 outlines these relationships. */ @@ -5710,13 +5518,7 @@ export interface components { * @enum {string} */ type: "Kafka"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - type: "Kafka"; - }; + } ; /** @description Networking Access Type can either be 'PUBLIC' (default) or VPC. VPC type is in public preview, please file a support ticket to enable VPC Network Access. */ StreamsKafkaNetworking: { access?: components["schemas"]["StreamsKafkaNetworkingAccess"]; @@ -5759,26 +5561,14 @@ export interface components { * @enum {string} */ type: "S3"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - type: "S3"; - }; + } ; StreamsSampleConnection: Omit & { /** * @description discriminator enum property added by openapi-typescript * @enum {string} */ type: "Sample"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - type: "Sample"; - }; + } ; /** * Synonym Mapping Status Detail * @description Contains the status of the index's synonym mappings on each search host. This field (and its subfields) only appear if the index has synonyms defined. @@ -5863,13 +5653,7 @@ export interface components { * @enum {string} */ providerName: "TENANT"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "TENANT"; - }; + } ; /** * Tenant Regional Replication Specifications * @description Details that explain how MongoDB Cloud replicates data in one region on the specified MongoDB database. @@ -5888,13 +5672,7 @@ export interface components { * @enum {string} */ providerName: "TENANT"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - providerName: "TENANT"; - }; + } ; /** Text Search Host Status Detail */ TextSearchHostStatusDetail: { /** @description Hostname that corresponds to the status detail. */ @@ -6403,13 +6181,7 @@ export interface components { * @enum {string} */ type: "WEEKLY"; - } & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - type: "WEEKLY"; - }; + } ; /** * htmlStrip * @description Filter that strips out HTML constructs. diff --git a/src/index.ts b/src/index.ts index 39fb0bc8..0f282e4d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,5 @@ +#!/usr/bin/env node + import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { Server } from "./server.js"; import logger from "./logger.js"; diff --git a/src/logger.ts b/src/logger.ts index 532ff506..064b7fe8 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -44,7 +44,7 @@ abstract class LoggerBase { class ConsoleLogger extends LoggerBase { log(level: LogLevel, id: MongoLogId, context: string, message: string): void { message = redact(message); - console.error(`[${level.toUpperCase()}] ${id} - ${context}: ${message}`); + console.error(`[${level.toUpperCase()}] ${id.__value} - ${context}: ${message}`); } } @@ -60,7 +60,7 @@ class Logger extends LoggerBase { message = redact(message); const mongoDBLevel = this.mapToMongoDBLogLevel(level); this.logWriter[mongoDBLevel]("MONGODB-MCP", id, context, message); - this.server.server.sendLoggingMessage({ + void this.server.server.sendLoggingMessage({ level, data: `[${context}]: ${message}`, }); diff --git a/src/tools/atlas/listClusters.ts b/src/tools/atlas/listClusters.ts index eb38f74e..16c85233 100644 --- a/src/tools/atlas/listClusters.ts +++ b/src/tools/atlas/listClusters.ts @@ -47,8 +47,8 @@ export class ListClustersTool extends AtlasToolBase { if (!clusters?.results?.length) { throw new Error("No clusters found."); } - const rows = clusters - .results!.map((result) => { + const rows = clusters.results + .map((result) => { return (result.clusters || []).map((cluster) => { return { ...result, ...cluster, clusters: undefined }; }); @@ -75,8 +75,8 @@ ${rows}`, if (!clusters?.results?.length) { throw new Error("No clusters found."); } - const rows = clusters - .results!.map((cluster) => { + const rows = clusters.results + .map((cluster) => { const connectionString = cluster.connectionStrings?.standard || "N/A"; const mongoDBVersion = cluster.mongoDBVersion || "N/A"; return `${cluster.name} | ${cluster.stateName} | ${mongoDBVersion} | ${connectionString}`; diff --git a/src/tools/atlas/listProjects.ts b/src/tools/atlas/listProjects.ts index 17fa6668..cdf6d6cc 100644 --- a/src/tools/atlas/listProjects.ts +++ b/src/tools/atlas/listProjects.ts @@ -16,8 +16,8 @@ export class ListProjectsTool extends AtlasToolBase { } // Format projects as a table - const rows = data! - .results!.map((project) => { + const rows = data.results + .map((project) => { const createdAt = project.created ? new Date(project.created).toLocaleString() : "N/A"; return `${project.name} | ${project.id} | ${createdAt}`; }) diff --git a/src/tools/mongodb/create/insertOne.ts b/src/tools/mongodb/create/insertOne.ts index b490efd4..795c603e 100644 --- a/src/tools/mongodb/create/insertOne.ts +++ b/src/tools/mongodb/create/insertOne.ts @@ -29,7 +29,7 @@ export class InsertOneTool extends MongoDBToolBase { return { content: [ { - text: `Inserted document with ID \`${result.insertedId}\` into collection \`${collection}\``, + text: `Inserted document with ID \`${result.insertedId.toString()}\` into collection \`${collection}\``, type: "text", }, ], diff --git a/src/tools/mongodb/metadata/collectionSchema.ts b/src/tools/mongodb/metadata/collectionSchema.ts index f780252d..dfa45a6c 100644 --- a/src/tools/mongodb/metadata/collectionSchema.ts +++ b/src/tools/mongodb/metadata/collectionSchema.ts @@ -33,7 +33,8 @@ export class CollectionSchemaTool extends MongoDBToolBase { let result = "| Field | Type | Confidence |\n"; result += "|-------|------|-------------|\n"; for (const field of fields) { - result += `| ${field.name} | \`${field.type}\` | ${(field.probability * 100).toFixed(0)}% |\n`; + const fieldType = Array.isArray(field.type) ? field.type.join(", ") : field.type; + result += `| ${field.name} | \`${fieldType}\` | ${(field.probability * 100).toFixed(0)}% |\n`; } return result; } diff --git a/src/tools/mongodb/metadata/collectionStorageSize.ts b/src/tools/mongodb/metadata/collectionStorageSize.ts index ab41261d..09b7e6d3 100644 --- a/src/tools/mongodb/metadata/collectionStorageSize.ts +++ b/src/tools/mongodb/metadata/collectionStorageSize.ts @@ -11,12 +11,12 @@ export class CollectionStorageSizeTool extends MongoDBToolBase { protected async execute({ database, collection }: ToolArgs): Promise { const provider = await this.ensureConnected(); - const [{ value }] = await provider + const [{ value }] = (await provider .aggregate(database, collection, [ { $collStats: { storageStats: {} } }, { $group: { _id: null, value: { $sum: "$storageStats.storageSize" } } }, ]) - .toArray(); + .toArray()) as [{ value: number }]; return { content: [ diff --git a/src/tools/mongodb/metadata/listDatabases.ts b/src/tools/mongodb/metadata/listDatabases.ts index 7a89d09c..bdbdd19a 100644 --- a/src/tools/mongodb/metadata/listDatabases.ts +++ b/src/tools/mongodb/metadata/listDatabases.ts @@ -16,7 +16,7 @@ export class ListDatabasesTool extends MongoDBToolBase { return { content: dbs.map((db) => { return { - text: `Name: ${db.name}, Size: ${db.sizeOnDisk} bytes`, + text: `Name: ${db.name}, Size: ${db.sizeOnDisk.toString()} bytes`, type: "text", }; }), diff --git a/src/tools/mongodb/update/updateMany.ts b/src/tools/mongodb/update/updateMany.ts index e692c36b..f02e2a62 100644 --- a/src/tools/mongodb/update/updateMany.ts +++ b/src/tools/mongodb/update/updateMany.ts @@ -49,7 +49,7 @@ export class UpdateManyTool extends MongoDBToolBase { message += ` Modified ${result.modifiedCount} document(s).`; } if (result.upsertedCount > 0) { - message += ` Upserted ${result.upsertedCount} document(s) (with id: ${result.upsertedId}).`; + message += ` Upserted ${result.upsertedCount} document(s) (with id: ${result.upsertedId?.toString()}).`; } } diff --git a/src/tools/mongodb/update/updateOne.ts b/src/tools/mongodb/update/updateOne.ts index b1a604c6..9d117b7b 100644 --- a/src/tools/mongodb/update/updateOne.ts +++ b/src/tools/mongodb/update/updateOne.ts @@ -49,7 +49,7 @@ export class UpdateOneTool extends MongoDBToolBase { message += ` Modified ${result.modifiedCount} document(s).`; } if (result.upsertedCount > 0) { - message += ` Upserted ${result.upsertedCount} document(s) (with id: ${result.upsertedId}).`; + message += ` Upserted ${result.upsertedCount} document(s) (with id: ${result.upsertedId?.toString()}).`; } } diff --git a/src/tools/tool.ts b/src/tools/tool.ts index c1889be5..d09be52d 100644 --- a/src/tools/tool.ts +++ b/src/tools/tool.ts @@ -1,4 +1,4 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { McpServer, ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z, ZodNever, ZodRawShape } from "zod"; import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { State } from "../state.js"; @@ -14,12 +14,12 @@ export abstract class ToolBase { protected abstract argsShape: ZodRawShape; - protected abstract execute(args: ToolArgs): Promise; + protected abstract execute(...args: Parameters>): Promise; protected constructor(protected state: State) {} public register(server: McpServer): void { - const callback = async (args: ToolArgs): Promise => { + const callback: ToolCallback = async (...args) => { try { // TODO: add telemetry here logger.debug( @@ -28,22 +28,15 @@ export abstract class ToolBase { `Executing ${this.name} with args: ${JSON.stringify(args)}` ); - return await this.execute(args); - } catch (error) { - logger.error(mongoLogId(1_000_000), "tool", `Error executing ${this.name}: ${error}`); + return await this.execute(...args); + } catch (error: unknown) { + logger.error(mongoLogId(1_000_000), "tool", `Error executing ${this.name}: ${error as string}`); return await this.handleError(error); } }; - if (this.argsShape) { - // Not sure why typescript doesn't like the type signature of callback. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - server.tool(this.name, this.description, this.argsShape, callback as any); - } else { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - server.tool(this.name, this.description, callback as any); - } + server.tool(this.name, this.description, this.argsShape, callback); } // This method is intended to be overridden by subclasses to handle errors