atlas-get-performance-advisor
Retrieve MongoDB Atlas performance advisor recommendations to optimize database operations. Get suggested indexes, drop index suggestions, schema improvements, and slow query logs for enhanced query performance.
Instructions
Get MongoDB Atlas performance advisor recommendations, which includes the operations: suggested indexes, drop index suggestions, schema suggestions, and a sample of the most recent (max 50) slow query logs
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectId | Yes | Atlas project ID to get performance advisor recommendations. The project ID is a hexadecimal identifier of 24 characters. If the user has only specified the name, use the `atlas-list-projects` tool to retrieve the user's projects with their ids. | |
| clusterName | Yes | Atlas cluster name to get performance advisor recommendations | |
| operations | No | Operations to get performance advisor recommendations | |
| since | No | Date to get slow query logs since. Must be a string in ISO 8601 format. Only relevant for the slowQueryLogs operation. | |
| namespaces | No | Namespaces to get slow query logs. Only relevant for the slowQueryLogs operation. |
Implementation Reference
- The execute method that implements the core logic of the tool. It fetches performance advisor data (suggested indexes, drop index suggestions, slow query logs, schema suggestions) based on the specified operations using Atlas API calls via helper utilities, checks if data exists, formats it into markdown sections, and returns it or an error message.protected async execute({ projectId, clusterName, operations, since, namespaces, }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> { try { const [suggestedIndexesResult, dropIndexSuggestionsResult, slowQueryLogsResult, schemaSuggestionsResult] = await Promise.allSettled([ operations.includes("suggestedIndexes") ? getSuggestedIndexes(this.session.apiClient, projectId, clusterName) : Promise.resolve(undefined), operations.includes("dropIndexSuggestions") ? getDropIndexSuggestions(this.session.apiClient, projectId, clusterName) : Promise.resolve(undefined), operations.includes("slowQueryLogs") ? getSlowQueries( this.session.apiClient, projectId, clusterName, since ? new Date(since) : undefined, namespaces ) : Promise.resolve(undefined), operations.includes("schemaSuggestions") ? getSchemaAdvice(this.session.apiClient, projectId, clusterName) : Promise.resolve(undefined), ]); const hasSuggestedIndexes = suggestedIndexesResult.status === "fulfilled" && suggestedIndexesResult.value?.suggestedIndexes && suggestedIndexesResult.value.suggestedIndexes.length > 0; const hasDropIndexSuggestions = dropIndexSuggestionsResult.status === "fulfilled" && dropIndexSuggestionsResult.value?.hiddenIndexes && dropIndexSuggestionsResult.value?.redundantIndexes && dropIndexSuggestionsResult.value?.unusedIndexes && (dropIndexSuggestionsResult.value.hiddenIndexes.length > 0 || dropIndexSuggestionsResult.value.redundantIndexes.length > 0 || dropIndexSuggestionsResult.value.unusedIndexes.length > 0); const hasSlowQueryLogs = slowQueryLogsResult.status === "fulfilled" && slowQueryLogsResult.value?.slowQueryLogs && slowQueryLogsResult.value.slowQueryLogs.length > 0; const hasSchemaSuggestions = schemaSuggestionsResult.status === "fulfilled" && schemaSuggestionsResult.value?.recommendations && schemaSuggestionsResult.value.recommendations.length > 0; // Inserts the performance advisor data with the relevant section header if it exists const performanceAdvisorData = [ `## Suggested Indexes\n${ hasSuggestedIndexes ? `${SUGGESTED_INDEXES_COPY}\n${JSON.stringify(suggestedIndexesResult.value?.suggestedIndexes)}` : "No suggested indexes found." }`, `## Drop Index Suggestions\n${hasDropIndexSuggestions ? JSON.stringify(dropIndexSuggestionsResult.value) : "No drop index suggestions found."}`, `## Slow Query Logs\n${hasSlowQueryLogs ? `${SLOW_QUERY_LOGS_COPY}\n${JSON.stringify(slowQueryLogsResult.value?.slowQueryLogs)}` : "No slow query logs found."}`, `## Schema Suggestions\n${hasSchemaSuggestions ? JSON.stringify(schemaSuggestionsResult.value?.recommendations) : "No schema suggestions found."}`, ]; if (performanceAdvisorData.length === 0) { return { content: [{ type: "text", text: "No performance advisor recommendations found." }], }; } return { content: formatUntrustedData("Performance advisor data", performanceAdvisorData.join("\n\n")), }; } catch (error) { return { content: [ { type: "text", text: `Error retrieving performance advisor data: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }
- Zod schema definition for the tool's input arguments: projectId, clusterName, operations (array of enums), since (optional datetime), namespaces (optional array).protected argsShape = { projectId: AtlasArgs.projectId().describe( "Atlas project ID to get performance advisor recommendations. The project ID is a hexadecimal identifier of 24 characters. If the user has only specified the name, use the `atlas-list-projects` tool to retrieve the user's projects with their ids." ), clusterName: AtlasArgs.clusterName().describe("Atlas cluster name to get performance advisor recommendations"), operations: z .array(PerformanceAdvisorOperationType) .default(PerformanceAdvisorOperationType.options) .describe("Operations to get performance advisor recommendations"), since: z .string() .datetime() .describe( "Date to get slow query logs since. Must be a string in ISO 8601 format. Only relevant for the slowQueryLogs operation." ) .optional(), namespaces: z .array(z.string()) .describe("Namespaces to get slow query logs. Only relevant for the slowQueryLogs operation.") .optional(), };
- src/tools/atlas/tools.ts:13-13 (registration)Re-export of the GetPerformanceAdvisorTool class from its implementation file, making it available for higher-level registration.export { GetPerformanceAdvisorTool } from "./read/getPerformanceAdvisor.js";
- src/tools/index.ts:7-11 (registration)Central registration of all tools into the AllTools array, including AtlasTools which encompasses the GetPerformanceAdvisorTool.export const AllTools: ToolClass[] = Object.values({ ...MongoDbTools, ...AtlasTools, ...AtlasLocalTools, });
- Supporting utility functions called by the handler: getSuggestedIndexes (lines 26-51), getDropIndexSuggestions (53-84), getSchemaAdvice (86-109), getSlowQueries (111-156) which interact with Atlas API to retrieve specific performance data.export async function getSuggestedIndexes( apiClient: ApiClient, projectId: string, clusterName: string ): Promise<{ suggestedIndexes: Array<SuggestedIndex> }> { try { const response = await apiClient.listClusterSuggestedIndexes({ params: { path: { groupId: projectId, clusterName, }, }, }); return { suggestedIndexes: (response as SuggestedIndexesResponse).content.suggestedIndexes ?? [], }; } catch (err) { apiClient.logger.debug({ id: LogId.atlasPaSuggestedIndexesFailure, context: "performanceAdvisorUtils", message: `Failed to list suggested indexes: ${err instanceof Error ? err.message : String(err)}`, }); throw new Error(`Failed to list suggested indexes: ${err instanceof Error ? err.message : String(err)}`); } } export async function getDropIndexSuggestions( apiClient: ApiClient, projectId: string, clusterName: string ): Promise<{ hiddenIndexes: Array<DropIndexSuggestion>; redundantIndexes: Array<DropIndexSuggestion>; unusedIndexes: Array<DropIndexSuggestion>; }> { try { const response = await apiClient.listDropIndexSuggestions({ params: { path: { groupId: projectId, clusterName, }, }, }); return { hiddenIndexes: (response as DropIndexesResponse).content.hiddenIndexes ?? [], redundantIndexes: (response as DropIndexesResponse).content.redundantIndexes ?? [], unusedIndexes: (response as DropIndexesResponse).content.unusedIndexes ?? [], }; } catch (err) { apiClient.logger.debug({ id: LogId.atlasPaDropIndexSuggestionsFailure, context: "performanceAdvisorUtils", message: `Failed to list drop index suggestions: ${err instanceof Error ? err.message : String(err)}`, }); throw new Error(`Failed to list drop index suggestions: ${err instanceof Error ? err.message : String(err)}`); } } export async function getSchemaAdvice( apiClient: ApiClient, projectId: string, clusterName: string ): Promise<{ recommendations: Array<SchemaRecommendation> }> { try { const response = await apiClient.listSchemaAdvice({ params: { path: { groupId: projectId, clusterName, }, }, }); return { recommendations: (response as SchemaAdviceResponse).content.recommendations ?? [] }; } catch (err) { apiClient.logger.debug({ id: LogId.atlasPaSchemaAdviceFailure, context: "performanceAdvisorUtils", message: `Failed to list schema advice: ${err instanceof Error ? err.message : String(err)}`, }); throw new Error(`Failed to list schema advice: ${err instanceof Error ? err.message : String(err)}`); } } export async function getSlowQueries( apiClient: ApiClient, projectId: string, clusterName: string, since?: Date, namespaces?: Array<string> ): Promise<{ slowQueryLogs: Array<SlowQueryLog> }> { try { const processIds = await getProcessIdsFromCluster(apiClient, projectId, clusterName); if (processIds.length === 0) { return { slowQueryLogs: [] }; } const slowQueryPromises = processIds.map((processId) => apiClient.listSlowQueryLogs({ params: { path: { groupId: projectId, processId, }, query: { ...(since && { since: since.getTime() }), ...(namespaces && { namespaces: namespaces }), nLogs: DEFAULT_SLOW_QUERY_LOGS_LIMIT, }, }, }) ); const responses = await Promise.allSettled(slowQueryPromises); const allSlowQueryLogs = responses.reduce((acc, response) => { return acc.concat(response.status === "fulfilled" ? (response.value.slowQueries ?? []) : []); }, [] as Array<SlowQueryLog>); return { slowQueryLogs: allSlowQueryLogs }; } catch (err) { apiClient.logger.debug({ id: LogId.atlasPaSlowQueryLogsFailure, context: "performanceAdvisorUtils", message: `Failed to list slow query logs: ${err instanceof Error ? err.message : String(err)}`, }); throw new Error(`Failed to list slow query logs: ${err instanceof Error ? err.message : String(err)}`); } }