diff --git a/src/coll.rs b/src/coll.rs
index 953906bca..b8064fd74 100644
--- a/src/coll.rs
+++ b/src/coll.rs
@@ -135,7 +135,7 @@ impl<T> Clone for Collection<T> {
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 struct CollectionInner {
     client: Client,
     db: Database,
@@ -183,6 +183,16 @@ impl<T> Collection<T> {
         }
     }
 
+    pub(crate) fn clone_unconcerned(&self) -> Self {
+        let mut new_inner = CollectionInner::clone(&self.inner);
+        new_inner.write_concern = None;
+        new_inner.read_concern = None;
+        Self {
+            inner: Arc::new(new_inner),
+            _phantom: Default::default(),
+        }
+    }
+
     /// Get the `Client` that this collection descended from.
     pub fn client(&self) -> &Client {
         &self.inner.client
diff --git a/src/lib.rs b/src/lib.rs
index bb59688ac..c09e91f14 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -337,6 +337,7 @@ mod index;
 mod operation;
 pub mod results;
 pub(crate) mod runtime;
+mod search_index;
 mod sdam;
 mod selection_criteria;
 mod serde_util;
@@ -362,7 +363,7 @@ pub use crate::{
     gridfs::{GridFsBucket, GridFsDownloadStream, GridFsUploadStream},
 };
 
-pub use {client::session::ClusterTime, coll::Namespace, index::IndexModel, sdam::public::*};
+pub use {client::session::ClusterTime, coll::Namespace, index::IndexModel, sdam::public::*, search_index::SearchIndexModel};
 
 #[cfg(all(feature = "tokio-runtime", feature = "sync",))]
 compile_error!(
diff --git a/src/operation.rs b/src/operation.rs
index 67358171c..52f2e8392 100644
--- a/src/operation.rs
+++ b/src/operation.rs
@@ -20,6 +20,7 @@ mod list_indexes;
 mod raw_output;
 mod run_command;
 mod run_cursor_command;
+mod search_index;
 mod update;
 
 #[cfg(test)]
@@ -73,6 +74,7 @@ pub(crate) use list_indexes::ListIndexes;
 pub(crate) use raw_output::RawOutput;
 pub(crate) use run_command::RunCommand;
 pub(crate) use run_cursor_command::RunCursorCommand;
+pub(crate) use search_index::{CreateSearchIndexes, DropSearchIndex, UpdateSearchIndex};
 pub(crate) use update::{Update, UpdateOrReplace};
 
 const SERVER_4_2_0_WIRE_VERSION: i32 = 8;
diff --git a/src/operation/search_index.rs b/src/operation/search_index.rs
new file mode 100644
index 000000000..57267f8d0
--- /dev/null
+++ b/src/operation/search_index.rs
@@ -0,0 +1,179 @@
+use bson::{doc, Document};
+use serde::Deserialize;
+
+use crate::{cmap::Command, error::Result, Namespace, SearchIndexModel};
+
+use super::OperationWithDefaults;
+
+#[derive(Debug)]
+pub(crate) struct CreateSearchIndexes {
+    ns: Namespace,
+    indexes: Vec<SearchIndexModel>,
+}
+
+impl CreateSearchIndexes {
+    pub(crate) fn new(ns: Namespace, indexes: Vec<SearchIndexModel>) -> Self {
+        Self { ns, indexes }
+    }
+}
+
+impl OperationWithDefaults for CreateSearchIndexes {
+    type O = Vec<String>;
+    type Command = Document;
+    const NAME: &'static str = "createSearchIndexes";
+
+    fn build(&mut self, _description: &crate::cmap::StreamDescription) -> Result<Command> {
+        Ok(Command::new(
+            Self::NAME.to_string(),
+            self.ns.db.clone(),
+            doc! {
+                Self::NAME: self.ns.coll.clone(),
+                "indexes": bson::to_bson(&self.indexes)?,
+            },
+        ))
+    }
+
+    fn handle_response(
+        &self,
+        response: crate::cmap::RawCommandResponse,
+        _description: &crate::cmap::StreamDescription,
+    ) -> Result<Self::O> {
+        #[derive(Debug, Deserialize)]
+        #[serde(rename_all = "camelCase")]
+        struct Response {
+            indexes_created: Vec<CreatedIndex>,
+        }
+
+        #[derive(Debug, Deserialize)]
+        struct CreatedIndex {
+            #[allow(unused)]
+            id: String,
+            name: String,
+        }
+
+        let response: Response = response.body()?;
+        Ok(response
+            .indexes_created
+            .into_iter()
+            .map(|ci| ci.name)
+            .collect())
+    }
+
+    fn supports_sessions(&self) -> bool {
+        false
+    }
+
+    fn supports_read_concern(&self, _description: &crate::cmap::StreamDescription) -> bool {
+        false
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct UpdateSearchIndex {
+    ns: Namespace,
+    name: String,
+    definition: Document,
+}
+
+impl UpdateSearchIndex {
+    pub(crate) fn new(ns: Namespace, name: String, definition: Document) -> Self {
+        Self {
+            ns,
+            name,
+            definition,
+        }
+    }
+}
+
+impl OperationWithDefaults for UpdateSearchIndex {
+    type O = ();
+    type Command = Document;
+    const NAME: &'static str = "updateSearchIndex";
+
+    fn build(
+        &mut self,
+        _description: &crate::cmap::StreamDescription,
+    ) -> crate::error::Result<crate::cmap::Command<Self::Command>> {
+        Ok(Command::new(
+            Self::NAME.to_string(),
+            self.ns.db.clone(),
+            doc! {
+                Self::NAME: self.ns.coll.clone(),
+                "name": &self.name,
+                "definition": &self.definition,
+            },
+        ))
+    }
+
+    fn handle_response(
+        &self,
+        response: crate::cmap::RawCommandResponse,
+        _description: &crate::cmap::StreamDescription,
+    ) -> crate::error::Result<Self::O> {
+        response.body()
+    }
+
+    fn supports_sessions(&self) -> bool {
+        false
+    }
+
+    fn supports_read_concern(&self, _description: &crate::cmap::StreamDescription) -> bool {
+        false
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct DropSearchIndex {
+    ns: Namespace,
+    name: String,
+}
+
+impl DropSearchIndex {
+    pub(crate) fn new(ns: Namespace, name: String) -> Self {
+        Self { ns, name }
+    }
+}
+
+impl OperationWithDefaults for DropSearchIndex {
+    type O = ();
+    type Command = Document;
+    const NAME: &'static str = "dropSearchIndex";
+
+    fn build(
+        &mut self,
+        _description: &crate::cmap::StreamDescription,
+    ) -> Result<Command<Self::Command>> {
+        Ok(Command::new(
+            Self::NAME.to_string(),
+            self.ns.db.clone(),
+            doc! {
+                Self::NAME: self.ns.coll.clone(),
+                "name": &self.name,
+            },
+        ))
+    }
+
+    fn handle_response(
+        &self,
+        response: crate::cmap::RawCommandResponse,
+        _description: &crate::cmap::StreamDescription,
+    ) -> Result<Self::O> {
+        response.body()
+    }
+
+    fn handle_error(&self, error: crate::error::Error) -> Result<Self::O> {
+        if error.is_ns_not_found() {
+            Ok(())
+        } else {
+            Err(error)
+        }
+    }
+
+    fn supports_sessions(&self) -> bool {
+        false
+    }
+
+    fn supports_read_concern(&self, _description: &crate::cmap::StreamDescription) -> bool {
+        false
+    }
+}
diff --git a/src/options.rs b/src/options.rs
index 2851fb009..a96ec7967 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -25,6 +25,7 @@ pub use crate::{
     db::options::*,
     gridfs::options::*,
     index::options::*,
+    search_index::options::*,
     selection_criteria::*,
 };
 
diff --git a/src/search_index.rs b/src/search_index.rs
new file mode 100644
index 000000000..91c18cb5c
--- /dev/null
+++ b/src/search_index.rs
@@ -0,0 +1,135 @@
+use self::options::*;
+use crate::{
+    bson::Document,
+    coll::options::AggregateOptions,
+    error::{Error, Result},
+    operation::{CreateSearchIndexes, DropSearchIndex, UpdateSearchIndex},
+    Collection,
+    Cursor,
+};
+
+use bson::doc;
+use serde::{Deserialize, Serialize};
+use typed_builder::TypedBuilder;
+
+impl<T> Collection<T> {
+    /// Convenience method for creating a single search index.
+    pub async fn create_search_index(
+        &self,
+        model: SearchIndexModel,
+        options: impl Into<Option<CreateSearchIndexOptions>>,
+    ) -> Result<String> {
+        let mut names = self.create_search_indexes(Some(model), options).await?;
+        match names.len() {
+            1 => Ok(names.pop().unwrap()),
+            n => Err(Error::internal(format!("expected 1 index name, got {}", n))),
+        }
+    }
+
+    /// Creates multiple search indexes on the collection.
+    pub async fn create_search_indexes(
+        &self,
+        models: impl IntoIterator<Item = SearchIndexModel>,
+        _options: impl Into<Option<CreateSearchIndexOptions>>,
+    ) -> Result<Vec<String>> {
+        let op = CreateSearchIndexes::new(self.namespace(), models.into_iter().collect());
+        self.client().execute_operation(op, None).await
+    }
+
+    /// Updates the search index with the given name to use the provided definition.
+    pub async fn update_search_index(
+        &self,
+        name: impl AsRef<str>,
+        definition: Document,
+        _options: impl Into<Option<UpdateSearchIndexOptions>>,
+    ) -> Result<()> {
+        let op = UpdateSearchIndex::new(
+            self.namespace(),
+            name.as_ref().to_string(),
+            definition.clone(),
+        );
+        self.client().execute_operation(op, None).await
+    }
+
+    /// Drops the search index with the given name.
+    pub async fn drop_search_index(
+        &self,
+        name: impl AsRef<str>,
+        _options: impl Into<Option<DropSearchIndexOptions>>,
+    ) -> Result<()> {
+        let op = DropSearchIndex::new(self.namespace(), name.as_ref().to_string());
+        self.client().execute_operation(op, None).await
+    }
+
+    /// Gets index information for one or more search indexes in the collection.
+    ///
+    /// If name is not specified, information for all indexes on the specified collection will be
+    /// returned.
+    pub async fn list_search_indexes(
+        &self,
+        name: impl Into<Option<&str>>,
+        aggregation_options: impl Into<Option<AggregateOptions>>,
+        _list_index_options: impl Into<Option<ListSearchIndexOptions>>,
+    ) -> Result<Cursor<Document>> {
+        let mut inner = doc! {};
+        if let Some(name) = name.into() {
+            inner.insert("name", name.to_string());
+        }
+        self.clone_unconcerned()
+            .aggregate(
+                vec![doc! {
+                    "$listSearchIndexes": inner,
+                }],
+                aggregation_options,
+            )
+            .await
+    }
+}
+
+/// Specifies the options for a search index.
+#[derive(Debug, Clone, Default, TypedBuilder, Serialize, Deserialize)]
+#[builder(field_defaults(default, setter(into)))]
+#[non_exhaustive]
+pub struct SearchIndexModel {
+    /// The definition for this index.
+    pub definition: Document,
+
+    /// The name for this index, if present.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub name: Option<String>,
+}
+
+pub mod options {
+    #[cfg(docsrs)]
+    use crate::Collection;
+    use serde::Deserialize;
+    use typed_builder::TypedBuilder;
+
+    /// Options for [Collection::create_search_index].  Present to allow additional options to be
+    /// added in the future as a non-breaking change.
+    #[derive(Clone, Debug, Default, TypedBuilder, Deserialize)]
+    #[builder(field_defaults(default, setter(into)))]
+    #[non_exhaustive]
+    pub struct CreateSearchIndexOptions {}
+
+    /// Options for [Collection::update_search_index].  Present to allow additional options to be
+    /// added in the future as a non-breaking change.
+    #[derive(Clone, Debug, Default, TypedBuilder, Deserialize)]
+    #[builder(field_defaults(default, setter(into)))]
+    #[non_exhaustive]
+    pub struct UpdateSearchIndexOptions {}
+
+    /// Options for [Collection::list_search_indexes].  Present to allow additional options to be
+    /// added in the future as a non-breaking change.
+    #[derive(Clone, Debug, Default, TypedBuilder, Deserialize)]
+    #[builder(field_defaults(default, setter(into)))]
+    #[non_exhaustive]
+    pub struct ListSearchIndexOptions {}
+
+    /// Options for [Collection::drop_search_index].  Present to allow additional options to be
+    /// added in the future as a non-breaking change.
+    #[derive(Clone, Debug, Default, TypedBuilder, Deserialize)]
+    #[builder(field_defaults(default, setter(into)))]
+    #[non_exhaustive]
+    pub struct DropSearchIndexOptions {}
+}
diff --git a/src/test/spec.rs b/src/test/spec.rs
index 4084aaabe..48515f47e 100644
--- a/src/test/spec.rs
+++ b/src/test/spec.rs
@@ -10,6 +10,7 @@ mod crud;
 mod crud_v1;
 mod faas;
 mod gridfs;
+mod index_management;
 #[cfg(all(not(feature = "sync"), not(feature = "tokio-sync")))]
 mod initial_dns_seedlist_discovery;
 mod load_balancers;
diff --git a/src/test/spec/index_management.rs b/src/test/spec/index_management.rs
new file mode 100644
index 000000000..6113af4a0
--- /dev/null
+++ b/src/test/spec/index_management.rs
@@ -0,0 +1,7 @@
+use crate::test::spec::unified_runner::run_unified_tests;
+
+#[cfg_attr(feature = "tokio-runtime", tokio::test)]
+#[cfg_attr(feature = "async-std-runtime", async_std::test)]
+async fn run() {
+    run_unified_tests(&["index-management"]).await;
+}
diff --git a/src/test/spec/json/index-management/README.rst b/src/test/spec/json/index-management/README.rst
new file mode 100644
index 000000000..090cda4be
--- /dev/null
+++ b/src/test/spec/json/index-management/README.rst
@@ -0,0 +1,200 @@
+======================
+Index Management Tests
+======================
+
+.. contents::
+
+----
+
+Test Plan
+=========
+
+These prose tests are ported from the legacy enumerate-indexes spec.
+
+Configurations
+--------------
+
+- standalone node
+- replica set primary node
+- replica set secondary node
+- mongos node
+
+Preparation
+-----------
+
+For each of the configurations:
+
+- Create a (new) database
+- Create a collection
+- Create a single column index, a compound index, and a unique index
+- Insert at least one document containing all the fields that the above
+  indicated indexes act on
+
+Tests
+
+- Run the driver's method that returns a list of index names, and:
+
+  - verify that *all* index names are represented in the result
+  - verify that there are no duplicate index names
+  - verify there are no returned indexes that do not exist
+
+- Run the driver's method that returns a list of index information records, and:
+
+  - verify all the indexes are represented in the result
+  - verify the "unique" flags show up for the unique index
+  - verify there are no duplicates in the returned list
+  - if the result consists of statically defined index models that include an ``ns`` field, verify
+    that its value is accurate
+
+Search Index Management Helpers
+-------------------------------
+
+These tests are intended to smoke test the search management helpers end-to-end against a live Atlas cluster.
+
+The search index management commands are asynchronous and mongod/mongos returns before the changes to a clusters' search indexes have completed.  When
+these prose tests specify "waiting for the changes", drivers should repeatedly poll the cluster with ``listSearchIndexes``
+until the changes are visible.  Each test specifies the condition that is considered "ready".  For example, when creating a 
+new search index, waiting until the inserted index has a status ``queryable: true`` indicates that the index was successfully
+created.
+
+The commands tested in these prose tests take a while to successfully complete.  Drivers should raise the timeout for each test to avoid timeout errors if 
+the test timeout is too low.  5 minutes is a sufficiently large timeout that any timeout that occurs indicates a real failure, but this value is not required and can be tweaked per-driver.
+
+There is a server-side limitation that prevents multiple search indexes from being created with the same name, definition and 
+collection name.  This limitation does not take into account collection uuid.  Because these commands are asynchronous, any cleanup
+code that may run after a test (cleaning a database or dropping search indexes) may not have completed by the next iteration of the 
+test (or the next test run, if running locally).  To address this issue, each test uses a randomly generated collection name.  Drivers
+may generate this collection name however they like, but a suggested implementation is a hex representation of an
+ObjectId (``new ObjectId().toHexString()`` in Node).
+
+Setup
+~~~~~
+
+These tests must run against an Atlas cluster with a 7.0+ server.  `Scripts are available <https://github.com/mongodb-labs/drivers-evergreen-tools/tree/master/.evergreen/atlas>`_ in drivers-evergreen-tools which can setup and teardown
+Atlas clusters.  To ensure that the Atlas cluster is cleaned up after each CI run, drivers should configure evergreen to run these tests 
+as a part of a task group.  Be sure that the cluster gets torn down! 
+
+When working locally on these tests, the same Atlas setup and teardown scripts can be used locally to provision a cluster for development.
+
+Case 1: Driver can successfully create and list search indexes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+#. Create a collection with the "create" command using a randomly generated name (referred to as ``coll0``).
+#. Create a new search index on ``coll0`` with the ``createSearchIndex`` helper.  Use the following definition:
+
+   .. code:: typescript
+
+     {
+       name: 'test-search-index',
+       definition: {
+         mappings: { dynamic: false }
+       }
+     }
+
+#. Assert that the command returns the name of the index: ``"test-search-index"``.
+#. Run ``coll0.listSearchIndexes()`` repeatedly every 5 seconds until the following condition is satisfied and store the value in a variable ``index``:
+
+   - An index with the ``name`` of ``test-search-index`` is present and the index has a field ``queryable`` with a value of ``true``.
+
+#. Assert that ``index`` has a property ``latestDefinition`` whose value is ``{ 'mappings': { 'dynamic': false } }``
+
+Case 2: Driver can successfully create multiple indexes in batch
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+#. Create a collection with the "create" command using a randomly generated name (referred to as ``coll0``).
+#. Create two new search indexes on ``coll0`` with the ``createSearchIndexes`` helper.  Use the following
+   definitions when creating the indexes.  These definitions are referred to as ``indexDefinitions``.
+
+   .. code:: typescript
+
+     {
+       name: 'test-search-index-1',
+       definition: {
+         mappings: { dynamic: false }
+       }
+     }
+
+     {
+       name: 'test-search-index-2',
+       definition: {
+         mappings: { dynamic: false }
+       }
+     }
+
+#. Assert that the command returns an array containing the new indexes' names: ``["test-search-index-1", "test-search-index-2"]``.
+#. Run ``coll0.listSearchIndexes()`` repeatedly every 5 seconds until the following conditions are satisfied.
+
+   - An index with the ``name`` of ``test-search-index-1`` is present and index has a field ``queryable`` with the value of ``true``. Store result in ``index1``.
+   - An index with the ``name`` of ``test-search-index-2`` is present and index has a field ``queryable`` with the value of ``true``. Store result in ``index2``.
+
+#. Assert that ``index1`` and ``index2`` have the property ``latestDefinition`` whose value is ``{ "mappings" : { "dynamic" : false } }``
+
+Case 3: Driver can successfully drop search indexes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+#. Create a collection with the "create" command using a randomly generated name (referred to as ``coll0``).
+#. Create a new search index on ``coll0`` with the following definition:
+
+   .. code:: typescript
+
+     {
+       name: 'test-search-index',
+       definition: {
+         mappings: { dynamic: false }
+       }
+     }
+
+#. Assert that the command returns the name of the index: ``"test-search-index"``.
+#. Run ``coll0.listSearchIndexes()`` repeatedly every 5 seconds until the following condition is satisfied:
+
+   - An index with the ``name`` of ``test-search-index`` is present and index has a field ``queryable`` with the value of ``true``.
+
+#. Run a ``dropSearchIndex`` on ``coll0``, using ``test-search-index`` for the name.
+#. Run ``coll0.listSearchIndexes()`` repeatedly every 5 seconds until ``listSearchIndexes`` returns an empty array.
+
+This test fails if it times out waiting for the deletion to succeed.
+
+Case 4: Driver can update a search index
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+#. Create a collection with the "create" command using a randomly generated name (referred to as ``coll0``).
+#. Create a new search index on ``coll0`` with the following definition:
+
+   .. code:: typescript
+
+     {
+       name: 'test-search-index',
+       definition: {
+         mappings: { dynamic: false }
+       }
+     }
+
+#. Assert that the command returns the name of the index: ``"test-search-index"``.
+#. Run ``coll0.listSearchIndexes()`` repeatedly every 5 seconds until the following condition is satisfied:
+
+   - An index with the ``name`` of ``test-search-index`` is present and index has a field ``queryable`` with the value of ``true``.
+
+#. Run a ``updateSearchIndex`` on ``coll0``, using the following definition.
+
+   .. code:: typescript
+
+     {
+       name: 'test-search-index',
+       definition: {
+         mappings: { dynamic: true }
+       }
+     }
+
+#. Assert that the command does not error and the server responds with a success.
+#. Run ``coll0.listSearchIndexes()`` repeatedly every 5 seconds until the following conditions are satisfied:
+
+   - An index with the ``name`` of ``test-search-index`` is present.  This index is referred to as ``index``.
+   - The index has a field ``queryable`` with a value of ``true`` and has a field ``status`` with the value of ``READY``.
+
+#. Assert that an index is present with the name ``test-search-index`` and the definition has a property ``latestDefinition`` whose value is ``{ 'mappings': { 'dynamic': true } }``.
+
+Case 5: ``dropSearchIndex`` suppresses namespace not found errors
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+#. Create a driver-side collection object for a randomly generated collection name.  Do not create this collection on the server.
+#. Run a ``dropSearchIndex`` command and assert that no error is thrown.
diff --git a/src/test/spec/json/index-management/createSearchIndex.json b/src/test/spec/json/index-management/createSearchIndex.json
new file mode 100644
index 000000000..04cffbe9c
--- /dev/null
+++ b/src/test/spec/json/index-management/createSearchIndex.json
@@ -0,0 +1,136 @@
+{
+  "description": "createSearchIndex",
+  "schemaVersion": "1.4",
+  "createEntities": [
+    {
+      "client": {
+        "id": "client0",
+        "useMultipleMongoses": false,
+        "observeEvents": [
+          "commandStartedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "database0",
+        "client": "client0",
+        "databaseName": "database0"
+      }
+    },
+    {
+      "collection": {
+        "id": "collection0",
+        "database": "database0",
+        "collectionName": "collection0"
+      }
+    }
+  ],
+  "runOnRequirements": [
+    {
+      "minServerVersion": "7.0.0",
+      "topologies": [
+        "replicaset",
+        "load-balanced",
+        "sharded"
+      ],
+      "serverless": "forbid"
+    }
+  ],
+  "tests": [
+    {
+      "description": "no name provided for an index definition",
+      "operations": [
+        {
+          "name": "createSearchIndex",
+          "object": "collection0",
+          "arguments": {
+            "model": {
+              "definition": {
+                "mappings": {
+                  "dynamic": true
+                }
+              }
+            }
+          },
+          "expectError": {
+            "isError": true,
+            "errorContains": "Search index commands are only supported with Atlas"
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "createSearchIndexes": "collection0",
+                  "indexes": [
+                    {
+                      "definition": {
+                        "mappings": {
+                          "dynamic": true
+                        }
+                      }
+                    }
+                  ],
+                  "$db": "database0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "name provided for an index definition",
+      "operations": [
+        {
+          "name": "createSearchIndex",
+          "object": "collection0",
+          "arguments": {
+            "model": {
+              "definition": {
+                "mappings": {
+                  "dynamic": true
+                }
+              },
+              "name": "test index"
+            }
+          },
+          "expectError": {
+            "isError": true,
+            "errorContains": "Search index commands are only supported with Atlas"
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "createSearchIndexes": "collection0",
+                  "indexes": [
+                    {
+                      "definition": {
+                        "mappings": {
+                          "dynamic": true
+                        }
+                      },
+                      "name": "test index"
+                    }
+                  ],
+                  "$db": "database0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/src/test/spec/json/index-management/createSearchIndex.yml b/src/test/spec/json/index-management/createSearchIndex.yml
new file mode 100644
index 000000000..6aa56f3bc
--- /dev/null
+++ b/src/test/spec/json/index-management/createSearchIndex.yml
@@ -0,0 +1,62 @@
+description: "createSearchIndex"
+schemaVersion: "1.4"
+createEntities:
+  - client:
+      id: &client0 client0
+      useMultipleMongoses: false
+      observeEvents:
+        - commandStartedEvent
+  - database:
+      id: &database0 database0
+      client: *client0
+      databaseName: *database0
+  - collection:
+      id: &collection0 collection0
+      database: *database0
+      collectionName: *collection0
+
+runOnRequirements:
+  - minServerVersion: "7.0.0"
+    topologies: [ replicaset, load-balanced, sharded ]
+    serverless: forbid
+
+tests:
+  - description: "no name provided for an index definition"
+    operations:
+      - name: createSearchIndex
+        object: *collection0
+        arguments:
+          model: { definition: &definition { mappings: { dynamic: true } } }
+        expectError:
+          # This test always errors in a non-Atlas environment.  The test functions as a unit test  by asserting
+          # that the driver constructs and sends the correct command.
+          isError: true
+          errorContains: Search index commands are only supported with Atlas
+    expectEvents:
+      - client: *client0
+        events:
+          - commandStartedEvent:
+              command:
+                createSearchIndexes: *collection0
+                indexes: [ { definition: *definition } ]
+                $db: *database0
+
+  - description: "name provided for an index definition"
+    operations:
+      - name: createSearchIndex
+        object: *collection0
+        arguments: 
+          model: { definition: &definition { mappings: { dynamic: true } } , name: 'test index' }
+        expectError:
+          # This test always errors in a non-Atlas environment.  The test functions as a unit test  by asserting
+          # that the driver constructs and sends the correct command.
+          isError: true
+          errorContains: Search index commands are only supported with Atlas
+    expectEvents:
+      - client: *client0
+        events:
+          - commandStartedEvent:
+              command:
+                createSearchIndexes: *collection0
+                indexes: [ { definition: *definition, name: 'test index' } ]
+                $db: *database0
\ No newline at end of file
diff --git a/src/test/spec/json/index-management/createSearchIndexes.json b/src/test/spec/json/index-management/createSearchIndexes.json
new file mode 100644
index 000000000..95dbedde7
--- /dev/null
+++ b/src/test/spec/json/index-management/createSearchIndexes.json
@@ -0,0 +1,172 @@
+{
+  "description": "createSearchIndexes",
+  "schemaVersion": "1.4",
+  "createEntities": [
+    {
+      "client": {
+        "id": "client0",
+        "useMultipleMongoses": false,
+        "observeEvents": [
+          "commandStartedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "database0",
+        "client": "client0",
+        "databaseName": "database0"
+      }
+    },
+    {
+      "collection": {
+        "id": "collection0",
+        "database": "database0",
+        "collectionName": "collection0"
+      }
+    }
+  ],
+  "runOnRequirements": [
+    {
+      "minServerVersion": "7.0.0",
+      "topologies": [
+        "replicaset",
+        "load-balanced",
+        "sharded"
+      ],
+      "serverless": "forbid"
+    }
+  ],
+  "tests": [
+    {
+      "description": "empty index definition array",
+      "operations": [
+        {
+          "name": "createSearchIndexes",
+          "object": "collection0",
+          "arguments": {
+            "models": []
+          },
+          "expectError": {
+            "isError": true,
+            "errorContains": "Search index commands are only supported with Atlas"
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "createSearchIndexes": "collection0",
+                  "indexes": [],
+                  "$db": "database0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "no name provided for an index definition",
+      "operations": [
+        {
+          "name": "createSearchIndexes",
+          "object": "collection0",
+          "arguments": {
+            "models": [
+              {
+                "definition": {
+                  "mappings": {
+                    "dynamic": true
+                  }
+                }
+              }
+            ]
+          },
+          "expectError": {
+            "isError": true,
+            "errorContains": "Search index commands are only supported with Atlas"
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "createSearchIndexes": "collection0",
+                  "indexes": [
+                    {
+                      "definition": {
+                        "mappings": {
+                          "dynamic": true
+                        }
+                      }
+                    }
+                  ],
+                  "$db": "database0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "name provided for an index definition",
+      "operations": [
+        {
+          "name": "createSearchIndexes",
+          "object": "collection0",
+          "arguments": {
+            "models": [
+              {
+                "definition": {
+                  "mappings": {
+                    "dynamic": true
+                  }
+                },
+                "name": "test index"
+              }
+            ]
+          },
+          "expectError": {
+            "isError": true,
+            "errorContains": "Search index commands are only supported with Atlas"
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "createSearchIndexes": "collection0",
+                  "indexes": [
+                    {
+                      "definition": {
+                        "mappings": {
+                          "dynamic": true
+                        }
+                      },
+                      "name": "test index"
+                    }
+                  ],
+                  "$db": "database0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/src/test/spec/json/index-management/createSearchIndexes.yml b/src/test/spec/json/index-management/createSearchIndexes.yml
new file mode 100644
index 000000000..54a6e84cc
--- /dev/null
+++ b/src/test/spec/json/index-management/createSearchIndexes.yml
@@ -0,0 +1,83 @@
+description: "createSearchIndexes"
+schemaVersion: "1.4"
+createEntities:
+  - client:
+      id: &client0 client0
+      useMultipleMongoses: false
+      observeEvents:
+        - commandStartedEvent
+  - database:
+      id: &database0 database0
+      client: *client0
+      databaseName: *database0
+  - collection:
+      id: &collection0 collection0
+      database: *database0
+      collectionName: *collection0
+
+runOnRequirements:
+  - minServerVersion: "7.0.0"
+    topologies: [ replicaset, load-balanced, sharded ]
+    serverless: forbid
+
+tests:
+  - description: "empty index definition array"
+    operations:
+      - name: createSearchIndexes
+        object: *collection0
+        arguments: 
+          models: []
+        expectError:
+          # This test always errors in a non-Atlas environment.  The test functions as a unit test  by asserting
+          # that the driver constructs and sends the correct command.
+          isError: true
+          errorContains: Search index commands are only supported with Atlas
+    expectEvents:
+      - client: *client0
+        events:
+          - commandStartedEvent:
+              command:
+                createSearchIndexes: *collection0
+                indexes: []
+                $db: *database0
+
+
+  - description: "no name provided for an index definition"
+    operations:
+      - name: createSearchIndexes
+        object: *collection0
+        arguments:
+          models: [ { definition: &definition { mappings: { dynamic: true } } } ]
+        expectError:
+          # This test always errors in a non-Atlas environment.  The test functions as a unit test  by asserting
+          # that the driver constructs and sends the correct command.
+          isError: true
+          errorContains: Search index commands are only supported with Atlas
+    expectEvents:
+      - client: *client0
+        events:
+          - commandStartedEvent:
+              command:
+                createSearchIndexes: *collection0
+                indexes: [ { definition: *definition } ]
+                $db: *database0
+
+  - description: "name provided for an index definition"
+    operations:
+      - name: createSearchIndexes
+        object: *collection0
+        arguments: 
+          models: [ { definition: &definition { mappings: { dynamic: true } } , name: 'test index' } ]
+        expectError:
+          # This test always errors in a non-Atlas environment.  The test functions as a unit test  by asserting
+          # that the driver constructs and sends the correct command.
+          isError: true
+          errorContains: Search index commands are only supported with Atlas
+    expectEvents:
+      - client: *client0
+        events:
+          - commandStartedEvent:
+              command:
+                createSearchIndexes: *collection0
+                indexes: [ { definition: *definition, name: 'test index' } ]
+                $db: *database0
\ No newline at end of file
diff --git a/src/test/spec/json/index-management/dropSearchIndex.json b/src/test/spec/json/index-management/dropSearchIndex.json
new file mode 100644
index 000000000..0f21a5b68
--- /dev/null
+++ b/src/test/spec/json/index-management/dropSearchIndex.json
@@ -0,0 +1,74 @@
+{
+  "description": "dropSearchIndex",
+  "schemaVersion": "1.4",
+  "createEntities": [
+    {
+      "client": {
+        "id": "client0",
+        "useMultipleMongoses": false,
+        "observeEvents": [
+          "commandStartedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "database0",
+        "client": "client0",
+        "databaseName": "database0"
+      }
+    },
+    {
+      "collection": {
+        "id": "collection0",
+        "database": "database0",
+        "collectionName": "collection0"
+      }
+    }
+  ],
+  "runOnRequirements": [
+    {
+      "minServerVersion": "7.0.0",
+      "topologies": [
+        "replicaset",
+        "load-balanced",
+        "sharded"
+      ],
+      "serverless": "forbid"
+    }
+  ],
+  "tests": [
+    {
+      "description": "sends the correct command",
+      "operations": [
+        {
+          "name": "dropSearchIndex",
+          "object": "collection0",
+          "arguments": {
+            "name": "test index"
+          },
+          "expectError": {
+            "isError": true,
+            "errorContains": "Search index commands are only supported with Atlas"
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "dropSearchIndex": "collection0",
+                  "name": "test index",
+                  "$db": "database0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/src/test/spec/json/index-management/dropSearchIndex.yml b/src/test/spec/json/index-management/dropSearchIndex.yml
new file mode 100644
index 000000000..e384cf26c
--- /dev/null
+++ b/src/test/spec/json/index-management/dropSearchIndex.yml
@@ -0,0 +1,42 @@
+description: "dropSearchIndex"
+schemaVersion: "1.4"
+createEntities:
+  - client:
+      id: &client0 client0
+      useMultipleMongoses: false
+      observeEvents:
+        - commandStartedEvent
+  - database:
+      id: &database0 database0
+      client: *client0
+      databaseName: *database0
+  - collection:
+      id: &collection0 collection0
+      database: *database0
+      collectionName: *collection0
+
+runOnRequirements:
+  - minServerVersion: "7.0.0"
+    topologies: [ replicaset, load-balanced, sharded ]
+    serverless: forbid
+
+tests:
+  - description: "sends the correct command"
+    operations:
+      - name: dropSearchIndex
+        object: *collection0
+        arguments:
+          name: &indexName 'test index'
+        expectError:
+          # This test always errors in a non-Atlas environment.  The test functions as a unit test  by asserting
+          # that the driver constructs and sends the correct command.
+          isError: true
+          errorContains: Search index commands are only supported with Atlas
+    expectEvents:
+      - client: *client0
+        events:
+          - commandStartedEvent:
+              command:
+                dropSearchIndex: *collection0
+                name: *indexName
+                $db: *database0
diff --git a/src/test/spec/json/index-management/listSearchIndexes.json b/src/test/spec/json/index-management/listSearchIndexes.json
new file mode 100644
index 000000000..24c51ad88
--- /dev/null
+++ b/src/test/spec/json/index-management/listSearchIndexes.json
@@ -0,0 +1,156 @@
+{
+  "description": "listSearchIndexes",
+  "schemaVersion": "1.4",
+  "createEntities": [
+    {
+      "client": {
+        "id": "client0",
+        "useMultipleMongoses": false,
+        "observeEvents": [
+          "commandStartedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "database0",
+        "client": "client0",
+        "databaseName": "database0"
+      }
+    },
+    {
+      "collection": {
+        "id": "collection0",
+        "database": "database0",
+        "collectionName": "collection0"
+      }
+    }
+  ],
+  "runOnRequirements": [
+    {
+      "minServerVersion": "7.0.0",
+      "topologies": [
+        "replicaset",
+        "load-balanced",
+        "sharded"
+      ],
+      "serverless": "forbid"
+    }
+  ],
+  "tests": [
+    {
+      "description": "when no name is provided, it does not populate the filter",
+      "operations": [
+        {
+          "name": "listSearchIndexes",
+          "object": "collection0",
+          "expectError": {
+            "isError": true,
+            "errorContains": "Search index commands are only supported with Atlas"
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "aggregate": "collection0",
+                  "pipeline": [
+                    {
+                      "$listSearchIndexes": {}
+                    }
+                  ]
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "when a name is provided, it is present in the filter",
+      "operations": [
+        {
+          "name": "listSearchIndexes",
+          "object": "collection0",
+          "arguments": {
+            "name": "test index"
+          },
+          "expectError": {
+            "isError": true,
+            "errorContains": "Search index commands are only supported with Atlas"
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "aggregate": "collection0",
+                  "pipeline": [
+                    {
+                      "$listSearchIndexes": {
+                        "name": "test index"
+                      }
+                    }
+                  ],
+                  "$db": "database0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "aggregation cursor options are supported",
+      "operations": [
+        {
+          "name": "listSearchIndexes",
+          "object": "collection0",
+          "arguments": {
+            "name": "test index",
+            "aggregationOptions": {
+              "batchSize": 10
+            }
+          },
+          "expectError": {
+            "isError": true,
+            "errorContains": "Search index commands are only supported with Atlas"
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "aggregate": "collection0",
+                  "cursor": {
+                    "batchSize": 10
+                  },
+                  "pipeline": [
+                    {
+                      "$listSearchIndexes": {
+                        "name": "test index"
+                      }
+                    }
+                  ],
+                  "$db": "database0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/src/test/spec/json/index-management/listSearchIndexes.yml b/src/test/spec/json/index-management/listSearchIndexes.yml
new file mode 100644
index 000000000..a50becdf1
--- /dev/null
+++ b/src/test/spec/json/index-management/listSearchIndexes.yml
@@ -0,0 +1,85 @@
+description: "listSearchIndexes"
+schemaVersion: "1.4"
+createEntities:
+  - client:
+      id: &client0 client0
+      useMultipleMongoses: false
+      observeEvents:
+        - commandStartedEvent
+  - database:
+      id: &database0 database0
+      client: *client0
+      databaseName: *database0
+  - collection:
+      id: &collection0 collection0
+      database: *database0
+      collectionName: *collection0
+
+runOnRequirements:
+  - minServerVersion: "7.0.0"
+    topologies: [ replicaset, load-balanced, sharded ]
+    serverless: forbid
+
+tests:
+  - description: "when no name is provided, it does not populate the filter"
+    operations:
+      - name: listSearchIndexes
+        object: *collection0
+        expectError:
+          # This test always errors in a non-Atlas environment.  The test functions as a unit test  by asserting
+          # that the driver constructs and sends the correct command.
+          isError: true
+          errorContains: Search index commands are only supported with Atlas
+    expectEvents:
+      - client: *client0
+        events:
+          - commandStartedEvent:
+              command:
+                aggregate: *collection0
+                pipeline:
+                  - $listSearchIndexes: {}
+
+  - description: "when a name is provided, it is present in the filter"
+    operations:
+      - name: listSearchIndexes
+        object: *collection0
+        arguments: 
+          name: &indexName "test index"
+        expectError:
+          # This test always errors in a non-Atlas environment.  The test functions as a unit test  by asserting
+          # that the driver constructs and sends the correct command.
+          isError: true
+          errorContains: Search index commands are only supported with Atlas
+    expectEvents:
+      - client: *client0
+        events:
+          - commandStartedEvent:
+              command:
+                aggregate: *collection0
+                pipeline:
+                  - $listSearchIndexes: { name: *indexName }
+                $db: *database0
+
+  - description: aggregation cursor options are supported
+    operations:
+      - name: listSearchIndexes
+        object: *collection0
+        arguments: 
+          name: &indexName "test index"
+          aggregationOptions: 
+            batchSize: 10
+        expectError:
+          # This test always errors in a non-Atlas environment.  The test functions as a unit test  by asserting
+          # that the driver constructs and sends the correct command.
+          isError: true
+          errorContains: Search index commands are only supported with Atlas
+    expectEvents:
+      - client: *client0
+        events:
+          - commandStartedEvent:
+              command:
+                aggregate: *collection0
+                cursor: { batchSize: 10 }
+                pipeline:
+                  - $listSearchIndexes: { name: *indexName }
+                $db: *database0
\ No newline at end of file
diff --git a/src/test/spec/json/index-management/searchIndexIgnoresReadWriteConcern.json b/src/test/spec/json/index-management/searchIndexIgnoresReadWriteConcern.json
new file mode 100644
index 000000000..102f5a767
--- /dev/null
+++ b/src/test/spec/json/index-management/searchIndexIgnoresReadWriteConcern.json
@@ -0,0 +1,252 @@
+{
+    "description": "search index operations ignore read and write concern",
+    "schemaVersion": "1.4",
+    "createEntities": [
+      {
+        "client": {
+          "id": "client0",
+          "useMultipleMongoses": false,
+          "uriOptions": {
+            "readConcernLevel": "local",
+            "w": 1
+          },
+          "observeEvents": [
+            "commandStartedEvent"
+          ]
+        }
+      },
+      {
+        "database": {
+          "id": "database0",
+          "client": "client0",
+          "databaseName": "database0"
+        }
+      },
+      {
+        "collection": {
+          "id": "collection0",
+          "database": "database0",
+          "collectionName": "collection0"
+        }
+      }
+    ],
+    "runOnRequirements": [
+      {
+        "minServerVersion": "7.0.0",
+        "topologies": [
+          "replicaset",
+          "load-balanced",
+          "sharded"
+        ],
+        "serverless": "forbid"
+      }
+    ],
+    "tests": [
+      {
+        "description": "createSearchIndex ignores read and write concern",
+        "operations": [
+          {
+            "name": "createSearchIndex",
+            "object": "collection0",
+            "arguments": {
+              "model": {
+                "definition": {
+                  "mappings": {
+                    "dynamic": true
+                  }
+                }
+              }
+            },
+            "expectError": {
+              "isError": true,
+              "errorContains": "Search index commands are only supported with Atlas"
+            }
+          }
+        ],
+        "expectEvents": [
+          {
+            "client": "client0",
+            "events": [
+              {
+                "commandStartedEvent": {
+                  "command": {
+                    "createSearchIndexes": "collection0",
+                    "indexes": [
+                      {
+                        "definition": {
+                          "mappings": {
+                            "dynamic": true
+                          }
+                        }
+                      }
+                    ],
+                    "$db": "database0",
+                    "writeConcern": {
+                      "$$exists": false
+                    },
+                    "readConcern": {
+                      "$$exists": false
+                    }
+                  }
+                }
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "description": "createSearchIndex ignores read and write concern",
+        "operations": [
+          {
+            "name": "createSearchIndexes",
+            "object": "collection0",
+            "arguments": {
+              "models": []
+            },
+            "expectError": {
+              "isError": true,
+              "errorContains": "Search index commands are only supported with Atlas"
+            }
+          }
+        ],
+        "expectEvents": [
+          {
+            "client": "client0",
+            "events": [
+              {
+                "commandStartedEvent": {
+                  "command": {
+                    "createSearchIndexes": "collection0",
+                    "indexes": [],
+                    "$db": "database0",
+                    "writeConcern": {
+                      "$$exists": false
+                    },
+                    "readConcern": {
+                      "$$exists": false
+                    }
+                  }
+                }
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "description": "dropSearchIndex ignores read and write concern",
+        "operations": [
+          {
+            "name": "dropSearchIndex",
+            "object": "collection0",
+            "arguments": {
+              "name": "test index"
+            },
+            "expectError": {
+              "isError": true,
+              "errorContains": "Search index commands are only supported with Atlas"
+            }
+          }
+        ],
+        "expectEvents": [
+          {
+            "client": "client0",
+            "events": [
+              {
+                "commandStartedEvent": {
+                  "command": {
+                    "dropSearchIndex": "collection0",
+                    "name": "test index",
+                    "$db": "database0",
+                    "writeConcern": {
+                      "$$exists": false
+                    },
+                    "readConcern": {
+                      "$$exists": false
+                    }
+                  }
+                }
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "description": "listSearchIndexes ignores read and write concern",
+        "operations": [
+          {
+            "name": "listSearchIndexes",
+            "object": "collection0",
+            "expectError": {
+              "isError": true,
+              "errorContains": "Search index commands are only supported with Atlas"
+            }
+          }
+        ],
+        "expectEvents": [
+          {
+            "client": "client0",
+            "events": [
+              {
+                "commandStartedEvent": {
+                  "command": {
+                    "aggregate": "collection0",
+                    "pipeline": [
+                      {
+                        "$listSearchIndexes": {}
+                      }
+                    ],
+                    "writeConcern": {
+                      "$$exists": false
+                    },
+                    "readConcern": {
+                      "$$exists": false
+                    }
+                  }
+                }
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "description": "updateSearchIndex ignores the read and write concern",
+        "operations": [
+          {
+            "name": "updateSearchIndex",
+            "object": "collection0",
+            "arguments": {
+              "name": "test index",
+              "definition": {}
+            },
+            "expectError": {
+              "isError": true,
+              "errorContains": "Search index commands are only supported with Atlas"
+            }
+          }
+        ],
+        "expectEvents": [
+          {
+            "client": "client0",
+            "events": [
+              {
+                "commandStartedEvent": {
+                  "command": {
+                    "updateSearchIndex": "collection0",
+                    "name": "test index",
+                    "definition": {},
+                    "$db": "database0",
+                    "writeConcern": {
+                      "$$exists": false
+                    },
+                    "readConcern": {
+                      "$$exists": false
+                    }
+                  }
+                }
+              }
+            ]
+          }
+        ]
+      }
+    ]
+  }
\ No newline at end of file
diff --git a/src/test/spec/json/index-management/updateSearchIndex.json b/src/test/spec/json/index-management/updateSearchIndex.json
new file mode 100644
index 000000000..88a46a306
--- /dev/null
+++ b/src/test/spec/json/index-management/updateSearchIndex.json
@@ -0,0 +1,76 @@
+{
+  "description": "updateSearchIndex",
+  "schemaVersion": "1.4",
+  "createEntities": [
+    {
+      "client": {
+        "id": "client0",
+        "useMultipleMongoses": false,
+        "observeEvents": [
+          "commandStartedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "database0",
+        "client": "client0",
+        "databaseName": "database0"
+      }
+    },
+    {
+      "collection": {
+        "id": "collection0",
+        "database": "database0",
+        "collectionName": "collection0"
+      }
+    }
+  ],
+  "runOnRequirements": [
+    {
+      "minServerVersion": "7.0.0",
+      "topologies": [
+        "replicaset",
+        "load-balanced",
+        "sharded"
+      ],
+      "serverless": "forbid"
+    }
+  ],
+  "tests": [
+    {
+      "description": "sends the correct command",
+      "operations": [
+        {
+          "name": "updateSearchIndex",
+          "object": "collection0",
+          "arguments": {
+            "name": "test index",
+            "definition": {}
+          },
+          "expectError": {
+            "isError": true,
+            "errorContains": "Search index commands are only supported with Atlas"
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "updateSearchIndex": "collection0",
+                  "name": "test index",
+                  "definition": {},
+                  "$db": "database0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/src/test/spec/json/index-management/updateSearchIndex.yml b/src/test/spec/json/index-management/updateSearchIndex.yml
new file mode 100644
index 000000000..bb18ab512
--- /dev/null
+++ b/src/test/spec/json/index-management/updateSearchIndex.yml
@@ -0,0 +1,45 @@
+description: "updateSearchIndex"
+schemaVersion: "1.4"
+createEntities:
+  - client:
+      id: &client0 client0
+      useMultipleMongoses: false
+      observeEvents:
+        - commandStartedEvent
+  - database:
+      id: &database0 database0
+      client: *client0
+      databaseName: *database0
+  - collection:
+      id: &collection0 collection0
+      database: *database0
+      collectionName: *collection0
+
+runOnRequirements:
+  - minServerVersion: "7.0.0"
+    topologies: [ replicaset, load-balanced, sharded ]
+    serverless: forbid
+
+tests:
+  - description: "sends the correct command"
+    operations:
+      - name: updateSearchIndex
+        object: *collection0
+        arguments:
+          name: &indexName 'test index'
+          definition: &definition {}
+        expectError:
+          # This test always errors in a non-Atlas environment.  The test functions as a unit test  by asserting
+          # that the driver constructs and sends the correct command.
+          isError: true
+          errorContains: Search index commands are only supported with Atlas
+    expectEvents:
+      - client: *client0
+        events:
+          - commandStartedEvent:
+              command:
+                updateSearchIndex: *collection0
+                name: *indexName
+                definition: *definition
+                $db: *database0
+
diff --git a/src/test/spec/unified_runner/operation.rs b/src/test/spec/unified_runner/operation.rs
index 7269e1546..41d1910c4 100644
--- a/src/test/spec/unified_runner/operation.rs
+++ b/src/test/spec/unified_runner/operation.rs
@@ -3,6 +3,8 @@ mod csfle;
 #[cfg(feature = "in-use-encryption-unstable")]
 use self::csfle::*;
 
+mod search_index;
+
 use std::{
     collections::HashMap,
     convert::TryInto,
@@ -383,6 +385,21 @@ impl<'de> Deserialize<'de> for Operation {
             #[cfg(feature = "in-use-encryption-unstable")]
             "removeKeyAltName" => deserialize_op::<RemoveKeyAltName>(definition.arguments),
             "iterateOnce" => deserialize_op::<IterateOnce>(definition.arguments),
+            "createSearchIndex" => {
+                deserialize_op::<search_index::CreateSearchIndex>(definition.arguments)
+            }
+            "createSearchIndexes" => {
+                deserialize_op::<search_index::CreateSearchIndexes>(definition.arguments)
+            }
+            "dropSearchIndex" => {
+                deserialize_op::<search_index::DropSearchIndex>(definition.arguments)
+            }
+            "listSearchIndexes" => {
+                deserialize_op::<search_index::ListSearchIndexes>(definition.arguments)
+            }
+            "updateSearchIndex" => {
+                deserialize_op::<search_index::UpdateSearchIndex>(definition.arguments)
+            }
             s => Ok(Box::new(UnimplementedOperation {
                 _name: s.to_string(),
             }) as Box<dyn TestOperation>),
diff --git a/src/test/spec/unified_runner/operation/search_index.rs b/src/test/spec/unified_runner/operation/search_index.rs
new file mode 100644
index 000000000..461d53df5
--- /dev/null
+++ b/src/test/spec/unified_runner/operation/search_index.rs
@@ -0,0 +1,151 @@
+use bson::{to_bson, Bson, Document};
+use futures_core::future::BoxFuture;
+use futures_util::{FutureExt, TryStreamExt};
+use serde::Deserialize;
+
+use crate::{
+    coll::options::AggregateOptions,
+    error::Result,
+    search_index::options::{
+        CreateSearchIndexOptions,
+        DropSearchIndexOptions,
+        ListSearchIndexOptions,
+        UpdateSearchIndexOptions,
+    },
+    test::spec::unified_runner::{Entity, TestRunner},
+    SearchIndexModel,
+};
+
+use super::TestOperation;
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase", deny_unknown_fields)]
+pub(super) struct CreateSearchIndex {
+    model: SearchIndexModel,
+    #[serde(flatten)]
+    options: CreateSearchIndexOptions,
+}
+
+impl TestOperation for CreateSearchIndex {
+    fn execute_entity_operation<'a>(
+        &'a self,
+        id: &'a str,
+        test_runner: &'a TestRunner,
+    ) -> BoxFuture<'a, Result<Option<Entity>>> {
+        async move {
+            let collection = test_runner.get_collection(id).await;
+            let name = collection
+                .create_search_index(self.model.clone(), self.options.clone())
+                .await?;
+            Ok(Some(Bson::String(name).into()))
+        }
+        .boxed()
+    }
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase", deny_unknown_fields)]
+pub(super) struct CreateSearchIndexes {
+    models: Vec<SearchIndexModel>,
+    #[serde(flatten)]
+    options: CreateSearchIndexOptions,
+}
+
+impl TestOperation for CreateSearchIndexes {
+    fn execute_entity_operation<'a>(
+        &'a self,
+        id: &'a str,
+        test_runner: &'a TestRunner,
+    ) -> BoxFuture<'a, Result<Option<Entity>>> {
+        async move {
+            let collection = test_runner.get_collection(id).await;
+            let names = collection
+                .create_search_indexes(self.models.clone(), self.options.clone())
+                .await?;
+            Ok(Some(to_bson(&names)?.into()))
+        }
+        .boxed()
+    }
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase", deny_unknown_fields)]
+pub(super) struct DropSearchIndex {
+    name: String,
+    #[serde(flatten)]
+    options: DropSearchIndexOptions,
+}
+
+impl TestOperation for DropSearchIndex {
+    fn execute_entity_operation<'a>(
+        &'a self,
+        id: &'a str,
+        test_runner: &'a TestRunner,
+    ) -> BoxFuture<'a, Result<Option<Entity>>> {
+        async move {
+            let collection = test_runner.get_collection(id).await;
+            collection
+                .drop_search_index(&self.name, self.options.clone())
+                .await?;
+            Ok(None)
+        }
+        .boxed()
+    }
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase", deny_unknown_fields)]
+pub(super) struct ListSearchIndexes {
+    name: Option<String>,
+    aggregation_options: Option<AggregateOptions>,
+    #[serde(flatten)]
+    options: ListSearchIndexOptions,
+}
+
+impl TestOperation for ListSearchIndexes {
+    fn execute_entity_operation<'a>(
+        &'a self,
+        id: &'a str,
+        test_runner: &'a TestRunner,
+    ) -> BoxFuture<'a, Result<Option<Entity>>> {
+        async move {
+            let collection = test_runner.get_collection(id).await;
+            let cursor = collection
+                .list_search_indexes(
+                    self.name.as_deref(),
+                    self.aggregation_options.clone(),
+                    self.options.clone(),
+                )
+                .await?;
+            let values: Vec<_> = cursor.try_collect().await?;
+            Ok(Some(to_bson(&values)?.into()))
+        }
+        .boxed()
+    }
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase", deny_unknown_fields)]
+pub(super) struct UpdateSearchIndex {
+    name: String,
+    definition: Document,
+    #[serde(flatten)]
+    options: UpdateSearchIndexOptions,
+}
+
+impl TestOperation for UpdateSearchIndex {
+    fn execute_entity_operation<'a>(
+        &'a self,
+        id: &'a str,
+        test_runner: &'a TestRunner,
+    ) -> BoxFuture<'a, Result<Option<Entity>>> {
+        async move {
+            let collection = test_runner.get_collection(id).await;
+            collection
+                .update_search_index(&self.name, self.definition.clone(), self.options.clone())
+                .await?;
+            Ok(None)
+        }
+        .boxed()
+    }
+}