Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion src/tools/atlas/create/createDBUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class CreateDBUserTool extends AtlasToolBase {
.optional()
.nullable()
.describe(
"Password for the new user. If the user hasn't supplied an explicit password, leave it unset and under no circumstances try to generate a random one. A secure password will be generated by the MCP server if necessary."
"Password for the new user. IMPORTANT: If the user hasn't supplied an explicit password, leave it unset and under no circumstances try to generate a random one. A secure password will be generated by the MCP server if necessary."
),
roles: z
.array(
Expand Down
24 changes: 13 additions & 11 deletions src/tools/atlas/read/inspectAccessList.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { z } from "zod";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { AtlasToolBase } from "../atlasTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { ToolArgs, OperationType, formatUntrustedData } from "../../tool.js";

export class InspectAccessListTool extends AtlasToolBase {
public name = "atlas-inspect-access-list";
Expand All @@ -20,23 +20,25 @@ export class InspectAccessListTool extends AtlasToolBase {
},
});

if (!accessList?.results?.length) {
throw new Error("No access list entries found.");
const results = accessList.results ?? [];

if (!results.length) {
return {
content: [{ type: "text", text: "No access list entries found." }],
};
Comment on lines +27 to +29
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this still be marked with isError: true or was this condition incorrectly classified as error earlier?

Copy link
Collaborator

Choose a reason for hiding this comment

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

The question applies to multiple other tools where these changes were made.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think these should have been errors - not having access list entries is not an erroneous condition in and of itself. cc @blva to confirm.

Copy link
Collaborator

@blva blva Aug 22, 2025

Choose a reason for hiding this comment

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

I agree, as a parallel the API itself returns 200. Everything was done correctly. Marking as error could lead customers/LLMs to think that the gathering information has failed

}

return {
content: [
{
type: "text",
text: `IP ADDRESS | CIDR | COMMENT
content: formatUntrustedData(
`Found ${results.length} access list entries`,
`IP ADDRESS | CIDR | COMMENT
------|------|------
${(accessList.results || [])
${results
.map((entry) => {
return `${entry.ipAddress} | ${entry.cidrBlock} | ${entry.comment}`;
})
.join("\n")}`,
},
],
.join("\n")}`
),
};
}
}
14 changes: 6 additions & 8 deletions src/tools/atlas/read/inspectCluster.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { z } from "zod";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { AtlasToolBase } from "../atlasTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { ToolArgs, OperationType, formatUntrustedData } from "../../tool.js";
import { Cluster, inspectCluster } from "../../../common/atlas/cluster.js";

export class InspectClusterTool extends AtlasToolBase {
Expand All @@ -21,14 +21,12 @@ export class InspectClusterTool extends AtlasToolBase {

private formatOutput(formattedCluster: Cluster): CallToolResult {
return {
content: [
{
type: "text",
text: `Cluster Name | Cluster Type | Tier | State | MongoDB Version | Connection String
content: formatUntrustedData(
"Cluster details:",
`Cluster Name | Cluster Type | Tier | State | MongoDB Version | Connection String
----------------|----------------|----------------|----------------|----------------|----------------
${formattedCluster.name || "Unknown"} | ${formattedCluster.instanceType} | ${formattedCluster.instanceSize || "N/A"} | ${formattedCluster.state || "UNKNOWN"} | ${formattedCluster.mongoDBVersion || "N/A"} | ${formattedCluster.connectionString || "N/A"}`,
},
],
${formattedCluster.name || "Unknown"} | ${formattedCluster.instanceType} | ${formattedCluster.instanceSize || "N/A"} | ${formattedCluster.state || "UNKNOWN"} | ${formattedCluster.mongoDBVersion || "N/A"} | ${formattedCluster.connectionString || "N/A"}`
),
};
}
}
4 changes: 2 additions & 2 deletions src/tools/atlas/read/listAlerts.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { z } from "zod";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { AtlasToolBase } from "../atlasTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { ToolArgs, OperationType, formatUntrustedData } from "../../tool.js";

export class ListAlertsTool extends AtlasToolBase {
public name = "atlas-list-alerts";
Expand Down Expand Up @@ -39,7 +39,7 @@ export class ListAlertsTool extends AtlasToolBase {
.join("\n");

return {
content: [{ type: "text", text: output }],
content: formatUntrustedData(`Found ${data.results.length} alerts in project ${projectId}`, output),
};
}
}
22 changes: 9 additions & 13 deletions src/tools/atlas/read/listClusters.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { z } from "zod";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { AtlasToolBase } from "../atlasTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { ToolArgs, OperationType, formatUntrustedData } from "../../tool.js";
import {
PaginatedClusterDescription20240805,
PaginatedOrgGroupView,
Expand Down Expand Up @@ -86,7 +86,9 @@ ${rows}`,
): CallToolResult {
// Check if both traditional clusters and flex clusters are absent
if (!clusters?.results?.length && !flexClusters?.results?.length) {
throw new Error("No clusters found.");
return {
content: [{ type: "text", text: "No clusters found." }],
};
}
const formattedClusters = clusters?.results?.map((cluster) => formatCluster(cluster)) || [];
const formattedFlexClusters = flexClusters?.results?.map((cluster) => formatFlexCluster(cluster)) || [];
Expand All @@ -96,18 +98,12 @@ ${rows}`,
})
.join("\n");
return {
content: [
{
type: "text",
text: `Here are your MongoDB Atlas clusters in project "${project.name}" (${project.id}):`,
},
{
type: "text",
text: `Cluster Name | Cluster Type | Tier | State | MongoDB Version | Connection String
content: formatUntrustedData(
`Found ${rows.length} clusters in project "${project.name}" (${project.id}):`,
`Cluster Name | Cluster Type | Tier | State | MongoDB Version | Connection String
----------------|----------------|----------------|----------------|----------------|----------------
${rows}`,
},
],
${rows}`
),
};
}
}
8 changes: 5 additions & 3 deletions src/tools/atlas/read/listDBUsers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { z } from "zod";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { AtlasToolBase } from "../atlasTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { ToolArgs, OperationType, formatUntrustedData } from "../../tool.js";
import { DatabaseUserRole, UserScope } from "../../../common/atlas/openapi.js";

export class ListDBUsersTool extends AtlasToolBase {
Expand All @@ -22,7 +22,9 @@ export class ListDBUsersTool extends AtlasToolBase {
});

if (!data?.results?.length) {
throw new Error("No database users found.");
return {
content: [{ type: "text", text: " No database users found" }],
};
}

const output =
Expand All @@ -35,7 +37,7 @@ export class ListDBUsersTool extends AtlasToolBase {
})
.join("\n");
return {
content: [{ type: "text", text: output }],
content: formatUntrustedData(`Found ${data.results.length} database users in project ${projectId}`, output),
};
}
}
Expand Down
13 changes: 9 additions & 4 deletions src/tools/atlas/read/listOrgs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { AtlasToolBase } from "../atlasTool.js";
import { OperationType } from "../../tool.js";
import { formatUntrustedData, OperationType } from "../../tool.js";

export class ListOrganizationsTool extends AtlasToolBase {
public name = "atlas-list-orgs";
Expand All @@ -12,10 +12,12 @@ export class ListOrganizationsTool extends AtlasToolBase {
const data = await this.session.apiClient.listOrganizations();

if (!data?.results?.length) {
throw new Error("No projects found in your MongoDB Atlas account.");
return {
content: [{ type: "text", text: "No organizations found in your MongoDB Atlas account." }],
};
}

// Format projects as a table
// Format organizations as a table
const output =
`Organization Name | Organization ID
----------------| ----------------
Expand All @@ -26,7 +28,10 @@ export class ListOrganizationsTool extends AtlasToolBase {
})
.join("\n");
return {
content: [{ type: "text", text: output }],
content: formatUntrustedData(
`Found ${data.results.length} organizations in your MongoDB Atlas account.`,
output
),
};
}
}
12 changes: 8 additions & 4 deletions src/tools/atlas/read/listProjects.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { AtlasToolBase } from "../atlasTool.js";
import { OperationType } from "../../tool.js";
import { formatUntrustedData, OperationType } from "../../tool.js";
import { z } from "zod";
import { ToolArgs } from "../../tool.js";

Expand All @@ -16,7 +16,9 @@ export class ListProjectsTool extends AtlasToolBase {
const orgData = await this.session.apiClient.listOrganizations();

if (!orgData?.results?.length) {
throw new Error("No organizations found in your MongoDB Atlas account.");
return {
content: [{ type: "text", text: "No organizations found in your MongoDB Atlas account." }],
};
}

const orgs: Record<string, string> = orgData.results
Expand All @@ -35,7 +37,9 @@ export class ListProjectsTool extends AtlasToolBase {
: await this.session.apiClient.listProjects();

if (!data?.results?.length) {
throw new Error("No projects found in your MongoDB Atlas account.");
return {
content: [{ type: "text", text: `No projects found in organization ${orgId}.` }],
};
}

// Format projects as a table
Expand All @@ -50,7 +54,7 @@ export class ListProjectsTool extends AtlasToolBase {
----------------| ----------------| ----------------| ----------------| ----------------
${rows}`;
return {
content: [{ type: "text", text: formattedProjects }],
content: formatUntrustedData(`Found ${rows.length} projects`, formattedProjects),
};
}
}
16 changes: 5 additions & 11 deletions src/tools/mongodb/metadata/collectionSchema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { ToolArgs, OperationType, formatUntrustedData } from "../../tool.js";
import { getSimplifiedSchema } from "mongodb-schema";

export class CollectionSchemaTool extends MongoDBToolBase {
Expand Down Expand Up @@ -28,16 +28,10 @@ export class CollectionSchemaTool extends MongoDBToolBase {
}

return {
content: [
{
text: `Found ${fieldsCount} fields in the schema for "${database}.${collection}"`,
type: "text",
},
{
text: JSON.stringify(schema),
type: "text",
},
],
content: formatUntrustedData(
`Found ${fieldsCount} fields in the schema for "${database}.${collection}"`,
JSON.stringify(schema)
),
};
}
}
13 changes: 2 additions & 11 deletions src/tools/mongodb/metadata/dbStats.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { ToolArgs, OperationType, formatUntrustedData } from "../../tool.js";
import { EJSON } from "bson";

export class DbStatsTool extends MongoDBToolBase {
Expand All @@ -20,16 +20,7 @@ export class DbStatsTool extends MongoDBToolBase {
});

return {
content: [
{
text: `Statistics for database ${database}`,
type: "text",
},
{
text: EJSON.stringify(result),
type: "text",
},
],
content: formatUntrustedData(`Statistics for database ${database}`, EJSON.stringify(result)),
};
}
}
16 changes: 5 additions & 11 deletions src/tools/mongodb/metadata/explain.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { ToolArgs, OperationType, formatUntrustedData } from "../../tool.js";
import { z } from "zod";
import { ExplainVerbosity, Document } from "mongodb";
import { AggregateArgs } from "../read/aggregate.js";
Expand Down Expand Up @@ -88,16 +88,10 @@ export class ExplainTool extends MongoDBToolBase {
}

return {
content: [
{
text: `Here is some information about the winning plan chosen by the query optimizer for running the given \`${method.name}\` operation in "${database}.${collection}". This information can be used to understand how the query was executed and to optimize the query performance.`,
type: "text",
},
{
text: JSON.stringify(result),
type: "text",
},
],
content: formatUntrustedData(
`Here is some information about the winning plan chosen by the query optimizer for running the given \`${method.name}\` operation in "${database}.${collection}". This information can be used to understand how the query was executed and to optimize the query performance.`,
JSON.stringify(result)
),
};
}
}
14 changes: 6 additions & 8 deletions src/tools/mongodb/metadata/listCollections.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
import { ToolArgs, OperationType } from "../../tool.js";
import { ToolArgs, OperationType, formatUntrustedData } from "../../tool.js";

export class ListCollectionsTool extends MongoDBToolBase {
public name = "list-collections";
Expand All @@ -20,19 +20,17 @@ export class ListCollectionsTool extends MongoDBToolBase {
content: [
{
type: "text",
text: `No collections found for database "${database}". To create a collection, use the "create-collection" tool.`,
text: `Found 0 collections for database "${database}". To create a collection, use the "create-collection" tool.`,
},
],
};
}

return {
content: collections.map((collection) => {
return {
text: `Name: "${collection.name}"`,
type: "text",
};
}),
content: formatUntrustedData(
`Found ${collections.length} collections for database "${database}".`,
collections.map((collection) => `"${collection.name}"`).join("\n")
),
};
}
}
14 changes: 7 additions & 7 deletions src/tools/mongodb/metadata/listDatabases.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { MongoDBToolBase } from "../mongodbTool.js";
import * as bson from "bson";
import { OperationType } from "../../tool.js";
import { formatUntrustedData, OperationType } from "../../tool.js";

export class ListDatabasesTool extends MongoDBToolBase {
public name = "list-databases";
Expand All @@ -14,12 +14,12 @@ export class ListDatabasesTool extends MongoDBToolBase {
const dbs = (await provider.listDatabases("")).databases as { name: string; sizeOnDisk: bson.Long }[];

return {
content: dbs.map((db) => {
return {
text: `Name: ${db.name}, Size: ${db.sizeOnDisk.toString()} bytes`,
type: "text",
};
}),
content: formatUntrustedData(
`Found ${dbs.length} databases`,
dbs.length > 0
? dbs.map((db) => `Name: ${db.name}, Size: ${db.sizeOnDisk.toString()} bytes`).join("\n")
: undefined
),
};
}
}
Loading
Loading