diff --git a/src/tools/atlas/read/inspectAccessList.ts b/src/tools/atlas/read/inspectAccessList.ts index 6c8eaed30..78cb8de3e 100644 --- a/src/tools/atlas/read/inspectAccessList.ts +++ b/src/tools/atlas/read/inspectAccessList.ts @@ -32,17 +32,14 @@ export class InspectAccessListTool extends AtlasToolBase { }; } + const entries = results.map((entry) => ({ + ipAddress: entry.ipAddress, + cidrBlock: entry.cidrBlock, + comment: entry.comment, + })); + return { - content: formatUntrustedData( - `Found ${results.length} access list entries`, - `IP ADDRESS | CIDR | COMMENT -------|------|------ -${results - .map((entry) => { - return `${entry.ipAddress} | ${entry.cidrBlock} | ${entry.comment}`; - }) - .join("\n")}` - ), + content: formatUntrustedData(`Found ${results.length} access list entries`, JSON.stringify(entries)), }; } } diff --git a/src/tools/atlas/read/inspectCluster.ts b/src/tools/atlas/read/inspectCluster.ts index 56e1e5a8b..d8a5d3f26 100644 --- a/src/tools/atlas/read/inspectCluster.ts +++ b/src/tools/atlas/read/inspectCluster.ts @@ -25,13 +25,17 @@ export class InspectClusterTool extends AtlasToolBase { } private formatOutput(formattedCluster: Cluster): CallToolResult { + const clusterDetails = { + name: formattedCluster.name || "Unknown", + instanceType: formattedCluster.instanceType, + instanceSize: formattedCluster.instanceSize || "N/A", + state: formattedCluster.state || "UNKNOWN", + mongoDBVersion: formattedCluster.mongoDBVersion || "N/A", + connectionString: formattedCluster.connectionString || "N/A", + }; + return { - 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"}` - ), + content: formatUntrustedData("Cluster details:", JSON.stringify(clusterDetails)), }; } } diff --git a/src/tools/atlas/read/listAlerts.ts b/src/tools/atlas/read/listAlerts.ts index d55a917f8..1e3a6998e 100644 --- a/src/tools/atlas/read/listAlerts.ts +++ b/src/tools/atlas/read/listAlerts.ts @@ -28,22 +28,20 @@ export class ListAlertsTool extends AtlasToolBase { return { content: [{ type: "text", text: "No alerts found in your MongoDB Atlas project." }] }; } - // Format alerts as a table - const output = - `Alert ID | Status | Created | Updated | Type | Comment -----------|---------|----------|----------|------|-------- -` + - data.results - .map((alert) => { - const created = alert.created ? new Date(alert.created).toLocaleString() : "N/A"; - const updated = alert.updated ? new Date(alert.updated).toLocaleString() : "N/A"; - const comment = alert.acknowledgementComment ?? "N/A"; - return `${alert.id} | ${alert.status} | ${created} | ${updated} | ${alert.eventTypeName} | ${comment}`; - }) - .join("\n"); + const alerts = data.results.map((alert) => ({ + id: alert.id, + status: alert.status, + created: alert.created ? new Date(alert.created).toISOString() : "N/A", + updated: alert.updated ? new Date(alert.updated).toISOString() : "N/A", + eventTypeName: alert.eventTypeName, + acknowledgementComment: alert.acknowledgementComment ?? "N/A", + })); return { - content: formatUntrustedData(`Found ${data.results.length} alerts in project ${projectId}`, output), + content: formatUntrustedData( + `Found ${data.results.length} alerts in project ${projectId}`, + JSON.stringify(alerts) + ), }; } } diff --git a/src/tools/atlas/read/listClusters.ts b/src/tools/atlas/read/listClusters.ts index 60344f7d3..d626f6d97 100644 --- a/src/tools/atlas/read/listClusters.ts +++ b/src/tools/atlas/read/listClusters.ts @@ -59,28 +59,22 @@ export class ListClustersTool extends AtlasToolBase { } const formattedClusters = clusters.results .map((result) => { - return (result.clusters || []).map((cluster) => { - return { ...result, ...cluster, clusters: undefined }; - }); + return (result.clusters || []).map((cluster) => ({ + projectName: result.groupName, + projectId: result.groupId, + clusterName: cluster.name, + })); }) .flat(); if (!formattedClusters.length) { throw new Error("No clusters found."); } - const rows = formattedClusters - .map((cluster) => { - return `${cluster.groupName} (${cluster.groupId}) | ${cluster.name}`; - }) - .join("\n"); + return { - content: [ - { - type: "text", - text: `Project | Cluster Name -----------------|---------------- -${rows}`, - }, - ], + content: formatUntrustedData( + `Found ${formattedClusters.length} clusters across all projects`, + JSON.stringify(formattedClusters) + ), }; } @@ -98,16 +92,11 @@ ${rows}`, const formattedClusters = clusters?.results?.map((cluster) => formatCluster(cluster)) || []; const formattedFlexClusters = flexClusters?.results?.map((cluster) => formatFlexCluster(cluster)) || []; const allClusters = [...formattedClusters, ...formattedFlexClusters]; + return { content: formatUntrustedData( `Found ${allClusters.length} clusters in project "${project.name}" (${project.id}):`, - `Cluster Name | Cluster Type | Tier | State | MongoDB Version | Connection String -----------------|----------------|----------------|----------------|----------------|---------------- -${allClusters - .map((formattedCluster) => { - return `${formattedCluster.name || "Unknown"} | ${formattedCluster.instanceType} | ${formattedCluster.instanceSize || "N/A"} | ${formattedCluster.state || "UNKNOWN"} | ${formattedCluster.mongoDBVersion || "N/A"} | ${formattedCluster.connectionString || "N/A"}`; - }) - .join("\n")}` + JSON.stringify(allClusters) ), }; } diff --git a/src/tools/atlas/read/listDBUsers.ts b/src/tools/atlas/read/listDBUsers.ts index 5ab23250c..7103f2664 100644 --- a/src/tools/atlas/read/listDBUsers.ts +++ b/src/tools/atlas/read/listDBUsers.ts @@ -2,7 +2,6 @@ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { AtlasToolBase } from "../atlasTool.js"; import type { ToolArgs, OperationType } from "../../tool.js"; import { formatUntrustedData } from "../../tool.js"; -import type { DatabaseUserRole, UserScope } from "../../../common/atlas/openapi.js"; import { AtlasArgs } from "../../args.js"; export const ListDBUsersArgs = { @@ -32,36 +31,26 @@ export class ListDBUsersTool extends AtlasToolBase { }; } - const output = - `Username | Roles | Scopes -----------------|----------------|---------------- -` + - data.results - .map((user) => { - return `${user.username} | ${formatRoles(user.roles)} | ${formatScopes(user.scopes)}`; - }) - .join("\n"); + const users = data.results.map((user) => ({ + username: user.username, + roles: + user.roles?.map((role) => ({ + roleName: role.roleName, + databaseName: role.databaseName, + collectionName: role.collectionName, + })) ?? [], + scopes: + user.scopes?.map((scope) => ({ + type: scope.type, + name: scope.name, + })) ?? [], + })); + return { - content: formatUntrustedData(`Found ${data.results.length} database users in project ${projectId}`, output), + content: formatUntrustedData( + `Found ${data.results.length} database users in project ${projectId}`, + JSON.stringify(users) + ), }; } } - -function formatRoles(roles?: DatabaseUserRole[]): string { - if (!roles?.length) { - return "N/A"; - } - return roles - .map( - (role) => - `${role.roleName}${role.databaseName ? `@${role.databaseName}${role.collectionName ? `:${role.collectionName}` : ""}` : ""}` - ) - .join(", "); -} - -function formatScopes(scopes?: UserScope[]): string { - if (!scopes?.length) { - return "All"; - } - return scopes.map((scope) => `${scope.type}:${scope.name}`).join(", "); -} diff --git a/src/tools/atlas/read/listOrgs.ts b/src/tools/atlas/read/listOrgs.ts index b36791939..0145524f3 100644 --- a/src/tools/atlas/read/listOrgs.ts +++ b/src/tools/atlas/read/listOrgs.ts @@ -18,20 +18,15 @@ export class ListOrganizationsTool extends AtlasToolBase { }; } - // Format organizations as a table - const output = - `Organization Name | Organization ID -----------------| ---------------- -` + - data.results - .map((org) => { - return `${org.name} | ${org.id}`; - }) - .join("\n"); + const orgs = data.results.map((org) => ({ + name: org.name, + id: org.id, + })); + return { content: formatUntrustedData( `Found ${data.results.length} organizations in your MongoDB Atlas account.`, - output + JSON.stringify(orgs) ), }; } diff --git a/tests/integration/tools/atlas/clusters.test.ts b/tests/integration/tools/atlas/clusters.test.ts index f340dc08f..e3c7c6d5c 100644 --- a/tests/integration/tools/atlas/clusters.test.ts +++ b/tests/integration/tools/atlas/clusters.test.ts @@ -84,7 +84,7 @@ describeWithAtlas("clusters", (integration) => { expect(elements).toHaveLength(2); expect(elements[0]?.text).toContain("Cluster details:"); expect(elements[1]?.text).toContain("