From 859c7bddb332c8361e9a3741f21123851e37a996 Mon Sep 17 00:00:00 2001 From: Manoj Pillay Date: Tue, 13 May 2025 15:45:06 -0700 Subject: [PATCH 1/7] Support for listing search indexes --- .../mongodb/read/collectionSearchIndexes.ts | 46 +++++++++++++++++++ src/tools/mongodb/tools.ts | 2 + .../read/collectionSearchIndexes.test.ts | 20 ++++++++ 3 files changed, 68 insertions(+) create mode 100644 src/tools/mongodb/read/collectionSearchIndexes.ts create mode 100644 tests/integration/tools/mongodb/read/collectionSearchIndexes.test.ts diff --git a/src/tools/mongodb/read/collectionSearchIndexes.ts b/src/tools/mongodb/read/collectionSearchIndexes.ts new file mode 100644 index 00000000..42cdd4c7 --- /dev/null +++ b/src/tools/mongodb/read/collectionSearchIndexes.ts @@ -0,0 +1,46 @@ +import {DbOperationArgs, MongoDBToolBase} from "../mongodbTool.js"; +import {CallToolResult} from "@modelcontextprotocol/sdk/types.js"; +import { ToolArgs, OperationType } from "../../tool.js"; +import {z} from "zod"; + +export const ListSearchIndexesArgs = { + indexName: z + .string() + .default('') + .optional() + .describe("The name of the index to return information about. Returns all indexes on collection if not provided."), +} + +export class CollectionSearchIndexesTool extends MongoDBToolBase { + protected name = "collection-search-indexes"; + protected description = "List one or all search indexes on a collection"; + protected argsShape = { + ...DbOperationArgs, + ...ListSearchIndexesArgs, + }; + + protected operationType: OperationType = "read"; + + protected async execute({ database, collection, indexName }: ToolArgs): Promise { + const provider = await this.ensureConnected(); + const indexes = await provider + .getSearchIndexes(database, collection, indexName); + + return { + content: [ + { + text: indexName + ? `Found ${indexes.length} search indexes in the collection "${collection}" with name "${indexName}":` + : `Found ${indexes.length} search indexes in the collection "${collection}"`, + type: "text", + }, + ...(indexes.map((indexDefinition) => { + return { + text: `Name "${indexDefinition.name}", definition: ${JSON.stringify(indexDefinition.latestDefinition)}`, + type: "text", + }; + }) as { text: string; type: "text" }[]), + ], + }; + } +} \ No newline at end of file diff --git a/src/tools/mongodb/tools.ts b/src/tools/mongodb/tools.ts index d64d53ea..9589efa6 100644 --- a/src/tools/mongodb/tools.ts +++ b/src/tools/mongodb/tools.ts @@ -18,12 +18,14 @@ 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 {CollectionSearchIndexesTool} from "./read/collectionSearchIndexes.js"; export const MongoDbTools = [ ConnectTool, ListCollectionsTool, ListDatabasesTool, CollectionIndexesTool, + CollectionSearchIndexesTool, CreateIndexTool, CollectionSchemaTool, FindTool, diff --git a/tests/integration/tools/mongodb/read/collectionSearchIndexes.test.ts b/tests/integration/tools/mongodb/read/collectionSearchIndexes.test.ts new file mode 100644 index 00000000..e3ea8156 --- /dev/null +++ b/tests/integration/tools/mongodb/read/collectionSearchIndexes.test.ts @@ -0,0 +1,20 @@ +import { describeWithMongoDB } from "../mongodbHelpers.js"; + +import { + databaseCollectionParameters, + databaseCollectionInvalidArgs, + validateThrowsForInvalidArguments, + validateToolMetadata, +} from "../../../helpers.js"; + +describeWithMongoDB("collectionSearchIndexes tool", (integration) => { + validateToolMetadata( + integration, + "collection-search-indexes", + "Describe the search indexes for a collection", + databaseCollectionParameters + ); + validateThrowsForInvalidArguments(integration, "collection-search-indexes", databaseCollectionInvalidArgs); + + // Real tests to be added once search indexes are supported in test env. +}); \ No newline at end of file From 0ba5de8b58306041f9a65d2c9ff1a39725ed9d57 Mon Sep 17 00:00:00 2001 From: Manoj Pillay <113068853+manoj-pillay-10gen@users.noreply.github.com> Date: Tue, 13 May 2025 15:49:55 -0700 Subject: [PATCH 2/7] Update src/tools/mongodb/read/collectionSearchIndexes.ts Removing space as suggested by copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/tools/mongodb/read/collectionSearchIndexes.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/mongodb/read/collectionSearchIndexes.ts b/src/tools/mongodb/read/collectionSearchIndexes.ts index 42cdd4c7..7f3a6880 100644 --- a/src/tools/mongodb/read/collectionSearchIndexes.ts +++ b/src/tools/mongodb/read/collectionSearchIndexes.ts @@ -30,8 +30,8 @@ export class CollectionSearchIndexesTool extends MongoDBToolBase { content: [ { text: indexName - ? `Found ${indexes.length} search indexes in the collection "${collection}" with name "${indexName}":` - : `Found ${indexes.length} search indexes in the collection "${collection}"`, + ? `Found ${indexes.length} search indexes in the collection "${collection}" with name "${indexName}":` + : `Found ${indexes.length} search indexes in the collection "${collection}"`, type: "text", }, ...(indexes.map((indexDefinition) => { From b40882d7de6a1fb24a6072889612d73c8771d311 Mon Sep 17 00:00:00 2001 From: Manoj Pillay Date: Tue, 13 May 2025 15:55:24 -0700 Subject: [PATCH 3/7] Prettier reformat --- .../mongodb/read/collectionSearchIndexes.ts | 81 ++++++++++--------- src/tools/mongodb/tools.ts | 2 +- .../read/collectionSearchIndexes.test.ts | 10 +-- 3 files changed, 49 insertions(+), 44 deletions(-) diff --git a/src/tools/mongodb/read/collectionSearchIndexes.ts b/src/tools/mongodb/read/collectionSearchIndexes.ts index 7f3a6880..f462a47d 100644 --- a/src/tools/mongodb/read/collectionSearchIndexes.ts +++ b/src/tools/mongodb/read/collectionSearchIndexes.ts @@ -1,46 +1,51 @@ -import {DbOperationArgs, MongoDBToolBase} from "../mongodbTool.js"; -import {CallToolResult} from "@modelcontextprotocol/sdk/types.js"; +import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js"; +import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { ToolArgs, OperationType } from "../../tool.js"; -import {z} from "zod"; +import { z } from "zod"; export const ListSearchIndexesArgs = { - indexName: z - .string() - .default('') - .optional() - .describe("The name of the index to return information about. Returns all indexes on collection if not provided."), -} + indexName: z + .string() + .default("") + .optional() + .describe( + "The name of the index to return information about. Returns all indexes on collection if not provided." + ), +}; export class CollectionSearchIndexesTool extends MongoDBToolBase { - protected name = "collection-search-indexes"; - protected description = "List one or all search indexes on a collection"; - protected argsShape = { - ...DbOperationArgs, - ...ListSearchIndexesArgs, - }; + protected name = "collection-search-indexes"; + protected description = "List one or all search indexes on a collection"; + protected argsShape = { + ...DbOperationArgs, + ...ListSearchIndexesArgs, + }; - protected operationType: OperationType = "read"; + protected operationType: OperationType = "read"; - protected async execute({ database, collection, indexName }: ToolArgs): Promise { - const provider = await this.ensureConnected(); - const indexes = await provider - .getSearchIndexes(database, collection, indexName); + protected async execute({ + database, + collection, + indexName, + }: ToolArgs): Promise { + const provider = await this.ensureConnected(); + const indexes = await provider.getSearchIndexes(database, collection, indexName); - return { - content: [ - { - text: indexName - ? `Found ${indexes.length} search indexes in the collection "${collection}" with name "${indexName}":` - : `Found ${indexes.length} search indexes in the collection "${collection}"`, - type: "text", - }, - ...(indexes.map((indexDefinition) => { - return { - text: `Name "${indexDefinition.name}", definition: ${JSON.stringify(indexDefinition.latestDefinition)}`, - type: "text", - }; - }) as { text: string; type: "text" }[]), - ], - }; - } -} \ No newline at end of file + return { + content: [ + { + text: indexName + ? `Found ${indexes.length} search indexes in the collection "${collection}" with name "${indexName}":` + : `Found ${indexes.length} search indexes in the collection "${collection}"`, + type: "text", + }, + ...(indexes.map((indexDefinition) => { + return { + text: `Name "${indexDefinition.name}", definition: ${JSON.stringify(indexDefinition.latestDefinition)}`, + type: "text", + }; + }) as { text: string; type: "text" }[]), + ], + }; + } +} diff --git a/src/tools/mongodb/tools.ts b/src/tools/mongodb/tools.ts index 9589efa6..cf1e52d3 100644 --- a/src/tools/mongodb/tools.ts +++ b/src/tools/mongodb/tools.ts @@ -18,7 +18,7 @@ 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 {CollectionSearchIndexesTool} from "./read/collectionSearchIndexes.js"; +import { CollectionSearchIndexesTool } from "./read/collectionSearchIndexes.js"; export const MongoDbTools = [ ConnectTool, diff --git a/tests/integration/tools/mongodb/read/collectionSearchIndexes.test.ts b/tests/integration/tools/mongodb/read/collectionSearchIndexes.test.ts index e3ea8156..37ca7469 100644 --- a/tests/integration/tools/mongodb/read/collectionSearchIndexes.test.ts +++ b/tests/integration/tools/mongodb/read/collectionSearchIndexes.test.ts @@ -1,10 +1,10 @@ import { describeWithMongoDB } from "../mongodbHelpers.js"; import { - databaseCollectionParameters, - databaseCollectionInvalidArgs, - validateThrowsForInvalidArguments, - validateToolMetadata, + databaseCollectionParameters, + databaseCollectionInvalidArgs, + validateThrowsForInvalidArguments, + validateToolMetadata, } from "../../../helpers.js"; describeWithMongoDB("collectionSearchIndexes tool", (integration) => { @@ -17,4 +17,4 @@ describeWithMongoDB("collectionSearchIndexes tool", (integration) => { validateThrowsForInvalidArguments(integration, "collection-search-indexes", databaseCollectionInvalidArgs); // Real tests to be added once search indexes are supported in test env. -}); \ No newline at end of file +}); From 5be970c270de570cd5d9deffcf97160ac041a9b4 Mon Sep 17 00:00:00 2001 From: Manoj Pillay Date: Tue, 13 May 2025 16:03:49 -0700 Subject: [PATCH 4/7] Fixed extra space. --- src/tools/mongodb/read/collectionSearchIndexes.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/mongodb/read/collectionSearchIndexes.ts b/src/tools/mongodb/read/collectionSearchIndexes.ts index f462a47d..5cfc720d 100644 --- a/src/tools/mongodb/read/collectionSearchIndexes.ts +++ b/src/tools/mongodb/read/collectionSearchIndexes.ts @@ -35,8 +35,8 @@ export class CollectionSearchIndexesTool extends MongoDBToolBase { content: [ { text: indexName - ? `Found ${indexes.length} search indexes in the collection "${collection}" with name "${indexName}":` - : `Found ${indexes.length} search indexes in the collection "${collection}"`, + ? `Found ${indexes.length} search indexes in the collection "${collection}" with name "${indexName}":` + : `Found ${indexes.length} search indexes in the collection "${collection}"`, type: "text", }, ...(indexes.map((indexDefinition) => { From 0192f61e8cbfb7e983304507cf1ba937106d5b24 Mon Sep 17 00:00:00 2001 From: Manoj Pillay Date: Tue, 13 May 2025 16:08:18 -0700 Subject: [PATCH 5/7] Matching tool description with description of API --- src/tools/mongodb/read/collectionSearchIndexes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/mongodb/read/collectionSearchIndexes.ts b/src/tools/mongodb/read/collectionSearchIndexes.ts index 5cfc720d..a2ac7f2c 100644 --- a/src/tools/mongodb/read/collectionSearchIndexes.ts +++ b/src/tools/mongodb/read/collectionSearchIndexes.ts @@ -15,7 +15,7 @@ export const ListSearchIndexesArgs = { export class CollectionSearchIndexesTool extends MongoDBToolBase { protected name = "collection-search-indexes"; - protected description = "List one or all search indexes on a collection"; + protected description = "Describe the search indexes for a collection"; protected argsShape = { ...DbOperationArgs, ...ListSearchIndexesArgs, From c0f6676f06adfdb650f8afb6d6628e09bd3ca22a Mon Sep 17 00:00:00 2001 From: Manoj Pillay Date: Wed, 14 May 2025 11:37:35 -0700 Subject: [PATCH 6/7] Addressed feedback and fixed test --- src/tools/mongodb/read/collectionSearchIndexes.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/tools/mongodb/read/collectionSearchIndexes.ts b/src/tools/mongodb/read/collectionSearchIndexes.ts index a2ac7f2c..d66f975b 100644 --- a/src/tools/mongodb/read/collectionSearchIndexes.ts +++ b/src/tools/mongodb/read/collectionSearchIndexes.ts @@ -12,6 +12,10 @@ export const ListSearchIndexesArgs = { "The name of the index to return information about. Returns all indexes on collection if not provided." ), }; +export interface SearchIndex { + name: string; + latestDefinition: Record; +} export class CollectionSearchIndexesTool extends MongoDBToolBase { protected name = "collection-search-indexes"; @@ -29,7 +33,13 @@ export class CollectionSearchIndexesTool extends MongoDBToolBase { indexName, }: ToolArgs): Promise { const provider = await this.ensureConnected(); - const indexes = await provider.getSearchIndexes(database, collection, indexName); + + const indexes: SearchIndex[] = (await provider.getSearchIndexes(database, collection, indexName)).map( + (doc) => ({ + name: doc.name, + latestDefinition: doc.latestDefinition, + }) + ); return { content: [ @@ -41,7 +51,7 @@ export class CollectionSearchIndexesTool extends MongoDBToolBase { }, ...(indexes.map((indexDefinition) => { return { - text: `Name "${indexDefinition.name}", definition: ${JSON.stringify(indexDefinition.latestDefinition)}`, + text: `\nName: "${indexDefinition.name}"\nDefinition: ${JSON.stringify(indexDefinition.latestDefinition, null, 2)}\n`, type: "text", }; }) as { text: string; type: "text" }[]), From 10091a112092f69e4c45ebfb02fb98fba24b4a23 Mon Sep 17 00:00:00 2001 From: Manoj Pillay Date: Wed, 14 May 2025 12:08:32 -0700 Subject: [PATCH 7/7] Fix lint issues. --- src/tools/mongodb/read/collectionSearchIndexes.ts | 12 ++++++------ tests/integration/helpers.ts | 11 +++++++++++ .../read/collectionSearchIndexes.test.ts | 7 +++---- 3 files changed, 20 insertions(+), 10 deletions(-) rename tests/integration/tools/{mongodb => atlas-search}/read/collectionSearchIndexes.test.ts (77%) diff --git a/src/tools/mongodb/read/collectionSearchIndexes.ts b/src/tools/mongodb/read/collectionSearchIndexes.ts index d66f975b..b6a3665e 100644 --- a/src/tools/mongodb/read/collectionSearchIndexes.ts +++ b/src/tools/mongodb/read/collectionSearchIndexes.ts @@ -34,12 +34,12 @@ export class CollectionSearchIndexesTool extends MongoDBToolBase { }: ToolArgs): Promise { const provider = await this.ensureConnected(); - const indexes: SearchIndex[] = (await provider.getSearchIndexes(database, collection, indexName)).map( - (doc) => ({ - name: doc.name, - latestDefinition: doc.latestDefinition, - }) - ); + const indexes: SearchIndex[] = ( + (await provider.getSearchIndexes(database, collection, indexName)) as SearchIndex[] + ).map((doc) => ({ + name: doc.name, + latestDefinition: doc.latestDefinition, + })); return { content: [ diff --git a/tests/integration/helpers.ts b/tests/integration/helpers.ts index 9d529376..179f75bb 100644 --- a/tests/integration/helpers.ts +++ b/tests/integration/helpers.ts @@ -182,6 +182,17 @@ export const databaseCollectionParameters: ParameterInfo[] = [ { name: "collection", type: "string", description: "Collection name", required: true }, ]; +export const collectionWithSearchIndexParameters: ParameterInfo[] = [ + ...databaseCollectionParameters, + { + name: "indexName", + type: "string", + description: + "The name of the index to return information about. Returns all indexes on collection if not provided.", + required: false, + }, +]; + export const databaseCollectionInvalidArgs = [ {}, { database: "test" }, diff --git a/tests/integration/tools/mongodb/read/collectionSearchIndexes.test.ts b/tests/integration/tools/atlas-search/read/collectionSearchIndexes.test.ts similarity index 77% rename from tests/integration/tools/mongodb/read/collectionSearchIndexes.test.ts rename to tests/integration/tools/atlas-search/read/collectionSearchIndexes.test.ts index 37ca7469..1a422e59 100644 --- a/tests/integration/tools/mongodb/read/collectionSearchIndexes.test.ts +++ b/tests/integration/tools/atlas-search/read/collectionSearchIndexes.test.ts @@ -1,10 +1,9 @@ -import { describeWithMongoDB } from "../mongodbHelpers.js"; - +import { describeWithMongoDB } from "../../mongodb/mongodbHelpers.js"; import { - databaseCollectionParameters, databaseCollectionInvalidArgs, validateThrowsForInvalidArguments, validateToolMetadata, + collectionWithSearchIndexParameters, } from "../../../helpers.js"; describeWithMongoDB("collectionSearchIndexes tool", (integration) => { @@ -12,7 +11,7 @@ describeWithMongoDB("collectionSearchIndexes tool", (integration) => { integration, "collection-search-indexes", "Describe the search indexes for a collection", - databaseCollectionParameters + collectionWithSearchIndexParameters ); validateThrowsForInvalidArguments(integration, "collection-search-indexes", databaseCollectionInvalidArgs);