diff --git a/package-lock.json b/package-lock.json
index 7d22747fb7..eb1779846f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6114,6 +6114,126 @@
         "node": ">=8"
       }
     },
+    "node_modules/@microsoft/api-extractor": {
+      "version": "7.52.8",
+      "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.52.8.tgz",
+      "integrity": "sha512-cszYIcjiNscDoMB1CIKZ3My61+JOhpERGlGr54i6bocvGLrcL/wo9o+RNXMBrb7XgLtKaizZWUpqRduQuHQLdg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@microsoft/api-extractor-model": "7.30.6",
+        "@microsoft/tsdoc": "~0.15.1",
+        "@microsoft/tsdoc-config": "~0.17.1",
+        "@rushstack/node-core-library": "5.13.1",
+        "@rushstack/rig-package": "0.5.3",
+        "@rushstack/terminal": "0.15.3",
+        "@rushstack/ts-command-line": "5.0.1",
+        "lodash": "~4.17.15",
+        "minimatch": "~3.0.3",
+        "resolve": "~1.22.1",
+        "semver": "~7.5.4",
+        "source-map": "~0.6.1",
+        "typescript": "5.8.2"
+      },
+      "bin": {
+        "api-extractor": "bin/api-extractor"
+      }
+    },
+    "node_modules/@microsoft/api-extractor-model": {
+      "version": "7.30.6",
+      "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.30.6.tgz",
+      "integrity": "sha512-znmFn69wf/AIrwHya3fxX6uB5etSIn6vg4Q4RB/tb5VDDs1rqREc+AvMC/p19MUN13CZ7+V/8pkYPTj7q8tftg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@microsoft/tsdoc": "~0.15.1",
+        "@microsoft/tsdoc-config": "~0.17.1",
+        "@rushstack/node-core-library": "5.13.1"
+      }
+    },
+    "node_modules/@microsoft/api-extractor/node_modules/minimatch": {
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz",
+      "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/@microsoft/api-extractor/node_modules/semver": {
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@microsoft/api-extractor/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@microsoft/tsdoc": {
+      "version": "0.15.1",
+      "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz",
+      "integrity": "sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@microsoft/tsdoc-config": {
+      "version": "0.17.1",
+      "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.17.1.tgz",
+      "integrity": "sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@microsoft/tsdoc": "0.15.1",
+        "ajv": "~8.12.0",
+        "jju": "~1.4.0",
+        "resolve": "~1.22.2"
+      }
+    },
+    "node_modules/@microsoft/tsdoc-config/node_modules/ajv": {
+      "version": "8.12.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+      "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/@microsoft/tsdoc-config/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/@mongodb-js/compass-components": {
       "version": "1.31.0",
       "resolved": "https://registry.npmjs.org/@mongodb-js/compass-components/-/compass-components-1.31.0.tgz",
@@ -9310,6 +9430,163 @@
         "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
       }
     },
+    "node_modules/@rushstack/node-core-library": {
+      "version": "5.13.1",
+      "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.13.1.tgz",
+      "integrity": "sha512-5yXhzPFGEkVc9Fu92wsNJ9jlvdwz4RNb2bMso+/+TH0nMm1jDDDsOIf4l8GAkPxGuwPw5DH24RliWVfSPhlW/Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ajv": "~8.13.0",
+        "ajv-draft-04": "~1.0.0",
+        "ajv-formats": "~3.0.1",
+        "fs-extra": "~11.3.0",
+        "import-lazy": "~4.0.0",
+        "jju": "~1.4.0",
+        "resolve": "~1.22.1",
+        "semver": "~7.5.4"
+      },
+      "peerDependencies": {
+        "@types/node": "*"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rushstack/node-core-library/node_modules/ajv": {
+      "version": "8.13.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz",
+      "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2",
+        "uri-js": "^4.4.1"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/@rushstack/node-core-library/node_modules/ajv-draft-04": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz",
+      "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "ajv": "^8.5.0"
+      },
+      "peerDependenciesMeta": {
+        "ajv": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rushstack/node-core-library/node_modules/ajv-formats": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
+      "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "ajv": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rushstack/node-core-library/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@rushstack/node-core-library/node_modules/semver": {
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@rushstack/rig-package": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.3.tgz",
+      "integrity": "sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "resolve": "~1.22.1",
+        "strip-json-comments": "~3.1.1"
+      }
+    },
+    "node_modules/@rushstack/terminal": {
+      "version": "0.15.3",
+      "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.15.3.tgz",
+      "integrity": "sha512-DGJ0B2Vm69468kZCJkPj3AH5nN+nR9SPmC0rFHtzsS4lBQ7/dgOwtwVxYP7W9JPDMuRBkJ4KHmWKr036eJsj9g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@rushstack/node-core-library": "5.13.1",
+        "supports-color": "~8.1.1"
+      },
+      "peerDependencies": {
+        "@types/node": "*"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rushstack/terminal/node_modules/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
+    "node_modules/@rushstack/ts-command-line": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.0.1.tgz",
+      "integrity": "sha512-bsbUucn41UXrQK7wgM8CNM/jagBytEyJqXw/umtI8d68vFm1Jwxh1OtLrlW7uGZgjCWiiPH6ooUNa1aVsuVr3Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@rushstack/terminal": "0.15.3",
+        "@types/argparse": "1.0.38",
+        "argparse": "~1.0.9",
+        "string-argv": "~0.3.1"
+      }
+    },
     "node_modules/@segment/analytics-core": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/@segment/analytics-core/-/analytics-core-1.4.1.tgz",
@@ -10748,6 +11025,13 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/@types/argparse": {
+      "version": "1.0.38",
+      "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz",
+      "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/@types/aria-query": {
       "version": "5.0.4",
       "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
@@ -18540,9 +18824,9 @@
       "license": "MIT"
     },
     "node_modules/fs-extra": {
-      "version": "11.2.0",
-      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
-      "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
+      "version": "11.3.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
+      "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==",
       "license": "MIT",
       "dependencies": {
         "graceful-fs": "^4.2.0",
@@ -20099,6 +20383,16 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/import-lazy": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
+      "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/import-local": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
@@ -21264,6 +21558,13 @@
         "url": "https://github.com/chalk/supports-color?sponsor=1"
       }
     },
+    "node_modules/jju": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
+      "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/jmespath": {
       "version": "0.16.0",
       "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz",
@@ -30596,6 +30897,16 @@
         "safe-buffer": "~5.2.0"
       }
     },
+    "node_modules/string-argv": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
+      "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.6.19"
+      }
+    },
     "node_modules/string-width": {
       "version": "4.2.3",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -31746,9 +32057,9 @@
       }
     },
     "node_modules/typescript": {
-      "version": "5.3.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
-      "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
+      "version": "5.8.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
+      "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
       "license": "Apache-2.0",
       "bin": {
         "tsc": "bin/tsc",
@@ -34564,6 +34875,8 @@
       "version": "3.10.3",
       "license": "Apache-2.0",
       "dependencies": {
+        "@babel/core": "^7.26.10",
+        "@babel/types": "^7.26.10",
         "@mongosh/arg-parser": "^3.10.2",
         "@mongosh/errors": "2.4.0",
         "@mongosh/history": "2.4.6",
@@ -34572,6 +34885,7 @@
         "mongodb-redact": "^1.1.5"
       },
       "devDependencies": {
+        "@microsoft/api-extractor": "^7.39.3",
         "@mongodb-js/eslint-config-mongosh": "^1.0.0",
         "@mongodb-js/prettier-config-devtools": "^1.0.1",
         "@mongodb-js/tsconfig-mongosh": "^1.0.0",
diff --git a/packages/build/src/packaging/package/helpers.ts b/packages/build/src/packaging/package/helpers.ts
index 352032c70d..556aaf900c 100644
--- a/packages/build/src/packaging/package/helpers.ts
+++ b/packages/build/src/packaging/package/helpers.ts
@@ -13,7 +13,9 @@ export async function execFile(
 ): Promise<ReturnType<typeof execFileWithoutLogging>> {
   const joinedCommand = [args[0], ...(args[1] ?? [])].join(' ');
   console.info(
-    'Running "' + joinedCommand + '" in ' + args[2]?.cwd ?? process.cwd()
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore TS2869 Right operand of ?? is unreachable because the left operand is never nullish.
+    `Running "${joinedCommand}" in ${args[2]?.cwd ?? process.cwd()}`
   );
   const result = await execFileWithoutLogging(...args);
   console.info('"' + joinedCommand + '" resulted in:', {
diff --git a/packages/cli-repl/src/cli-repl.spec.ts b/packages/cli-repl/src/cli-repl.spec.ts
index 20bec91c48..93d5226dd8 100644
--- a/packages/cli-repl/src/cli-repl.spec.ts
+++ b/packages/cli-repl/src/cli-repl.spec.ts
@@ -2466,8 +2466,8 @@ describe('CliRepl', function () {
       });
 
       afterEach(async function () {
-        expect(output).not.to.include('Tab completion error');
-        expect(output).not.to.include(
+        expect(output, output).not.to.include('Tab completion error');
+        expect(output, output).not.to.include(
           'listCollections requires authentication'
         );
         await cliRepl.mongoshRepl.close();
diff --git a/packages/cli-repl/src/mongosh-repl.spec.ts b/packages/cli-repl/src/mongosh-repl.spec.ts
index 3227fdced9..54cd324fd8 100644
--- a/packages/cli-repl/src/mongosh-repl.spec.ts
+++ b/packages/cli-repl/src/mongosh-repl.spec.ts
@@ -2,7 +2,7 @@
 import { MongoshCommandFailed } from '@mongosh/errors';
 import type { ServiceProvider } from '@mongosh/service-provider-core';
 import { bson } from '@mongosh/service-provider-core';
-import { ADMIN_DB } from '@mongosh/shell-api/lib/enums';
+import { ADMIN_DB } from '../../shell-api/lib/enums';
 import { CliUserConfig } from '@mongosh/types';
 import { EventEmitter, once } from 'events';
 import path from 'path';
diff --git a/packages/shell-api/api-extractor.json b/packages/shell-api/api-extractor.json
new file mode 100644
index 0000000000..e85014822d
--- /dev/null
+++ b/packages/shell-api/api-extractor.json
@@ -0,0 +1,55 @@
+{
+  "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
+  "mainEntryPointFilePath": "<projectFolder>/lib/api.d.ts",
+  "apiReport": {
+    "enabled": false
+  },
+  "docModel": {
+    "enabled": false
+  },
+  "bundledPackages": [
+    "@mongodb-js/devtools-connect",
+    "@mongodb-js/devtools-proxy-support",
+    "@mongodb-js/oidc-plugin",
+    "@mongosh/arg-parser",
+    "@mongosh/service-provider-core",
+    "@mongosh/types",
+    "mongodb"
+  ],
+  "dtsRollup": {
+    "enabled": true,
+    "untrimmedFilePath": "",
+    "publicTrimmedFilePath": "<projectFolder>/lib/api-raw.d.ts"
+  },
+  "tsdocMetadata": {
+    "enabled": false
+  },
+  "newlineKind": "lf",
+  "messages": {
+    "compilerMessageReporting": {
+      "default": {
+        "logLevel": "error"
+      }
+    },
+    "extractorMessageReporting": {
+      "default": {
+        "logLevel": "error"
+      },
+      "ae-internal-missing-underscore": {
+        "logLevel": "none",
+        "addToApiReportFile": false
+      },
+      "ae-forgotten-export": {
+        "logLevel": "none"
+      },
+      "ae-missing-release-tag": {
+        "logLevel": "none"
+      }
+    },
+    "tsdocMessageReporting": {
+      "default": {
+        "logLevel": "none"
+      }
+    }
+  }
+}
diff --git a/packages/shell-api/bin/api-postprocess.ts b/packages/shell-api/bin/api-postprocess.ts
new file mode 100644
index 0000000000..0e1c6ad10f
--- /dev/null
+++ b/packages/shell-api/bin/api-postprocess.ts
@@ -0,0 +1,162 @@
+import * as babel from '@babel/core';
+import type * as BabelTypes from '@babel/types';
+import { promises as fs } from 'fs';
+import path from 'path';
+import { signatures } from '../';
+import enUs from '../../i18n/src/locales/en_US';
+
+function applyAsyncRewriterChanges() {
+  return ({
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    types: t,
+  }: {
+    types: typeof BabelTypes;
+  }): babel.PluginObj<{
+    processedMethods: [string, string, BabelTypes.ClassBody][];
+  }> => {
+    return {
+      pre() {
+        this.processedMethods = [];
+      },
+      post() {
+        for (const className of Object.keys(signatures)) {
+          for (const methodName of Object.keys(
+            signatures[className].attributes ?? {}
+          )) {
+            if (
+              signatures[className].attributes?.[methodName].returnsPromise &&
+              !signatures[className].attributes?.[methodName].inherited
+            ) {
+              if (
+                !this.processedMethods.find(
+                  ([cls, method]) => cls === className && method === methodName
+                )
+              ) {
+                // eslint-disable-next-line no-console
+                console.error(
+                  `Expected to find and transpile type for @returnsPromise-annotated method ${className}.${methodName}`
+                );
+              }
+            }
+          }
+        }
+      },
+      visitor: {
+        TSDeclareMethod(path) {
+          if ('isMongoshAsyncRewrittenMethod' in path.node) return;
+
+          if (path.parent.type !== 'ClassBody') return;
+          if (path.parentPath.parent.type !== 'ClassDeclaration') return;
+          const classId = path.parentPath.parent.id;
+          if (classId?.type !== 'Identifier') return;
+          const className = classId.name;
+          if (path.node.key.type !== 'Identifier') return;
+          const methodName = path.node.key.name;
+
+          if (
+            this.processedMethods.find(
+              ([cls, method, classBody]) =>
+                cls === className &&
+                method === methodName &&
+                classBody !== path.parent
+            )
+          ) {
+            throw new Error(`Duplicate method: ${className}.${methodName}`);
+          }
+          this.processedMethods.push([className, methodName, path.parent]);
+
+          const classHelp = (enUs['shell-api'] as any).classes[className];
+          if (
+            classHelp &&
+            classHelp.help.attributes &&
+            classHelp.help.attributes[methodName]
+          ) {
+            const methodHelp = classHelp.help.attributes[methodName];
+            if (methodHelp && methodHelp.description) {
+              //console.log(`${className}.${methodName}`, methodHelp.description);
+              path.addComment(
+                'leading',
+                `\n${methodHelp.description as string}\n`,
+                false
+              );
+            }
+          }
+
+          if (!signatures[className]?.attributes?.[methodName]?.returnsPromise)
+            return;
+
+          const { returnType } = path.node;
+          if (returnType?.type !== 'TSTypeAnnotation') return;
+          if (returnType.typeAnnotation.type !== 'TSTypeReference') return;
+          if (returnType.typeAnnotation.typeName.type !== 'Identifier') return;
+          if (returnType.typeAnnotation.typeName.name !== 'Promise') return;
+          if (!returnType.typeAnnotation.typeParameters?.params.length) return;
+          path.replaceWith({
+            ...path.node,
+            returnType: {
+              ...returnType,
+              typeAnnotation:
+                returnType.typeAnnotation.typeParameters.params[0],
+            },
+            isMongoshAsyncRewrittenMethod: true,
+          });
+        },
+      },
+    };
+  };
+}
+
+async function main() {
+  // eslint-disable-next-line no-console
+  console.log('Postprocessing lib/api-raw.d.ts as lib/api-processed.d.ts...');
+  const apiRaw = await fs.readFile(
+    path.resolve(__dirname, '..', 'lib', 'api-raw.d.ts'),
+    'utf8'
+  );
+  const result = babel.transformSync(apiRaw, {
+    code: true,
+    ast: false,
+    configFile: false,
+    babelrc: false,
+    browserslistConfigFile: false,
+    compact: false,
+    sourceType: 'module',
+    plugins: [applyAsyncRewriterChanges()],
+    parserOpts: {
+      plugins: ['typescript'],
+    },
+  });
+  const apiGlobals = await fs.readFile(
+    path.resolve(__dirname, '..', 'src', 'api-globals.d.ts'),
+    'utf8'
+  );
+
+  const code = (result?.code ?? '') + '\n' + apiGlobals;
+  await fs.writeFile(
+    path.resolve(__dirname, '..', 'lib', 'api-processed.d.ts'),
+    code
+  );
+
+  // eslint-disable-next-line no-console
+  console.log('Writing lib/api-export.js...');
+  const exportCode = `"use strict";
+module.exports = { api: ${JSON.stringify(code)} };
+`;
+  await fs.writeFile(
+    path.resolve(__dirname, '..', 'lib', 'api-export.js'),
+    exportCode
+  );
+
+  // eslint-disable-next-line no-console
+  console.log('Writing lib/api-export.d.ts...');
+  await fs.writeFile(
+    path.resolve(__dirname, '..', 'lib', 'api-export.d.ts'),
+    'export declare const api;'
+  );
+}
+
+main().catch((err) =>
+  process.nextTick(() => {
+    throw err;
+  })
+);
diff --git a/packages/shell-api/package.json b/packages/shell-api/package.json
index 617089d133..30e8681757 100644
--- a/packages/shell-api/package.json
+++ b/packages/shell-api/package.json
@@ -4,6 +4,16 @@
   "description": "MongoDB Shell API Classes Package",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
+  "exports": {
+    ".": {
+      "default": "./lib/index.js",
+      "types": "./lib/index.d.ts"
+    },
+    "./api": {
+      "default": "./lib/api-export.js",
+      "types": "./lib/api-export.d.ts"
+    }
+  },
   "config": {
     "unsafe-perm": true
   },
@@ -12,7 +22,8 @@
     "url": "git://github.com/mongodb-js/mongosh.git"
   },
   "scripts": {
-    "compile": "tsc -p tsconfig.json",
+    "compile": "tsc -p tsconfig.json && npm run api-generate",
+    "api-generate": "api-extractor run && ts-node bin/api-postprocess.ts",
     "pretest": "npm run compile",
     "eslint": "eslint",
     "lint": "npm run eslint . && npm run prettier -- --check .",
@@ -40,6 +51,8 @@
     "build"
   ],
   "dependencies": {
+    "@babel/core": "^7.26.10",
+    "@babel/types": "^7.26.10",
     "@mongosh/arg-parser": "^3.10.2",
     "@mongosh/errors": "2.4.0",
     "@mongosh/history": "2.4.6",
@@ -48,6 +61,7 @@
     "mongodb-redact": "^1.1.5"
   },
   "devDependencies": {
+    "@microsoft/api-extractor": "^7.39.3",
     "@mongodb-js/eslint-config-mongosh": "^1.0.0",
     "@mongodb-js/prettier-config-devtools": "^1.0.1",
     "@mongodb-js/tsconfig-mongosh": "^1.0.0",
diff --git a/packages/shell-api/src/aggregation-cursor.spec.ts b/packages/shell-api/src/aggregation-cursor.spec.ts
index 7784f37478..cf470b8694 100644
--- a/packages/shell-api/src/aggregation-cursor.spec.ts
+++ b/packages/shell-api/src/aggregation-cursor.spec.ts
@@ -36,6 +36,7 @@ describe('AggregationCursor', function () {
         type: 'function',
         returnsPromise: false,
         deprecated: false,
+        inherited: true,
         returnType: 'AggregationCursor',
         platforms: ALL_PLATFORMS,
         topologies: ALL_TOPOLOGIES,
diff --git a/packages/shell-api/src/api-globals.d.ts b/packages/shell-api/src/api-globals.d.ts
new file mode 100644
index 0000000000..c0b219a32e
--- /dev/null
+++ b/packages/shell-api/src/api-globals.d.ts
@@ -0,0 +1,44 @@
+declare global {
+  const use: ShellApi['use'];
+  const show: ShellApi['show'];
+  const exit: ShellApi['exit'];
+  const quit: ShellApi['quit'];
+  const Mongo: ShellApi['Mongo'];
+  const connect: ShellApi['connect'];
+  const it: ShellApi['it'];
+  const version: ShellApi['version'];
+  const load: ShellApi['load'];
+  const enableTelemetry: ShellApi['enableTelemetry'];
+  const disableTelemetry: ShellApi['disableTelemetry'];
+  const passwordPrompt: ShellApi['passwordPrompt'];
+  const sleep: ShellApi['sleep'];
+  const print: ShellApi['print'];
+  const printjson: ShellApi['printjson'];
+  const convertShardKeyToHashed: ShellApi['convertShardKeyToHashed'];
+  const cls: ShellApi['cls'];
+  const isInteractive: ShellApi['isInteractive'];
+
+  const DBRef: ShellBson['DBRef'];
+  const bsonsize: ShellBson['bsonsize'];
+  const MaxKey: ShellBson['MaxKey'];
+  const MinKey: ShellBson['MinKey'];
+  const ObjectId: ShellBson['ObjectId'];
+  const Timestamp: ShellBson['Timestamp'];
+  const Code: ShellBson['Code'];
+  const NumberDecimal: ShellBson['NumberDecimal'];
+  const NumberInt: ShellBson['NumberInt'];
+  const NumberLong: ShellBson['NumberLong'];
+  const ISODate: ShellBson['ISODate'];
+  const BinData: ShellBson['BinData'];
+  const HexData: ShellBson['HexData'];
+  const UUID: ShellBson['UUID'];
+  const MD5: ShellBson['MD5'];
+  const Decimal128: ShellBson['Decimal128'];
+  const BSONSymbol: ShellBson['BSONSymbol'];
+  const Int32: ShellBson['Int32'];
+  const Long: ShellBson['Long'];
+  const Binary: ShellBson['Binary'];
+  const Double: ShellBson['Double'];
+  const EJSON: ShellBson['EJSON'];
+  const BSONRegExp: ShellBson['BSONRegExp'];
+}
diff --git a/packages/shell-api/src/api.ts b/packages/shell-api/src/api.ts
new file mode 100644
index 0000000000..5f382258ca
--- /dev/null
+++ b/packages/shell-api/src/api.ts
@@ -0,0 +1,10 @@
+export { CollectionWithSchema } from './collection';
+export { ShellBson } from './shell-bson';
+export { Streams } from './streams';
+export { DatabaseWithSchema } from './database';
+import Shard from './shard';
+import ReplicaSet from './replica-set';
+import ShellApi from './shell-api';
+import Mongo from './mongo';
+
+export { Mongo, Shard, ReplicaSet, ShellApi };
diff --git a/packages/shell-api/src/bulk.spec.ts b/packages/shell-api/src/bulk.spec.ts
index 54947ead9f..16eb749ccf 100644
--- a/packages/shell-api/src/bulk.spec.ts
+++ b/packages/shell-api/src/bulk.spec.ts
@@ -11,7 +11,7 @@ import type { EventEmitter } from 'events';
 import type { StubbedInstance } from 'ts-sinon';
 import { stubInterface } from 'ts-sinon';
 import Bulk, { BulkFindOp } from './bulk';
-import Collection from './collection';
+import { Collection } from './collection';
 import { ALL_PLATFORMS, ALL_SERVER_VERSIONS, ALL_TOPOLOGIES } from './enums';
 import { signatures, toShellResult } from './index';
 import { BulkWriteResult } from './result';
diff --git a/packages/shell-api/src/bulk.ts b/packages/shell-api/src/bulk.ts
index 366979443e..c289b1414d 100644
--- a/packages/shell-api/src/bulk.ts
+++ b/packages/shell-api/src/bulk.ts
@@ -20,7 +20,7 @@ import type {
 import { asPrintable } from './enums';
 import { assertArgsDefinedType, shallowClone } from './helpers';
 import { BulkWriteResult } from './result';
-import type Collection from './collection';
+import type { CollectionWithSchema } from './collection';
 
 @shellApiClassDefault
 export class BulkFindOp extends ShellApiWithMongoClass {
@@ -131,14 +131,14 @@ export class BulkFindOp extends ShellApiWithMongoClass {
 @shellApiClassDefault
 export default class Bulk extends ShellApiWithMongoClass {
   _mongo: Mongo;
-  _collection: Collection;
+  _collection: CollectionWithSchema;
   _batchCounts: any;
   _executed: boolean;
   _serviceProviderBulkOp: OrderedBulkOperation | UnorderedBulkOperation;
   _ordered: boolean;
 
   constructor(
-    collection: Collection,
+    collection: CollectionWithSchema,
     innerBulk: OrderedBulkOperation | UnorderedBulkOperation,
     ordered = false
   ) {
diff --git a/packages/shell-api/src/change-stream-cursor.spec.ts b/packages/shell-api/src/change-stream-cursor.spec.ts
index 83fd198e08..3a92b4227b 100644
--- a/packages/shell-api/src/change-stream-cursor.spec.ts
+++ b/packages/shell-api/src/change-stream-cursor.spec.ts
@@ -17,8 +17,8 @@ import { NodeDriverServiceProvider } from '../../service-provider-node-driver';
 import ShellInstanceState from './shell-instance-state';
 import Mongo from './mongo';
 import { ensureMaster, ensureResult } from '../test/helpers';
-import type Database from './database';
-import type Collection from './collection';
+import type { DatabaseWithSchema } from './database';
+import type { CollectionWithSchema } from './collection';
 import { MongoshUnimplementedError } from '@mongosh/errors';
 import { EventEmitter } from 'events';
 import { dummyOptions } from './helpers.spec';
@@ -124,8 +124,8 @@ describe('ChangeStreamCursor', function () {
     let serviceProvider: NodeDriverServiceProvider;
     let instanceState: ShellInstanceState;
     let mongo: Mongo;
-    let db: Database;
-    let coll: Collection;
+    let db: DatabaseWithSchema;
+    let coll: CollectionWithSchema;
     let cursor: ChangeStreamCursor;
 
     before(async function () {
diff --git a/packages/shell-api/src/collection.spec.ts b/packages/shell-api/src/collection.spec.ts
index 63b7480072..9e7e17ee05 100644
--- a/packages/shell-api/src/collection.spec.ts
+++ b/packages/shell-api/src/collection.spec.ts
@@ -11,9 +11,9 @@ import {
   shellApiType,
   ADMIN_DB,
 } from './enums';
-import Database from './database';
+import { Database } from './database';
 import Mongo from './mongo';
-import Collection from './collection';
+import { Collection } from './collection';
 import ChangeStreamCursor from './change-stream-cursor';
 import Explainable from './explainable';
 import type {
@@ -33,6 +33,7 @@ import {
   MongoshInvalidInputError,
   MongoshRuntimeError,
 } from '@mongosh/errors';
+import type { StringKey } from './helpers';
 
 const sinonChai = require('sinon-chai'); // weird with import
 
@@ -127,12 +128,23 @@ describe('Collection', function () {
     });
   });
   describe('commands', function () {
-    let mongo: Mongo;
+    type ServerSchema = {
+      db1: {
+        coll1: {
+          schema: {};
+        };
+      };
+    };
+    let mongo: Mongo<ServerSchema>;
     let serviceProvider: StubbedInstance<ServiceProvider>;
-    let database: Database;
+    let database: Database<ServerSchema, ServerSchema['db1']>;
     let bus: StubbedInstance<EventEmitter>;
     let instanceState: ShellInstanceState;
-    let collection: Collection;
+    let collection: Collection<
+      ServerSchema,
+      ServerSchema['db1'],
+      ServerSchema['db1']['coll1']
+    >;
 
     beforeEach(function () {
       bus = stubInterface<EventEmitter>();
@@ -149,8 +161,15 @@ describe('Collection', function () {
         undefined,
         serviceProvider
       );
-      database = new Database(mongo, 'db1');
-      collection = new Collection(mongo, database, 'coll1');
+      database = new Database<ServerSchema, ServerSchema['db1']>(
+        mongo,
+        'db1' as StringKey<ServerSchema>
+      );
+      collection = new Collection<
+        ServerSchema,
+        ServerSchema['db1'],
+        ServerSchema['db1']['coll1']
+      >(mongo, database, 'coll1');
     });
     describe('aggregate', function () {
       let serviceProviderCursor: StubbedInstance<ServiceProviderAggregationCursor>;
@@ -2802,13 +2821,24 @@ describe('Collection', function () {
   });
 
   describe('fle2', function () {
-    let mongo1: Mongo;
-    let mongo2: Mongo;
+    type ServerSchema = {
+      db1: {
+        collfle2: {
+          schema: {};
+        };
+      };
+    };
+    let mongo1: Mongo<ServerSchema>;
+    let mongo2: Mongo<ServerSchema>;
     let serviceProvider: StubbedInstance<ServiceProvider>;
-    let database: Database;
+    let database: Database<ServerSchema, ServerSchema['db1']>;
     let bus: StubbedInstance<EventEmitter>;
     let instanceState: ShellInstanceState;
-    let collection: Collection;
+    let collection: Collection<
+      ServerSchema,
+      ServerSchema['db1'],
+      ServerSchema['db1']['collfle2']
+    >;
     let keyId: any[];
     beforeEach(function () {
       bus = stubInterface<EventEmitter>();
@@ -2821,7 +2851,8 @@ describe('Collection', function () {
       keyId = [
         { $binary: { base64: 'oh3caogGQ4Sf34ugKnZ7Xw==', subType: '04' } },
       ];
-      mongo1 = new Mongo(
+
+      mongo1 = new Mongo<ServerSchema>(
         instanceState,
         undefined,
         {
@@ -2836,8 +2867,15 @@ describe('Collection', function () {
         undefined,
         serviceProvider
       );
-      database = new Database(mongo1, 'db1');
-      collection = new Collection(mongo1, database, 'collfle2');
+      database = new Database<ServerSchema, ServerSchema['db1']>(
+        mongo1,
+        'db1' as StringKey<ServerSchema>
+      );
+      collection = new Collection(
+        mongo1,
+        database,
+        'collfle2' as StringKey<ServerSchema['db1']>
+      );
       mongo2 = new Mongo(
         instanceState,
         undefined,
diff --git a/packages/shell-api/src/collection.ts b/packages/shell-api/src/collection.ts
index 7b7432d77b..f919d0b1f0 100644
--- a/packages/shell-api/src/collection.ts
+++ b/packages/shell-api/src/collection.ts
@@ -22,6 +22,10 @@ import type {
   FindAndModifyMethodShellOptions,
   RemoveShellOptions,
   MapReduceShellOptions,
+  GenericCollectionSchema,
+  GenericDatabaseSchema,
+  GenericServerSideSchema,
+  StringKey,
   SearchIndexDefinition,
 } from './helpers';
 import {
@@ -43,7 +47,6 @@ import {
   buildConfigChunksCollectionMatch,
   onlyShardedCollectionsInConfigFilter,
   aggregateBackgroundOptionNotSupportedHelp,
-  getConfigDB,
 } from './helpers';
 import type {
   AnyBulkWriteOperation,
@@ -70,7 +73,7 @@ import type {
   AggregateOptions,
   SearchIndexDescription,
 } from '@mongosh/service-provider-core';
-import type { RunCommandCursor, Database } from './index';
+import type { RunCommandCursor, Database, DatabaseWithSchema } from './index';
 import {
   AggregationCursor,
   BulkWriteResult,
@@ -94,16 +97,40 @@ import PlanCache from './plan-cache';
 import ChangeStreamCursor from './change-stream-cursor';
 import { ShellApiErrors } from './error-codes';
 
+export type CollectionWithSchema<
+  M extends GenericServerSideSchema = GenericServerSideSchema,
+  D extends GenericDatabaseSchema = M[keyof M],
+  C extends GenericCollectionSchema = D[keyof D],
+  N extends StringKey<D> = StringKey<D>
+> = Collection<M, D, C, N> & {
+  [k in StringKey<D> as k extends `${N}.${infer S}` ? S : never]: Collection<
+    M,
+    D,
+    D[k],
+    k
+  >;
+};
+
 @shellApiClassDefault
 @addSourceToResults
-export default class Collection extends ShellApiWithMongoClass {
-  _mongo: Mongo;
-  _database: Database;
-  _name: string;
-  constructor(mongo: Mongo, database: Database, name: string) {
+export class Collection<
+  M extends GenericServerSideSchema = GenericServerSideSchema,
+  D extends GenericDatabaseSchema = M[keyof M],
+  C extends GenericCollectionSchema = D[keyof D],
+  N extends StringKey<D> = StringKey<D>
+> extends ShellApiWithMongoClass {
+  _mongo: Mongo<M>;
+  _database: DatabaseWithSchema<M, D>;
+  _name: N;
+
+  constructor(
+    mongo: Mongo<M>,
+    database: DatabaseWithSchema<M, D> | Database<M, D>,
+    name: N
+  ) {
     super();
     this._mongo = mongo;
-    this._database = database;
+    this._database = database as DatabaseWithSchema<M, D>;
     this._name = name;
     const proxy = new Proxy(this, {
       get: (target, prop): any => {
@@ -536,7 +563,7 @@ export default class Collection extends ShellApiWithMongoClass {
     query: Document = {},
     projection?: Document,
     options: FindOptions = {}
-  ): Promise<Document | null> {
+  ): Promise<C['schema'] | null> {
     if (projection) {
       options.projection = projection;
     }
@@ -1417,10 +1444,10 @@ export default class Collection extends ShellApiWithMongoClass {
   /**
    * Returns the collection database.
    *
-   * @return {Database}
+   * @return {DatabaseWithSchema}
    */
-  @returnType('Database')
-  getDB(): Database {
+  @returnType('DatabaseWithSchema')
+  getDB(): DatabaseWithSchema<M, D> {
     this._emitCollectionApiCall('getDB');
     return this._database;
   }
@@ -1431,7 +1458,7 @@ export default class Collection extends ShellApiWithMongoClass {
    * @return {Mongo}
    */
   @returnType('Mongo')
-  getMongo(): Mongo {
+  getMongo(): Mongo<M> {
     this._emitCollectionApiCall('getMongo');
     return this._mongo;
   }
@@ -1561,9 +1588,9 @@ export default class Collection extends ShellApiWithMongoClass {
     return `${this._database._name}.${this._name}`;
   }
 
-  getName(): string {
+  getName(): N {
     this._emitCollectionApiCall('getName');
-    return `${this._name}`;
+    return this._name;
   }
 
   @returnsPromise
@@ -1768,7 +1795,7 @@ export default class Collection extends ShellApiWithMongoClass {
     }
 
     const ns = `${this._database._name}.${this._name}`;
-    const config = this._mongo.getDB('config');
+    const config = this._mongo.getDB('config' as StringKey<M>);
     if (collStats[0].shard) {
       result.shards = shardStats;
     }
@@ -2077,7 +2104,7 @@ export default class Collection extends ShellApiWithMongoClass {
    * @returns collection info based on given collStats.
    */
   async _getShardedCollectionInfo(
-    config: Database,
+    config: DatabaseWithSchema<M, D>,
     collStats: Document[]
   ): Promise<Document> {
     const ns = `${this._database._name}.${this._name}`;
@@ -2135,10 +2162,11 @@ export default class Collection extends ShellApiWithMongoClass {
   > {
     this._emitCollectionApiCall('getShardDistribution', {});
 
-    await getConfigDB(this._database); // Warns if not connected to mongos
-
-    const result = {} as GetShardDistributionResult;
-    const config = this._mongo.getDB('config');
+    const result = {} as Document;
+    // TODO: can we get around casting here?
+    const config = this._mongo.getDB(
+      'config' as StringKey<M>
+    ) as DatabaseWithSchema<M, D>;
 
     const collStats = await (
       await this.aggregate({ $collStats: { storageStats: {} } })
@@ -2248,7 +2276,10 @@ export default class Collection extends ShellApiWithMongoClass {
     }
     result.Totals = totalValue;
 
-    return new CommandResult<GetShardDistributionResult>('StatsResult', result);
+    return new CommandResult<GetShardDistributionResult>(
+      'StatsResult',
+      result as GetShardDistributionResult
+    );
   }
 
   @serverVersions(['3.1.0', ServerVersions.latest])
diff --git a/packages/shell-api/src/cursor.spec.ts b/packages/shell-api/src/cursor.spec.ts
index 3ec90db013..72c639d5be 100644
--- a/packages/shell-api/src/cursor.spec.ts
+++ b/packages/shell-api/src/cursor.spec.ts
@@ -55,6 +55,7 @@ describe('Cursor', function () {
         type: 'function',
         returnsPromise: false,
         deprecated: false,
+        inherited: true,
         returnType: 'Cursor',
         platforms: ALL_PLATFORMS,
         topologies: ALL_TOPOLOGIES,
diff --git a/packages/shell-api/src/database.spec.ts b/packages/shell-api/src/database.spec.ts
index 4cc7cb7e22..366a858aeb 100644
--- a/packages/shell-api/src/database.spec.ts
+++ b/packages/shell-api/src/database.spec.ts
@@ -6,8 +6,8 @@ import { stubInterface } from 'ts-sinon';
 import type { EventEmitter } from 'events';
 import { ALL_PLATFORMS, ALL_SERVER_VERSIONS, ALL_TOPOLOGIES } from './enums';
 import { signatures, toShellResult } from './index';
-import Database from './database';
-import Collection from './collection';
+import { Database } from './database';
+import { Collection } from './collection';
 import Mongo from './mongo';
 import type {
   AggregationCursor as ServiceProviderAggCursor,
diff --git a/packages/shell-api/src/database.ts b/packages/shell-api/src/database.ts
index c148cc14e1..ccdb61ec5a 100644
--- a/packages/shell-api/src/database.ts
+++ b/packages/shell-api/src/database.ts
@@ -1,5 +1,6 @@
 import type Mongo from './mongo';
-import Collection from './collection';
+import type { CollectionWithSchema } from './collection';
+import { Collection } from './collection';
 import {
   returnsPromise,
   returnType,
@@ -11,6 +12,11 @@ import {
   ShellApiWithMongoClass,
 } from './decorators';
 import { asPrintable, ServerVersions, Topologies } from './enums';
+import type {
+  GenericDatabaseSchema,
+  GenericServerSideSchema,
+  StringKey,
+} from './helpers';
 import {
   adaptAggregateOptions,
   adaptOptions,
@@ -68,20 +74,33 @@ type AuthDoc = {
   mechanism?: string;
 };
 
+export type DatabaseWithSchema<
+  M extends GenericServerSideSchema = GenericServerSideSchema,
+  D extends GenericDatabaseSchema = GenericDatabaseSchema
+> = Database<M, D> & {
+  [k in StringKey<D>]: Collection<M, D, D[k], k>;
+};
+
 @shellApiClassDefault
-export default class Database extends ShellApiWithMongoClass {
-  _mongo: Mongo;
-  _name: string;
-  _collections: Record<string, Collection>;
+export class Database<
+  M extends GenericServerSideSchema = GenericServerSideSchema,
+  D extends GenericDatabaseSchema = GenericDatabaseSchema
+> extends ShellApiWithMongoClass {
+  _mongo: Mongo<M>;
+  _name: StringKey<M>;
+  _collections: Record<StringKey<D>, CollectionWithSchema<M, D>>;
   _session: Session | undefined;
-  _cachedCollectionNames: string[] = [];
+  _cachedCollectionNames: StringKey<D>[] = [];
   _cachedHello: Document | null = null;
 
-  constructor(mongo: Mongo, name: string, session?: Session) {
+  constructor(mongo: Mongo<M>, name: StringKey<M>, session?: Session) {
     super();
     this._mongo = mongo;
     this._name = name;
-    const collections: Record<string, Collection> = Object.create(null);
+    const collections: Record<
+      string,
+      CollectionWithSchema<M, D>
+    > = Object.create(null);
     this._collections = collections;
     this._session = session;
     const proxy = new Proxy(this, {
@@ -99,7 +118,11 @@ export default class Database extends ShellApiWithMongoClass {
         }
 
         if (!collections[prop]) {
-          collections[prop] = new Collection(mongo, proxy, prop);
+          collections[prop] = new Collection<M, D>(
+            mongo,
+            proxy,
+            prop
+          ) as CollectionWithSchema<M, D>;
         }
 
         return collections[prop];
@@ -315,11 +338,11 @@ export default class Database extends ShellApiWithMongoClass {
   }
 
   @returnType('Mongo')
-  getMongo(): Mongo {
+  getMongo(): Mongo<M> {
     return this._mongo;
   }
 
-  getName(): string {
+  getName(): StringKey<M> {
     return this._name;
   }
 
@@ -330,9 +353,9 @@ export default class Database extends ShellApiWithMongoClass {
    */
   @returnsPromise
   @apiVersions([1])
-  async getCollectionNames(): Promise<string[]> {
+  async getCollectionNames(): Promise<StringKey<D>[]> {
     this._emitDatabaseApiCall('getCollectionNames');
-    return this._getCollectionNames();
+    return (await this._getCollectionNames()) as StringKey<D>[];
   }
 
   /**
@@ -473,17 +496,19 @@ export default class Database extends ShellApiWithMongoClass {
   }
 
   @returnType('Database')
-  getSiblingDB(db: string): Database {
+  getSiblingDB<K extends StringKey<M>>(db: K): DatabaseWithSchema<M, M[K]> {
     assertArgsDefinedType([db], ['string'], 'Database.getSiblingDB');
     this._emitDatabaseApiCall('getSiblingDB', { db });
     if (this._session) {
-      return this._session.getDatabase(db);
+      return this._session.getDatabase(db) as DatabaseWithSchema<M, M[K]>;
     }
     return this._mongo._getDb(db);
   }
 
   @returnType('Collection')
-  getCollection(coll: string): Collection {
+  getCollection<K extends StringKey<D>>(
+    coll: K
+  ): CollectionWithSchema<M, D, D[K], K> {
     assertArgsDefinedType([coll], ['string'], 'Database.getColl');
     this._emitDatabaseApiCall('getCollection', { coll });
     if (!isValidCollectionName(coll)) {
@@ -493,13 +518,18 @@ export default class Database extends ShellApiWithMongoClass {
       );
     }
 
-    const collections: Record<string, Collection> = this._collections;
+    const collections: Record<string, CollectionWithSchema<M, D>> = this
+      ._collections;
 
     if (!collections[coll]) {
-      collections[coll] = new Collection(this._mongo, this, coll);
+      collections[coll] = new Collection<M, D>(
+        this._mongo,
+        this,
+        coll
+      ) as CollectionWithSchema<M, D>;
     }
 
-    return collections[coll];
+    return collections[coll] as CollectionWithSchema<M, D, D[K], K>;
   }
 
   @returnsPromise
diff --git a/packages/shell-api/src/decorators.ts b/packages/shell-api/src/decorators.ts
index a8839bdfcc..9c6ca8b380 100644
--- a/packages/shell-api/src/decorators.ts
+++ b/packages/shell-api/src/decorators.ts
@@ -381,6 +381,7 @@ export interface TypeSignature {
   isDirectShellCommand?: boolean;
   acceptsRawInput?: boolean;
   shellCommandCompleter?: ShellCommandCompleter;
+  inherited?: boolean;
 }
 
 /**
@@ -426,6 +427,7 @@ type ClassSignature = {
       isDirectShellCommand: boolean;
       acceptsRawInput?: boolean;
       shellCommandCompleter?: ShellCommandCompleter;
+      inherited?: true;
     };
   };
 };
@@ -582,6 +584,7 @@ function shellApiClassGeneric<T extends { prototype: any }>(
         isDirectShellCommand: method.isDirectShellCommand,
         acceptsRawInput: method.acceptsRawInput,
         shellCommandCompleter: method.shellCommandCompleter,
+        inherited: true,
       };
 
       const attributeHelpKeyPrefix = `${superClassHelpKeyPrefix}.attributes.${propertyName}`;
diff --git a/packages/shell-api/src/explainable-cursor.spec.ts b/packages/shell-api/src/explainable-cursor.spec.ts
index 3b6c2331c5..55ee41c3f2 100644
--- a/packages/shell-api/src/explainable-cursor.spec.ts
+++ b/packages/shell-api/src/explainable-cursor.spec.ts
@@ -31,6 +31,7 @@ describe('ExplainableCursor', function () {
         type: 'function',
         returnsPromise: false,
         deprecated: false,
+        inherited: true,
         returnType: 'ExplainableCursor',
         platforms: ALL_PLATFORMS,
         topologies: ALL_TOPOLOGIES,
diff --git a/packages/shell-api/src/explainable.spec.ts b/packages/shell-api/src/explainable.spec.ts
index 044aebce14..4993e0454f 100644
--- a/packages/shell-api/src/explainable.spec.ts
+++ b/packages/shell-api/src/explainable.spec.ts
@@ -6,10 +6,10 @@ import type { EventEmitter } from 'events';
 import { ALL_PLATFORMS, ALL_SERVER_VERSIONS, ALL_TOPOLOGIES } from './enums';
 import type { ExplainableCursor } from './index';
 import { signatures, toShellResult } from './index';
-import Database from './database';
+import { Database } from './database';
 import type Cursor from './cursor';
 import Mongo from './mongo';
-import Collection from './collection';
+import { Collection } from './collection';
 import Explainable from './explainable';
 import type { ServiceProvider, Document } from '@mongosh/service-provider-core';
 import { bson } from '@mongosh/service-provider-core';
diff --git a/packages/shell-api/src/explainable.ts b/packages/shell-api/src/explainable.ts
index 393840af81..875493267e 100644
--- a/packages/shell-api/src/explainable.ts
+++ b/packages/shell-api/src/explainable.ts
@@ -1,4 +1,4 @@
-import type Collection from './collection';
+import type { CollectionWithSchema } from './collection';
 import type Mongo from './mongo';
 import ExplainableCursor from './explainable-cursor';
 import {
@@ -37,11 +37,11 @@ import type {
 @shellApiClassDefault
 export default class Explainable extends ShellApiWithMongoClass {
   _mongo: Mongo;
-  _collection: Collection;
+  _collection: CollectionWithSchema;
   _verbosity: ExplainVerbosityLike;
   constructor(
     mongo: Mongo,
-    collection: Collection,
+    collection: CollectionWithSchema,
     verbosity: ExplainVerbosityLike
   ) {
     super();
@@ -77,7 +77,7 @@ export default class Explainable extends ShellApiWithMongoClass {
     });
   }
 
-  getCollection(): Collection {
+  getCollection(): CollectionWithSchema {
     this._emitExplainableApiCall('getCollection');
     return this._collection;
   }
diff --git a/packages/shell-api/src/field-level-encryption.spec.ts b/packages/shell-api/src/field-level-encryption.spec.ts
index 9fab4b6246..2bf80279e6 100644
--- a/packages/shell-api/src/field-level-encryption.spec.ts
+++ b/packages/shell-api/src/field-level-encryption.spec.ts
@@ -16,7 +16,7 @@ import { Duplex } from 'stream';
 import sinon from 'sinon';
 import type { StubbedInstance } from 'ts-sinon';
 import { stubInterface } from 'ts-sinon';
-import type Database from './database';
+import type { Database } from './database';
 import { signatures, toShellResult } from './decorators';
 import {
   ALL_PLATFORMS,
@@ -34,7 +34,7 @@ import {
   makeFakeHTTPConnection,
   fakeAWSHandlers,
 } from '../../../testing/fake-kms';
-import Collection from './collection';
+import { Collection } from './collection';
 import { dummyOptions } from './helpers.spec';
 import type { IncomingMessage } from 'http';
 
@@ -112,7 +112,7 @@ describe('Field Level Encryption', function () {
       sp.createClientEncryption?.returns(libmongoc);
       sp.initialDb = 'test';
       instanceState = new ShellInstanceState(sp, stubInterface<EventEmitter>());
-      instanceState.currentDb = stubInterface<Database>();
+      instanceState.currentDb = stubInterface<Database>() as any;
       mongo = new Mongo(
         instanceState,
         'localhost:27017',
@@ -195,7 +195,7 @@ describe('Field Level Encryption', function () {
       });
       sp.initialDb = 'test';
       instanceState = new ShellInstanceState(sp, stubInterface<EventEmitter>());
-      instanceState.currentDb = stubInterface<Database>();
+      instanceState.currentDb = stubInterface<Database>() as any;
       mongo = new Mongo(
         instanceState,
         'localhost:27017',
@@ -617,7 +617,7 @@ describe('Field Level Encryption', function () {
       sp.createClientEncryption?.returns(libmongoc);
       sp.initialDb = 'test';
       instanceState = new ShellInstanceState(sp, stubInterface<EventEmitter>());
-      instanceState.currentDb = stubInterface<Database>();
+      instanceState.currentDb = stubInterface<Database>() as any;
     });
     it('accepts the same local key twice', function () {
       const localKmsOptions: ClientSideFieldLevelEncryptionOptions = {
@@ -709,7 +709,7 @@ describe('Field Level Encryption', function () {
       sp.createClientEncryption?.returns(libmongoc);
       sp.initialDb = 'test';
       instanceState = new ShellInstanceState(sp, stubInterface<EventEmitter>());
-      instanceState.currentDb = stubInterface<Database>();
+      instanceState.currentDb = stubInterface<Database>() as any;
     });
     it('fails to construct when FLE options are missing on Mongo', function () {
       mongo = new Mongo(
diff --git a/packages/shell-api/src/field-level-encryption.ts b/packages/shell-api/src/field-level-encryption.ts
index 486ca41c05..e4408b2a2f 100644
--- a/packages/shell-api/src/field-level-encryption.ts
+++ b/packages/shell-api/src/field-level-encryption.ts
@@ -19,7 +19,7 @@ import type {
   GCPEncryptionKeyOptions,
 } from '@mongosh/service-provider-core';
 import type { Document, BinaryType } from '@mongosh/service-provider-core';
-import type Collection from './collection';
+import type { CollectionWithSchema } from './collection';
 import Cursor from './cursor';
 import type { DeleteResult } from './result';
 import { assertArgsDefinedType, assertKeysDefined } from './helpers';
@@ -173,7 +173,7 @@ export class ClientEncryption extends ShellApiWithMongoClass {
     dbName: string,
     collName: string,
     options: CreateEncryptedCollectionOptions
-  ): Promise<{ collection: Collection; encryptedFields: Document }> {
+  ): Promise<{ collection: CollectionWithSchema; encryptedFields: Document }> {
     assertArgsDefinedType(
       [dbName],
       ['string'],
@@ -217,7 +217,7 @@ export class ClientEncryption extends ShellApiWithMongoClass {
 export class KeyVault extends ShellApiWithMongoClass {
   public _mongo: Mongo;
   public _clientEncryption: ClientEncryption;
-  private _keyColl: Collection;
+  private _keyColl: CollectionWithSchema;
   constructor(clientEncryption: ClientEncryption) {
     super();
     this._mongo = clientEncryption._mongo;
diff --git a/packages/shell-api/src/helpers.ts b/packages/shell-api/src/helpers.ts
index 69ec523e08..97d1ad4370 100644
--- a/packages/shell-api/src/helpers.ts
+++ b/packages/shell-api/src/helpers.ts
@@ -16,8 +16,8 @@ import {
   MongoshUnimplementedError,
 } from '@mongosh/errors';
 import crypto from 'crypto';
-import type Database from './database';
-import type Collection from './collection';
+import type { Database } from './database';
+import type { Collection } from './collection';
 import type { CursorIterationResult } from './result';
 import { ShellApiErrors } from './error-codes';
 import type {
@@ -1307,6 +1307,16 @@ export function buildConfigChunksCollectionMatch(
     : { ns: configCollectionsInfo._id }; // old format
 }
 
+export interface GenericCollectionSchema {
+  schema: Document;
+}
+export interface GenericDatabaseSchema {
+  [key: string]: GenericCollectionSchema;
+}
+export interface GenericServerSideSchema {
+  [key: string]: GenericDatabaseSchema;
+}
+export type StringKey<T> = keyof T & string;
 export const aggregateBackgroundOptionNotSupportedHelp =
   'the background option is not supported by the aggregate method and will be ignored, ' +
   'use runCommand to use { background: true } with Atlas Data Federation';
diff --git a/packages/shell-api/src/index.ts b/packages/shell-api/src/index.ts
index e5f0fb4066..719178460d 100644
--- a/packages/shell-api/src/index.ts
+++ b/packages/shell-api/src/index.ts
@@ -1,8 +1,12 @@
 import AggregationCursor from './aggregation-cursor';
 import RunCommandCursor from './run-command-cursor';
-import Collection from './collection';
+import { CollectionWithSchema, Collection } from './collection';
 import Cursor from './cursor';
-import Database, { CollectionNamesWithTypes } from './database';
+import {
+  Database,
+  DatabaseWithSchema,
+  CollectionNamesWithTypes,
+} from './database';
 import Explainable from './explainable';
 import ExplainableCursor from './explainable-cursor';
 import Help, { HelpProperties } from './help';
@@ -42,7 +46,9 @@ export {
   Cursor,
   CursorIterationResult,
   Database,
+  DatabaseWithSchema,
   Collection,
+  CollectionWithSchema,
   Explainable,
   ExplainableCursor,
   Help,
diff --git a/packages/shell-api/src/integration.spec.ts b/packages/shell-api/src/integration.spec.ts
index 58f15ce4e0..41eddfc286 100644
--- a/packages/shell-api/src/integration.spec.ts
+++ b/packages/shell-api/src/integration.spec.ts
@@ -3,8 +3,8 @@ import { NodeDriverServiceProvider } from '../../service-provider-node-driver';
 import ShellInstanceState from './shell-instance-state';
 import type Cursor from './cursor';
 import Explainable from './explainable';
-import type Database from './database';
-import type Collection from './collection';
+import type { DatabaseWithSchema } from './database';
+import type { CollectionWithSchema } from './collection';
 import {
   skipIfServerVersion,
   skipIfApiStrict,
@@ -69,7 +69,9 @@ describe('Shell API (integration)', function () {
     expect(collectionNames).to.not.include(collectionName);
   };
 
-  const loadQueryCache = async (collection: Collection): Promise<any> => {
+  const loadQueryCache = async (
+    collection: CollectionWithSchema
+  ): Promise<any> => {
     const res = await collection.insertMany([
       { _id: 1, item: 'abc', price: 12, quantity: 2, type: 'apparel' },
       { _id: 2, item: 'jkl', price: 20, quantity: 1, type: 'electronics' },
@@ -103,7 +105,9 @@ describe('Shell API (integration)', function () {
     ).toArray();
   };
 
-  const loadMRExample = async (collection: Collection): Promise<any> => {
+  const loadMRExample = async (
+    collection: CollectionWithSchema
+  ): Promise<any> => {
     const res = await collection.insertMany([
       {
         _id: 1,
@@ -225,8 +229,8 @@ describe('Shell API (integration)', function () {
   let shellApi: ShellApi;
   let mongo: Mongo;
   let dbName: string;
-  let database: Database;
-  let collection: Collection;
+  let database: DatabaseWithSchema;
+  let collection: CollectionWithSchema;
   let collectionName: string;
 
   beforeEach(async function () {
diff --git a/packages/shell-api/src/interruptor.spec.ts b/packages/shell-api/src/interruptor.spec.ts
index c378a28fe5..64d8554465 100644
--- a/packages/shell-api/src/interruptor.spec.ts
+++ b/packages/shell-api/src/interruptor.spec.ts
@@ -4,7 +4,7 @@ import { expect } from 'chai';
 import type { EventEmitter } from 'events';
 import type { StubbedInstance } from 'ts-sinon';
 import { stubInterface } from 'ts-sinon';
-import Database from './database';
+import { Database } from './database';
 import Mongo from './mongo';
 import { InterruptFlag, MongoshInterruptedError } from './interruptor';
 import ShellInstanceState from './shell-instance-state';
diff --git a/packages/shell-api/src/mongo-errors.spec.ts b/packages/shell-api/src/mongo-errors.spec.ts
index 3b028f277d..9f0d8b63fc 100644
--- a/packages/shell-api/src/mongo-errors.spec.ts
+++ b/packages/shell-api/src/mongo-errors.spec.ts
@@ -5,10 +5,10 @@ import type { StubbedInstance } from 'ts-sinon';
 import { stubInterface } from 'ts-sinon';
 import type { ServiceProvider } from '@mongosh/service-provider-core';
 import { bson } from '@mongosh/service-provider-core';
-import Database from './database';
+import { Database } from './database';
 import type { EventEmitter } from 'events';
 import ShellInstanceState from './shell-instance-state';
-import Collection from './collection';
+import { Collection } from './collection';
 
 class MongoError extends Error {
   code?: number;
diff --git a/packages/shell-api/src/mongo.spec.ts b/packages/shell-api/src/mongo.spec.ts
index 303a57dfec..f8422220a0 100644
--- a/packages/shell-api/src/mongo.spec.ts
+++ b/packages/shell-api/src/mongo.spec.ts
@@ -17,10 +17,10 @@ import type {
   WriteConcern,
 } from '@mongosh/service-provider-core';
 import { bson } from '@mongosh/service-provider-core';
-import type Database from './database';
+import type { DatabaseWithSchema } from './database';
 import { EventEmitter } from 'events';
 import ShellInstanceState from './shell-instance-state';
-import Collection from './collection';
+import { Collection } from './collection';
 import type Cursor from './cursor';
 import ChangeStreamCursor from './change-stream-cursor';
 import NoDatabase from './no-db';
@@ -99,7 +99,7 @@ describe('Mongo', function () {
     const driverSession = { driverSession: 1 };
     let mongo: Mongo;
     let serviceProvider: StubbedInstance<ServiceProvider>;
-    let database: StubbedInstance<Database>;
+    let database: StubbedInstance<DatabaseWithSchema>;
     let bus: StubbedInstance<EventEmitter>;
     let instanceState: ShellInstanceState;
 
@@ -118,7 +118,7 @@ describe('Mongo', function () {
         undefined,
         serviceProvider
       );
-      database = stubInterface<Database>();
+      database = stubInterface<DatabaseWithSchema>();
       instanceState.currentDb = database;
     });
     describe('show', function () {
@@ -940,14 +940,16 @@ describe('Mongo', function () {
         expect(coll._database._name).to.equal('db1');
       });
 
-      it('throws if name is not a valid connection string', function () {
+      it('throws if name is not a valid collection string', function () {
         expect(() => {
+          // @ts-expect-error db is not valid, but that's the point of the test
           mongo.getCollection('db');
         }).to.throw('Collection must be of the format <db>.<collection>');
       });
 
       it('throws if name is empty', function () {
         expect(() => {
+          // @ts-expect-error db is not valid, but that's the point of the test
           mongo.getCollection('');
         }).to.throw('Collection must be of the format <db>.<collection>');
       });
diff --git a/packages/shell-api/src/mongo.ts b/packages/shell-api/src/mongo.ts
index 193b91c0d8..efaf5ab047 100644
--- a/packages/shell-api/src/mongo.ts
+++ b/packages/shell-api/src/mongo.ts
@@ -44,14 +44,15 @@ import {
   mapCliToDriver,
   generateConnectionInfoFromCliArgs,
 } from '@mongosh/arg-parser';
-import type Collection from './collection';
-import Database from './database';
+import type { DatabaseWithSchema } from './database';
+import { Database } from './database';
 import type ShellInstanceState from './shell-instance-state';
 import { ClientBulkWriteResult } from './result';
 import { CommandResult } from './result';
 import { redactURICredentials } from '@mongosh/history';
 import { asPrintable, ServerVersions, Topologies } from './enums';
 import Session from './session';
+import type { GenericServerSideSchema, StringKey } from './helpers';
 import {
   assertArgsDefinedType,
   processFLEOptions,
@@ -64,6 +65,7 @@ import { KeyVault, ClientEncryption } from './field-level-encryption';
 import { ShellApiErrors } from './error-codes';
 import type { LogEntry } from './log-entry';
 import { parseAnyLogEntry } from './log-entry';
+import type { CollectionWithSchema } from './collection';
 import type { ShellBson } from './shell-bson';
 
 /* Utility, inverse of Readonly<T> */
@@ -73,16 +75,19 @@ type Mutable<T> = {
 
 @shellApiClassDefault
 @classPlatforms(['CLI'])
-export default class Mongo extends ShellApiClass {
+export default class Mongo<
+  M extends GenericServerSideSchema = GenericServerSideSchema
+> extends ShellApiClass {
   private __serviceProvider: ServiceProvider | null = null;
-  public readonly _databases: Record<string, Database> = Object.create(null);
+  public readonly _databases: Record<StringKey<M>, DatabaseWithSchema<M>> =
+    Object.create(null);
   public _instanceState: ShellInstanceState;
   public _connectionInfo: ConnectionInfo;
   private _explicitEncryptionOnly = false;
   private _keyVault: KeyVault | undefined; // need to keep it around so that the ShellApi ClientEncryption class can access it
   private _clientEncryption: ClientEncryption | undefined;
   private _readPreferenceWasExplicitlyRequested = false;
-  private _cachedDatabaseNames: string[] = [];
+  private _cachedDatabaseNames: StringKey<M>[] = [];
 
   constructor(
     instanceState: ShellInstanceState,
@@ -252,7 +257,7 @@ export default class Mongo extends ShellApiClass {
     }
   }
 
-  _getDb(name: string): Database {
+  _getDb<K extends StringKey<M>>(name: K): DatabaseWithSchema<M, M[K]> {
     assertArgsDefinedType([name], ['string']);
     if (!isValidDatabaseName(name)) {
       throw new MongoshInvalidInputError(
@@ -262,20 +267,25 @@ export default class Mongo extends ShellApiClass {
     }
 
     if (!(name in this._databases)) {
-      this._databases[name] = new Database(this, name);
+      this._databases[name] = new Database<M>(this, name) as DatabaseWithSchema<
+        M,
+        M[K]
+      >;
     }
-    return this._databases[name];
+    return this._databases[name] as DatabaseWithSchema<M, M[K]>;
   }
 
   @returnType('Database')
-  getDB(db: string): Database {
+  getDB<K extends StringKey<M>>(db: K): DatabaseWithSchema<M, M[K]> {
     assertArgsDefinedType([db], ['string'], 'Mongo.getDB');
     this._instanceState.messageBus.emit('mongosh:getDB', { db });
     return this._getDb(db);
   }
 
   @returnType('Collection')
-  getCollection(name: string): Collection {
+  getCollection<KD extends StringKey<M>, KC extends StringKey<M[KD]>>(
+    name: `${KD}.${KC}`
+  ): CollectionWithSchema<M, M[KD], M[KD][KC]> {
     assertArgsDefinedType([name], ['string']);
     const { db, coll } = /^(?<db>[^.]+)\.(?<coll>.+)$/.exec(name)?.groups ?? {};
     if (!db || !coll) {
@@ -284,14 +294,16 @@ export default class Mongo extends ShellApiClass {
         CommonErrors.InvalidArgument
       );
     }
-    return this._getDb(db).getCollection(coll);
+    return this._getDb(db as StringKey<M>).getCollection(
+      coll
+    ) as CollectionWithSchema<M, M[KD], M[KD][KC]>;
   }
 
   getURI(): string {
     return this._uri;
   }
 
-  use(db: string): string {
+  use(db: StringKey<M>): string {
     assertArgsDefinedType([db], ['string'], 'Mongo.use');
     this._instanceState.messageBus.emit('mongosh:use', { db });
 
@@ -404,9 +416,13 @@ export default class Mongo extends ShellApiClass {
 
   @returnsPromise
   @apiVersions([1])
-  async getDBNames(options: ListDatabasesOptions = {}): Promise<string[]> {
+  async getDBNames(
+    options: ListDatabasesOptions = {}
+  ): Promise<StringKey<M>[]> {
     this._emitMongoApiCall('getDBNames', { options });
-    return (await this._listDatabases(options)).databases.map((db) => db.name);
+    return (await this._listDatabases(options)).databases.map(
+      (db) => db.name as StringKey<M>
+    );
   }
 
   @returnsPromise
@@ -883,17 +899,23 @@ export default class Mongo extends ShellApiClass {
     for (const approach of [
       // Try $documents if available (NB: running $documents on an empty db requires SERVER-63811 i.e. 6.0.3+).
       () =>
-        this.getDB('_fakeDbForMongoshCSKTH').aggregate([
+        this.getDB('_fakeDbForMongoshCSKTH' as StringKey<M>).aggregate([
+          { $documents: [{}] },
+          ...pipeline,
+        ]),
+      () =>
+        this.getDB('admin' as StringKey<M>).aggregate([
           { $documents: [{}] },
           ...pipeline,
         ]),
-      () => this.getDB('admin').aggregate([{ $documents: [{}] }, ...pipeline]),
       // If that fails, try a default collection like admin.system.version.
       () =>
-        this.getDB('admin').getCollection('system.version').aggregate(pipeline),
+        this.getDB('admin' as StringKey<M>)
+          .getCollection('system.version')
+          .aggregate(pipeline),
       // If that fails, try using $collStats for local.oplog.rs.
       () =>
-        this.getDB('local')
+        this.getDB('local' as StringKey<M>)
           .getCollection('oplog.rs')
           .aggregate([{ $collStats: {} }, ...pipeline]),
     ]) {
diff --git a/packages/shell-api/src/plan-cache.spec.ts b/packages/shell-api/src/plan-cache.spec.ts
index aba263fb94..8efb5403b5 100644
--- a/packages/shell-api/src/plan-cache.spec.ts
+++ b/packages/shell-api/src/plan-cache.spec.ts
@@ -4,7 +4,7 @@ import { ALL_PLATFORMS, ALL_TOPOLOGIES, ServerVersions } from './enums';
 import { signatures, toShellResult } from './index';
 import type { StubbedInstance } from 'ts-sinon';
 import { stubInterface } from 'ts-sinon';
-import type Collection from './collection';
+import type { CollectionWithSchema } from './collection';
 import type AggregationCursor from './aggregation-cursor';
 
 describe('PlanCache', function () {
@@ -50,11 +50,11 @@ describe('PlanCache', function () {
   });
   describe('commands', function () {
     let planCache: PlanCache;
-    let collection: StubbedInstance<Collection>;
+    let collection: StubbedInstance<CollectionWithSchema>;
     let aggCursor: StubbedInstance<AggregationCursor>;
 
     beforeEach(function () {
-      collection = stubInterface<Collection>();
+      collection = stubInterface<CollectionWithSchema>();
       planCache = new PlanCache(collection);
     });
     describe('clear', function () {
diff --git a/packages/shell-api/src/plan-cache.ts b/packages/shell-api/src/plan-cache.ts
index 1be3022624..0da8453a62 100644
--- a/packages/shell-api/src/plan-cache.ts
+++ b/packages/shell-api/src/plan-cache.ts
@@ -7,16 +7,16 @@ import {
   ShellApiWithMongoClass,
 } from './decorators';
 import type { Document } from '@mongosh/service-provider-core';
-import type Collection from './collection';
+import type { CollectionWithSchema } from './collection';
 import { asPrintable, ServerVersions } from './enums';
 import { MongoshDeprecatedError } from '@mongosh/errors';
 import type Mongo from './mongo';
 
 @shellApiClassDefault
 export default class PlanCache extends ShellApiWithMongoClass {
-  _collection: Collection;
+  _collection: CollectionWithSchema;
 
-  constructor(collection: Collection) {
+  constructor(collection: CollectionWithSchema) {
     super();
     this._collection = collection;
   }
diff --git a/packages/shell-api/src/replica-set.spec.ts b/packages/shell-api/src/replica-set.spec.ts
index f03129b3c1..dbfdeb82cb 100644
--- a/packages/shell-api/src/replica-set.spec.ts
+++ b/packages/shell-api/src/replica-set.spec.ts
@@ -23,7 +23,7 @@ import {
   skipIfApiStrict,
 } from '../../../testing/integration-testing-hooks';
 import { NodeDriverServiceProvider } from '../../service-provider-node-driver';
-import Database from './database';
+import { Database } from './database';
 import {
   ADMIN_DB,
   ALL_PLATFORMS,
diff --git a/packages/shell-api/src/replica-set.ts b/packages/shell-api/src/replica-set.ts
index cb0b0872df..064b502118 100644
--- a/packages/shell-api/src/replica-set.ts
+++ b/packages/shell-api/src/replica-set.ts
@@ -7,7 +7,7 @@ import {
 import { redactURICredentials } from '@mongosh/history';
 import type { Document } from '@mongosh/service-provider-core';
 import type Mongo from './mongo';
-import type Database from './database';
+import type { Database, DatabaseWithSchema } from './database';
 import {
   deprecated,
   returnsPromise,
@@ -18,6 +18,7 @@ import {
 import { asPrintable } from './enums';
 import { assertArgsDefinedType } from './helpers';
 import type { CommandResult } from './result';
+import type { GenericDatabaseSchema, GenericServerSideSchema } from './helpers';
 
 export type ReplSetMemberConfig = {
   _id: number;
@@ -35,15 +36,18 @@ export type ReplSetConfig = {
 };
 
 @shellApiClassDefault
-export default class ReplicaSet extends ShellApiWithMongoClass {
-  _database: Database;
+export default class ReplicaSet<
+  M extends GenericServerSideSchema = GenericServerSideSchema,
+  D extends GenericDatabaseSchema = GenericDatabaseSchema
+> extends ShellApiWithMongoClass {
+  _database: DatabaseWithSchema<M, D>;
 
-  constructor(database: Database) {
+  constructor(database: DatabaseWithSchema<M, D> | Database<M, D>) {
     super();
-    this._database = database;
+    this._database = database as DatabaseWithSchema<M, D>;
   }
 
-  get _mongo(): Mongo {
+  get _mongo(): Mongo<M> {
     return this._database._mongo;
   }
 
diff --git a/packages/shell-api/src/session.spec.ts b/packages/shell-api/src/session.spec.ts
index f3003caeb7..f44562d195 100644
--- a/packages/shell-api/src/session.spec.ts
+++ b/packages/shell-api/src/session.spec.ts
@@ -25,7 +25,7 @@ import {
   skipIfApiStrict,
 } from '../../../testing/integration-testing-hooks';
 import { ensureMaster, ensureSessionExists } from '../test/helpers';
-import Database from './database';
+import { Database } from './database';
 import { CommonErrors, MongoshInvalidInputError } from '@mongosh/errors';
 import { EventEmitter } from 'events';
 import { dummyOptions } from './helpers.spec';
diff --git a/packages/shell-api/src/session.ts b/packages/shell-api/src/session.ts
index cdae162d54..8619ae64d1 100644
--- a/packages/shell-api/src/session.ts
+++ b/packages/shell-api/src/session.ts
@@ -14,21 +14,25 @@ import type {
 } from '@mongosh/service-provider-core';
 import { asPrintable } from './enums';
 import type Mongo from './mongo';
-import Database from './database';
+import type { DatabaseWithSchema } from './database';
+import { Database } from './database';
 import { CommonErrors, MongoshInvalidInputError } from '@mongosh/errors';
+import type { GenericServerSideSchema, StringKey } from './helpers';
 import { assertArgsDefinedType, isValidDatabaseName } from './helpers';
 
 @shellApiClassDefault
 @classPlatforms(['CLI'])
-export default class Session extends ShellApiWithMongoClass {
+export default class Session<
+  M extends GenericServerSideSchema = GenericServerSideSchema
+> extends ShellApiWithMongoClass {
   public id: ServerSessionId | undefined;
   public _session: ClientSession;
   public _options: ClientSessionOptions;
-  public _mongo: Mongo;
-  private _databases: Record<string, Database>;
+  public _mongo: Mongo<M>;
+  private _databases: Record<string, DatabaseWithSchema<M>>;
 
   constructor(
-    mongo: Mongo,
+    mongo: Mongo<M>,
     options: ClientSessionOptions,
     session: ClientSession
   ) {
@@ -47,7 +51,7 @@ export default class Session extends ShellApiWithMongoClass {
     return this._session.id;
   }
 
-  getDatabase(name: string): Database {
+  getDatabase<K extends StringKey<M>>(name: K): DatabaseWithSchema<M, M[K]> {
     assertArgsDefinedType([name], ['string'], 'Session.getDatabase');
 
     if (!isValidDatabaseName(name)) {
@@ -58,9 +62,13 @@ export default class Session extends ShellApiWithMongoClass {
     }
 
     if (!(name in this._databases)) {
-      this._databases[name] = new Database(this._mongo, name, this);
+      this._databases[name] = new Database<M>(
+        this._mongo,
+        name,
+        this
+      ) as DatabaseWithSchema<M, M[K]>;
     }
-    return this._databases[name];
+    return this._databases[name] as DatabaseWithSchema<M, M[K]>;
   }
 
   advanceOperationTime(ts: TimestampType): void {
diff --git a/packages/shell-api/src/shard.spec.ts b/packages/shell-api/src/shard.spec.ts
index cfc6fd37fa..339e7544b9 100644
--- a/packages/shell-api/src/shard.spec.ts
+++ b/packages/shell-api/src/shard.spec.ts
@@ -29,7 +29,8 @@ import {
   skipIfServerVersion,
   skipIfApiStrict,
 } from '../../../testing/integration-testing-hooks';
-import Database from './database';
+import type { DatabaseWithSchema } from './database';
+import { Database } from './database';
 import { inspect } from 'util';
 import { dummyOptions } from './helpers.spec';
 
@@ -37,7 +38,7 @@ describe('Shard', function () {
   skipIfApiStrict();
 
   describe('help', function () {
-    const apiClass: any = new Shard({} as any);
+    const apiClass: any = new Shard({} as DatabaseWithSchema);
     it('calls help function', async function () {
       expect((await toShellResult(apiClass.help())).type).to.equal('Help');
       expect((await toShellResult(apiClass.help)).type).to.equal('Help');
@@ -76,7 +77,7 @@ describe('Shard', function () {
   describe('Metadata', function () {
     describe('toShellResult', function () {
       const mongo = { _uri: 'test_uri' } as Mongo;
-      const db = { _mongo: mongo, _name: 'test' } as Database;
+      const db = { _mongo: mongo, _name: 'test' } as DatabaseWithSchema;
       const sh = new Shard(db);
       it('value', async function () {
         expect((await toShellResult(sh)).printable).to.equal(
@@ -2455,7 +2456,7 @@ describe('Shard', function () {
           const instanceState = new ShellInstanceState(
             apiStrictServiceProvider
           );
-          const sh = new Shard(instanceState.currentDb);
+          const sh = new Shard(instanceState.currentDb as DatabaseWithSchema);
 
           const result = await sh.status();
           expect(result.type).to.equal('StatsResult');
@@ -3439,7 +3440,7 @@ describe('Shard', function () {
         new EventEmitter()
       );
       instanceState = new ShellInstanceState(serviceProvider);
-      sh = new Shard(instanceState.currentDb);
+      sh = new Shard(instanceState.currentDb as DatabaseWithSchema);
 
       // check replset uninitialized
       let members = await (
diff --git a/packages/shell-api/src/shard.ts b/packages/shell-api/src/shard.ts
index be2a4e250e..67520e052a 100644
--- a/packages/shell-api/src/shard.ts
+++ b/packages/shell-api/src/shard.ts
@@ -1,4 +1,4 @@
-import type Database from './database';
+import type { Database, DatabaseWithSchema } from './database';
 import {
   shellApiClassDefault,
   returnsPromise,
@@ -12,7 +12,12 @@ import type {
   Document,
   CheckMetadataConsistencyOptions,
 } from '@mongosh/service-provider-core';
-import type { ShardInfo, ShardingStatusResult } from './helpers';
+import type {
+  ShardInfo,
+  ShardingStatusResult,
+  GenericDatabaseSchema,
+  GenericServerSideSchema,
+} from './helpers';
 import {
   assertArgsDefinedType,
   getConfigDB,
@@ -28,15 +33,18 @@ import type RunCommandCursor from './run-command-cursor';
 import semver from 'semver';
 
 @shellApiClassDefault
-export default class Shard extends ShellApiWithMongoClass {
-  _database: Database;
+export default class Shard<
+  M extends GenericServerSideSchema = GenericServerSideSchema,
+  D extends GenericDatabaseSchema = GenericDatabaseSchema
+> extends ShellApiWithMongoClass {
+  _database: DatabaseWithSchema<M, D>;
 
-  constructor(database: Database) {
+  constructor(database: DatabaseWithSchema<M, D> | Database<M, D>) {
     super();
-    this._database = database;
+    this._database = database as DatabaseWithSchema<M, D>;
   }
 
-  get _mongo(): Mongo {
+  get _mongo(): Mongo<M> {
     return this._database._mongo;
   }
 
@@ -205,7 +213,7 @@ export default class Shard extends ShellApiWithMongoClass {
   @apiVersions([1])
   async status(
     verbose = false,
-    configDB?: Database
+    configDB?: DatabaseWithSchema<M, D>
   ): Promise<CommandResult<ShardingStatusResult>> {
     const result = await getPrintableShardStatus(
       configDB ?? (await getConfigDB(this._database)),
diff --git a/packages/shell-api/src/shell-api.ts b/packages/shell-api/src/shell-api.ts
index 1f553bd431..ffbadcf52b 100644
--- a/packages/shell-api/src/shell-api.ts
+++ b/packages/shell-api/src/shell-api.ts
@@ -14,7 +14,7 @@ import {
 } from './decorators';
 import { asPrintable } from './enums';
 import Mongo from './mongo';
-import type Database from './database';
+import type { DatabaseWithSchema } from './database';
 import type { CommandResult } from './result';
 import { CursorIterationResult } from './result';
 import type ShellInstanceState from './shell-instance-state';
@@ -266,7 +266,11 @@ export default class ShellApi extends ShellApiClass {
   @returnsPromise
   @returnType('Database')
   @platforms(['CLI'])
-  async connect(uri: string, user?: string, pwd?: string): Promise<Database> {
+  async connect(
+    uri: string,
+    user?: string,
+    pwd?: string
+  ): Promise<DatabaseWithSchema> {
     assertArgsDefinedType(
       [uri, user, pwd],
       ['string', [undefined, 'string'], [undefined, 'string']],
diff --git a/packages/shell-api/src/shell-instance-state.ts b/packages/shell-api/src/shell-instance-state.ts
index 0ce2d93fc7..4d34899899 100644
--- a/packages/shell-api/src/shell-instance-state.ts
+++ b/packages/shell-api/src/shell-instance-state.ts
@@ -25,8 +25,8 @@ import type {
   AggregationCursor,
   Cursor,
   RunCommandCursor,
-  Database,
   ShellResult,
+  DatabaseWithSchema,
 } from './index';
 import { getShellApiType, Mongo, ReplicaSet, Shard, ShellApi } from './index';
 import { InterruptFlag } from './interruptor';
@@ -142,14 +142,14 @@ const CONTROL_CHAR_REGEXP = /[\x00-\x1F\x7F-\x9F]/g;
  * shell API is concerned) and keeps track of all open connections (a.k.a. Mongo
  * instances).
  */
-export default class ShellInstanceState {
+export class ShellInstanceState {
   public currentCursor:
     | Cursor
     | AggregationCursor
     | ChangeStreamCursor
     | RunCommandCursor
     | null;
-  public currentDb: Database;
+  public currentDb: DatabaseWithSchema;
   public messageBus: MongoshBus;
   public initialServiceProvider: ServiceProvider; // the initial service provider
   private connectionInfoCache: {
@@ -219,7 +219,7 @@ export default class ShellInstanceState {
         initialServiceProvider.initialDb || DEFAULT_DB
       );
     } else {
-      this.currentDb = new NoDatabase() as Database;
+      this.currentDb = new NoDatabase() as DatabaseWithSchema;
     }
     this.currentCursor = null;
     this.context = {};
@@ -282,7 +282,7 @@ export default class ShellInstanceState {
     this.preFetchCollectionAndDatabaseNames = value;
   }
 
-  public setDbFunc(newDb: any): Database {
+  public setDbFunc(newDb: any): DatabaseWithSchema {
     this.currentDb = newDb;
     this.context.rs = new ReplicaSet(this.currentDb);
     this.context.sh = new Shard(this.currentDb);
@@ -351,7 +351,7 @@ export default class ShellInstanceState {
     contextObject.sh = new Shard(this.currentDb);
     contextObject.sp = Streams.newInstance(this.currentDb);
 
-    const setFunc = (newDb: any): Database => {
+    const setFunc = (newDb: any): DatabaseWithSchema => {
       if (getShellApiType(newDb) !== 'Database') {
         throw new MongoshInvalidInputError(
           "Cannot reassign 'db' to non-Database type",
@@ -728,3 +728,5 @@ export default class ShellInstanceState {
     }
   }
 }
+
+export default ShellInstanceState;
diff --git a/packages/shell-api/src/stream-processor.ts b/packages/shell-api/src/stream-processor.ts
index 789fc9dd74..0a436d05c7 100644
--- a/packages/shell-api/src/stream-processor.ts
+++ b/packages/shell-api/src/stream-processor.ts
@@ -12,7 +12,7 @@ import {
 import type { Streams } from './streams';
 
 @shellApiClassDefault
-export default class StreamProcessor extends ShellApiWithMongoClass {
+export class StreamProcessor extends ShellApiWithMongoClass {
   constructor(public _streams: Streams, public name: string) {
     super();
   }
@@ -152,3 +152,4 @@ export default class StreamProcessor extends ShellApiWithMongoClass {
     return;
   }
 }
+export default StreamProcessor;
diff --git a/packages/shell-api/src/streams.spec.ts b/packages/shell-api/src/streams.spec.ts
index 8a26b6d71b..538045b10f 100644
--- a/packages/shell-api/src/streams.spec.ts
+++ b/packages/shell-api/src/streams.spec.ts
@@ -2,7 +2,7 @@ import { expect } from 'chai';
 import sinon from 'sinon';
 
 import type Mongo from './mongo';
-import Database from './database';
+import { Database } from './database';
 import { Streams } from './streams';
 import { InterruptFlag, MongoshInterruptedError } from './interruptor';
 import type { MongoshInvalidInputError } from '@mongosh/errors';
@@ -23,7 +23,8 @@ describe('Streams', function () {
         runCommand: identity,
       },
     } as unknown as Mongo;
-    streams = new Streams(new Database(mongo, 'testDb'));
+    const db = new Database(mongo, 'testDb');
+    streams = new Streams(db);
   });
 
   describe('createStreamProcessor', function () {
diff --git a/packages/shell-api/src/streams.ts b/packages/shell-api/src/streams.ts
index 127677148b..c0963521b5 100644
--- a/packages/shell-api/src/streams.ts
+++ b/packages/shell-api/src/streams.ts
@@ -8,13 +8,20 @@ import {
 } from './decorators';
 import StreamProcessor from './stream-processor';
 import { ADMIN_DB, asPrintable, shellApiType } from './enums';
-import type Database from './database';
+import type { Database, DatabaseWithSchema } from './database';
 import type Mongo from './mongo';
+import type { GenericDatabaseSchema, GenericServerSideSchema } from './helpers';
 
 @shellApiClassDefault
-export class Streams extends ShellApiWithMongoClass {
-  public static newInstance(database: Database) {
-    return new Proxy(new Streams(database), {
+export class Streams<
+  M extends GenericServerSideSchema = GenericServerSideSchema,
+  D extends GenericDatabaseSchema = GenericDatabaseSchema
+> extends ShellApiWithMongoClass {
+  public static newInstance<
+    M extends GenericServerSideSchema = GenericServerSideSchema,
+    D extends GenericDatabaseSchema = GenericDatabaseSchema
+  >(database: DatabaseWithSchema<M, D>) {
+    return new Proxy(new Streams<M, D>(database), {
       get(target, prop) {
         const v = (target as any)[prop];
         if (v !== undefined) {
@@ -27,14 +34,14 @@ export class Streams extends ShellApiWithMongoClass {
     });
   }
 
-  private _database: Database;
+  private _database: DatabaseWithSchema<M, D>;
 
-  constructor(database: Database) {
+  constructor(database: DatabaseWithSchema<M, D> | Database<M, D>) {
     super();
-    this._database = database;
+    this._database = database as DatabaseWithSchema<M, D>;
   }
 
-  get _mongo(): Mongo {
+  get _mongo(): Mongo<M> {
     return this._database._mongo;
   }
 
@@ -42,7 +49,7 @@ export class Streams extends ShellApiWithMongoClass {
     return 'Atlas Stream Processing';
   }
 
-  getProcessor(name: string) {
+  getProcessor(name: string): StreamProcessor {
     return new StreamProcessor(this, name);
   }