Skip to content

Commit b8894ea

Browse files
committed
chore: add integration tests for collection-indexes
1 parent 23e48f3 commit b8894ea

File tree

3 files changed

+135
-8
lines changed

3 files changed

+135
-8
lines changed

src/tools/mongodb/read/collectionIndexes.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,36 @@ export class CollectionIndexesTool extends MongoDBToolBase {
1313
const indexes = await provider.getIndexes(database, collection);
1414

1515
return {
16-
content: indexes.map((indexDefinition) => {
17-
return {
18-
text: `Field: ${indexDefinition.name}: ${JSON.stringify(indexDefinition.key)}`,
16+
content: [
17+
{
18+
text: `Found ${indexes.length} indexes in the collection "${collection}":`,
1919
type: "text",
20-
};
21-
}),
20+
},
21+
...(indexes.map((indexDefinition) => {
22+
return {
23+
text: `Name "${indexDefinition.name}", definition: ${JSON.stringify(indexDefinition.key)}`,
24+
type: "text",
25+
};
26+
}) as { text: string; type: "text" }[]),
27+
],
2228
};
2329
}
30+
31+
protected handleError(
32+
error: unknown,
33+
args: ToolArgs<typeof this.argsShape>
34+
): Promise<CallToolResult> | CallToolResult {
35+
if (error instanceof Error && "codeName" in error && error.codeName === "NamespaceNotFound") {
36+
return {
37+
content: [
38+
{
39+
text: `The indexes for "${args.database}.${args.collection}" cannot be determined because the collection does not exist.`,
40+
type: "text",
41+
},
42+
],
43+
};
44+
}
45+
46+
return super.handleError(error, args);
47+
}
2448
}

tests/integration/tools/mongodb/read/aggregate.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { pipeline } from "stream";
21
import {
3-
getResponseContent,
42
databaseCollectionParameters,
53
setupIntegrationTest,
64
validateToolMetadata,
@@ -92,7 +90,11 @@ describe("aggregate tool", () => {
9290

9391
validateAutoConnectBehavior(integration, "aggregate", () => {
9492
return {
95-
args: { database: integration.randomDbName(), collection: "coll1" },
93+
args: {
94+
database: integration.randomDbName(),
95+
collection: "coll1",
96+
pipeline: [{ $match: { name: "Liva" } }],
97+
},
9698
expectedResponse: 'Found 0 documents in the collection "coll1"',
9799
};
98100
});
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { IndexDirection } from "mongodb";
2+
import {
3+
databaseCollectionParameters,
4+
setupIntegrationTest,
5+
validateToolMetadata,
6+
validateAutoConnectBehavior,
7+
validateThrowsForInvalidArguments,
8+
getResponseElements,
9+
databaseCollectionInvalidArgs,
10+
} from "../../../helpers.js";
11+
12+
describe("collectionIndexes tool", () => {
13+
const integration = setupIntegrationTest();
14+
15+
validateToolMetadata(
16+
integration,
17+
"collection-indexes",
18+
"Describe the indexes for a collection",
19+
databaseCollectionParameters
20+
);
21+
22+
validateThrowsForInvalidArguments(integration, "collection-indexes", databaseCollectionInvalidArgs);
23+
24+
it("can inspect indexes on non-existent database", async () => {
25+
await integration.connectMcpClient();
26+
const response = await integration.mcpClient().callTool({
27+
name: "collection-indexes",
28+
arguments: { database: "non-existent", collection: "people" },
29+
});
30+
31+
const elements = getResponseElements(response.content);
32+
expect(elements).toHaveLength(1);
33+
expect(elements[0].text).toEqual(
34+
'The indexes for "non-existent.people" cannot be determined because the collection does not exist.'
35+
);
36+
});
37+
38+
it("returns the _id index for a new collection", async () => {
39+
await integration.mongoClient().db(integration.randomDbName()).createCollection("people");
40+
41+
await integration.connectMcpClient();
42+
const response = await integration.mcpClient().callTool({
43+
name: "collection-indexes",
44+
arguments: {
45+
database: integration.randomDbName(),
46+
collection: "people",
47+
},
48+
});
49+
50+
const elements = getResponseElements(response.content);
51+
expect(elements).toHaveLength(2);
52+
expect(elements[0].text).toEqual('Found 1 indexes in the collection "people":');
53+
expect(elements[1].text).toEqual('Name "_id_", definition: {"_id":1}');
54+
});
55+
56+
it("returns all indexes for a collection", async () => {
57+
await integration.mongoClient().db(integration.randomDbName()).createCollection("people");
58+
59+
const indexTypes: IndexDirection[] = [-1, 1, "2d", "2dsphere", "text", "hashed"];
60+
for (const indexType of indexTypes) {
61+
await integration
62+
.mongoClient()
63+
.db(integration.randomDbName())
64+
.collection("people")
65+
.createIndex({ [`prop_${indexType}`]: indexType });
66+
}
67+
68+
await integration.connectMcpClient();
69+
const response = await integration.mcpClient().callTool({
70+
name: "collection-indexes",
71+
arguments: {
72+
database: integration.randomDbName(),
73+
collection: "people",
74+
},
75+
});
76+
77+
const elements = getResponseElements(response.content);
78+
expect(elements).toHaveLength(indexTypes.length + 2);
79+
expect(elements[0].text).toEqual(`Found ${indexTypes.length + 1} indexes in the collection "people":`);
80+
expect(elements[1].text).toEqual('Name "_id_", definition: {"_id":1}');
81+
82+
for (const indexType of indexTypes) {
83+
const index = elements.find((element) => element.text.includes(`prop_${indexType}`));
84+
expect(index).toBeDefined();
85+
86+
let expectedDefinition = JSON.stringify({ [`prop_${indexType}`]: indexType });
87+
if (indexType === "text") {
88+
expectedDefinition = '{"_fts":"text"';
89+
}
90+
91+
expect(index!.text).toContain(`definition: ${expectedDefinition}`);
92+
}
93+
});
94+
95+
validateAutoConnectBehavior(integration, "collection-indexes", () => {
96+
return {
97+
args: { database: integration.randomDbName(), collection: "coll1" },
98+
expectedResponse: `The indexes for "${integration.randomDbName()}.coll1" cannot be determined because the collection does not exist.`,
99+
};
100+
});
101+
});

0 commit comments

Comments
 (0)