Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
7a27749
feat: Adds scaffolding for atlas-local tools MCP-155 (#498)
Luke-Sanderson Sep 1, 2025
a27f2d4
Merge branch 'main' into feat-MCP-40
jeroenvervaeke Sep 5, 2025
8a2db27
feat(atlas-local): Added Atlas Local List Deployments tool (#520)
jeroenvervaeke Sep 9, 2025
6938a8f
feat(atlas-local): Add Atlas Local List Deployments tool (#538)
Luke-Sanderson Sep 11, 2025
e774083
feat(atlas-local): Add Atlas Local Create Deployment tool (#546)
Luke-Sanderson Sep 12, 2025
bb717ab
feat(atlas-local): Accuracy tests for Atlas Local (#554)
Luke-Sanderson Sep 15, 2025
0d14679
feat(atlas-local): Split Atlas Local tests from Atlas (#552)
Luke-Sanderson Sep 15, 2025
cb5d335
feat(atlas-local): Adds Atlas Local Connect Deployment tool (#612)
cveticm Oct 7, 2025
91c11cc
feat: added atlas local deployment id to telemetry (#627)
jeroenvervaeke Oct 9, 2025
8efb029
refactor: Replace z.string with CommonArgs.string (#629)
Luke-Sanderson Oct 9, 2025
c0f3e49
Merge branch 'main' into feat-MCP-40
Luke-Sanderson Oct 9, 2025
cac14ae
Merge branch 'main' into feat-MCP-40
Luke-Sanderson Oct 9, 2025
bd4a061
Merge branch 'main' into feat-MCP-40
Luke-Sanderson Oct 9, 2025
14ade77
fix: knip ignore atlas-local dependency
Luke-Sanderson Oct 9, 2025
5c5c2e7
Merge branch 'main' into feat-MCP-40
Luke-Sanderson Oct 10, 2025
5afc312
docs(atlas-local): Adds the Atlas Local Tools to the readme
Luke-Sanderson Oct 10, 2025
c4a44e0
fix: Small changes from PR suggestions
Luke-Sanderson Oct 10, 2025
9eb0c1a
refactor: Move all lookupDeploymentId calls to resolveTelemetryMetadata
Luke-Sanderson Oct 10, 2025
74d2218
refactor: Update atlas local error handling
Luke-Sanderson Oct 10, 2025
eb488ff
Merge branch 'main' into feat-MCP-40
jeroenvervaeke Oct 14, 2025
e33df95
move atlas local client initialization to 'TransportRunnerBase'
jeroenvervaeke Oct 16, 2025
c3efcd1
use the @mongodb-js/atlas-local package instead of the @mongodb-js-pr…
jeroenvervaeke Oct 16, 2025
123ab82
fix bug with fetching deployment id caused by refactor
jeroenvervaeke Oct 17, 2025
eda00a2
Merge branch 'main' into feat-MCP-40
jeroenvervaeke Oct 17, 2025
a8e10bd
only lookup deploymentid in atlas local delete tool when telemetry is…
jeroenvervaeke Oct 20, 2025
c29581f
fix integration tests
jeroenvervaeke Oct 20, 2025
e38743f
fix error message in listSearchIndexes test
jeroenvervaeke Oct 20, 2025
08eb04c
removed debug log
jeroenvervaeke Oct 20, 2025
a197b08
Merge branch 'main' into feat-MCP-40
jeroenvervaeke Oct 20, 2025
30aabae
Merge branch 'main' into feat-MCP-40
jeroenvervaeke Oct 20, 2025
3e46dbb
adressed pr comments in atlasLocal.ts
jeroenvervaeke Oct 21, 2025
035d4c7
addressed PR comments in atlasLocalTools + simplified telemetry, clos…
jeroenvervaeke Oct 21, 2025
4730bfb
reverted emitToolEvent to be sync again
jeroenvervaeke Oct 21, 2025
e0c8a72
move AtlasLocalTools to toolConstructors
jeroenvervaeke Oct 21, 2025
13b989e
return json instead of markdown table for list deployments
jeroenvervaeke Oct 21, 2025
78fd715
fix list deployments test
jeroenvervaeke Oct 21, 2025
596a783
Merge branch 'main' into feat-MCP-40
jeroenvervaeke Oct 21, 2025
f20c09f
Update src/tools/atlasLocal/read/listDeployments.ts
jeroenvervaeke Oct 21, 2025
318e429
Update src/tools/atlasLocal/atlasLocalTool.ts
jeroenvervaeke Oct 21, 2025
939cfd5
Update src/tools/atlasLocal/atlasLocalTool.ts
jeroenvervaeke Oct 21, 2025
d535757
ran npm run fix, and cleaned up code after accepting suggestions
jeroenvervaeke Oct 21, 2025
db06cc1
fix accuracy tests
jeroenvervaeke Oct 21, 2025
04e505c
updated listDeployments.test.ts after accepting suggestions
jeroenvervaeke Oct 21, 2025
5ae9405
addressed test comments
jeroenvervaeke Oct 21, 2025
3de5b26
added comment describing test in 'should return an error when creatin…
jeroenvervaeke Oct 21, 2025
e3c6708
ran 'npm run fix'
jeroenvervaeke Oct 21, 2025
56d981d
prefixed list deployments accuacy prompts with 'local'
jeroenvervaeke Oct 21, 2025
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
Prev Previous commit
Next Next commit
fix integration tests
  • Loading branch information
jeroenvervaeke committed Oct 20, 2025
commit c29581f299b2736bc908c38b565bebf52967dfa5
34 changes: 2 additions & 32 deletions tests/integration/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import { MCPConnectionManager } from "../../src/common/connectionManager.js";
import { DeviceId } from "../../src/helpers/deviceId.js";
import { connectionErrorHandler } from "../../src/common/connectionErrorHandler.js";
import { Keychain } from "../../src/common/keychain.js";
import type { Client as AtlasLocalClient } from "@mongodb-js/atlas-local";
import { Elicitation } from "../../src/elicitation.js";
import type { MockClientCapabilities, createMockElicitInput } from "../utils/elicitationMocks.js";
import { VectorSearchEmbeddingsManager } from "../../src/common/search/vectorSearchEmbeddingsManager.js";
import { defaultCreateAtlasLocalClient } from "../../src/common/atlasLocal.js";

export const driverOptions = setupDriverConfig({
config,
Expand Down Expand Up @@ -115,6 +115,7 @@ export function setupIntegrationTest(
connectionManager,
keychain: new Keychain(),
vectorSearchEmbeddingsManager: new VectorSearchEmbeddingsManager(userConfig, connectionManager),
atlasLocalClient: await defaultCreateAtlasLocalClient(),
});

// Mock hasValidAccessToken for tests
Expand Down Expand Up @@ -408,37 +409,6 @@ export function waitUntil<T extends ConnectionState>(
});
}

export function waitUntilAtlasLocalClientIsSet(
mcpServer: Server,
signal: AbortSignal,
timeout: number = 5000
): Promise<AtlasLocalClient> {
let ts: NodeJS.Timeout | undefined;

const timeoutSignal = AbortSignal.timeout(timeout);
const combinedSignal = AbortSignal.any([signal, timeoutSignal]);

return new Promise<AtlasLocalClient>((resolve, reject) => {
ts = setInterval(() => {
if (combinedSignal.aborted) {
return reject(new Error(`Aborted: ${combinedSignal.reason}`));
}

// wait until session.client != undefined
// do not wait more than 1 second, should take a few milliseconds at most
// try every 50ms to see if the client is set, if it's not set after 1 second, throw an error
const client = mcpServer.session.atlasLocalClient;
if (client) {
return resolve(client);
}
}, 100);
}).finally(() => {
if (ts !== undefined) {
clearInterval(ts);
}
});
}

export function getDataFromUntrustedContent(content: string): string {
const regex = /^[ \t]*<untrusted-user-data-[0-9a-f\\-]*>(?<data>.*)^[ \t]*<\/untrusted-user-data-[0-9a-f\\-]*>/gms;
const match = regex.exec(content);
Expand Down
13 changes: 2 additions & 11 deletions tests/integration/tools/atlas-local/connectDeployment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
getResponseElements,
setupIntegrationTest,
validateToolMetadata,
waitUntilAtlasLocalClientIsSet,
} from "../../helpers.js";
import { afterEach, describe, expect, it } from "vitest";

Expand All @@ -19,10 +18,6 @@ const integration = setupIntegrationTest(
// Docker is not available on macOS in GitHub Actions
// That's why we skip the tests on macOS in GitHub Actions
describe.skipIf(isMacOSInGitHubActions)("atlas-local-connect-deployment", () => {
beforeEach(async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);
});

validateToolMetadata(integration, "atlas-local-connect-deployment", "Connect to a MongoDB Atlas Local deployment", [
{
name: "deploymentName",
Expand Down Expand Up @@ -56,9 +51,7 @@ describe.skipIf(isMacOSInGitHubActions)("atlas-local-connect-deployment with dep
let deploymentName: string = "";
let deploymentNamesToCleanup: string[] = [];

beforeEach(async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);

beforeEach(async () => {
// Create deployments
deploymentName = `test-deployment-1-${Date.now()}`;
deploymentNamesToCleanup.push(deploymentName);
Expand Down Expand Up @@ -103,10 +96,8 @@ describe.skipIf(isMacOSInGitHubActions)("atlas-local-connect-deployment with dep
});

describe.skipIf(!isMacOSInGitHubActions)("atlas-local-connect-deployment [MacOS in GitHub Actions]", () => {
it("should not have the atlas-local-connect-deployment tool", async ({ signal }) => {
it("should not have the atlas-local-connect-deployment tool", async () => {
// This should throw an error because the client is not set within the timeout of 5 seconds (default)
await expect(waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal)).rejects.toThrow();

const { tools } = await integration.mcpClient().listTools();
const connectDeployment = tools.find((tool) => tool.name === "atlas-local-connect-deployment");
expect(connectDeployment).toBeUndefined();
Expand Down
28 changes: 7 additions & 21 deletions tests/integration/tools/atlas-local/createDeployment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
expectDefined,
getResponseElements,
setupIntegrationTest,
waitUntilAtlasLocalClientIsSet,
} from "../../helpers.js";
import { afterEach, describe, expect, it } from "vitest";

Expand Down Expand Up @@ -34,28 +33,22 @@ describe("atlas-local-create-deployment", () => {
() => defaultDriverOptions
);

it.skipIf(isMacOSInGitHubActions)("should have the atlas-local-create-deployment tool", async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);

it.skipIf(isMacOSInGitHubActions)("should have the atlas-local-create-deployment tool", async () => {
const { tools } = await integration.mcpClient().listTools();
const createDeployment = tools.find((tool) => tool.name === "atlas-local-create-deployment");
expectDefined(createDeployment);
});

it.skipIf(!isMacOSInGitHubActions)(
"[MacOS in GitHub Actions] should not have the atlas-local-create-deployment tool",
async ({ signal }) => {
// This should throw an error because the client is not set within the timeout of 5 seconds (default)
await expect(waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal)).rejects.toThrow();

async () => {
const { tools } = await integration.mcpClient().listTools();
const createDeployment = tools.find((tool) => tool.name === "atlas-local-create-deployment");
expect(createDeployment).toBeUndefined();
}
);

it.skipIf(isMacOSInGitHubActions)("should have correct metadata", async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);
it.skipIf(isMacOSInGitHubActions)("should have correct metadata", async () => {
const { tools } = await integration.mcpClient().listTools();
const createDeployment = tools.find((tool) => tool.name === "atlas-local-create-deployment");
expectDefined(createDeployment);
Expand All @@ -64,8 +57,7 @@ describe("atlas-local-create-deployment", () => {
expect(createDeployment.inputSchema.properties).toHaveProperty("deploymentName");
});

it.skipIf(isMacOSInGitHubActions)("should create a deployment when calling the tool", async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);
it.skipIf(isMacOSInGitHubActions)("should create a deployment when calling the tool", async () => {
const deploymentName = `test-deployment-${Date.now()}`;

// Check that deployment doesn't exist before creation
Expand Down Expand Up @@ -97,9 +89,7 @@ describe("atlas-local-create-deployment", () => {

it.skipIf(isMacOSInGitHubActions)(
"should return an error when creating a deployment that already exists",
async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);

async () => {
// Create a deployment
const deploymentName = `test-deployment-${Date.now()}`;
deploymentNamesToCleanup.push(deploymentName);
Expand All @@ -119,9 +109,7 @@ describe("atlas-local-create-deployment", () => {
}
);

it.skipIf(isMacOSInGitHubActions)("should create a deployment with the correct name", async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);

it.skipIf(isMacOSInGitHubActions)("should create a deployment with the correct name", async () => {
// Create a deployment
const deploymentName = `test-deployment-${Date.now()}`;
deploymentNamesToCleanup.push(deploymentName);
Expand All @@ -147,9 +135,7 @@ describe("atlas-local-create-deployment", () => {
expect(elements[1]?.text ?? "").toContain("Running");
});

it.skipIf(isMacOSInGitHubActions)("should create a deployment when name is not provided", async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);

it.skipIf(isMacOSInGitHubActions)("should create a deployment when name is not provided", async () => {
// Create a deployment
const createResponse = await integration.mcpClient().callTool({
name: "atlas-local-create-deployment",
Expand Down
19 changes: 5 additions & 14 deletions tests/integration/tools/atlas-local/deleteDeployment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
expectDefined,
getResponseElements,
setupIntegrationTest,
waitUntilAtlasLocalClientIsSet,
} from "../../helpers.js";
import { describe, expect, it } from "vitest";

Expand All @@ -18,28 +17,22 @@ describe("atlas-local-delete-deployment", () => {
() => defaultDriverOptions
);

it.skipIf(isMacOSInGitHubActions)("should have the atlas-local-delete-deployment tool", async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);

it.skipIf(isMacOSInGitHubActions)("should have the atlas-local-delete-deployment tool", async () => {
const { tools } = await integration.mcpClient().listTools();
const deleteDeployment = tools.find((tool) => tool.name === "atlas-local-delete-deployment");
expectDefined(deleteDeployment);
});

it.skipIf(!isMacOSInGitHubActions)(
"[MacOS in GitHub Actions] should not have the atlas-local-delete-deployment tool",
async ({ signal }) => {
// This should throw an error because the client is not set within the timeout of 5 seconds (default)
await expect(waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal)).rejects.toThrow();

async () => {
const { tools } = await integration.mcpClient().listTools();
const deleteDeployment = tools.find((tool) => tool.name === "atlas-local-delete-deployment");
expect(deleteDeployment).toBeUndefined();
}
);

it.skipIf(isMacOSInGitHubActions)("should have correct metadata", async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);
it.skipIf(isMacOSInGitHubActions)("should have correct metadata", async () => {
const { tools } = await integration.mcpClient().listTools();
const deleteDeployment = tools.find((tool) => tool.name === "atlas-local-delete-deployment");
expectDefined(deleteDeployment);
Expand All @@ -50,8 +43,7 @@ describe("atlas-local-delete-deployment", () => {

it.skipIf(isMacOSInGitHubActions)(
"should return 'no such container' error when deployment to delete does not exist",
async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);
async () => {
const deploymentName = "non-existent";

const response = await integration.mcpClient().callTool({
Expand All @@ -66,8 +58,7 @@ describe("atlas-local-delete-deployment", () => {
}
);

it.skipIf(isMacOSInGitHubActions)("should delete a deployment when calling the tool", async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);
it.skipIf(isMacOSInGitHubActions)("should delete a deployment when calling the tool", async () => {
// Create a deployment
const deploymentName = `test-deployment-${Date.now()}`;
await integration.mcpClient().callTool({
Expand Down
17 changes: 4 additions & 13 deletions tests/integration/tools/atlas-local/listDeployments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
expectDefined,
getResponseElements,
setupIntegrationTest,
waitUntilAtlasLocalClientIsSet,
} from "../../helpers.js";
import { describe, expect, it } from "vitest";

Expand All @@ -18,28 +17,22 @@ describe("atlas-local-list-deployments", () => {
() => defaultDriverOptions
);

it.skipIf(isMacOSInGitHubActions)("should have the atlas-local-list-deployments tool", async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);

it.skipIf(isMacOSInGitHubActions)("should have the atlas-local-list-deployments tool", async () => {
const { tools } = await integration.mcpClient().listTools();
const listDeployments = tools.find((tool) => tool.name === "atlas-local-list-deployments");
expectDefined(listDeployments);
});

it.skipIf(!isMacOSInGitHubActions)(
"[MacOS in GitHub Actions] should not have the atlas-local-list-deployments tool",
async ({ signal }) => {
// This should throw an error because the client is not set within the timeout of 5 seconds (default)
await expect(waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal)).rejects.toThrow();

async () => {
const { tools } = await integration.mcpClient().listTools();
const listDeployments = tools.find((tool) => tool.name === "atlas-local-list-deployments");
expect(listDeployments).toBeUndefined();
}
);

it.skipIf(isMacOSInGitHubActions)("should have correct metadata", async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);
it.skipIf(isMacOSInGitHubActions)("should have correct metadata", async () => {
const { tools } = await integration.mcpClient().listTools();
const listDeployments = tools.find((tool) => tool.name === "atlas-local-list-deployments");
expectDefined(listDeployments);
Expand All @@ -48,9 +41,7 @@ describe("atlas-local-list-deployments", () => {
expect(listDeployments.inputSchema.properties).toEqual({});
});

it.skipIf(isMacOSInGitHubActions)("should not crash when calling the tool", async ({ signal }) => {
await waitUntilAtlasLocalClientIsSet(integration.mcpServer(), signal);

it.skipIf(isMacOSInGitHubActions)("should not crash when calling the tool", async () => {
const response = await integration.mcpClient().callTool({
name: "atlas-local-list-deployments",
arguments: {},
Expand Down
Loading