mongodb-mcp-server 0.1.2 → 0.1.3
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/pull_request_template.md +5 -0
- package/.github/workflows/code_health.yaml +3 -3
- package/.github/workflows/docker.yaml +1 -1
- package/.smithery/smithery.yaml +10 -0
- package/README.md +15 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/errors.js +1 -0
- package/dist/errors.js.map +1 -1
- package/dist/helpers/indexCheck.js +63 -0
- package/dist/helpers/indexCheck.js.map +1 -0
- package/dist/logger.js +0 -1
- package/dist/logger.js.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/telemetry/telemetry.js +78 -115
- package/dist/telemetry/telemetry.js.map +1 -1
- package/dist/tools/mongodb/delete/deleteMany.js +18 -0
- package/dist/tools/mongodb/delete/deleteMany.js.map +1 -1
- package/dist/tools/mongodb/metadata/explain.js +1 -1
- package/dist/tools/mongodb/metadata/explain.js.map +1 -1
- package/dist/tools/mongodb/mongodbTool.js +10 -0
- package/dist/tools/mongodb/mongodbTool.js.map +1 -1
- package/dist/tools/mongodb/read/aggregate.js +9 -0
- package/dist/tools/mongodb/read/aggregate.js.map +1 -1
- package/dist/tools/mongodb/read/count.js +13 -0
- package/dist/tools/mongodb/read/count.js.map +1 -1
- package/dist/tools/mongodb/read/find.js +7 -0
- package/dist/tools/mongodb/read/find.js.map +1 -1
- package/dist/tools/mongodb/update/updateMany.js +20 -0
- package/dist/tools/mongodb/update/updateMany.js.map +1 -1
- package/dist/tools/tool.js +4 -4
- package/dist/tools/tool.js.map +1 -1
- package/package.json +2 -2
- package/src/config.ts +2 -0
- package/src/errors.ts +1 -0
- package/src/helpers/indexCheck.ts +83 -0
- package/src/logger.ts +0 -1
- package/src/server.ts +1 -1
- package/src/telemetry/telemetry.ts +98 -150
- package/src/telemetry/types.ts +0 -1
- package/src/tools/mongodb/delete/deleteMany.ts +20 -0
- package/src/tools/mongodb/metadata/explain.ts +1 -1
- package/src/tools/mongodb/mongodbTool.ts +10 -0
- package/src/tools/mongodb/read/aggregate.ts +11 -0
- package/src/tools/mongodb/read/count.ts +15 -0
- package/src/tools/mongodb/read/find.ts +9 -0
- package/src/tools/mongodb/update/updateMany.ts +22 -0
- package/src/tools/tool.ts +5 -5
- package/tests/integration/indexCheck.test.ts +463 -0
- package/tests/integration/server.test.ts +5 -4
- package/tests/integration/telemetry.test.ts +28 -0
- package/tests/integration/tools/mongodb/mongodbHelpers.ts +1 -0
- package/tests/unit/indexCheck.test.ts +149 -0
- package/tests/unit/telemetry.test.ts +58 -106
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ApiClient } from "../../src/common/atlas/apiClient.js";
|
|
2
2
|
import { Session } from "../../src/session.js";
|
|
3
|
-
import { Telemetry } from "../../src/telemetry/telemetry.js";
|
|
3
|
+
import { DEVICE_ID_TIMEOUT, Telemetry } from "../../src/telemetry/telemetry.js";
|
|
4
4
|
import { BaseEvent, TelemetryResult } from "../../src/telemetry/types.js";
|
|
5
5
|
import { EventCache } from "../../src/telemetry/eventCache.js";
|
|
6
6
|
import { config } from "../../src/config.js";
|
|
@@ -16,8 +16,6 @@ const MockApiClient = ApiClient as jest.MockedClass<typeof ApiClient>;
|
|
|
16
16
|
jest.mock("../../src/telemetry/eventCache.js");
|
|
17
17
|
const MockEventCache = EventCache as jest.MockedClass<typeof EventCache>;
|
|
18
18
|
|
|
19
|
-
const nextTick = () => new Promise((resolve) => process.nextTick(resolve));
|
|
20
|
-
|
|
21
19
|
describe("Telemetry", () => {
|
|
22
20
|
const machineId = "test-machine-id";
|
|
23
21
|
const hashedMachineId = createHmac("sha256", machineId.toUpperCase()).update("atlascli").digest("hex");
|
|
@@ -26,11 +24,6 @@ describe("Telemetry", () => {
|
|
|
26
24
|
let mockEventCache: jest.Mocked<EventCache>;
|
|
27
25
|
let session: Session;
|
|
28
26
|
let telemetry: Telemetry;
|
|
29
|
-
let telemetryConfig: {
|
|
30
|
-
eventCache: EventCache;
|
|
31
|
-
getRawMachineId: () => Promise<string>;
|
|
32
|
-
getContainerEnv: () => Promise<boolean>;
|
|
33
|
-
};
|
|
34
27
|
|
|
35
28
|
// Helper function to create properly typed test events
|
|
36
29
|
function createTestEvent(options?: {
|
|
@@ -84,11 +77,19 @@ describe("Telemetry", () => {
|
|
|
84
77
|
expect(appendEvents.length).toBe(appendEventsCalls);
|
|
85
78
|
|
|
86
79
|
if (sendEventsCalledWith) {
|
|
87
|
-
expect(sendEvents[0]?.[0]).
|
|
80
|
+
expect(sendEvents[0]?.[0]).toEqual(
|
|
81
|
+
sendEventsCalledWith.map((event) => ({
|
|
82
|
+
...event,
|
|
83
|
+
properties: {
|
|
84
|
+
...telemetry.getCommonProperties(),
|
|
85
|
+
...event.properties,
|
|
86
|
+
},
|
|
87
|
+
}))
|
|
88
|
+
);
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
if (appendEventsCalledWith) {
|
|
91
|
-
expect(appendEvents[0]?.[0]).
|
|
92
|
+
expect(appendEvents[0]?.[0]).toEqual(appendEventsCalledWith);
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
|
|
@@ -124,13 +125,10 @@ describe("Telemetry", () => {
|
|
|
124
125
|
setAgentRunner: jest.fn().mockResolvedValue(undefined),
|
|
125
126
|
} as unknown as Session;
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
telemetry = Telemetry.create(session, config, {
|
|
128
129
|
eventCache: mockEventCache,
|
|
129
130
|
getRawMachineId: () => Promise.resolve(machineId),
|
|
130
|
-
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
telemetry = Telemetry.create(session, config, telemetryConfig);
|
|
131
|
+
});
|
|
134
132
|
|
|
135
133
|
config.telemetry = "enabled";
|
|
136
134
|
});
|
|
@@ -140,8 +138,7 @@ describe("Telemetry", () => {
|
|
|
140
138
|
it("should send events successfully", async () => {
|
|
141
139
|
const testEvent = createTestEvent();
|
|
142
140
|
|
|
143
|
-
telemetry.emitEvents([testEvent]);
|
|
144
|
-
await nextTick(); // wait for the event to be sent
|
|
141
|
+
await telemetry.emitEvents([testEvent]);
|
|
145
142
|
|
|
146
143
|
verifyMockCalls({
|
|
147
144
|
sendEventsCalls: 1,
|
|
@@ -155,8 +152,7 @@ describe("Telemetry", () => {
|
|
|
155
152
|
|
|
156
153
|
const testEvent = createTestEvent();
|
|
157
154
|
|
|
158
|
-
telemetry.emitEvents([testEvent]);
|
|
159
|
-
await nextTick(); // wait for the event to be sent
|
|
155
|
+
await telemetry.emitEvents([testEvent]);
|
|
160
156
|
|
|
161
157
|
verifyMockCalls({
|
|
162
158
|
sendEventsCalls: 1,
|
|
@@ -179,8 +175,7 @@ describe("Telemetry", () => {
|
|
|
179
175
|
// Set up mock to return cached events
|
|
180
176
|
mockEventCache.getEvents.mockReturnValueOnce([cachedEvent]);
|
|
181
177
|
|
|
182
|
-
telemetry.emitEvents([newEvent]);
|
|
183
|
-
await nextTick(); // wait for the event to be sent
|
|
178
|
+
await telemetry.emitEvents([newEvent]);
|
|
184
179
|
|
|
185
180
|
verifyMockCalls({
|
|
186
181
|
sendEventsCalls: 1,
|
|
@@ -189,7 +184,9 @@ describe("Telemetry", () => {
|
|
|
189
184
|
});
|
|
190
185
|
});
|
|
191
186
|
|
|
192
|
-
it("should correctly add common properties to events",
|
|
187
|
+
it("should correctly add common properties to events", () => {
|
|
188
|
+
const commonProps = telemetry.getCommonProperties();
|
|
189
|
+
|
|
193
190
|
// Use explicit type assertion
|
|
194
191
|
const expectedProps: Record<string, string> = {
|
|
195
192
|
mcp_client_version: "1.0.0",
|
|
@@ -200,86 +197,48 @@ describe("Telemetry", () => {
|
|
|
200
197
|
device_id: hashedMachineId,
|
|
201
198
|
};
|
|
202
199
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
telemetry.emitEvents([testEvent]);
|
|
206
|
-
await nextTick(); // wait for the event to be sent
|
|
207
|
-
|
|
208
|
-
const checkEvent = {
|
|
209
|
-
...testEvent,
|
|
210
|
-
properties: {
|
|
211
|
-
...testEvent.properties,
|
|
212
|
-
...expectedProps,
|
|
213
|
-
},
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
verifyMockCalls({
|
|
217
|
-
sendEventsCalls: 1,
|
|
218
|
-
clearEventsCalls: 1,
|
|
219
|
-
sendEventsCalledWith: [checkEvent],
|
|
220
|
-
});
|
|
200
|
+
expect(commonProps).toMatchObject(expectedProps);
|
|
221
201
|
});
|
|
222
202
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
203
|
+
describe("machine ID resolution", () => {
|
|
204
|
+
beforeEach(() => {
|
|
205
|
+
jest.clearAllMocks();
|
|
206
|
+
jest.useFakeTimers();
|
|
227
207
|
});
|
|
228
208
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
209
|
+
afterEach(() => {
|
|
210
|
+
jest.clearAllMocks();
|
|
211
|
+
jest.useRealTimers();
|
|
232
212
|
});
|
|
233
213
|
|
|
234
|
-
|
|
235
|
-
|
|
214
|
+
it("should successfully resolve the machine ID", async () => {
|
|
215
|
+
telemetry = Telemetry.create(session, config, {
|
|
216
|
+
getRawMachineId: () => Promise.resolve(machineId),
|
|
217
|
+
});
|
|
236
218
|
|
|
237
|
-
|
|
219
|
+
expect(telemetry["isBufferingEvents"]).toBe(true);
|
|
220
|
+
expect(telemetry.getCommonProperties().device_id).toBe(undefined);
|
|
238
221
|
|
|
239
|
-
|
|
240
|
-
sendEventsCalls: 1,
|
|
241
|
-
clearEventsCalls: 1,
|
|
242
|
-
appendEventsCalls: 1,
|
|
243
|
-
sendEventsCalledWith: [newEvent],
|
|
244
|
-
appendEventsCalledWith: [newEvent2],
|
|
245
|
-
});
|
|
246
|
-
});
|
|
222
|
+
await telemetry.deviceIdPromise;
|
|
247
223
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const testEvent = createTestEvent();
|
|
251
|
-
|
|
252
|
-
telemetry.emitEvents([testEvent]);
|
|
253
|
-
await nextTick(); // wait for the event to be sent
|
|
254
|
-
|
|
255
|
-
const checkEvent = {
|
|
256
|
-
...testEvent,
|
|
257
|
-
properties: {
|
|
258
|
-
...testEvent.properties,
|
|
259
|
-
device_id: hashedMachineId,
|
|
260
|
-
},
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
verifyMockCalls({
|
|
264
|
-
sendEventsCalls: 1,
|
|
265
|
-
clearEventsCalls: 1,
|
|
266
|
-
sendEventsCalledWith: [checkEvent],
|
|
267
|
-
});
|
|
224
|
+
expect(telemetry["isBufferingEvents"]).toBe(false);
|
|
225
|
+
expect(telemetry.getCommonProperties().device_id).toBe(hashedMachineId);
|
|
268
226
|
});
|
|
269
227
|
|
|
270
228
|
it("should handle machine ID resolution failure", async () => {
|
|
271
229
|
const loggerSpy = jest.spyOn(logger, "debug");
|
|
272
230
|
|
|
273
231
|
telemetry = Telemetry.create(session, config, {
|
|
274
|
-
...telemetryConfig,
|
|
275
232
|
getRawMachineId: () => Promise.reject(new Error("Failed to get device ID")),
|
|
276
233
|
});
|
|
277
234
|
|
|
278
|
-
|
|
235
|
+
expect(telemetry["isBufferingEvents"]).toBe(true);
|
|
236
|
+
expect(telemetry.getCommonProperties().device_id).toBe(undefined);
|
|
279
237
|
|
|
280
|
-
telemetry.
|
|
238
|
+
await telemetry.deviceIdPromise;
|
|
281
239
|
|
|
282
|
-
|
|
240
|
+
expect(telemetry["isBufferingEvents"]).toBe(false);
|
|
241
|
+
expect(telemetry.getCommonProperties().device_id).toBe("unknown");
|
|
283
242
|
|
|
284
243
|
expect(loggerSpy).toHaveBeenCalledWith(
|
|
285
244
|
LogId.telemetryDeviceIdFailure,
|
|
@@ -288,28 +247,27 @@ describe("Telemetry", () => {
|
|
|
288
247
|
);
|
|
289
248
|
});
|
|
290
249
|
|
|
291
|
-
it("should timeout if machine ID resolution takes too long", () => {
|
|
250
|
+
it("should timeout if machine ID resolution takes too long", async () => {
|
|
292
251
|
const loggerSpy = jest.spyOn(logger, "debug");
|
|
293
252
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
telemetry = Telemetry.create(session, config, {
|
|
297
|
-
...telemetryConfig,
|
|
298
|
-
getRawMachineId: () => new Promise(() => {}), // Never resolves
|
|
299
|
-
});
|
|
253
|
+
telemetry = Telemetry.create(session, config, { getRawMachineId: () => new Promise(() => {}) });
|
|
300
254
|
|
|
301
|
-
|
|
255
|
+
expect(telemetry["isBufferingEvents"]).toBe(true);
|
|
256
|
+
expect(telemetry.getCommonProperties().device_id).toBe(undefined);
|
|
302
257
|
|
|
303
|
-
|
|
258
|
+
jest.advanceTimersByTime(DEVICE_ID_TIMEOUT / 2);
|
|
304
259
|
|
|
305
|
-
|
|
260
|
+
// Make sure the timeout doesn't happen prematurely.
|
|
261
|
+
expect(telemetry["isBufferingEvents"]).toBe(true);
|
|
262
|
+
expect(telemetry.getCommonProperties().device_id).toBe(undefined);
|
|
306
263
|
|
|
307
|
-
jest.
|
|
264
|
+
jest.advanceTimersByTime(DEVICE_ID_TIMEOUT);
|
|
308
265
|
|
|
309
|
-
|
|
266
|
+
await telemetry.deviceIdPromise;
|
|
310
267
|
|
|
311
|
-
expect(
|
|
312
|
-
|
|
268
|
+
expect(telemetry.getCommonProperties().device_id).toBe("unknown");
|
|
269
|
+
expect(telemetry["isBufferingEvents"]).toBe(false);
|
|
270
|
+
expect(loggerSpy).toHaveBeenCalledWith(
|
|
313
271
|
LogId.telemetryDeviceIdTimeout,
|
|
314
272
|
"telemetry",
|
|
315
273
|
"Device ID retrieval timed out"
|
|
@@ -330,12 +288,9 @@ describe("Telemetry", () => {
|
|
|
330
288
|
it("should not send events", async () => {
|
|
331
289
|
const testEvent = createTestEvent();
|
|
332
290
|
|
|
333
|
-
telemetry.emitEvents([testEvent]);
|
|
334
|
-
await nextTick(); // wait for the event to be sent
|
|
291
|
+
await telemetry.emitEvents([testEvent]);
|
|
335
292
|
|
|
336
|
-
verifyMockCalls(
|
|
337
|
-
sendEventsCalls: 0,
|
|
338
|
-
});
|
|
293
|
+
verifyMockCalls();
|
|
339
294
|
});
|
|
340
295
|
});
|
|
341
296
|
|
|
@@ -358,12 +313,9 @@ describe("Telemetry", () => {
|
|
|
358
313
|
it("should not send events", async () => {
|
|
359
314
|
const testEvent = createTestEvent();
|
|
360
315
|
|
|
361
|
-
telemetry.emitEvents([testEvent]);
|
|
362
|
-
await nextTick(); // wait for the event to be sent
|
|
316
|
+
await telemetry.emitEvents([testEvent]);
|
|
363
317
|
|
|
364
|
-
verifyMockCalls(
|
|
365
|
-
sendEventsCalls: 0,
|
|
366
|
-
});
|
|
318
|
+
verifyMockCalls();
|
|
367
319
|
});
|
|
368
320
|
});
|
|
369
321
|
});
|