|
| 1 | +import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; |
| 2 | +import type { Document } from "mongodb"; |
| 3 | +import type { ToolArgs, OperationType } from "../../tool.js"; |
| 4 | +import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js"; |
| 5 | +import { formatUntrustedData } from "../../tool.js"; |
| 6 | + |
| 7 | +export class ListSearchIndexesTool extends MongoDBToolBase { |
| 8 | + public name = "list-search-indexes"; |
| 9 | + protected description = "Describes the search and vector search indexes for a collection"; |
| 10 | + protected argsShape = DbOperationArgs; |
| 11 | + public operationType: OperationType = "metadata"; |
| 12 | + |
| 13 | + protected async execute({ database, collection }: ToolArgs<typeof DbOperationArgs>): Promise<CallToolResult> { |
| 14 | + const provider = await this.ensureConnected(); |
| 15 | + const indexes: Document[] = await provider.getSearchIndexes(database, collection); |
| 16 | + const trimmedIndexDefinitions = this.pickRelevantInformation(indexes); |
| 17 | + |
| 18 | + if (trimmedIndexDefinitions.length > 0) { |
| 19 | + return { |
| 20 | + content: formatUntrustedData( |
| 21 | + `Found ${trimmedIndexDefinitions.length} search and vector search indexes in ${database}.${collection}`, |
| 22 | + indexes.map((index) => JSON.stringify(index)).join("\n") |
| 23 | + ), |
| 24 | + }; |
| 25 | + } else { |
| 26 | + return { |
| 27 | + content: formatUntrustedData( |
| 28 | + `There are no search or vector search indexes in ${database}.${collection}` |
| 29 | + ), |
| 30 | + }; |
| 31 | + } |
| 32 | + } |
| 33 | + |
| 34 | + /** |
| 35 | + * Atlas Search index status contains a lot of information that is not relevant for the agent at this stage. |
| 36 | + * Like for example, the status on each of the dedicated nodes. We only care about the main status, if it's |
| 37 | + * queryable and the index name. We are also picking the index definition as it can be used by the agent to |
| 38 | + * understand which fields are available for searching. |
| 39 | + **/ |
| 40 | + protected pickRelevantInformation(indexes: Document[]): Document[] { |
| 41 | + return indexes.map((index) => ({ |
| 42 | + name: index["name"] ?? "default", |
| 43 | + type: index["type"] ?? "UNKNOWN", |
| 44 | + status: index["status"] ?? "UNKNOWN", |
| 45 | + queryable: index["queryable"] ?? false, |
| 46 | + latestDefinition: index["latestDefinition"], |
| 47 | + })); |
| 48 | + } |
| 49 | + |
| 50 | + protected handleError(): Promise<CallToolResult> | CallToolResult { |
| 51 | + return { |
| 52 | + content: [ |
| 53 | + { |
| 54 | + text: "This MongoDB cluster does not support Search Indexes. Make sure you are using an Atlas Cluster, either remotely in Atlas or using the Atlas Local image, or your cluster supports MongoDB Search.", |
| 55 | + type: "text", |
| 56 | + }, |
| 57 | + ], |
| 58 | + }; |
| 59 | + } |
| 60 | +} |
0 commit comments