Skip to content

Commit 632680d

Browse files
committed
feat: add support for managing search indexes
1 parent 2183ddb commit 632680d

File tree

4 files changed

+154
-17
lines changed

4 files changed

+154
-17
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { z } from "zod";
2+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3+
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
4+
import { ToolArgs, OperationType } from "../../tool.js";
5+
import { IndexDirection } from "mongodb";
6+
7+
export class CreateSearchIndexTool extends MongoDBToolBase {
8+
protected name = "create-search-index";
9+
protected description = "Create an Atlas Search index for a collection";
10+
protected argsShape = {
11+
...DbOperationArgs,
12+
name: z.string().optional().describe("The name of the index"),
13+
type: z.enum(["search", "vectorSearch"]).optional().default("search").describe("The type of the index"),
14+
analyzer: z
15+
.string()
16+
.optional()
17+
.default("lucene.standard")
18+
.describe(
19+
"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."
20+
),
21+
mappings: z.object({
22+
dynamic: z
23+
.boolean()
24+
.optional()
25+
.default(false)
26+
.describe(
27+
"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."
28+
),
29+
fields: z
30+
.record(
31+
z.string().describe("The field name"),
32+
z
33+
.object({
34+
type: z
35+
.enum([
36+
"autocomplete",
37+
"boolean",
38+
"date",
39+
"document",
40+
"embeddedDocuments",
41+
"geo",
42+
"knnVector",
43+
"number",
44+
"objectId",
45+
"string",
46+
"token",
47+
"uuid",
48+
])
49+
.describe("The field type"),
50+
})
51+
.passthrough()
52+
53+
.describe(
54+
"The field index definition. It must contain the field type, as well as any additional options for that field type."
55+
)
56+
)
57+
.optional()
58+
.describe("The field mapping definitions. If `dynamic` is set to false, this is required."),
59+
}),
60+
};
61+
62+
protected operationType: OperationType = "create";
63+
64+
protected async execute({
65+
database,
66+
collection,
67+
name,
68+
type,
69+
analyzer,
70+
mappings,
71+
}: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
72+
const provider = await this.ensureConnected();
73+
const indexes = await provider.createSearchIndexes(database, collection, [
74+
{
75+
name,
76+
type,
77+
definition: {
78+
analyzer,
79+
mappings,
80+
},
81+
},
82+
]);
83+
84+
return {
85+
content: [
86+
{
87+
text: `Created the index "${indexes[0]}" on collection "${collection}" in database "${database}"`,
88+
type: "text",
89+
},
90+
],
91+
};
92+
}
93+
}

src/tools/mongodb/delete/dropIndex.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2+
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
3+
import { ToolArgs, OperationType } from "../../tool.js";
4+
import { z } from "zod";
5+
6+
export class DropIndexTool extends MongoDBToolBase {
7+
protected name = "drop-index";
8+
protected description = "Removes an index from a collection.";
9+
protected argsShape = {
10+
...DbOperationArgs,
11+
name: z.string().describe("The name of the index to drop"),
12+
};
13+
protected operationType: OperationType = "delete";
14+
15+
protected async execute({ database, collection, name }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
16+
const provider = await this.ensureConnected();
17+
await provider.mongoClient.db(database).collection(collection).dropIndex(name);
18+
await provider.dropSearchIndex(database, collection, name);
19+
20+
return {
21+
content: [
22+
{
23+
text: `Successfully dropped index "${name}" in "${database}.${collection}"`,
24+
type: "text",
25+
},
26+
],
27+
};
28+
}
29+
}

src/tools/mongodb/read/collectionIndexes.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,26 @@ export class CollectionIndexesTool extends MongoDBToolBase {
1111
protected async execute({ database, collection }: ToolArgs<typeof DbOperationArgs>): Promise<CallToolResult> {
1212
const provider = await this.ensureConnected();
1313
const indexes = await provider.getIndexes(database, collection);
14+
const searchIndexes = await provider.getSearchIndexes(database, collection);
1415

1516
return {
1617
content: [
1718
{
1819
text: `Found ${indexes.length} indexes in the collection "${collection}":`,
1920
type: "text",
2021
},
21-
...(indexes.map((indexDefinition) => {
22+
...indexes.map((indexDefinition) => {
2223
return {
2324
text: `Name "${indexDefinition.name}", definition: ${JSON.stringify(indexDefinition.key)}`,
2425
type: "text",
25-
};
26-
}) as { text: string; type: "text" }[]),
26+
} as const;
27+
}),
28+
...searchIndexes.map((indexDefinition) => {
29+
return {
30+
text: `Search index name: "${indexDefinition.name}", status: ${indexDefinition.status}, definition: ${JSON.stringify(indexDefinition.latestDefinition)}`,
31+
type: "text",
32+
} as const;
33+
}),
2734
],
2835
};
2936
}

src/tools/mongodb/tools.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// TODO: https://github.com/mongodb-js/mongodb-mcp-server/issues/141 - reenable when the connect tool is reenabled
22
// import { ConnectTool } from "./metadata/connect.js";
33
import { ListCollectionsTool } from "./metadata/listCollections.js";
4-
import { CollectionIndexesTool } from "./read/collectionIndexes.js";
4+
import { CollectionIndexesTool as ListIndexesTool } from "./read/collectionIndexes.js";
55
import { ListDatabasesTool } from "./metadata/listDatabases.js";
66
import { CreateIndexTool } from "./create/createIndex.js";
77
import { CollectionSchemaTool } from "./metadata/collectionSchema.js";
@@ -19,27 +19,35 @@ import { DropCollectionTool } from "./delete/dropCollection.js";
1919
import { ExplainTool } from "./metadata/explain.js";
2020
import { CreateCollectionTool } from "./create/createCollection.js";
2121
import { LogsTool } from "./metadata/logs.js";
22+
import { CreateSearchIndexTool } from "./create/createSearchIndex.js";
23+
import { DropIndexTool } from "./delete/dropIndex.js";
2224

2325
export const MongoDbTools = [
2426
// TODO: https://github.com/mongodb-js/mongodb-mcp-server/issues/141 - reenable when the connect tool is reenabled
2527
// ConnectTool,
28+
CreateCollectionTool,
2629
ListCollectionsTool,
27-
ListDatabasesTool,
28-
CollectionIndexesTool,
29-
CreateIndexTool,
3030
CollectionSchemaTool,
31-
FindTool,
32-
InsertManyTool,
33-
DeleteManyTool,
3431
CollectionStorageSizeTool,
35-
CountTool,
36-
DbStatsTool,
37-
AggregateTool,
38-
UpdateManyTool,
3932
RenameCollectionTool,
40-
DropDatabaseTool,
4133
DropCollectionTool,
42-
ExplainTool,
43-
CreateCollectionTool,
34+
35+
ListDatabasesTool,
36+
DropDatabaseTool,
37+
DbStatsTool,
4438
LogsTool,
39+
40+
FindTool,
41+
AggregateTool,
42+
CountTool,
43+
ExplainTool,
44+
45+
InsertManyTool,
46+
DeleteManyTool,
47+
UpdateManyTool,
48+
49+
CreateIndexTool,
50+
CreateSearchIndexTool,
51+
ListIndexesTool,
52+
DropIndexTool,
4553
];

0 commit comments

Comments
 (0)