Skip to content

chore: better connect tool guidance with Atlas MCP-48 #349

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ The MongoDB MCP Server can be configured using multiple methods, with the follow
| `connectionString` | MongoDB connection string for direct database connections. Optional, if not set, you'll need to call the `connect` tool before interacting with MongoDB data. |
| `logPath` | Folder to store logs. |
| `disabledTools` | An array of tool names, operation types, and/or categories of tools that will be disabled. |
| `readOnly` | When set to true, only allows read and metadata operation types, disabling create/update/delete operations. |
| `readOnly` | When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations. |
| `indexCheck` | When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan. |
| `telemetry` | When set to disabled, disables telemetry collection. |

Expand Down Expand Up @@ -318,10 +318,11 @@ Operation types:
- `delete` - Tools that delete resources, such as delete document, drop collection, etc.
- `read` - Tools that read resources, such as find, aggregate, list clusters, etc.
- `metadata` - Tools that read metadata, such as list databases, list collections, collection schema, etc.
- `connect` - Tools that allow you to connect or switch the connection to a MongoDB instance. If this is disabled, you will need to provide a connection string through the config when starting the server.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a new tool operation type to more clearly cluster the connection tools and allow users to disable them if they want to be 100% certain they're always connected to the same cluster (this was another recommendation by the IS team).

Right now, I'm keeping that enabled when working with --readOnly, but am open to be convinced otherwise.


#### Read-Only Mode

The `readOnly` configuration option allows you to restrict the MCP server to only use tools with "read" and "metadata" operation types. When enabled, all tools that have "create", "update" or "delete" operation types will not be registered with the server.
The `readOnly` configuration option allows you to restrict the MCP server to only use tools with "read", "connect", and "metadata" operation types. When enabled, all tools that have "create", "update" or "delete" operation types will not be registered with the server.

This is useful for scenarios where you want to provide access to MongoDB data for analysis without allowing any modifications to the data or infrastructure.

Expand Down
11 changes: 8 additions & 3 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { type ServerCommand } from "./telemetry/types.js";
import { CallToolRequestSchema, CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import assert from "assert";
import { detectContainerEnv } from "./common/container.js";
import { ToolBase } from "./tools/tool.js";

export interface ServerOptions {
session: Session;
Expand All @@ -22,9 +23,10 @@ export interface ServerOptions {

export class Server {
public readonly session: Session;
private readonly mcpServer: McpServer;
public readonly mcpServer: McpServer;
private readonly telemetry: Telemetry;
public readonly userConfig: UserConfig;
public readonly tools: ToolBase[] = [];
private readonly startTime: number;

constructor({ session, mcpServer, userConfig, telemetry }: ServerOptions) {
Expand Down Expand Up @@ -141,8 +143,11 @@ export class Server {
}

private registerTools() {
for (const tool of [...AtlasTools, ...MongoDbTools]) {
new tool(this.session, this.userConfig, this.telemetry).register(this.mcpServer);
for (const toolConstructor of [...AtlasTools, ...MongoDbTools]) {
const tool = new toolConstructor(this.session, this.userConfig, this.telemetry);
if (tool.register(this)) {
this.tools.push(tool);
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/tools/atlas/atlasTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { z } from "zod";
import { ApiClientError } from "../../common/atlas/apiClientError.js";

export abstract class AtlasToolBase extends ToolBase {
protected category: ToolCategory = "atlas";
public category: ToolCategory = "atlas";

protected verifyAllowed(): boolean {
if (!this.config.apiClientId || !this.config.apiClientSecret) {
Expand All @@ -29,7 +29,7 @@ export abstract class AtlasToolBase extends ToolBase {
type: "text",
text: `Unable to authenticate with MongoDB Atlas, API error: ${error.message}

Hint: Your API credentials may be invalid, expired or lack permissions.
Hint: Your API credentials may be invalid, expired or lack permissions.
Please check your Atlas API credentials and ensure they have the appropriate permissions.
For more information on setting up API keys, visit: https://www.mongodb.com/docs/atlas/configure-api-access/`,
},
Expand All @@ -44,7 +44,7 @@ For more information on setting up API keys, visit: https://www.mongodb.com/docs
{
type: "text",
text: `Received a Forbidden API Error: ${error.message}

You don't have sufficient permissions to perform this action in MongoDB Atlas
Please ensure your API key has the necessary roles assigned.
For more information on Atlas API access roles, visit: https://www.mongodb.com/docs/atlas/api/service-accounts-overview/`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ function sleep(ms: number): Promise<void> {
}

export class ConnectClusterTool extends AtlasToolBase {
protected name = "atlas-connect-cluster";
public name = "atlas-connect-cluster";
protected description = "Connect to MongoDB Atlas cluster";
protected operationType: OperationType = "metadata";
public operationType: OperationType = "connect";
protected argsShape = {
projectId: z.string().describe("Atlas project ID"),
clusterName: z.string().describe("Atlas cluster name"),
Expand Down
4 changes: 2 additions & 2 deletions src/tools/atlas/create/createAccessList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { ToolArgs, OperationType } from "../../tool.js";
const DEFAULT_COMMENT = "Added by Atlas MCP";

export class CreateAccessListTool extends AtlasToolBase {
protected name = "atlas-create-access-list";
public name = "atlas-create-access-list";
protected description = "Allow Ip/CIDR ranges to access your MongoDB Atlas clusters.";
protected operationType: OperationType = "create";
public operationType: OperationType = "create";
protected argsShape = {
projectId: z.string().describe("Atlas project ID"),
ipAddresses: z
Expand Down
4 changes: 2 additions & 2 deletions src/tools/atlas/create/createDBUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { CloudDatabaseUser, DatabaseUserRole } from "../../../common/atlas/opena
import { generateSecurePassword } from "../../../common/atlas/generatePassword.js";

export class CreateDBUserTool extends AtlasToolBase {
protected name = "atlas-create-db-user";
public name = "atlas-create-db-user";
protected description = "Create an MongoDB Atlas database user";
protected operationType: OperationType = "create";
public operationType: OperationType = "create";
protected argsShape = {
projectId: z.string().describe("Atlas project ID"),
username: z.string().describe("Username for the new user"),
Expand Down
4 changes: 2 additions & 2 deletions src/tools/atlas/create/createFreeCluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { ToolArgs, OperationType } from "../../tool.js";
import { ClusterDescription20240805 } from "../../../common/atlas/openapi.js";

export class CreateFreeClusterTool extends AtlasToolBase {
protected name = "atlas-create-free-cluster";
public name = "atlas-create-free-cluster";
protected description = "Create a free MongoDB Atlas cluster";
protected operationType: OperationType = "create";
public operationType: OperationType = "create";
protected argsShape = {
projectId: z.string().describe("Atlas project ID to create the cluster in"),
name: z.string().describe("Name of the cluster"),
Expand Down
4 changes: 2 additions & 2 deletions src/tools/atlas/create/createProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { ToolArgs, OperationType } from "../../tool.js";
import { Group } from "../../../common/atlas/openapi.js";

export class CreateProjectTool extends AtlasToolBase {
protected name = "atlas-create-project";
public name = "atlas-create-project";
protected description = "Create a MongoDB Atlas project";
protected operationType: OperationType = "create";
public operationType: OperationType = "create";
protected argsShape = {
projectName: z.string().optional().describe("Name for the new project"),
organizationId: z.string().optional().describe("Organization ID for the new project"),
Expand Down
4 changes: 2 additions & 2 deletions src/tools/atlas/read/inspectAccessList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { AtlasToolBase } from "../atlasTool.js";
import { ToolArgs, OperationType } from "../../tool.js";

export class InspectAccessListTool extends AtlasToolBase {
protected name = "atlas-inspect-access-list";
public name = "atlas-inspect-access-list";
protected description = "Inspect Ip/CIDR ranges with access to your MongoDB Atlas clusters.";
protected operationType: OperationType = "read";
public operationType: OperationType = "read";
protected argsShape = {
projectId: z.string().describe("Atlas project ID"),
};
Expand Down
4 changes: 2 additions & 2 deletions src/tools/atlas/read/inspectCluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { ToolArgs, OperationType } from "../../tool.js";
import { Cluster, inspectCluster } from "../../../common/atlas/cluster.js";

export class InspectClusterTool extends AtlasToolBase {
protected name = "atlas-inspect-cluster";
public name = "atlas-inspect-cluster";
protected description = "Inspect MongoDB Atlas cluster";
protected operationType: OperationType = "read";
public operationType: OperationType = "read";
protected argsShape = {
projectId: z.string().describe("Atlas project ID"),
clusterName: z.string().describe("Atlas cluster name"),
Expand Down
4 changes: 2 additions & 2 deletions src/tools/atlas/read/listAlerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { AtlasToolBase } from "../atlasTool.js";
import { ToolArgs, OperationType } from "../../tool.js";

export class ListAlertsTool extends AtlasToolBase {
protected name = "atlas-list-alerts";
public name = "atlas-list-alerts";
protected description = "List MongoDB Atlas alerts";
protected operationType: OperationType = "read";
public operationType: OperationType = "read";
protected argsShape = {
projectId: z.string().describe("Atlas project ID to list alerts for"),
};
Expand Down
4 changes: 2 additions & 2 deletions src/tools/atlas/read/listClusters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import {
import { formatCluster, formatFlexCluster } from "../../../common/atlas/cluster.js";

export class ListClustersTool extends AtlasToolBase {
protected name = "atlas-list-clusters";
public name = "atlas-list-clusters";
protected description = "List MongoDB Atlas clusters";
protected operationType: OperationType = "read";
public operationType: OperationType = "read";
protected argsShape = {
projectId: z.string().describe("Atlas project ID to filter clusters").optional(),
};
Expand Down
4 changes: 2 additions & 2 deletions src/tools/atlas/read/listDBUsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { ToolArgs, OperationType } from "../../tool.js";
import { DatabaseUserRole, UserScope } from "../../../common/atlas/openapi.js";

export class ListDBUsersTool extends AtlasToolBase {
protected name = "atlas-list-db-users";
public name = "atlas-list-db-users";
protected description = "List MongoDB Atlas database users";
protected operationType: OperationType = "read";
public operationType: OperationType = "read";
protected argsShape = {
projectId: z.string().describe("Atlas project ID to filter DB users"),
};
Expand Down
4 changes: 2 additions & 2 deletions src/tools/atlas/read/listOrgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { AtlasToolBase } from "../atlasTool.js";
import { OperationType } from "../../tool.js";

export class ListOrganizationsTool extends AtlasToolBase {
protected name = "atlas-list-orgs";
public name = "atlas-list-orgs";
protected description = "List MongoDB Atlas organizations";
protected operationType: OperationType = "read";
public operationType: OperationType = "read";
protected argsShape = {};

protected async execute(): Promise<CallToolResult> {
Expand Down
4 changes: 2 additions & 2 deletions src/tools/atlas/read/listProjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { z } from "zod";
import { ToolArgs } from "../../tool.js";

export class ListProjectsTool extends AtlasToolBase {
protected name = "atlas-list-projects";
public name = "atlas-list-projects";
protected description = "List MongoDB Atlas projects";
protected operationType: OperationType = "read";
public operationType: OperationType = "read";
protected argsShape = {
orgId: z.string().describe("Atlas organization ID to filter projects").optional(),
};
Expand Down
2 changes: 1 addition & 1 deletion src/tools/atlas/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ListDBUsersTool } from "./read/listDBUsers.js";
import { CreateDBUserTool } from "./create/createDBUser.js";
import { CreateProjectTool } from "./create/createProject.js";
import { ListOrganizationsTool } from "./read/listOrgs.js";
import { ConnectClusterTool } from "./metadata/connectCluster.js";
import { ConnectClusterTool } from "./connect/connectCluster.js";
import { ListAlertsTool } from "./read/listAlerts.js";

export const AtlasTools = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { z } from "zod";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { MongoDBToolBase } from "../mongodbTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import assert from "assert";
import { UserConfig } from "../../../config.js";
import { Telemetry } from "../../../telemetry/telemetry.js";
import { Session } from "../../../session.js";
import { Server } from "../../../server.js";

const disconnectedSchema = z
.object({
Expand All @@ -33,7 +33,7 @@ const connectedDescription =
const disconnectedDescription = "Connect to a MongoDB instance";

export class ConnectTool extends MongoDBToolBase {
protected name: typeof connectedName | typeof disconnectedName = disconnectedName;
public name: typeof connectedName | typeof disconnectedName = disconnectedName;
protected description: typeof connectedDescription | typeof disconnectedDescription = disconnectedDescription;

// Here the default is empty just to trigger registration, but we're going to override it with the correct
Expand All @@ -42,7 +42,7 @@ export class ConnectTool extends MongoDBToolBase {
connectionString: z.string().optional(),
};

protected operationType: OperationType = "metadata";
public operationType: OperationType = "connect";

constructor(session: Session, config: UserConfig, telemetry: Telemetry) {
super(session, config, telemetry);
Expand Down Expand Up @@ -72,10 +72,13 @@ export class ConnectTool extends MongoDBToolBase {
};
}

public register(server: McpServer): void {
super.register(server);
public register(server: Server): boolean {
if (super.register(server)) {
this.updateMetadata();
return true;
}

this.updateMetadata();
return false;
}

private updateMetadata(): void {
Expand Down
4 changes: 2 additions & 2 deletions src/tools/mongodb/create/createCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
import { OperationType, ToolArgs } from "../../tool.js";

export class CreateCollectionTool extends MongoDBToolBase {
protected name = "create-collection";
public name = "create-collection";
protected description =
"Creates a new collection in a database. If the database doesn't exist, it will be created automatically.";
protected argsShape = DbOperationArgs;

protected operationType: OperationType = "create";
public operationType: OperationType = "create";

protected async execute({ collection, database }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
const provider = await this.ensureConnected();
Expand Down
4 changes: 2 additions & 2 deletions src/tools/mongodb/create/createIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { ToolArgs, OperationType } from "../../tool.js";
import { IndexDirection } from "mongodb";

export class CreateIndexTool extends MongoDBToolBase {
protected name = "create-index";
public name = "create-index";
protected description = "Create an index for a collection";
protected argsShape = {
...DbOperationArgs,
keys: z.record(z.string(), z.custom<IndexDirection>()).describe("The index definition"),
name: z.string().optional().describe("The name of the index"),
};

protected operationType: OperationType = "create";
public operationType: OperationType = "create";

protected async execute({
database,
Expand Down
4 changes: 2 additions & 2 deletions src/tools/mongodb/create/insertMany.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
import { ToolArgs, OperationType } from "../../tool.js";

export class InsertManyTool extends MongoDBToolBase {
protected name = "insert-many";
public name = "insert-many";
protected description = "Insert an array of documents into a MongoDB collection";
protected argsShape = {
...DbOperationArgs,
Expand All @@ -14,7 +14,7 @@ export class InsertManyTool extends MongoDBToolBase {
"The array of documents to insert, matching the syntax of the document argument of db.collection.insertMany()"
),
};
protected operationType: OperationType = "create";
public operationType: OperationType = "create";

protected async execute({
database,
Expand Down
4 changes: 2 additions & 2 deletions src/tools/mongodb/delete/deleteMany.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ToolArgs, OperationType } from "../../tool.js";
import { checkIndexUsage } from "../../../helpers/indexCheck.js";

export class DeleteManyTool extends MongoDBToolBase {
protected name = "delete-many";
public name = "delete-many";
protected description = "Removes all documents that match the filter from a MongoDB collection";
protected argsShape = {
...DbOperationArgs,
Expand All @@ -16,7 +16,7 @@ export class DeleteManyTool extends MongoDBToolBase {
"The query filter, specifying the deletion criteria. Matches the syntax of the filter argument of db.collection.deleteMany()"
),
};
protected operationType: OperationType = "delete";
public operationType: OperationType = "delete";

protected async execute({
database,
Expand Down
4 changes: 2 additions & 2 deletions src/tools/mongodb/delete/dropCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
import { ToolArgs, OperationType } from "../../tool.js";

export class DropCollectionTool extends MongoDBToolBase {
protected name = "drop-collection";
public name = "drop-collection";
protected description =
"Removes a collection or view from the database. The method also removes any indexes associated with the dropped collection.";
protected argsShape = {
...DbOperationArgs,
};
protected operationType: OperationType = "delete";
public operationType: OperationType = "delete";

protected async execute({ database, collection }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
const provider = await this.ensureConnected();
Expand Down
4 changes: 2 additions & 2 deletions src/tools/mongodb/delete/dropDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
import { ToolArgs, OperationType } from "../../tool.js";

export class DropDatabaseTool extends MongoDBToolBase {
protected name = "drop-database";
public name = "drop-database";
protected description = "Removes the specified database, deleting the associated data files";
protected argsShape = {
database: DbOperationArgs.database,
};
protected operationType: OperationType = "delete";
public operationType: OperationType = "delete";

protected async execute({ database }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
const provider = await this.ensureConnected();
Expand Down
4 changes: 2 additions & 2 deletions src/tools/mongodb/metadata/collectionSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { ToolArgs, OperationType } from "../../tool.js";
import { getSimplifiedSchema } from "mongodb-schema";

export class CollectionSchemaTool extends MongoDBToolBase {
protected name = "collection-schema";
public name = "collection-schema";
protected description = "Describe the schema for a collection";
protected argsShape = DbOperationArgs;

protected operationType: OperationType = "metadata";
public operationType: OperationType = "metadata";

protected async execute({ database, collection }: ToolArgs<typeof DbOperationArgs>): Promise<CallToolResult> {
const provider = await this.ensureConnected();
Expand Down
Loading
Loading