• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mongodb-js / mongodb-mcp-server / 18714130420

22 Oct 2025 11:06AM UTC coverage: 80.129% (-1.8%) from 81.905%
18714130420

Pull #674

github

web-flow
Merge ec48e82c7 into 17b595b2f
Pull Request #674: chore: move perf advisor to long running tests - MCP-269

1317 of 1776 branches covered (74.16%)

Branch coverage included in aggregate %.

6018 of 7378 relevant lines covered (81.57%)

73.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

4.03
/src/common/atlas/performanceAdvisorUtils.ts
1
import { LogId } from "../logger.js";
3✔
2
import type { ApiClient } from "./apiClient.js";
3
import { getProcessIdsFromCluster } from "./cluster.js";
3✔
4
import type { components } from "./openapi.js";
5

6
export type SuggestedIndex = components["schemas"]["PerformanceAdvisorIndex"];
7
export type DropIndexSuggestion = components["schemas"]["DropIndexSuggestionsIndex"];
8
export type SlowQueryLog = components["schemas"]["PerformanceAdvisorSlowQuery"];
9

10
export const DEFAULT_SLOW_QUERY_LOGS_LIMIT = 50;
3✔
11

12
export const SUGGESTED_INDEXES_COPY = `Note: The "Weight" field is measured in bytes, and represents the estimated number of bytes saved in disk reads per executed read query that would be saved by implementing an index suggestion. Please convert this to MB or GB for easier readability.`;
3✔
13
export const SLOW_QUERY_LOGS_COPY = `Please notify the user that the MCP server tool limits slow query logs to the most recent ${DEFAULT_SLOW_QUERY_LOGS_LIMIT} slow query logs. This is a limitation of the MCP server tool only. More slow query logs and performance suggestions can be seen in the Atlas UI. Please give to the user the following docs about the performance advisor: https://www.mongodb.com/docs/atlas/performance-advisor/.`;
3✔
14

15
interface SuggestedIndexesResponse {
16
    content: components["schemas"]["PerformanceAdvisorResponse"];
17
}
18
interface DropIndexesResponse {
19
    content: components["schemas"]["DropIndexSuggestionsResponse"];
20
}
21
interface SchemaAdviceResponse {
22
    content: components["schemas"]["SchemaAdvisorResponse"];
23
}
24
export type SchemaRecommendation = components["schemas"]["SchemaAdvisorItemRecommendation"];
25

26
export async function getSuggestedIndexes(
×
27
    apiClient: ApiClient,
×
28
    projectId: string,
×
29
    clusterName: string
×
30
): Promise<{ suggestedIndexes: Array<SuggestedIndex> }> {
×
31
    try {
×
32
        const response = await apiClient.listClusterSuggestedIndexes({
×
33
            params: {
×
34
                path: {
×
35
                    groupId: projectId,
×
36
                    clusterName,
×
37
                },
×
38
            },
×
39
        });
×
40
        return {
×
41
            suggestedIndexes: (response as SuggestedIndexesResponse).content.suggestedIndexes ?? [],
×
42
        };
×
43
    } catch (err) {
×
44
        apiClient.logger.debug({
×
45
            id: LogId.atlasPaSuggestedIndexesFailure,
×
46
            context: "performanceAdvisorUtils",
×
47
            message: `Failed to list suggested indexes: ${err instanceof Error ? err.message : String(err)}`,
×
48
        });
×
49
        throw new Error(`Failed to list suggested indexes: ${err instanceof Error ? err.message : String(err)}`);
×
50
    }
×
51
}
×
52

53
export async function getDropIndexSuggestions(
×
54
    apiClient: ApiClient,
×
55
    projectId: string,
×
56
    clusterName: string
×
57
): Promise<{
58
    hiddenIndexes: Array<DropIndexSuggestion>;
59
    redundantIndexes: Array<DropIndexSuggestion>;
60
    unusedIndexes: Array<DropIndexSuggestion>;
61
}> {
×
62
    try {
×
63
        const response = await apiClient.listDropIndexes({
×
64
            params: {
×
65
                path: {
×
66
                    groupId: projectId,
×
67
                    clusterName,
×
68
                },
×
69
            },
×
70
        });
×
71
        return {
×
72
            hiddenIndexes: (response as DropIndexesResponse).content.hiddenIndexes ?? [],
×
73
            redundantIndexes: (response as DropIndexesResponse).content.redundantIndexes ?? [],
×
74
            unusedIndexes: (response as DropIndexesResponse).content.unusedIndexes ?? [],
×
75
        };
×
76
    } catch (err) {
×
77
        apiClient.logger.debug({
×
78
            id: LogId.atlasPaDropIndexSuggestionsFailure,
×
79
            context: "performanceAdvisorUtils",
×
80
            message: `Failed to list drop index suggestions: ${err instanceof Error ? err.message : String(err)}`,
×
81
        });
×
82
        throw new Error(`Failed to list drop index suggestions: ${err instanceof Error ? err.message : String(err)}`);
×
83
    }
×
84
}
×
85

86
export async function getSchemaAdvice(
×
87
    apiClient: ApiClient,
×
88
    projectId: string,
×
89
    clusterName: string
×
90
): Promise<{ recommendations: Array<SchemaRecommendation> }> {
×
91
    try {
×
92
        const response = await apiClient.listSchemaAdvice({
×
93
            params: {
×
94
                path: {
×
95
                    groupId: projectId,
×
96
                    clusterName,
×
97
                },
×
98
            },
×
99
        });
×
100
        return { recommendations: (response as SchemaAdviceResponse).content.recommendations ?? [] };
×
101
    } catch (err) {
×
102
        apiClient.logger.debug({
×
103
            id: LogId.atlasPaSchemaAdviceFailure,
×
104
            context: "performanceAdvisorUtils",
×
105
            message: `Failed to list schema advice: ${err instanceof Error ? err.message : String(err)}`,
×
106
        });
×
107
        throw new Error(`Failed to list schema advice: ${err instanceof Error ? err.message : String(err)}`);
×
108
    }
×
109
}
×
110

111
export async function getSlowQueries(
×
112
    apiClient: ApiClient,
×
113
    projectId: string,
×
114
    clusterName: string,
×
115
    since?: Date,
×
116
    namespaces?: Array<string>
×
117
): Promise<{ slowQueryLogs: Array<SlowQueryLog> }> {
×
118
    try {
×
119
        const processIds = await getProcessIdsFromCluster(apiClient, projectId, clusterName);
×
120

121
        if (processIds.length === 0) {
×
122
            return { slowQueryLogs: [] };
×
123
        }
×
124

125
        const slowQueryPromises = processIds.map((processId) =>
×
126
            apiClient.listSlowQueries({
×
127
                params: {
×
128
                    path: {
×
129
                        groupId: projectId,
×
130
                        processId,
×
131
                    },
×
132
                    query: {
×
133
                        ...(since && { since: since.getTime() }),
×
134
                        ...(namespaces && { namespaces: namespaces }),
×
135
                        nLogs: DEFAULT_SLOW_QUERY_LOGS_LIMIT,
×
136
                    },
×
137
                },
×
138
            })
×
139
        );
×
140

141
        const responses = await Promise.allSettled(slowQueryPromises);
×
142

143
        const allSlowQueryLogs = responses.reduce((acc, response) => {
×
144
            return acc.concat(response.status === "fulfilled" ? (response.value.slowQueries ?? []) : []);
×
145
        }, [] as Array<SlowQueryLog>);
×
146

147
        return { slowQueryLogs: allSlowQueryLogs };
×
148
    } catch (err) {
×
149
        apiClient.logger.debug({
×
150
            id: LogId.atlasPaSlowQueryLogsFailure,
×
151
            context: "performanceAdvisorUtils",
×
152
            message: `Failed to list slow query logs: ${err instanceof Error ? err.message : String(err)}`,
×
153
        });
×
154
        throw new Error(`Failed to list slow query logs: ${err instanceof Error ? err.message : String(err)}`);
×
155
    }
×
156
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc