-
Notifications
You must be signed in to change notification settings - Fork 139
feat: add ability to create vector search indexes MCP-234 MCP-243 #621
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
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
503a4bc
feat: add ability to create vector search indexes
nirinchev 0b9df0d
fix tests
nirinchev 3c59376
tweak create index args to be compatible with clients
nirinchev 69aa6d0
add tests
nirinchev 88acf38
add primitive feature flagging
nirinchev 428d373
fix test
nirinchev f934235
simplify the args definition
nirinchev 6231b28
fix accuracy tests
nirinchev 9207f8b
Merge branch 'main' into ni/create-vector-index
nirinchev 2d3b74e
fix drop index accuracy test
nirinchev 75092a8
apply copilot suggestion
nirinchev e627258
add vector search detection and a more graceful error message
nirinchev d887fbd
fix tests
nirinchev d86bd88
Merge branch 'main' into ni/create-vector-index
nirinchev afde113
address PR comments
nirinchev 60cf24d
add a hint to the llm that the vector may take a while to build
nirinchev 5de8c7e
fix tests
nirinchev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,158 @@ | ||
import { z } from "zod"; | ||
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; | ||
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js"; | ||
import type { ToolArgs, OperationType } from "../../tool.js"; | ||
import type { ToolCategory } from "../../tool.js"; | ||
import { type ToolArgs, type OperationType, FeatureFlags } from "../../tool.js"; | ||
import type { IndexDirection } from "mongodb"; | ||
|
||
export class CreateIndexTool extends MongoDBToolBase { | ||
private vectorSearchIndexDefinition = z.object({ | ||
type: z.literal("vectorSearch"), | ||
fields: z | ||
.array( | ||
z.discriminatedUnion("type", [ | ||
z | ||
.object({ | ||
type: z.literal("filter"), | ||
path: z | ||
.string() | ||
.describe( | ||
"Name of the field to index. For nested fields, use dot notation to specify path to embedded fields" | ||
), | ||
}) | ||
.strict() | ||
.describe("Definition for a field that will be used for pre-filtering results."), | ||
z | ||
.object({ | ||
type: z.literal("vector"), | ||
path: z | ||
.string() | ||
.describe( | ||
"Name of the field to index. For nested fields, use dot notation to specify path to embedded fields" | ||
), | ||
numDimensions: z | ||
.number() | ||
.min(1) | ||
.max(8192) | ||
.default(this.config.vectorSearchDimensions) | ||
.describe( | ||
"Number of vector dimensions that MongoDB Vector Search enforces at index-time and query-time" | ||
), | ||
similarity: z | ||
.enum(["cosine", "euclidean", "dotProduct"]) | ||
.default(this.config.vectorSearchSimilarityFunction) | ||
.describe( | ||
"Vector similarity function to use to search for top K-nearest neighbors. You can set this field only for vector-type fields." | ||
), | ||
quantization: z | ||
.enum(["none", "scalar", "binary"]) | ||
.optional() | ||
.default("none") | ||
.describe( | ||
"Type of automatic vector quantization for your vectors. Use this setting only if your embeddings are float or double vectors." | ||
), | ||
}) | ||
.strict() | ||
.describe("Definition for a field that contains vector embeddings."), | ||
]) | ||
) | ||
.nonempty() | ||
.refine((fields) => fields.some((f) => f.type === "vector"), { | ||
message: "At least one vector field must be defined", | ||
}) | ||
.describe( | ||
"Definitions for the vector and filter fields to index, one definition per document. You must specify `vector` for fields that contain vector embeddings and `filter` for additional fields to filter on. At least one vector-type field definition is required." | ||
), | ||
}); | ||
|
||
public name = "create-index"; | ||
protected description = "Create an index for a collection"; | ||
protected argsShape = { | ||
...DbOperationArgs, | ||
keys: z.object({}).catchall(z.custom<IndexDirection>()).describe("The index definition"), | ||
name: z.string().optional().describe("The name of the index"), | ||
definition: z | ||
.array( | ||
z.discriminatedUnion("type", [ | ||
z.object({ | ||
type: z.literal("classic"), | ||
keys: z.object({}).catchall(z.custom<IndexDirection>()).describe("The index definition"), | ||
}), | ||
...(this.isFeatureFlagEnabled(FeatureFlags.VectorSearch) ? [this.vectorSearchIndexDefinition] : []), | ||
]) | ||
) | ||
.describe( | ||
"The index definition. Use 'classic' for standard indexes and 'vectorSearch' for vector search indexes" | ||
), | ||
}; | ||
|
||
public operationType: OperationType = "create"; | ||
|
||
protected async execute({ | ||
database, | ||
collection, | ||
keys, | ||
name, | ||
definition: definitions, | ||
}: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> { | ||
const provider = await this.ensureConnected(); | ||
const indexes = await provider.createIndexes(database, collection, [ | ||
{ | ||
key: keys, | ||
name, | ||
}, | ||
]); | ||
let indexes: string[] = []; | ||
const definition = definitions[0]; | ||
if (!definition) { | ||
throw new Error("Index definition not provided. Expected one of the following: `classic`, `vectorSearch`"); | ||
} | ||
nirinchev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
let responseClarification = ""; | ||
|
||
switch (definition.type) { | ||
case "classic": | ||
indexes = await provider.createIndexes(database, collection, [ | ||
{ | ||
key: definition.keys, | ||
name, | ||
}, | ||
]); | ||
break; | ||
case "vectorSearch": | ||
{ | ||
const isVectorSearchSupported = await this.session.isSearchSupported(); | ||
if (!isVectorSearchSupported) { | ||
// TODO: remove hacky casts once we merge the local dev tools | ||
const isLocalAtlasAvailable = | ||
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. We are checking if a tool exists in a few places already in other places, maybe we can extract this to a function and refactor? |
||
(this.server?.tools.filter((t) => t.category === ("atlas-local" as unknown as ToolCategory)) | ||
.length ?? 0) > 0; | ||
|
||
const CTA = isLocalAtlasAvailable ? "`atlas-local` tools" : "Atlas CLI"; | ||
himanshusinghs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return { | ||
content: [ | ||
{ | ||
text: `The connected MongoDB deployment does not support vector search indexes. Either connect to a MongoDB Atlas cluster or use the ${CTA} to create and manage a local Atlas deployment.`, | ||
type: "text", | ||
}, | ||
], | ||
isError: true, | ||
}; | ||
} | ||
|
||
indexes = await provider.createSearchIndexes(database, collection, [ | ||
{ | ||
name, | ||
definition: { | ||
fields: definition.fields, | ||
}, | ||
type: "vectorSearch", | ||
}, | ||
]); | ||
|
||
responseClarification = | ||
" Since this is a vector search index, it may take a while for the index to build. Use the `list-indexes` tool to check the index status."; | ||
} | ||
|
||
break; | ||
} | ||
|
||
return { | ||
content: [ | ||
{ | ||
text: `Created the index "${indexes[0]}" on collection "${collection}" in database "${database}"`, | ||
text: `Created the index "${indexes[0]}" on collection "${collection}" in database "${database}".${responseClarification}`, | ||
type: "text", | ||
}, | ||
], | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.