Skip to content

feat: add support for managing search indexes #181

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions src/tools/mongodb/create/createSearchIndex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { z } from "zod";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
import { ToolArgs, OperationType } from "../../tool.js";

export class CreateSearchIndexTool extends MongoDBToolBase {
protected name = "create-search-index";
protected description = "Create an Atlas Search index for a collection";
protected argsShape = {
...DbOperationArgs,
name: z.string().optional().describe("The name of the index"),
type: z.enum(["search", "vectorSearch"]).optional().default("search").describe("The type of the index"),
analyzer: z
.string()
.optional()
.default("lucene.standard")
.describe(
"The analyzer to use for the index. Can be one of the built-in lucene analyzers (`lucene.standard`, `lucene.simple`, `lucene.whitespace`, `lucene.keyword`), a language-specific analyzer, such as `lucene.cjk` or `lucene.czech`, or a custom analyzer defined in the Atlas UI."
),
mappings: z.object({
dynamic: z
.boolean()
.optional()
.default(false)
.describe(
"Enables or disables dynamic mapping of fields for this index. If set to true, Atlas Search recursively indexes all dynamically indexable fields. If set to false, you must specify individual fields to index using mappings.fields."
),
fields: z
.record(
z.string().describe("The field name"),
z
.object({
type: z
.enum([
"autocomplete",
"boolean",
"date",
"document",
"embeddedDocuments",
"geo",
"knnVector",
"number",
"objectId",
"string",
"token",
"uuid",
])
.describe("The field type"),
})
.passthrough()

.describe(
"The field index definition. It must contain the field type, as well as any additional options for that field type."
)
)
.optional()
.describe("The field mapping definitions. If `dynamic` is set to false, this is required."),
}),
};

protected operationType: OperationType = "create";

protected async execute({
database,
collection,
name,
type,
analyzer,
mappings,
}: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
const provider = await this.ensureConnected();
const indexes = await provider.createSearchIndexes(database, collection, [
{
name,
type,
definition: {
analyzer,
mappings,
},
},
]);

return {
content: [
{
text: `Created the index "${indexes[0]}" on collection "${collection}" in database "${database}"`,
type: "text",
},
],
};
}
}
57 changes: 57 additions & 0 deletions src/tools/mongodb/delete/dropIndex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { z } from "zod";
import { MongoServerError } from "mongodb";

export class DropIndexTool extends MongoDBToolBase {
protected name = "drop-index";
protected description = "Removes an index from a collection.";
protected argsShape = {
...DbOperationArgs,
name: z.string().describe("The name of the index to drop"),
};
protected operationType: OperationType = "delete";

protected async execute({ database, collection, name }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
const provider = await this.ensureConnected();
await provider.mongoClient.db(database).collection(collection).dropIndex(name);
try {
await provider.dropSearchIndex(database, collection, name);
} catch (error) {
if (error instanceof MongoServerError && error.codeName === "SearchNotEnabled") {
// If search is not enabled (e.g. due to connecting to a non-Atlas cluster), we can ignore the error
// and return an empty array for search indexes.
} else {
throw error;
}
}

return {
content: [
{
text: `Successfully dropped index "${name}" in "${database}.${collection}"`,
type: "text",
},
],
};
}

protected handleError(
error: unknown,
args: ToolArgs<typeof this.argsShape>
): Promise<CallToolResult> | CallToolResult {
if (error instanceof Error && "codeName" in error && error.codeName === "NamespaceNotFound") {
return {
content: [
{
text: `Cannot drop index "${args.name}" because the namespace "${args.database}.${args.collection}" does not exist.`,
type: "text",
},
],
};
}

return super.handleError(error, args);
}
}
29 changes: 25 additions & 4 deletions src/tools/mongodb/read/collectionIndexes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { Document } from "bson";
import { MongoServerError } from "mongodb";

export class CollectionIndexesTool extends MongoDBToolBase {
protected name = "collection-indexes";
@@ -12,18 +14,37 @@ export class CollectionIndexesTool extends MongoDBToolBase {
const provider = await this.ensureConnected();
const indexes = await provider.getIndexes(database, collection);

let searchIndexes: Document[];
try {
searchIndexes = await provider.getSearchIndexes(database, collection);
} catch (error) {
if (error instanceof MongoServerError && error.codeName === "SearchNotEnabled") {
// If search is not enabled (e.g. due to connecting to a non-Atlas cluster), we can ignore the error
// and return an empty array for search indexes.
searchIndexes = [];
} else {
throw error;
}
}

return {
content: [
{
text: `Found ${indexes.length} indexes in the collection "${collection}":`,
text: `Found ${indexes.length + searchIndexes.length} indexes in the collection "${collection}":`,
type: "text",
},
...(indexes.map((indexDefinition) => {
...indexes.map((indexDefinition) => {
return {
text: `Name "${indexDefinition.name}", definition: ${JSON.stringify(indexDefinition.key)}`,
type: "text",
};
}) as { text: string; type: "text" }[]),
} as const;
}),
...searchIndexes.map((indexDefinition) => {
return {
text: `Search index name: "${indexDefinition.name}", status: ${indexDefinition.status}, definition: ${JSON.stringify(indexDefinition.latestDefinition)}`,
type: "text",
} as const;
}),
],
};
}
36 changes: 22 additions & 14 deletions src/tools/mongodb/tools.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// TODO: https://github.com/mongodb-js/mongodb-mcp-server/issues/141 - reenable when the connect tool is reenabled
// import { ConnectTool } from "./metadata/connect.js";
import { ListCollectionsTool } from "./metadata/listCollections.js";
import { CollectionIndexesTool } from "./read/collectionIndexes.js";
import { CollectionIndexesTool as ListIndexesTool } from "./read/collectionIndexes.js";
import { ListDatabasesTool } from "./metadata/listDatabases.js";
import { CreateIndexTool } from "./create/createIndex.js";
import { CollectionSchemaTool } from "./metadata/collectionSchema.js";
@@ -19,27 +19,35 @@ import { DropCollectionTool } from "./delete/dropCollection.js";
import { ExplainTool } from "./metadata/explain.js";
import { CreateCollectionTool } from "./create/createCollection.js";
import { LogsTool } from "./metadata/logs.js";
import { CreateSearchIndexTool } from "./create/createSearchIndex.js";
import { DropIndexTool } from "./delete/dropIndex.js";

export const MongoDbTools = [
// TODO: https://github.com/mongodb-js/mongodb-mcp-server/issues/141 - reenable when the connect tool is reenabled
// ConnectTool,
CreateCollectionTool,
ListCollectionsTool,
ListDatabasesTool,
CollectionIndexesTool,
CreateIndexTool,
CollectionSchemaTool,
FindTool,
InsertManyTool,
DeleteManyTool,
CollectionStorageSizeTool,
CountTool,
DbStatsTool,
AggregateTool,
UpdateManyTool,
RenameCollectionTool,
DropDatabaseTool,
DropCollectionTool,
ExplainTool,
CreateCollectionTool,

ListDatabasesTool,
DropDatabaseTool,
DbStatsTool,
LogsTool,

FindTool,
AggregateTool,
CountTool,
ExplainTool,

InsertManyTool,
DeleteManyTool,
UpdateManyTool,

CreateIndexTool,
CreateSearchIndexTool,
ListIndexesTool,
DropIndexTool,
];
4 changes: 4 additions & 0 deletions tests/integration/helpers.ts
Original file line number Diff line number Diff line change
@@ -224,3 +224,7 @@ export function validateThrowsForInvalidArguments(
export function expectDefined<T>(arg: T): asserts arg is Exclude<T, undefined> {
expect(arg).toBeDefined();
}

export function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
67 changes: 67 additions & 0 deletions tests/integration/tools/atlas-search/atlasSearchHelpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { ObjectId } from "bson";
import { defaultTestConfig, IntegrationTest, setupIntegrationTest } from "../../helpers.js";
import { waitClusterState, withProject } from "../atlas/atlasHelpers.js";

export function describeWithAtlasSearch(
name: string,
fn: (integration: IntegrationTest & { connectMcpClient: () => Promise<void> }) => void
): void {
const describeFn =
process.env.MDB_MCP_API_CLIENT_ID?.length && process.env.MDB_MCP_API_CLIENT_SECRET?.length
? describe
: describe.skip;

describeFn("atlas-search", () => {
const integration = setupIntegrationTest(() => ({
...defaultTestConfig,
apiClientId: process.env.MDB_MCP_API_CLIENT_ID,
apiClientSecret: process.env.MDB_MCP_API_CLIENT_SECRET,
}));

describe(name, () => {
withProject(integration, ({ getProjectId }) => {
const clusterName = `ClusterTest-${new ObjectId()}`;
beforeAll(async () => {
const projectId = getProjectId();

await integration.mcpClient().callTool({
name: "atlas-create-free-cluster",
arguments: {
projectId,
name: clusterName,
region: "US_EAST_1",
},
});

await waitClusterState(integration.mcpServer().session, projectId, clusterName, "IDLE");
await integration.mcpServer().session.apiClient.createProjectIpAccessList({
params: {
path: {
groupId: projectId,
},
},
body: [
{
comment: "MCP test",
cidrBlock: "0.0.0.0/0",
},
],
});
});

fn({
...integration,
connectMcpClient: async () => {
await integration.mcpClient().callTool({
name: "atlas-connect-cluster",
arguments: { projectId: getProjectId(), clusterName },
});

expect(integration.mcpServer().session.connectedAtlasCluster).toBeDefined();
expect(integration.mcpServer().session.serviceProvider).toBeDefined();
},
});
});
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { ObjectId } from "bson";
import { expectDefined, getResponseElements } from "../../../helpers.js";
import { describeWithAtlasSearch } from "../atlasSearchHelpers.js";

describeWithAtlasSearch("collectionIndexes tool", (integration) => {
it("can inspect search indexes", async () => {
await integration.connectMcpClient();

const provider = integration.mcpServer().session.serviceProvider;
expectDefined(provider);

const database = new ObjectId().toString();

await provider.mongoClient
.db(database)
.collection("coll1")
.insertMany([
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
{ name: "Charlie", age: 35 },
]);

const name = await provider.mongoClient
.db(database)
.collection("coll1")
.createSearchIndex({
name: "searchIndex1",
definition: {
mappings: {
dynamic: true,
},
analyzer: "lucene.danish",
},
});

const response = await integration.mcpClient().callTool({
name: "collection-indexes",
arguments: { database, collection: "coll1" },
});

const elements = getResponseElements(response.content);
expect(elements).toHaveLength(3);
expect(elements[0].text).toEqual(`Found 2 indexes in the collection "coll1":`);
expect(elements[1].text).toEqual('Name "_id_", definition: {"_id":1}');
expect(elements[2].text).toContain(`Search index name: "${name}"`);
expect(elements[2].text).toContain('"analyzer":"lucene.danish"');
});
});
17 changes: 0 additions & 17 deletions tests/integration/tools/atlas/accessLists.test.ts
Original file line number Diff line number Diff line change
@@ -22,23 +22,6 @@ describeWithAtlas("ip access lists", (integration) => {
values.push(ipInfo.currentIpv4Address);
});

afterAll(async () => {
const apiClient = integration.mcpServer().session.apiClient;

const projectId = getProjectId();

for (const value of values) {
await apiClient.deleteProjectIpAccessList({
params: {
path: {
groupId: projectId,
entryValue: value,
},
},
});
}
});

describe("atlas-create-access-list", () => {
it("should have correct metadata", async () => {
const { tools } = await integration.mcpClient().listTools();
89 changes: 73 additions & 16 deletions tests/integration/tools/atlas/atlasHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ObjectId } from "mongodb";
import { Group } from "../../../../src/common/atlas/openapi.js";
import { ApiClient } from "../../../../src/common/atlas/apiClient.js";
import { setupIntegrationTest, IntegrationTest, defaultTestConfig } from "../../helpers.js";
import { setupIntegrationTest, IntegrationTest, defaultTestConfig, sleep } from "../../helpers.js";
import { Session } from "../../../../src/session.js";

export type IntegrationTestFunction = (integration: IntegrationTest) => void;

export function describeWithAtlas(name: string, fn: IntegrationTestFunction) {
export function describeWithAtlas(name: string, fn: IntegrationTestFunction): void {
const testDefinition = () => {
const integration = setupIntegrationTest(() => ({
...defaultTestConfig,
@@ -21,7 +22,8 @@ export function describeWithAtlas(name: string, fn: IntegrationTestFunction) {
if (!process.env.MDB_MCP_API_CLIENT_ID?.length || !process.env.MDB_MCP_API_CLIENT_SECRET?.length) {
return describe.skip("atlas", testDefinition);
}
return describe("atlas", testDefinition);

describe("atlas", testDefinition);
}

interface ProjectTestArgs {
@@ -30,20 +32,40 @@ interface ProjectTestArgs {

type ProjectTestFunction = (args: ProjectTestArgs) => void;

export function withProject(integration: IntegrationTest, fn: ProjectTestFunction) {
return describe("project", () => {
export function withProject(integration: IntegrationTest, fn: ProjectTestFunction): void {
describe("with project", () => {
let projectId: string = "";
const projectName = `testProj-${new ObjectId()}`;

beforeAll(async () => {
const apiClient = integration.mcpServer().session.apiClient;

const group = await createProject(apiClient);
const group = await createProject(apiClient, projectName);
projectId = group.id || "";
});

afterAll(async () => {
const apiClient = integration.mcpServer().session.apiClient;

const clusters = await apiClient.listClusters({
params: {
path: {
groupId: projectId,
},
},
});

const deletePromises =
clusters?.results?.map((cluster) => {
if (cluster.name) {
return deleteAndWaitCluster(integration.mcpServer().session, projectId, cluster.name);
}

return Promise.resolve();
}) ?? [];

await Promise.all(deletePromises);

await apiClient.deleteProject({
params: {
path: {
@@ -53,12 +75,8 @@ export function withProject(integration: IntegrationTest, fn: ProjectTestFunctio
});
});

const args = {
fn({
getProjectId: () => projectId,
};

describe("with project", () => {
fn(args);
});
});
}
@@ -81,11 +99,7 @@ export function parseTable(text: string): Record<string, string>[] {
});
}

export const randomId = new ObjectId().toString();

async function createProject(apiClient: ApiClient): Promise<Group> {
const projectName: string = `testProj-` + randomId;

async function createProject(apiClient: ApiClient, projectName: string): Promise<Group> {
const orgs = await apiClient.listOrganizations();
if (!orgs?.results?.length || !orgs.results[0].id) {
throw new Error("No orgs found");
@@ -104,3 +118,46 @@ async function createProject(apiClient: ApiClient): Promise<Group> {

return group;
}

export async function waitClusterState(session: Session, projectId: string, clusterName: string, state: string) {
while (true) {
const cluster = await session.apiClient.getCluster({
params: {
path: {
groupId: projectId,
clusterName,
},
},
});
if (cluster?.stateName === state) {
return;
}
await sleep(1000);
}
}

async function deleteAndWaitCluster(session: Session, projectId: string, clusterName: string) {
await session.apiClient.deleteCluster({
params: {
path: {
groupId: projectId,
clusterName,
},
},
});
while (true) {
try {
await session.apiClient.getCluster({
params: {
path: {
groupId: projectId,
clusterName,
},
},
});
await sleep(1000);
} catch {
break;
}
}
}
61 changes: 3 additions & 58 deletions tests/integration/tools/atlas/clusters.test.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,11 @@
import { Session } from "../../../../src/session.js";
import { ObjectId } from "bson";
import { expectDefined } from "../../helpers.js";
import { describeWithAtlas, withProject, randomId } from "./atlasHelpers.js";
import { describeWithAtlas, withProject, waitClusterState } from "./atlasHelpers.js";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";

function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

async function deleteAndWaitCluster(session: Session, projectId: string, clusterName: string) {
await session.apiClient.deleteCluster({
params: {
path: {
groupId: projectId,
clusterName,
},
},
});
while (true) {
try {
await session.apiClient.getCluster({
params: {
path: {
groupId: projectId,
clusterName,
},
},
});
await sleep(1000);
} catch {
break;
}
}
}

async function waitClusterState(session: Session, projectId: string, clusterName: string, state: string) {
while (true) {
const cluster = await session.apiClient.getCluster({
params: {
path: {
groupId: projectId,
clusterName,
},
},
});
if (cluster?.stateName === state) {
return;
}
await sleep(1000);
}
}

describeWithAtlas("clusters", (integration) => {
withProject(integration, ({ getProjectId }) => {
const clusterName = "ClusterTest-" + randomId;

afterAll(async () => {
const projectId = getProjectId();

const session: Session = integration.mcpServer().session;

await deleteAndWaitCluster(session, projectId, clusterName);
});
const clusterName = `ClusterTest-${new ObjectId()}`;

describe("atlas-create-free-cluster", () => {
it("should have correct metadata", async () => {
21 changes: 3 additions & 18 deletions tests/integration/tools/atlas/dbUsers.test.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { Session } from "../../../../src/session.js";
import { describeWithAtlas, withProject, randomId } from "./atlasHelpers.js";
import { describeWithAtlas, withProject } from "./atlasHelpers.js";
import { expectDefined } from "../../helpers.js";
import { ObjectId } from "bson";

describeWithAtlas("db users", (integration) => {
const userName = "testuser-" + randomId;
const userName = `testuser-${new ObjectId()}`;
withProject(integration, ({ getProjectId }) => {
afterAll(async () => {
const projectId = getProjectId();

const session: Session = integration.mcpServer().session;
await session.apiClient.deleteDatabaseUser({
params: {
path: {
groupId: projectId,
username: userName,
databaseName: "admin",
},
},
});
});

describe("atlas-create-db-user", () => {
it("should have correct metadata", async () => {
const { tools } = await integration.mcpClient().listTools();
2 changes: 1 addition & 1 deletion tests/integration/tools/atlas/orgs.test.ts
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ describeWithAtlas("orgs", (integration) => {
expect(response.content).toHaveLength(1);
const data = parseTable(response.content[0].text as string);
expect(data).toHaveLength(1);
expect(data[0]["Organization Name"]).toEqual("MongoDB MCP Test");
expect(data[0]["Organization Name"]).toBeDefined();
});
});
});
4 changes: 1 addition & 3 deletions tests/integration/tools/atlas/projects.test.ts
Original file line number Diff line number Diff line change
@@ -3,10 +3,8 @@ import { ObjectId } from "mongodb";
import { parseTable, describeWithAtlas } from "./atlasHelpers.js";
import { expectDefined } from "../../helpers.js";

const randomId = new ObjectId().toString();

describeWithAtlas("projects", (integration) => {
const projName = "testProj-" + randomId;
const projName = `testProj-${new ObjectId()}`;

afterAll(async () => {
const session = integration.mcpServer().session;
114 changes: 114 additions & 0 deletions tests/integration/tools/mongodb/delete/dropIndex.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { describeWithMongoDB, validateAutoConnectBehavior } from "../mongodbHelpers.js";

import {
getResponseContent,
databaseCollectionParameters,
validateToolMetadata,
validateThrowsForInvalidArguments,
} from "../../../helpers.js";

describeWithMongoDB("dropIndex tool", (integration) => {
validateToolMetadata(integration, "drop-index", "Removes an index from a collection.", [
...databaseCollectionParameters,
{
name: "name",
type: "string",
description: "The name of the index to drop",
required: true,
},
]);

validateThrowsForInvalidArguments(integration, "drop-index", [
{},
{ collection: "bar", name: "_id_" },
{ database: "test", name: "_id_" },
{ collection: "bar", database: "test" },
{ collection: "bar", database: 123, name: "_id_" },
{ collection: [], database: "test", name: "_id_" },
{ collection: "bar", database: "test", name: {} },
]);

it("returns an error when dropping from non-existing collection", async () => {
await integration.connectMcpClient();
const response = await integration.mcpClient().callTool({
name: "drop-index",
arguments: {
database: integration.randomDbName(),
collection: "coll1",
name: "_id_",
},
});

const content = getResponseContent(response.content);
expect(content).toContain(
`Cannot drop index "_id_" because the namespace "${integration.randomDbName()}.coll1" does not exist.`
);
});

it("returns an error when dropping a non-existent index", async () => {
await integration.mongoClient().db(integration.randomDbName()).createCollection("coll1");

await integration.connectMcpClient();
const response = await integration.mcpClient().callTool({
name: "drop-index",
arguments: {
database: integration.randomDbName(),
collection: "coll1",
name: "non-existent-index",
},
});

const content = getResponseContent(response.content);
expect(content).toContain("index not found with name [non-existent-index]");
});

it("removes an existing index", async () => {
await integration.mongoClient().db(integration.randomDbName()).createCollection("coll1");
await integration
.mongoClient()
.db(integration.randomDbName())
.collection("coll1")
.createIndex({ a: 1 }, { name: "index-a" });

let indexes = await integration
.mongoClient()
.db(integration.randomDbName())
.collection("coll1")
.listIndexes()
.toArray();
expect(indexes).toHaveLength(2);
expect(indexes[0]).toHaveProperty("name", "_id_");
expect(indexes[1]).toHaveProperty("name", "index-a");

await integration.connectMcpClient();
const response = await integration.mcpClient().callTool({
name: "drop-index",
arguments: {
database: integration.randomDbName(),
collection: "coll1",
name: "index-a",
},
});
const content = getResponseContent(response.content);
expect(content).toContain(`Successfully dropped index "index-a" in "${integration.randomDbName()}.coll1"`);
indexes = await integration
.mongoClient()
.db(integration.randomDbName())
.collection("coll1")
.listIndexes()
.toArray();
expect(indexes).toHaveLength(1);
expect(indexes[0]).toHaveProperty("name", "_id_");
});

validateAutoConnectBehavior(integration, "drop-index", () => {
return {
args: {
database: integration.randomDbName(),
collection: "coll1",
name: "index-a",
},
expectedResponse: `Cannot drop index "_id_" because the namespace "${integration.randomDbName()}.coll1" does not exist.`,
};
});
});
4 changes: 1 addition & 3 deletions tests/integration/tools/mongodb/mongodbHelpers.ts
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ export function describeWithMongoDB(
fn: (integration: IntegrationTest & MongoDBIntegrationTest & { connectMcpClient: () => Promise<void> }) => void,
getUserConfig: (mdbIntegration: MongoDBIntegrationTest) => UserConfig = () => defaultTestConfig,
describeFn = describe
) {
): void {
describeFn(name, () => {
const mdbIntegration = setupMongoDBIntegrationTest();
const integration = setupIntegrationTest(() => ({
@@ -76,8 +76,6 @@ export function setupMongoDBIntegrationTest(): MongoDBIntegrationTest {
let dbsDir = path.join(tmpDir, "mongodb-runner", "dbs");
for (let i = 0; i < 10; i++) {
try {
// TODO: Fix this type once mongodb-runner is updated.
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
mongoCluster = await MongoCluster.start({
tmpDir: dbsDir,
logDir: path.join(tmpDir, "mongodb-runner", "logs"),