Skip to content

feat: create and update Search Index #244

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

Merged
merged 7 commits into from
May 14, 2025
Merged
Show file tree
Hide file tree
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
47 changes: 47 additions & 0 deletions src/tools/mongodb/create/createSearchIndex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { DbOperationArgs, MongoDBToolBase, SearchIndexArgs } from "../mongodbTool.js";
import { OperationType, ToolArgs } from "../../tool.js";

const SEARCH_INDEX_TYPE = "search";

export class CreateSearchIndexTool extends MongoDBToolBase {
protected name = "create-search-index";
protected description = "Create an Atlas Search index for a collection";
protected argsShape = {
...DbOperationArgs,
name: SearchIndexArgs.name,
analyzer: SearchIndexArgs.analyzer,
mappings: SearchIndexArgs.mappings,
};

protected operationType: OperationType = "create";

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

return {
content: [
{
text: `Created the search index "${indexes[0]}" on collection "${collection}" in database "${database}"`,
Copy link
Preview

Copilot AI May 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before using indexes[0] in the success message, add a runtime check to ensure that the indexes array is not empty. This change will help prevent potential runtime errors if index creation unexpectedly fails.

Copilot uses AI. Check for mistakes.

type: "text",
},
],
};
}
}
51 changes: 51 additions & 0 deletions src/tools/mongodb/mongodbTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,57 @@ export const DbOperationArgs = {
collection: z.string().describe("Collection name"),
};

export const SearchIndexArgs = {
name: z.string().describe("The name of the index"),
Copy link
Collaborator Author

@edgarw19 edgarw19 May 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This currently includes a few common arguments as a starting point.

It excludes custom analyzers/synonyms/storedsource since but we can add those if needed

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."
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be better to link the docs page instead of saying defined in the Atlas UI.
https://www.mongodb.com/docs/atlas/atlas-search/analyzers/language/

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mihirmpatil consider that those are used to infer user generic queries. Best to make relevant context clear for machines and users.

),
mappings: z
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vector search index definition is different compared to this. See https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-type/
I think we'll be better off with a new type for vector search index definition.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this PR is specific to search indexes. I've opened a vector index PR here #252

.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",
"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."),
})
.describe("Document describing the index to create."),
};

export enum VectorFieldType {
VECTOR = "vector",
FILTER = "filter",
Expand Down
4 changes: 4 additions & 0 deletions src/tools/mongodb/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ 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 { UpdateSearchIndexTool } from "./update/updateSearchIndex.js";
import { CreateVectorIndexTool } from "./create/createVectorIndex.js";
import { UpdateVectorIndexTool } from "./update/updateVectorIndex.js";
import { CollectionSearchIndexesTool } from "./read/collectionSearchIndexes.js";
Expand Down Expand Up @@ -45,6 +47,8 @@ export const MongoDbTools = [
ExplainTool,
CreateCollectionTool,
LogsTool,
CreateSearchIndexTool,
UpdateSearchIndexTool,
CreateVectorIndexTool,
UpdateVectorIndexTool,
DropSearchIndexTool,
Expand Down
41 changes: 41 additions & 0 deletions src/tools/mongodb/update/updateSearchIndex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { DbOperationArgs, MongoDBToolBase, SearchIndexArgs } from "../mongodbTool.js";
import { OperationType, ToolArgs } from "../../tool.js";

export class UpdateSearchIndexTool extends MongoDBToolBase {
protected name = "update-search-index";
protected description = "Updates an Atlas Search index for a collection";
protected argsShape = {
...DbOperationArgs,
name: SearchIndexArgs.name,
analyzer: SearchIndexArgs.analyzer,
mappings: SearchIndexArgs.mappings,
};

protected operationType: OperationType = "update";

protected async execute({
database,
collection,
name,
analyzer,
mappings,
}: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
const provider = await this.ensureConnected();
// @ts-expect-error: Interface expects a SearchIndexDefinition. However,
// passing analyzer/mappings at the root for the definition is necessary for the call to succeed.
await provider.updateSearchIndex(database, collection, name, {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the index does not exist, MCP inspector shows a descriptive error message

"Error running update-search-index: Search index sample_mflix.comments.test3 cannot be found"

analyzer,
mappings,
});

return {
content: [
{
text: `Successfully updated search index "${name}" on collection "${collection}" in database "${database}"`,
type: "text",
},
],
};
}
}
Loading