mongodb-mcp-server 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/code_health.yaml +53 -4
- package/.github/workflows/prepare_release.yaml +4 -4
- package/README.md +2 -0
- package/dist/common/atlas/apiClient.js +30 -2
- package/dist/common/atlas/apiClient.js.map +1 -1
- package/dist/config.js +2 -7
- package/dist/config.js.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/logger.js +52 -27
- package/dist/logger.js.map +1 -1
- package/dist/packageInfo.js +6 -0
- package/dist/packageInfo.js.map +1 -0
- package/dist/server.js +71 -8
- package/dist/server.js.map +1 -1
- package/dist/session.js +17 -12
- package/dist/session.js.map +1 -1
- package/dist/telemetry/constants.js +15 -0
- package/dist/telemetry/constants.js.map +1 -0
- package/dist/telemetry/eventCache.js +53 -0
- package/dist/telemetry/eventCache.js.map +1 -0
- package/dist/telemetry/telemetry.js +96 -0
- package/dist/telemetry/telemetry.js.map +1 -0
- package/dist/telemetry/types.js +2 -0
- package/dist/telemetry/types.js.map +1 -0
- package/dist/tools/atlas/atlasTool.js +8 -3
- package/dist/tools/atlas/atlasTool.js.map +1 -1
- package/dist/tools/atlas/createAccessList.js +0 -1
- package/dist/tools/atlas/createAccessList.js.map +1 -1
- package/dist/tools/atlas/createDBUser.js +0 -1
- package/dist/tools/atlas/createDBUser.js.map +1 -1
- package/dist/tools/atlas/createFreeCluster.js +0 -1
- package/dist/tools/atlas/createFreeCluster.js.map +1 -1
- package/dist/tools/atlas/createProject.js +0 -1
- package/dist/tools/atlas/createProject.js.map +1 -1
- package/dist/tools/atlas/inspectAccessList.js +0 -1
- package/dist/tools/atlas/inspectAccessList.js.map +1 -1
- package/dist/tools/atlas/inspectCluster.js +0 -1
- package/dist/tools/atlas/inspectCluster.js.map +1 -1
- package/dist/tools/atlas/listClusters.js +0 -1
- package/dist/tools/atlas/listClusters.js.map +1 -1
- package/dist/tools/atlas/listDBUsers.js +0 -1
- package/dist/tools/atlas/listDBUsers.js.map +1 -1
- package/dist/tools/atlas/listOrgs.js +0 -1
- package/dist/tools/atlas/listOrgs.js.map +1 -1
- package/dist/tools/atlas/listProjects.js +10 -4
- package/dist/tools/atlas/listProjects.js.map +1 -1
- package/dist/tools/mongodb/metadata/collectionSchema.js +15 -13
- package/dist/tools/mongodb/metadata/collectionSchema.js.map +1 -1
- package/dist/tools/mongodb/metadata/collectionStorageSize.js +32 -3
- package/dist/tools/mongodb/metadata/collectionStorageSize.js.map +1 -1
- package/dist/tools/mongodb/metadata/connect.js +5 -6
- package/dist/tools/mongodb/metadata/connect.js.map +1 -1
- package/dist/tools/mongodb/metadata/dbStats.js +6 -1
- package/dist/tools/mongodb/metadata/dbStats.js.map +1 -1
- package/dist/tools/mongodb/metadata/explain.js +14 -7
- package/dist/tools/mongodb/metadata/explain.js.map +1 -1
- package/dist/tools/mongodb/metadata/logs.js +45 -0
- package/dist/tools/mongodb/metadata/logs.js.map +1 -0
- package/dist/tools/mongodb/mongodbTool.js +10 -11
- package/dist/tools/mongodb/mongodbTool.js.map +1 -1
- package/dist/tools/mongodb/read/aggregate.js +3 -3
- package/dist/tools/mongodb/read/aggregate.js.map +1 -1
- package/dist/tools/mongodb/read/collectionIndexes.js +24 -5
- package/dist/tools/mongodb/read/collectionIndexes.js.map +1 -1
- package/dist/tools/mongodb/read/find.js +3 -2
- package/dist/tools/mongodb/read/find.js.map +1 -1
- package/dist/tools/mongodb/tools.js +2 -0
- package/dist/tools/mongodb/tools.js.map +1 -1
- package/dist/tools/mongodb/update/renameCollection.js +28 -4
- package/dist/tools/mongodb/update/renameCollection.js.map +1 -1
- package/dist/tools/mongodb/update/updateMany.js +5 -7
- package/dist/tools/mongodb/update/updateMany.js.map +1 -1
- package/dist/tools/tool.js +39 -10
- package/dist/tools/tool.js.map +1 -1
- package/eslint.config.js +29 -10
- package/global.d.ts +1 -0
- package/package.json +6 -2
- package/scripts/apply.ts +9 -7
- package/scripts/filter.ts +3 -2
- package/src/common/atlas/apiClient.ts +48 -7
- package/src/config.ts +4 -10
- package/src/index.ts +10 -6
- package/src/logger.ts +66 -28
- package/src/packageInfo.ts +6 -0
- package/src/server.ts +103 -9
- package/src/session.ts +34 -17
- package/src/telemetry/constants.ts +15 -0
- package/src/telemetry/eventCache.ts +62 -0
- package/src/telemetry/telemetry.ts +137 -0
- package/src/telemetry/types.ts +60 -0
- package/src/tools/atlas/atlasTool.ts +7 -5
- package/src/tools/atlas/createAccessList.ts +0 -2
- package/src/tools/atlas/createDBUser.ts +0 -2
- package/src/tools/atlas/createFreeCluster.ts +0 -2
- package/src/tools/atlas/createProject.ts +0 -1
- package/src/tools/atlas/inspectAccessList.ts +0 -2
- package/src/tools/atlas/inspectCluster.ts +0 -2
- package/src/tools/atlas/listClusters.ts +0 -2
- package/src/tools/atlas/listDBUsers.ts +0 -2
- package/src/tools/atlas/listOrgs.ts +0 -2
- package/src/tools/atlas/listProjects.ts +12 -4
- package/src/tools/mongodb/metadata/collectionSchema.ts +16 -14
- package/src/tools/mongodb/metadata/collectionStorageSize.ts +41 -3
- package/src/tools/mongodb/metadata/connect.ts +5 -6
- package/src/tools/mongodb/metadata/dbStats.ts +6 -1
- package/src/tools/mongodb/metadata/explain.ts +20 -7
- package/src/tools/mongodb/metadata/logs.ts +55 -0
- package/src/tools/mongodb/mongodbTool.ts +12 -15
- package/src/tools/mongodb/read/aggregate.ts +3 -3
- package/src/tools/mongodb/read/collectionIndexes.ts +29 -5
- package/src/tools/mongodb/read/find.ts +3 -2
- package/src/tools/mongodb/tools.ts +2 -0
- package/src/tools/mongodb/update/renameCollection.ts +33 -4
- package/src/tools/mongodb/update/updateMany.ts +5 -7
- package/src/tools/tool.ts +51 -15
- package/tests/integration/helpers.ts +84 -107
- package/tests/integration/inMemoryTransport.ts +3 -2
- package/tests/integration/server.test.ts +47 -21
- package/tests/integration/tools/atlas/accessLists.test.ts +13 -15
- package/tests/integration/tools/atlas/atlasHelpers.ts +3 -8
- package/tests/integration/tools/atlas/clusters.test.ts +12 -13
- package/tests/integration/tools/atlas/dbUsers.test.ts +9 -9
- package/tests/integration/tools/atlas/orgs.test.ts +4 -4
- package/tests/integration/tools/atlas/projects.test.ts +10 -12
- package/tests/integration/tools/mongodb/create/createCollection.test.ts +19 -62
- package/tests/integration/tools/mongodb/create/createIndex.test.ts +41 -87
- package/tests/integration/tools/mongodb/create/insertMany.test.ts +35 -78
- package/tests/integration/tools/mongodb/delete/deleteMany.test.ts +25 -62
- package/tests/integration/tools/mongodb/delete/dropCollection.test.ts +22 -71
- package/tests/integration/tools/mongodb/delete/dropDatabase.test.ts +29 -63
- package/tests/integration/tools/mongodb/metadata/collectionSchema.test.ts +154 -0
- package/tests/integration/tools/mongodb/metadata/collectionStorageSize.test.ts +86 -0
- package/tests/integration/tools/mongodb/metadata/connect.test.ts +33 -23
- package/tests/integration/tools/mongodb/metadata/dbStats.test.ts +104 -0
- package/tests/integration/tools/mongodb/metadata/explain.test.ts +171 -0
- package/tests/integration/tools/mongodb/metadata/listCollections.test.ts +28 -56
- package/tests/integration/tools/mongodb/metadata/listDatabases.test.ts +32 -26
- package/tests/integration/tools/mongodb/metadata/logs.test.ts +83 -0
- package/tests/integration/tools/mongodb/mongodbHelpers.ts +165 -0
- package/tests/integration/tools/mongodb/read/aggregate.test.ts +99 -0
- package/tests/integration/tools/mongodb/read/collectionIndexes.test.ts +99 -0
- package/tests/integration/tools/mongodb/read/count.test.ts +31 -79
- package/tests/integration/tools/mongodb/read/find.test.ts +182 -0
- package/tests/integration/tools/mongodb/update/renameCollection.test.ts +194 -0
- package/tests/integration/tools/mongodb/update/updateMany.test.ts +238 -0
- package/tsconfig.jest.json +2 -1
- package/tsconfig.json +1 -1
- package/tsconfig.lint.json +8 -0
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
-
import { setupIntegrationTest } from "../../helpers.js";
|
|
3
|
-
import { Session } from "../../../../src/session.js";
|
|
4
2
|
import { ObjectId } from "mongodb";
|
|
5
|
-
import { parseTable,
|
|
3
|
+
import { parseTable, describeWithAtlas } from "./atlasHelpers.js";
|
|
4
|
+
import { expectDefined } from "../../helpers.js";
|
|
6
5
|
|
|
7
6
|
const randomId = new ObjectId().toString();
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
describeWithAtlas("projects", (integration) => {
|
|
10
9
|
const projName = "testProj-" + randomId;
|
|
11
10
|
|
|
12
11
|
afterAll(async () => {
|
|
13
|
-
const session
|
|
14
|
-
session.ensureAuthenticated();
|
|
12
|
+
const session = integration.mcpServer().session;
|
|
15
13
|
|
|
16
14
|
const projects = await session.apiClient.listProjects();
|
|
17
15
|
for (const project of projects?.results || []) {
|
|
@@ -31,10 +29,10 @@ describeAtlas("projects", (integration) => {
|
|
|
31
29
|
describe("atlas-create-project", () => {
|
|
32
30
|
it("should have correct metadata", async () => {
|
|
33
31
|
const { tools } = await integration.mcpClient().listTools();
|
|
34
|
-
const createProject = tools.find((tool) => tool.name === "atlas-create-project")
|
|
35
|
-
|
|
32
|
+
const createProject = tools.find((tool) => tool.name === "atlas-create-project");
|
|
33
|
+
expectDefined(createProject);
|
|
36
34
|
expect(createProject.inputSchema.type).toBe("object");
|
|
37
|
-
|
|
35
|
+
expectDefined(createProject.inputSchema.properties);
|
|
38
36
|
expect(createProject.inputSchema.properties).toHaveProperty("projectName");
|
|
39
37
|
expect(createProject.inputSchema.properties).toHaveProperty("organizationId");
|
|
40
38
|
});
|
|
@@ -51,10 +49,10 @@ describeAtlas("projects", (integration) => {
|
|
|
51
49
|
describe("atlas-list-projects", () => {
|
|
52
50
|
it("should have correct metadata", async () => {
|
|
53
51
|
const { tools } = await integration.mcpClient().listTools();
|
|
54
|
-
const listProjects = tools.find((tool) => tool.name === "atlas-list-projects")
|
|
55
|
-
|
|
52
|
+
const listProjects = tools.find((tool) => tool.name === "atlas-list-projects");
|
|
53
|
+
expectDefined(listProjects);
|
|
56
54
|
expect(listProjects.inputSchema.type).toBe("object");
|
|
57
|
-
|
|
55
|
+
expectDefined(listProjects.inputSchema.properties);
|
|
58
56
|
expect(listProjects.inputSchema.properties).toHaveProperty("orgId");
|
|
59
57
|
});
|
|
60
58
|
|
|
@@ -1,50 +1,22 @@
|
|
|
1
|
+
import { describeWithMongoDB, validateAutoConnectBehavior } from "../mongodbHelpers.js";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
getResponseContent,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
databaseCollectionParameters,
|
|
6
|
+
validateToolMetadata,
|
|
7
|
+
validateThrowsForInvalidArguments,
|
|
8
|
+
databaseCollectionInvalidArgs,
|
|
6
9
|
} from "../../../helpers.js";
|
|
7
|
-
import { toIncludeSameMembers } from "jest-extended";
|
|
8
|
-
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
-
import { ObjectId } from "bson";
|
|
10
|
-
import config from "../../../../../src/config.js";
|
|
11
|
-
|
|
12
|
-
describe("createCollection tool", () => {
|
|
13
|
-
const integration = setupIntegrationTest();
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
describeWithMongoDB("createCollection tool", (integration) => {
|
|
12
|
+
validateToolMetadata(
|
|
13
|
+
integration,
|
|
14
|
+
"create-collection",
|
|
15
|
+
"Creates a new collection in a database. If the database doesn't exist, it will be created automatically.",
|
|
16
|
+
databaseCollectionParameters
|
|
17
|
+
);
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
describe("with invalid arguments", () => {
|
|
27
|
-
const args = [
|
|
28
|
-
{},
|
|
29
|
-
{ database: 123, collection: "bar" },
|
|
30
|
-
{ foo: "bar", database: "test", collection: "bar" },
|
|
31
|
-
{ collection: [], database: "test" },
|
|
32
|
-
];
|
|
33
|
-
for (const arg of args) {
|
|
34
|
-
it(`throws a schema error for: ${JSON.stringify(arg)}`, async () => {
|
|
35
|
-
await integration.connectMcpClient();
|
|
36
|
-
try {
|
|
37
|
-
await integration.mcpClient().callTool({ name: "create-collection", arguments: arg });
|
|
38
|
-
expect.fail("Expected an error to be thrown");
|
|
39
|
-
} catch (error) {
|
|
40
|
-
expect(error).toBeInstanceOf(McpError);
|
|
41
|
-
const mcpError = error as McpError;
|
|
42
|
-
expect(mcpError.code).toEqual(-32602);
|
|
43
|
-
expect(mcpError.message).toContain("Invalid arguments for tool create-collection");
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
});
|
|
19
|
+
validateThrowsForInvalidArguments(integration, "create-collection", databaseCollectionInvalidArgs);
|
|
48
20
|
|
|
49
21
|
describe("with non-existent database", () => {
|
|
50
22
|
it("creates a new collection", async () => {
|
|
@@ -114,25 +86,10 @@ describe("createCollection tool", () => {
|
|
|
114
86
|
});
|
|
115
87
|
});
|
|
116
88
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
name: "create-collection",
|
|
123
|
-
arguments: { database: integration.randomDbName(), collection: "new-collection" },
|
|
124
|
-
});
|
|
125
|
-
const content = getResponseContent(response.content);
|
|
126
|
-
expect(content).toEqual(`Collection "new-collection" created in database "${integration.randomDbName()}".`);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it("throws an error if connection string is not configured", async () => {
|
|
130
|
-
const response = await integration.mcpClient().callTool({
|
|
131
|
-
name: "create-collection",
|
|
132
|
-
arguments: { database: integration.randomDbName(), collection: "new-collection" },
|
|
133
|
-
});
|
|
134
|
-
const content = getResponseContent(response.content);
|
|
135
|
-
expect(content).toContain("You need to connect to a MongoDB instance before you can access its data.");
|
|
136
|
-
});
|
|
89
|
+
validateAutoConnectBehavior(integration, "create-collection", () => {
|
|
90
|
+
return {
|
|
91
|
+
args: { database: integration.randomDbName(), collection: "new-collection" },
|
|
92
|
+
expectedResponse: `Collection "new-collection" created in database "${integration.randomDbName()}".`,
|
|
93
|
+
};
|
|
137
94
|
});
|
|
138
95
|
});
|
|
@@ -1,63 +1,38 @@
|
|
|
1
|
+
import { describeWithMongoDB, validateAutoConnectBehavior } from "../mongodbHelpers.js";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
getResponseContent,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
databaseCollectionParameters,
|
|
6
|
+
validateToolMetadata,
|
|
7
|
+
validateThrowsForInvalidArguments,
|
|
8
|
+
expectDefined,
|
|
6
9
|
} from "../../../helpers.js";
|
|
7
|
-
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
8
10
|
import { IndexDirection } from "mongodb";
|
|
9
|
-
import config from "../../../../../src/config.js";
|
|
10
|
-
|
|
11
|
-
describe("createIndex tool", () => {
|
|
12
|
-
const integration = setupIntegrationTest();
|
|
13
|
-
|
|
14
|
-
it("should have correct metadata", async () => {
|
|
15
|
-
const { tools } = await integration.mcpClient().listTools();
|
|
16
|
-
const createIndex = tools.find((tool) => tool.name === "create-index")!;
|
|
17
|
-
expect(createIndex).toBeDefined();
|
|
18
|
-
expect(createIndex.description).toBe("Create an index for a collection");
|
|
19
|
-
|
|
20
|
-
validateParameters(createIndex, [
|
|
21
|
-
...dbOperationParameters,
|
|
22
|
-
{
|
|
23
|
-
name: "keys",
|
|
24
|
-
type: "object",
|
|
25
|
-
description: "The index definition",
|
|
26
|
-
required: true,
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
name: "name",
|
|
30
|
-
type: "string",
|
|
31
|
-
description: "The name of the index",
|
|
32
|
-
required: false,
|
|
33
|
-
},
|
|
34
|
-
]);
|
|
35
|
-
});
|
|
36
11
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
12
|
+
describeWithMongoDB("createIndex tool", (integration) => {
|
|
13
|
+
validateToolMetadata(integration, "create-index", "Create an index for a collection", [
|
|
14
|
+
...databaseCollectionParameters,
|
|
15
|
+
{
|
|
16
|
+
name: "keys",
|
|
17
|
+
type: "object",
|
|
18
|
+
description: "The index definition",
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "name",
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "The name of the index",
|
|
25
|
+
required: false,
|
|
26
|
+
},
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
validateThrowsForInvalidArguments(integration, "create-index", [
|
|
30
|
+
{},
|
|
31
|
+
{ collection: "bar", database: 123, keys: { foo: 1 } },
|
|
32
|
+
{ collection: [], database: "test", keys: { foo: 1 } },
|
|
33
|
+
{ collection: "bar", database: "test", keys: { foo: 1 }, name: 123 },
|
|
34
|
+
{ collection: "bar", database: "test", keys: "foo", name: "my-index" },
|
|
35
|
+
]);
|
|
61
36
|
|
|
62
37
|
const validateIndex = async (collection: string, expected: { name: string; key: object }[]) => {
|
|
63
38
|
const mongoClient = integration.mongoClient();
|
|
@@ -69,8 +44,8 @@ describe("createIndex tool", () => {
|
|
|
69
44
|
expect(indexes[0].name).toEqual("_id_");
|
|
70
45
|
for (const index of expected) {
|
|
71
46
|
const foundIndex = indexes.find((i) => i.name === index.name);
|
|
72
|
-
|
|
73
|
-
expect(foundIndex
|
|
47
|
+
expectDefined(foundIndex);
|
|
48
|
+
expect(foundIndex.key).toEqual(index.key);
|
|
74
49
|
}
|
|
75
50
|
};
|
|
76
51
|
|
|
@@ -215,35 +190,14 @@ describe("createIndex tool", () => {
|
|
|
215
190
|
});
|
|
216
191
|
}
|
|
217
192
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
keys: { prop1: 1 },
|
|
228
|
-
},
|
|
229
|
-
});
|
|
230
|
-
const content = getResponseContent(response.content);
|
|
231
|
-
expect(content).toEqual(
|
|
232
|
-
`Created the index "prop1_1" on collection "coll1" in database "${integration.randomDbName()}"`
|
|
233
|
-
);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
it("throws an error if connection string is not configured", async () => {
|
|
237
|
-
const response = await integration.mcpClient().callTool({
|
|
238
|
-
name: "create-index",
|
|
239
|
-
arguments: {
|
|
240
|
-
database: integration.randomDbName(),
|
|
241
|
-
collection: "coll1",
|
|
242
|
-
keys: { prop1: 1 },
|
|
243
|
-
},
|
|
244
|
-
});
|
|
245
|
-
const content = getResponseContent(response.content);
|
|
246
|
-
expect(content).toContain("You need to connect to a MongoDB instance before you can access its data.");
|
|
247
|
-
});
|
|
193
|
+
validateAutoConnectBehavior(integration, "create-index", () => {
|
|
194
|
+
return {
|
|
195
|
+
args: {
|
|
196
|
+
database: integration.randomDbName(),
|
|
197
|
+
collection: "coll1",
|
|
198
|
+
keys: { prop1: 1 },
|
|
199
|
+
},
|
|
200
|
+
expectedResponse: `Created the index "prop1_1" on collection "coll1" in database "${integration.randomDbName()}"`,
|
|
201
|
+
};
|
|
248
202
|
});
|
|
249
203
|
});
|
|
@@ -1,60 +1,36 @@
|
|
|
1
|
+
import { describeWithMongoDB, validateAutoConnectBehavior } from "../mongodbHelpers.js";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
getResponseContent,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
databaseCollectionParameters,
|
|
6
|
+
validateToolMetadata,
|
|
7
|
+
validateThrowsForInvalidArguments,
|
|
8
|
+
expectDefined,
|
|
6
9
|
} from "../../../helpers.js";
|
|
7
|
-
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
-
import config from "../../../../../src/config.js";
|
|
9
|
-
|
|
10
|
-
describe("insertMany tool", () => {
|
|
11
|
-
const integration = setupIntegrationTest();
|
|
12
|
-
|
|
13
|
-
it("should have correct metadata", async () => {
|
|
14
|
-
const { tools } = await integration.mcpClient().listTools();
|
|
15
|
-
const insertMany = tools.find((tool) => tool.name === "insert-many")!;
|
|
16
|
-
expect(insertMany).toBeDefined();
|
|
17
|
-
expect(insertMany.description).toBe("Insert an array of documents into a MongoDB collection");
|
|
18
|
-
|
|
19
|
-
validateParameters(insertMany, [
|
|
20
|
-
...dbOperationParameters,
|
|
21
|
-
{
|
|
22
|
-
name: "documents",
|
|
23
|
-
type: "array",
|
|
24
|
-
description:
|
|
25
|
-
"The array of documents to insert, matching the syntax of the document argument of db.collection.insertMany()",
|
|
26
|
-
required: true,
|
|
27
|
-
},
|
|
28
|
-
]);
|
|
29
|
-
});
|
|
30
10
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
});
|
|
11
|
+
describeWithMongoDB("insertMany tool", (integration) => {
|
|
12
|
+
validateToolMetadata(integration, "insert-many", "Insert an array of documents into a MongoDB collection", [
|
|
13
|
+
...databaseCollectionParameters,
|
|
14
|
+
{
|
|
15
|
+
name: "documents",
|
|
16
|
+
type: "array",
|
|
17
|
+
description:
|
|
18
|
+
"The array of documents to insert, matching the syntax of the document argument of db.collection.insertMany()",
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
validateThrowsForInvalidArguments(integration, "insert-many", [
|
|
24
|
+
{},
|
|
25
|
+
{ collection: "bar", database: 123, documents: [] },
|
|
26
|
+
{ collection: [], database: "test", documents: [] },
|
|
27
|
+
{ collection: "bar", database: "test", documents: "my-document" },
|
|
28
|
+
{ collection: "bar", database: "test", documents: { name: "Peter" } },
|
|
29
|
+
]);
|
|
54
30
|
|
|
55
31
|
const validateDocuments = async (collection: string, expectedDocuments: object[]) => {
|
|
56
32
|
const collections = await integration.mongoClient().db(integration.randomDbName()).listCollections().toArray();
|
|
57
|
-
|
|
33
|
+
expectDefined(collections.find((c) => c.name === collection));
|
|
58
34
|
|
|
59
35
|
const docs = await integration
|
|
60
36
|
.mongoClient()
|
|
@@ -109,33 +85,14 @@ describe("insertMany tool", () => {
|
|
|
109
85
|
expect(content).toContain(insertedIds[0].toString());
|
|
110
86
|
});
|
|
111
87
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
documents: [{ prop1: "value1" }],
|
|
122
|
-
},
|
|
123
|
-
});
|
|
124
|
-
const content = getResponseContent(response.content);
|
|
125
|
-
expect(content).toContain('Inserted `1` document(s) into collection "coll1"');
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it("throws an error if connection string is not configured", async () => {
|
|
129
|
-
const response = await integration.mcpClient().callTool({
|
|
130
|
-
name: "insert-many",
|
|
131
|
-
arguments: {
|
|
132
|
-
database: integration.randomDbName(),
|
|
133
|
-
collection: "coll1",
|
|
134
|
-
documents: [{ prop1: "value1" }],
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
const content = getResponseContent(response.content);
|
|
138
|
-
expect(content).toContain("You need to connect to a MongoDB instance before you can access its data.");
|
|
139
|
-
});
|
|
88
|
+
validateAutoConnectBehavior(integration, "insert-many", () => {
|
|
89
|
+
return {
|
|
90
|
+
args: {
|
|
91
|
+
database: integration.randomDbName(),
|
|
92
|
+
collection: "coll1",
|
|
93
|
+
documents: [{ prop1: "value1" }],
|
|
94
|
+
},
|
|
95
|
+
expectedResponse: 'Inserted `1` document(s) into collection "coll1"',
|
|
96
|
+
};
|
|
140
97
|
});
|
|
141
98
|
});
|
|
@@ -1,23 +1,19 @@
|
|
|
1
|
+
import { describeWithMongoDB, validateAutoConnectBehavior } from "../mongodbHelpers.js";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
getResponseContent,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
databaseCollectionParameters,
|
|
6
|
+
validateToolMetadata,
|
|
7
|
+
validateThrowsForInvalidArguments,
|
|
6
8
|
} from "../../../helpers.js";
|
|
7
|
-
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
-
import config from "../../../../../src/config.js";
|
|
9
|
-
|
|
10
|
-
describe("deleteMany tool", () => {
|
|
11
|
-
const integration = setupIntegrationTest();
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
...dbOperationParameters,
|
|
10
|
+
describeWithMongoDB("deleteMany tool", (integration) => {
|
|
11
|
+
validateToolMetadata(
|
|
12
|
+
integration,
|
|
13
|
+
"delete-many",
|
|
14
|
+
"Removes all documents that match the filter from a MongoDB collection",
|
|
15
|
+
[
|
|
16
|
+
...databaseCollectionParameters,
|
|
21
17
|
{
|
|
22
18
|
name: "filter",
|
|
23
19
|
type: "object",
|
|
@@ -25,31 +21,17 @@ describe("deleteMany tool", () => {
|
|
|
25
21
|
"The query filter, specifying the deletion criteria. Matches the syntax of the filter argument of db.collection.deleteMany()",
|
|
26
22
|
required: false,
|
|
27
23
|
},
|
|
28
|
-
]
|
|
29
|
-
|
|
24
|
+
]
|
|
25
|
+
);
|
|
30
26
|
|
|
31
27
|
describe("with invalid arguments", () => {
|
|
32
|
-
|
|
28
|
+
validateThrowsForInvalidArguments(integration, "delete-many", [
|
|
33
29
|
{},
|
|
34
30
|
{ collection: "bar", database: 123, filter: {} },
|
|
35
31
|
{ collection: [], database: "test", filter: {} },
|
|
36
32
|
{ collection: "bar", database: "test", filter: "my-document" },
|
|
37
33
|
{ collection: "bar", database: "test", filter: [{ name: "Peter" }] },
|
|
38
|
-
];
|
|
39
|
-
for (const arg of args) {
|
|
40
|
-
it(`throws a schema error for: ${JSON.stringify(arg)}`, async () => {
|
|
41
|
-
await integration.connectMcpClient();
|
|
42
|
-
try {
|
|
43
|
-
await integration.mcpClient().callTool({ name: "delete-many", arguments: arg });
|
|
44
|
-
expect.fail("Expected an error to be thrown");
|
|
45
|
-
} catch (error) {
|
|
46
|
-
expect(error).toBeInstanceOf(McpError);
|
|
47
|
-
const mcpError = error as McpError;
|
|
48
|
-
expect(mcpError.code).toEqual(-32602);
|
|
49
|
-
expect(mcpError.message).toContain("Invalid arguments for tool delete-many");
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
}
|
|
34
|
+
]);
|
|
53
35
|
});
|
|
54
36
|
|
|
55
37
|
it("doesn't create the collection if it doesn't exist", async () => {
|
|
@@ -159,33 +141,14 @@ describe("deleteMany tool", () => {
|
|
|
159
141
|
await validateDocuments([]);
|
|
160
142
|
});
|
|
161
143
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
filter: {},
|
|
172
|
-
},
|
|
173
|
-
});
|
|
174
|
-
const content = getResponseContent(response.content);
|
|
175
|
-
expect(content).toContain('Deleted `0` document(s) from collection "coll1"');
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it("throws an error if connection string is not configured", async () => {
|
|
179
|
-
const response = await integration.mcpClient().callTool({
|
|
180
|
-
name: "delete-many",
|
|
181
|
-
arguments: {
|
|
182
|
-
database: integration.randomDbName(),
|
|
183
|
-
collection: "coll1",
|
|
184
|
-
filter: {},
|
|
185
|
-
},
|
|
186
|
-
});
|
|
187
|
-
const content = getResponseContent(response.content);
|
|
188
|
-
expect(content).toContain("You need to connect to a MongoDB instance before you can access its data.");
|
|
189
|
-
});
|
|
144
|
+
validateAutoConnectBehavior(integration, "delete-many", () => {
|
|
145
|
+
return {
|
|
146
|
+
args: {
|
|
147
|
+
database: integration.randomDbName(),
|
|
148
|
+
collection: "coll1",
|
|
149
|
+
filter: {},
|
|
150
|
+
},
|
|
151
|
+
expectedResponse: 'Deleted `0` document(s) from collection "coll1"',
|
|
152
|
+
};
|
|
190
153
|
});
|
|
191
154
|
});
|
|
@@ -1,48 +1,22 @@
|
|
|
1
|
+
import { describeWithMongoDB, validateAutoConnectBehavior } from "../mongodbHelpers.js";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
getResponseContent,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
databaseCollectionParameters,
|
|
6
|
+
validateToolMetadata,
|
|
7
|
+
validateThrowsForInvalidArguments,
|
|
8
|
+
databaseCollectionInvalidArgs,
|
|
6
9
|
} from "../../../helpers.js";
|
|
7
|
-
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
-
import config from "../../../../../src/config.js";
|
|
9
|
-
|
|
10
|
-
describe("dropCollection tool", () => {
|
|
11
|
-
const integration = setupIntegrationTest();
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
describeWithMongoDB("dropCollection tool", (integration) => {
|
|
12
|
+
validateToolMetadata(
|
|
13
|
+
integration,
|
|
14
|
+
"drop-collection",
|
|
15
|
+
"Removes a collection or view from the database. The method also removes any indexes associated with the dropped collection.",
|
|
16
|
+
databaseCollectionParameters
|
|
17
|
+
);
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe("with invalid arguments", () => {
|
|
25
|
-
const args = [
|
|
26
|
-
{},
|
|
27
|
-
{ database: 123, collection: "bar" },
|
|
28
|
-
{ foo: "bar", database: "test", collection: "bar" },
|
|
29
|
-
{ collection: [], database: "test" },
|
|
30
|
-
];
|
|
31
|
-
for (const arg of args) {
|
|
32
|
-
it(`throws a schema error for: ${JSON.stringify(arg)}`, async () => {
|
|
33
|
-
await integration.connectMcpClient();
|
|
34
|
-
try {
|
|
35
|
-
await integration.mcpClient().callTool({ name: "drop-collection", arguments: arg });
|
|
36
|
-
expect.fail("Expected an error to be thrown");
|
|
37
|
-
} catch (error) {
|
|
38
|
-
expect(error).toBeInstanceOf(McpError);
|
|
39
|
-
const mcpError = error as McpError;
|
|
40
|
-
expect(mcpError.code).toEqual(-32602);
|
|
41
|
-
expect(mcpError.message).toContain("Invalid arguments for tool drop-collection");
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
});
|
|
19
|
+
validateThrowsForInvalidArguments(integration, "drop-collection", databaseCollectionInvalidArgs);
|
|
46
20
|
|
|
47
21
|
it("can drop non-existing collection", async () => {
|
|
48
22
|
await integration.connectMcpClient();
|
|
@@ -83,36 +57,13 @@ describe("dropCollection tool", () => {
|
|
|
83
57
|
expect(collections[0].name).toBe("coll2");
|
|
84
58
|
});
|
|
85
59
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
name: "drop-collection",
|
|
95
|
-
arguments: {
|
|
96
|
-
database: integration.randomDbName(),
|
|
97
|
-
collection: "coll1",
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
const content = getResponseContent(response.content);
|
|
101
|
-
expect(content).toContain(
|
|
102
|
-
`Successfully dropped collection "coll1" from database "${integration.randomDbName()}"`
|
|
103
|
-
);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it("throws an error if connection string is not configured", async () => {
|
|
107
|
-
const response = await integration.mcpClient().callTool({
|
|
108
|
-
name: "drop-collection",
|
|
109
|
-
arguments: {
|
|
110
|
-
database: integration.randomDbName(),
|
|
111
|
-
collection: "coll1",
|
|
112
|
-
},
|
|
113
|
-
});
|
|
114
|
-
const content = getResponseContent(response.content);
|
|
115
|
-
expect(content).toContain("You need to connect to a MongoDB instance before you can access its data.");
|
|
116
|
-
});
|
|
60
|
+
validateAutoConnectBehavior(integration, "drop-collection", () => {
|
|
61
|
+
return {
|
|
62
|
+
args: {
|
|
63
|
+
database: integration.randomDbName(),
|
|
64
|
+
collection: "coll1",
|
|
65
|
+
},
|
|
66
|
+
expectedResponse: `Successfully dropped collection "coll1" from database "${integration.randomDbName()}"`,
|
|
67
|
+
};
|
|
117
68
|
});
|
|
118
69
|
});
|