-
Notifications
You must be signed in to change notification settings - Fork 44
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
Changes from all commits
4e68c4a
49a75e8
49ac3d8
66102db
6b4371d
9c2c185
7ecba1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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}"`, | ||
type: "text", | ||
}, | ||
], | ||
}; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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"), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be better to link the docs page instead of saying There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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/ There was a problem hiding this comment. Choose a reason for hiding this commentThe 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", | ||
|
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, { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
|
||
analyzer, | ||
mappings, | ||
}); | ||
|
||
return { | ||
content: [ | ||
{ | ||
text: `Successfully updated search index "${name}" on collection "${collection}" in database "${database}"`, | ||
type: "text", | ||
}, | ||
], | ||
}; | ||
} | ||
} |
There was a problem hiding this comment.
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.