mongodb-mcp-server 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/pull_request_template.md +5 -0
- package/.github/workflows/accuracy-tests.yml +55 -0
- package/.github/workflows/check.yml +1 -1
- package/.github/workflows/code_health.yaml +4 -4
- package/.github/workflows/code_health_fork.yaml +0 -14
- package/.github/workflows/dependabot_pr.yaml +26 -0
- package/.github/workflows/docker.yaml +1 -1
- package/.github/workflows/jira-issue.yml +72 -0
- package/.smithery/smithery.yaml +10 -0
- package/.vscode/extensions.json +1 -1
- package/.vscode/launch.json +11 -1
- package/.vscode/settings.json +1 -11
- package/Dockerfile +1 -0
- package/README.md +132 -31
- package/dist/common/atlas/accessListUtils.js +36 -0
- package/dist/common/atlas/accessListUtils.js.map +1 -0
- package/dist/common/atlas/apiClient.js +25 -6
- package/dist/common/atlas/apiClient.js.map +1 -1
- package/dist/common/atlas/cluster.js +1 -1
- package/dist/common/atlas/cluster.js.map +1 -1
- package/dist/{config.js → common/config.js} +8 -1
- package/dist/common/config.js.map +1 -0
- package/dist/{errors.js → common/errors.js} +1 -0
- package/dist/common/errors.js.map +1 -0
- package/dist/{logger.js → common/logger.js} +20 -19
- package/dist/common/logger.js.map +1 -0
- package/dist/common/managedTimeout.js +20 -0
- package/dist/common/managedTimeout.js.map +1 -0
- package/dist/common/packageInfo.js.map +1 -0
- package/dist/{session.js → common/session.js} +20 -21
- package/dist/common/session.js.map +1 -0
- package/dist/common/sessionStore.js +73 -0
- package/dist/common/sessionStore.js.map +1 -0
- package/dist/helpers/container.js +28 -0
- package/dist/helpers/container.js.map +1 -0
- package/dist/helpers/generatePassword.js.map +1 -0
- package/dist/helpers/indexCheck.js +63 -0
- package/dist/helpers/indexCheck.js.map +1 -0
- package/dist/index.js +30 -37
- package/dist/index.js.map +1 -1
- package/dist/server.js +44 -7
- package/dist/server.js.map +1 -1
- package/dist/telemetry/constants.js +1 -1
- package/dist/telemetry/constants.js.map +1 -1
- package/dist/telemetry/telemetry.js +86 -116
- package/dist/telemetry/telemetry.js.map +1 -1
- package/dist/tools/atlas/atlasTool.js +3 -3
- package/dist/tools/atlas/atlasTool.js.map +1 -1
- package/dist/tools/atlas/connect/connectCluster.js +198 -0
- package/dist/tools/atlas/connect/connectCluster.js.map +1 -0
- package/dist/tools/atlas/create/createAccessList.js +9 -10
- package/dist/tools/atlas/create/createAccessList.js.map +1 -1
- package/dist/tools/atlas/create/createDBUser.js +3 -1
- package/dist/tools/atlas/create/createDBUser.js.map +1 -1
- package/dist/tools/atlas/create/createFreeCluster.js +2 -0
- package/dist/tools/atlas/create/createFreeCluster.js.map +1 -1
- package/dist/tools/atlas/create/createProject.js.map +1 -1
- package/dist/tools/atlas/read/inspectAccessList.js.map +1 -1
- package/dist/tools/atlas/read/inspectCluster.js.map +1 -1
- package/dist/tools/atlas/read/listAlerts.js.map +1 -1
- package/dist/tools/atlas/read/listClusters.js.map +1 -1
- package/dist/tools/atlas/read/listDBUsers.js.map +1 -1
- package/dist/tools/atlas/read/listOrgs.js.map +1 -1
- package/dist/tools/atlas/read/listProjects.js.map +1 -1
- package/dist/tools/atlas/tools.js +1 -1
- package/dist/tools/atlas/tools.js.map +1 -1
- package/dist/tools/mongodb/{metadata → connect}/connect.js +7 -4
- package/dist/tools/mongodb/connect/connect.js.map +1 -0
- package/dist/tools/mongodb/create/createCollection.js.map +1 -1
- package/dist/tools/mongodb/create/createIndex.js +1 -1
- package/dist/tools/mongodb/create/createIndex.js.map +1 -1
- package/dist/tools/mongodb/create/insertMany.js +1 -1
- package/dist/tools/mongodb/create/insertMany.js.map +1 -1
- package/dist/tools/mongodb/delete/deleteMany.js +20 -1
- package/dist/tools/mongodb/delete/deleteMany.js.map +1 -1
- package/dist/tools/mongodb/delete/dropCollection.js.map +1 -1
- package/dist/tools/mongodb/delete/dropDatabase.js.map +1 -1
- package/dist/tools/mongodb/metadata/collectionSchema.js.map +1 -1
- package/dist/tools/mongodb/metadata/collectionStorageSize.js.map +1 -1
- package/dist/tools/mongodb/metadata/dbStats.js.map +1 -1
- package/dist/tools/mongodb/metadata/explain.js +2 -2
- package/dist/tools/mongodb/metadata/explain.js.map +1 -1
- package/dist/tools/mongodb/metadata/listCollections.js.map +1 -1
- package/dist/tools/mongodb/metadata/listDatabases.js.map +1 -1
- package/dist/tools/mongodb/metadata/logs.js.map +1 -1
- package/dist/tools/mongodb/mongodbTool.js +47 -10
- package/dist/tools/mongodb/mongodbTool.js.map +1 -1
- package/dist/tools/mongodb/read/aggregate.js +10 -1
- package/dist/tools/mongodb/read/aggregate.js.map +1 -1
- package/dist/tools/mongodb/read/collectionIndexes.js.map +1 -1
- package/dist/tools/mongodb/read/count.js +15 -1
- package/dist/tools/mongodb/read/count.js.map +1 -1
- package/dist/tools/mongodb/read/find.js +14 -4
- package/dist/tools/mongodb/read/find.js.map +1 -1
- package/dist/tools/mongodb/tools.js +1 -1
- package/dist/tools/mongodb/tools.js.map +1 -1
- package/dist/tools/mongodb/update/renameCollection.js.map +1 -1
- package/dist/tools/mongodb/update/updateMany.js +24 -2
- package/dist/tools/mongodb/update/updateMany.js.map +1 -1
- package/dist/tools/tool.js +12 -9
- package/dist/tools/tool.js.map +1 -1
- package/dist/transports/base.js +26 -0
- package/dist/transports/base.js.map +1 -0
- package/dist/{helpers/EJsonTransport.js → transports/stdio.js} +24 -2
- package/dist/transports/stdio.js.map +1 -0
- package/dist/transports/streamableHttp.js +140 -0
- package/dist/transports/streamableHttp.js.map +1 -0
- package/eslint.config.js +13 -4
- package/package.json +43 -33
- package/resources/test-summary-template.html +415 -0
- package/scripts/accuracy/generateTestSummary.ts +335 -0
- package/scripts/accuracy/runAccuracyTests.sh +45 -0
- package/scripts/accuracy/updateAccuracyRunStatus.ts +21 -0
- package/src/common/atlas/accessListUtils.ts +54 -0
- package/src/common/atlas/apiClient.ts +25 -6
- package/src/common/atlas/cluster.ts +1 -1
- package/src/{config.ts → common/config.ts} +16 -2
- package/src/{errors.ts → common/errors.ts} +1 -0
- package/src/{logger.ts → common/logger.ts} +21 -24
- package/src/common/managedTimeout.ts +27 -0
- package/src/{session.ts → common/session.ts} +24 -26
- package/src/common/sessionStore.ts +111 -0
- package/src/helpers/container.ts +35 -0
- package/src/helpers/indexCheck.ts +83 -0
- package/src/index.ts +30 -40
- package/src/server.ts +55 -11
- package/src/telemetry/constants.ts +1 -1
- package/src/telemetry/telemetry.ts +109 -153
- package/src/telemetry/types.ts +2 -1
- package/src/tools/atlas/atlasTool.ts +4 -4
- package/src/tools/atlas/connect/connectCluster.ts +259 -0
- package/src/tools/atlas/create/createAccessList.ts +15 -13
- package/src/tools/atlas/create/createDBUser.ts +5 -3
- package/src/tools/atlas/create/createFreeCluster.ts +4 -2
- package/src/tools/atlas/create/createProject.ts +2 -2
- package/src/tools/atlas/read/inspectAccessList.ts +2 -2
- package/src/tools/atlas/read/inspectCluster.ts +2 -2
- package/src/tools/atlas/read/listAlerts.ts +2 -2
- package/src/tools/atlas/read/listClusters.ts +2 -2
- package/src/tools/atlas/read/listDBUsers.ts +2 -2
- package/src/tools/atlas/read/listOrgs.ts +2 -2
- package/src/tools/atlas/read/listProjects.ts +2 -2
- package/src/tools/atlas/tools.ts +1 -1
- package/src/tools/mongodb/{metadata → connect}/connect.ts +12 -9
- package/src/tools/mongodb/create/createCollection.ts +2 -2
- package/src/tools/mongodb/create/createIndex.ts +3 -3
- package/src/tools/mongodb/create/insertMany.ts +3 -3
- package/src/tools/mongodb/delete/deleteMany.ts +24 -3
- package/src/tools/mongodb/delete/dropCollection.ts +2 -2
- package/src/tools/mongodb/delete/dropDatabase.ts +2 -2
- package/src/tools/mongodb/metadata/collectionSchema.ts +2 -2
- package/src/tools/mongodb/metadata/collectionStorageSize.ts +2 -2
- package/src/tools/mongodb/metadata/dbStats.ts +2 -2
- package/src/tools/mongodb/metadata/explain.ts +4 -4
- package/src/tools/mongodb/metadata/listCollections.ts +2 -2
- package/src/tools/mongodb/metadata/listDatabases.ts +2 -2
- package/src/tools/mongodb/metadata/logs.ts +2 -2
- package/src/tools/mongodb/mongodbTool.ts +60 -14
- package/src/tools/mongodb/read/aggregate.ts +14 -3
- package/src/tools/mongodb/read/collectionIndexes.ts +2 -2
- package/src/tools/mongodb/read/count.ts +19 -3
- package/src/tools/mongodb/read/find.ts +20 -6
- package/src/tools/mongodb/tools.ts +1 -1
- package/src/tools/mongodb/update/renameCollection.ts +2 -2
- package/src/tools/mongodb/update/updateMany.ts +28 -4
- package/src/tools/tool.ts +23 -18
- package/src/transports/base.ts +34 -0
- package/src/{helpers/EJsonTransport.ts → transports/stdio.ts} +30 -1
- package/src/transports/streamableHttp.ts +178 -0
- package/tests/accuracy/aggregate.test.ts +27 -0
- package/tests/accuracy/collectionIndexes.test.ts +40 -0
- package/tests/accuracy/collectionSchema.test.ts +28 -0
- package/tests/accuracy/collectionStorageSize.test.ts +41 -0
- package/tests/accuracy/count.test.ts +44 -0
- package/tests/accuracy/createCollection.test.ts +46 -0
- package/tests/accuracy/createIndex.test.ts +37 -0
- package/tests/accuracy/dbStats.test.ts +15 -0
- package/tests/accuracy/deleteMany.test.ts +44 -0
- package/tests/accuracy/dropCollection.test.ts +74 -0
- package/tests/accuracy/dropDatabase.test.ts +41 -0
- package/tests/accuracy/explain.test.ts +73 -0
- package/tests/accuracy/find.test.ts +114 -0
- package/tests/accuracy/insertMany.test.ts +48 -0
- package/tests/accuracy/listCollections.test.ts +60 -0
- package/tests/accuracy/listDatabases.test.ts +31 -0
- package/tests/accuracy/logs.test.ts +28 -0
- package/tests/accuracy/renameCollection.test.ts +31 -0
- package/tests/accuracy/sdk/accuracyResultStorage/diskStorage.ts +189 -0
- package/tests/accuracy/sdk/accuracyResultStorage/getAccuracyResultStorage.ts +11 -0
- package/tests/accuracy/sdk/accuracyResultStorage/mongodbStorage.ts +151 -0
- package/tests/accuracy/sdk/accuracyResultStorage/resultStorage.ts +117 -0
- package/tests/accuracy/sdk/accuracyScorer.ts +93 -0
- package/tests/accuracy/sdk/accuracyTestingClient.ts +94 -0
- package/tests/accuracy/sdk/agent.ts +56 -0
- package/tests/accuracy/sdk/constants.ts +26 -0
- package/tests/accuracy/sdk/describeAccuracyTests.ts +126 -0
- package/tests/accuracy/sdk/gitInfo.ts +7 -0
- package/tests/accuracy/sdk/matcher.ts +193 -0
- package/tests/accuracy/sdk/models.ts +95 -0
- package/tests/accuracy/test-data-dumps/comics.books.json +417 -0
- package/tests/accuracy/test-data-dumps/comics.characters.json +402 -0
- package/tests/accuracy/test-data-dumps/mflix.movies.json +496 -0
- package/tests/accuracy/test-data-dumps/mflix.shows.json +572 -0
- package/tests/accuracy/updateMany.test.ts +42 -0
- package/tests/integration/helpers.ts +9 -9
- package/tests/integration/indexCheck.test.ts +464 -0
- package/tests/integration/server.test.ts +6 -4
- package/tests/integration/telemetry.test.ts +29 -0
- package/tests/integration/tools/atlas/accessLists.test.ts +22 -2
- package/tests/integration/tools/atlas/alerts.test.ts +3 -2
- package/tests/integration/tools/atlas/atlasHelpers.ts +3 -0
- package/tests/integration/tools/atlas/clusters.test.ts +68 -16
- package/tests/integration/tools/atlas/dbUsers.test.ts +14 -1
- package/tests/integration/tools/atlas/orgs.test.ts +2 -1
- package/tests/integration/tools/atlas/projects.test.ts +4 -3
- package/tests/integration/tools/mongodb/{metadata → connect}/connect.test.ts +34 -3
- package/tests/integration/tools/mongodb/create/createCollection.test.ts +1 -0
- package/tests/integration/tools/mongodb/create/createIndex.test.ts +1 -0
- package/tests/integration/tools/mongodb/create/insertMany.test.ts +1 -0
- package/tests/integration/tools/mongodb/delete/deleteMany.test.ts +1 -0
- package/tests/integration/tools/mongodb/delete/dropCollection.test.ts +1 -1
- package/tests/integration/tools/mongodb/delete/dropDatabase.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/collectionSchema.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/collectionStorageSize.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/dbStats.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/explain.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/listCollections.test.ts +1 -0
- package/tests/integration/tools/mongodb/metadata/listDatabases.test.ts +3 -2
- package/tests/integration/tools/mongodb/metadata/logs.test.ts +1 -0
- package/tests/integration/tools/mongodb/mongodbHelpers.ts +67 -2
- package/tests/integration/tools/mongodb/read/aggregate.test.ts +2 -1
- package/tests/integration/tools/mongodb/read/collectionIndexes.test.ts +1 -0
- package/tests/integration/tools/mongodb/read/count.test.ts +1 -0
- package/tests/integration/tools/mongodb/read/find.test.ts +2 -1
- package/tests/integration/tools/mongodb/update/renameCollection.test.ts +1 -0
- package/tests/integration/tools/mongodb/update/updateMany.test.ts +1 -0
- package/tests/integration/transports/stdio.test.ts +40 -0
- package/tests/integration/transports/streamableHttp.test.ts +56 -0
- package/tests/matchers/toIncludeSameMembers.test.ts +59 -0
- package/tests/matchers/toIncludeSameMembers.ts +12 -0
- package/tests/setup.ts +7 -0
- package/tests/unit/accessListUtils.test.ts +39 -0
- package/tests/unit/accuracyScorer.test.ts +390 -0
- package/tests/unit/{apiClient.test.ts → common/apiClient.test.ts} +15 -15
- package/tests/unit/common/managedTimeout.test.ts +67 -0
- package/tests/unit/{session.test.ts → common/session.test.ts} +7 -12
- package/tests/unit/helpers/indexCheck.test.ts +150 -0
- package/tests/unit/telemetry.test.ts +99 -137
- package/tests/unit/{EJsonTransport.test.ts → transports/stdio.test.ts} +4 -4
- package/tests/vitest.d.ts +11 -0
- package/tsconfig.json +0 -1
- package/{tsconfig.jest.json → tsconfig.test.json} +1 -2
- package/vitest.config.ts +41 -0
- package/dist/common/atlas/generatePassword.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/helpers/EJsonTransport.js.map +0 -1
- package/dist/helpers/packageInfo.js.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/session.js.map +0 -1
- package/dist/tools/atlas/metadata/connectCluster.js +0 -100
- package/dist/tools/atlas/metadata/connectCluster.js.map +0 -1
- package/dist/tools/mongodb/metadata/connect.js.map +0 -1
- package/global.d.ts +0 -1
- package/jest.config.cjs +0 -22
- package/src/tools/atlas/metadata/connectCluster.ts +0 -121
- /package/dist/{helpers → common}/packageInfo.js +0 -0
- /package/dist/{common/atlas → helpers}/generatePassword.js +0 -0
- /package/src/{helpers → common}/packageInfo.ts +0 -0
- /package/src/{common/atlas → helpers}/generatePassword.ts +0 -0
|
@@ -12,11 +12,17 @@ export const LogId = {
|
|
|
12
12
|
serverCloseRequested: mongoLogId(1_000_003),
|
|
13
13
|
serverClosed: mongoLogId(1_000_004),
|
|
14
14
|
serverCloseFailure: mongoLogId(1_000_005),
|
|
15
|
+
serverDuplicateLoggers: mongoLogId(1_000_006),
|
|
15
16
|
|
|
16
17
|
atlasCheckCredentials: mongoLogId(1_001_001),
|
|
17
18
|
atlasDeleteDatabaseUserFailure: mongoLogId(1_001_002),
|
|
18
19
|
atlasConnectFailure: mongoLogId(1_001_003),
|
|
19
20
|
atlasInspectFailure: mongoLogId(1_001_004),
|
|
21
|
+
atlasConnectAttempt: mongoLogId(1_001_005),
|
|
22
|
+
atlasConnectSucceeded: mongoLogId(1_001_006),
|
|
23
|
+
atlasApiRevokeFailure: mongoLogId(1_001_007),
|
|
24
|
+
atlasIpAccessListAdded: mongoLogId(1_001_008),
|
|
25
|
+
atlasIpAccessListAddFailure: mongoLogId(1_001_009),
|
|
20
26
|
|
|
21
27
|
telemetryDisabled: mongoLogId(1_002_001),
|
|
22
28
|
telemetryEmitFailure: mongoLogId(1_002_002),
|
|
@@ -25,7 +31,6 @@ export const LogId = {
|
|
|
25
31
|
telemetryMetadataError: mongoLogId(1_002_005),
|
|
26
32
|
telemetryDeviceIdFailure: mongoLogId(1_002_006),
|
|
27
33
|
telemetryDeviceIdTimeout: mongoLogId(1_002_007),
|
|
28
|
-
telemetryContainerEnvFailure: mongoLogId(1_002_008),
|
|
29
34
|
|
|
30
35
|
toolExecute: mongoLogId(1_003_001),
|
|
31
36
|
toolExecuteFailure: mongoLogId(1_003_002),
|
|
@@ -35,9 +40,16 @@ export const LogId = {
|
|
|
35
40
|
mongodbDisconnectFailure: mongoLogId(1_004_002),
|
|
36
41
|
|
|
37
42
|
toolUpdateFailure: mongoLogId(1_005_001),
|
|
43
|
+
|
|
44
|
+
streamableHttpTransportStarted: mongoLogId(1_006_001),
|
|
45
|
+
streamableHttpTransportSessionCloseFailure: mongoLogId(1_006_002),
|
|
46
|
+
streamableHttpTransportSessionCloseNotification: mongoLogId(1_006_003),
|
|
47
|
+
streamableHttpTransportSessionCloseNotificationFailure: mongoLogId(1_006_004),
|
|
48
|
+
streamableHttpTransportRequestFailure: mongoLogId(1_006_005),
|
|
49
|
+
streamableHttpTransportCloseFailure: mongoLogId(1_006_006),
|
|
38
50
|
} as const;
|
|
39
51
|
|
|
40
|
-
abstract class LoggerBase {
|
|
52
|
+
export abstract class LoggerBase {
|
|
41
53
|
abstract log(level: LogLevel, id: MongoLogId, context: string, message: string): void;
|
|
42
54
|
|
|
43
55
|
info(id: MongoLogId, context: string, message: string): void {
|
|
@@ -72,14 +84,14 @@ abstract class LoggerBase {
|
|
|
72
84
|
}
|
|
73
85
|
}
|
|
74
86
|
|
|
75
|
-
class ConsoleLogger extends LoggerBase {
|
|
87
|
+
export class ConsoleLogger extends LoggerBase {
|
|
76
88
|
log(level: LogLevel, id: MongoLogId, context: string, message: string): void {
|
|
77
89
|
message = redact(message);
|
|
78
|
-
console.error(`[${level.toUpperCase()}] ${id.__value} - ${context}: ${message}`);
|
|
90
|
+
console.error(`[${level.toUpperCase()}] ${id.__value} - ${context}: ${message} (${process.pid})`);
|
|
79
91
|
}
|
|
80
92
|
}
|
|
81
93
|
|
|
82
|
-
class DiskLogger extends LoggerBase {
|
|
94
|
+
export class DiskLogger extends LoggerBase {
|
|
83
95
|
private constructor(private logWriter: MongoLogWriter) {
|
|
84
96
|
super();
|
|
85
97
|
}
|
|
@@ -131,7 +143,7 @@ class DiskLogger extends LoggerBase {
|
|
|
131
143
|
}
|
|
132
144
|
}
|
|
133
145
|
|
|
134
|
-
class McpLogger extends LoggerBase {
|
|
146
|
+
export class McpLogger extends LoggerBase {
|
|
135
147
|
constructor(private server: McpServer) {
|
|
136
148
|
super();
|
|
137
149
|
}
|
|
@@ -150,18 +162,12 @@ class McpLogger extends LoggerBase {
|
|
|
150
162
|
}
|
|
151
163
|
|
|
152
164
|
class CompositeLogger extends LoggerBase {
|
|
153
|
-
private loggers: LoggerBase[];
|
|
165
|
+
private loggers: LoggerBase[] = [];
|
|
154
166
|
|
|
155
167
|
constructor(...loggers: LoggerBase[]) {
|
|
156
168
|
super();
|
|
157
169
|
|
|
158
|
-
|
|
159
|
-
// default to ConsoleLogger
|
|
160
|
-
this.loggers = [new ConsoleLogger()];
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
this.loggers = [...loggers];
|
|
170
|
+
this.setLoggers(...loggers);
|
|
165
171
|
}
|
|
166
172
|
|
|
167
173
|
setLoggers(...loggers: LoggerBase[]): void {
|
|
@@ -178,14 +184,5 @@ class CompositeLogger extends LoggerBase {
|
|
|
178
184
|
}
|
|
179
185
|
}
|
|
180
186
|
|
|
181
|
-
const logger = new CompositeLogger();
|
|
187
|
+
const logger = new CompositeLogger(new ConsoleLogger());
|
|
182
188
|
export default logger;
|
|
183
|
-
|
|
184
|
-
export async function initializeLogger(server: McpServer, logPath: string): Promise<LoggerBase> {
|
|
185
|
-
const diskLogger = await DiskLogger.fromPath(logPath);
|
|
186
|
-
const mcpLogger = new McpLogger(server);
|
|
187
|
-
|
|
188
|
-
logger.setLoggers(mcpLogger, diskLogger);
|
|
189
|
-
|
|
190
|
-
return logger;
|
|
191
|
-
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface ManagedTimeout {
|
|
2
|
+
cancel: () => void;
|
|
3
|
+
restart: () => void;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function setManagedTimeout(callback: () => Promise<void> | void, timeoutMS: number): ManagedTimeout {
|
|
7
|
+
let timeoutId: NodeJS.Timeout | undefined = setTimeout(() => {
|
|
8
|
+
void callback();
|
|
9
|
+
}, timeoutMS);
|
|
10
|
+
|
|
11
|
+
function cancel() {
|
|
12
|
+
clearTimeout(timeoutId);
|
|
13
|
+
timeoutId = undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function restart() {
|
|
17
|
+
cancel();
|
|
18
|
+
timeoutId = setTimeout(() => {
|
|
19
|
+
void callback();
|
|
20
|
+
}, timeoutMS);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
cancel,
|
|
25
|
+
restart,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver";
|
|
2
|
-
import { ApiClient, ApiClientCredentials } from "./
|
|
2
|
+
import { ApiClient, ApiClientCredentials } from "./atlas/apiClient.js";
|
|
3
3
|
import { Implementation } from "@modelcontextprotocol/sdk/types.js";
|
|
4
4
|
import logger, { LogId } from "./logger.js";
|
|
5
5
|
import EventEmitter from "events";
|
|
6
6
|
import { ConnectOptions } from "./config.js";
|
|
7
|
-
import { setAppNameParamIfMissing } from "
|
|
8
|
-
import { packageInfo } from "./
|
|
7
|
+
import { setAppNameParamIfMissing } from "../helpers/connectionOptions.js";
|
|
8
|
+
import { packageInfo } from "./packageInfo.js";
|
|
9
9
|
|
|
10
10
|
export interface SessionOptions {
|
|
11
11
|
apiBaseUrl: string;
|
|
@@ -67,35 +67,33 @@ export class Session extends EventEmitter<{
|
|
|
67
67
|
}
|
|
68
68
|
this.serviceProvider = undefined;
|
|
69
69
|
}
|
|
70
|
-
if (
|
|
71
|
-
this.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
username: this.connectedAtlasCluster.username,
|
|
80
|
-
databaseName: "admin",
|
|
70
|
+
if (this.connectedAtlasCluster?.username && this.connectedAtlasCluster?.projectId) {
|
|
71
|
+
void this.apiClient
|
|
72
|
+
.deleteDatabaseUser({
|
|
73
|
+
params: {
|
|
74
|
+
path: {
|
|
75
|
+
groupId: this.connectedAtlasCluster.projectId,
|
|
76
|
+
username: this.connectedAtlasCluster.username,
|
|
77
|
+
databaseName: "admin",
|
|
78
|
+
},
|
|
81
79
|
},
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
80
|
+
})
|
|
81
|
+
.catch((err: unknown) => {
|
|
82
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
83
|
+
logger.error(
|
|
84
|
+
LogId.atlasDeleteDatabaseUserFailure,
|
|
85
|
+
"atlas-connect-cluster",
|
|
86
|
+
`Error deleting previous database user: ${error.message}`
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
this.connectedAtlasCluster = undefined;
|
|
90
|
+
}
|
|
94
91
|
this.emit("disconnect");
|
|
95
92
|
}
|
|
96
93
|
|
|
97
94
|
async close(): Promise<void> {
|
|
98
95
|
await this.disconnect();
|
|
96
|
+
await this.apiClient.close();
|
|
99
97
|
this.emit("close");
|
|
100
98
|
}
|
|
101
99
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import logger, { LogId, LoggerBase, McpLogger } from "./logger.js";
|
|
4
|
+
import { ManagedTimeout, setManagedTimeout } from "./managedTimeout.js";
|
|
5
|
+
|
|
6
|
+
export class SessionStore {
|
|
7
|
+
private sessions: {
|
|
8
|
+
[sessionId: string]: {
|
|
9
|
+
logger: LoggerBase;
|
|
10
|
+
transport: StreamableHTTPServerTransport;
|
|
11
|
+
abortTimeout: ManagedTimeout;
|
|
12
|
+
notificationTimeout: ManagedTimeout;
|
|
13
|
+
};
|
|
14
|
+
} = {};
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
private readonly idleTimeoutMS: number,
|
|
18
|
+
private readonly notificationTimeoutMS: number
|
|
19
|
+
) {
|
|
20
|
+
if (idleTimeoutMS <= 0) {
|
|
21
|
+
throw new Error("idleTimeoutMS must be greater than 0");
|
|
22
|
+
}
|
|
23
|
+
if (notificationTimeoutMS <= 0) {
|
|
24
|
+
throw new Error("notificationTimeoutMS must be greater than 0");
|
|
25
|
+
}
|
|
26
|
+
if (idleTimeoutMS <= notificationTimeoutMS) {
|
|
27
|
+
throw new Error("idleTimeoutMS must be greater than notificationTimeoutMS");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getSession(sessionId: string): StreamableHTTPServerTransport | undefined {
|
|
32
|
+
this.resetTimeout(sessionId);
|
|
33
|
+
return this.sessions[sessionId]?.transport;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private resetTimeout(sessionId: string): void {
|
|
37
|
+
const session = this.sessions[sessionId];
|
|
38
|
+
if (!session) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
session.abortTimeout.restart();
|
|
43
|
+
|
|
44
|
+
session.notificationTimeout.restart();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private sendNotification(sessionId: string): void {
|
|
48
|
+
const session = this.sessions[sessionId];
|
|
49
|
+
if (!session) {
|
|
50
|
+
logger.warning(
|
|
51
|
+
LogId.streamableHttpTransportSessionCloseNotificationFailure,
|
|
52
|
+
"sessionStore",
|
|
53
|
+
`session ${sessionId} not found, no notification delivered`
|
|
54
|
+
);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
session.logger.info(
|
|
58
|
+
LogId.streamableHttpTransportSessionCloseNotification,
|
|
59
|
+
"sessionStore",
|
|
60
|
+
"Session is about to be closed due to inactivity"
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
setSession(sessionId: string, transport: StreamableHTTPServerTransport, mcpServer: McpServer): void {
|
|
65
|
+
const session = this.sessions[sessionId];
|
|
66
|
+
if (session) {
|
|
67
|
+
throw new Error(`Session ${sessionId} already exists`);
|
|
68
|
+
}
|
|
69
|
+
const abortTimeout = setManagedTimeout(async () => {
|
|
70
|
+
if (this.sessions[sessionId]) {
|
|
71
|
+
this.sessions[sessionId].logger.info(
|
|
72
|
+
LogId.streamableHttpTransportSessionCloseNotification,
|
|
73
|
+
"sessionStore",
|
|
74
|
+
"Session closed due to inactivity"
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
await this.closeSession(sessionId);
|
|
78
|
+
}
|
|
79
|
+
}, this.idleTimeoutMS);
|
|
80
|
+
const notificationTimeout = setManagedTimeout(
|
|
81
|
+
() => this.sendNotification(sessionId),
|
|
82
|
+
this.notificationTimeoutMS
|
|
83
|
+
);
|
|
84
|
+
this.sessions[sessionId] = { logger: new McpLogger(mcpServer), transport, abortTimeout, notificationTimeout };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async closeSession(sessionId: string, closeTransport: boolean = true): Promise<void> {
|
|
88
|
+
const session = this.sessions[sessionId];
|
|
89
|
+
if (!session) {
|
|
90
|
+
throw new Error(`Session ${sessionId} not found`);
|
|
91
|
+
}
|
|
92
|
+
session.abortTimeout.cancel();
|
|
93
|
+
session.notificationTimeout.cancel();
|
|
94
|
+
if (closeTransport) {
|
|
95
|
+
try {
|
|
96
|
+
await session.transport.close();
|
|
97
|
+
} catch (error) {
|
|
98
|
+
logger.error(
|
|
99
|
+
LogId.streamableHttpTransportSessionCloseFailure,
|
|
100
|
+
"streamableHttpTransport",
|
|
101
|
+
`Error closing transport ${sessionId}: ${error instanceof Error ? error.message : String(error)}`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
delete this.sessions[sessionId];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async closeAllSessions(): Promise<void> {
|
|
109
|
+
await Promise.all(Object.keys(this.sessions).map((sessionId) => this.closeSession(sessionId)));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
|
|
3
|
+
let containerEnv: boolean | undefined;
|
|
4
|
+
|
|
5
|
+
export async function detectContainerEnv(): Promise<boolean> {
|
|
6
|
+
if (containerEnv !== undefined) {
|
|
7
|
+
return containerEnv;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const detect = async function (): Promise<boolean> {
|
|
11
|
+
if (process.platform !== "linux") {
|
|
12
|
+
return false; // we only support linux containers for now
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (process.env.container) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const exists = await Promise.all(
|
|
20
|
+
["/.dockerenv", "/run/.containerenv", "/var/run/.containerenv"].map(async (file) => {
|
|
21
|
+
try {
|
|
22
|
+
await fs.access(file);
|
|
23
|
+
return true;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
return exists.includes(true);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
containerEnv = await detect();
|
|
34
|
+
return containerEnv;
|
|
35
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Document } from "mongodb";
|
|
2
|
+
import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver";
|
|
3
|
+
import { ErrorCodes, MongoDBError } from "../common/errors.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check if the query plan uses an index
|
|
7
|
+
* @param explainResult The result of the explain query
|
|
8
|
+
* @returns true if an index is used, false if it's a full collection scan
|
|
9
|
+
*/
|
|
10
|
+
export function usesIndex(explainResult: Document): boolean {
|
|
11
|
+
const queryPlanner = explainResult?.queryPlanner as Document | undefined;
|
|
12
|
+
const winningPlan = queryPlanner?.winningPlan as Document | undefined;
|
|
13
|
+
const stage = winningPlan?.stage as string | undefined;
|
|
14
|
+
const inputStage = winningPlan?.inputStage as Document | undefined;
|
|
15
|
+
|
|
16
|
+
// Check for index scan stages (including MongoDB 8.0+ stages)
|
|
17
|
+
const indexScanStages = [
|
|
18
|
+
"IXSCAN",
|
|
19
|
+
"COUNT_SCAN",
|
|
20
|
+
"EXPRESS_IXSCAN",
|
|
21
|
+
"EXPRESS_CLUSTERED_IXSCAN",
|
|
22
|
+
"EXPRESS_UPDATE",
|
|
23
|
+
"EXPRESS_DELETE",
|
|
24
|
+
"IDHACK",
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
if (stage && indexScanStages.includes(stage)) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (inputStage && inputStage.stage && indexScanStages.includes(inputStage.stage as string)) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Recursively check deeper stages
|
|
36
|
+
if (inputStage && inputStage.inputStage) {
|
|
37
|
+
return usesIndex({ queryPlanner: { winningPlan: inputStage } });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (stage === "COLLSCAN") {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Default to false (conservative approach)
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Generate an error message for index check failure
|
|
50
|
+
*/
|
|
51
|
+
export function getIndexCheckErrorMessage(database: string, collection: string, operation: string): string {
|
|
52
|
+
return `Index check failed: The ${operation} operation on "${database}.${collection}" performs a collection scan (COLLSCAN) instead of using an index. Consider adding an index for better performance. Use 'explain' tool for query plan analysis or 'collection-indexes' to view existing indexes. To disable this check, set MDB_MCP_INDEX_CHECK to false.`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Generic function to perform index usage check
|
|
57
|
+
*/
|
|
58
|
+
export async function checkIndexUsage(
|
|
59
|
+
provider: NodeDriverServiceProvider,
|
|
60
|
+
database: string,
|
|
61
|
+
collection: string,
|
|
62
|
+
operation: string,
|
|
63
|
+
explainCallback: () => Promise<Document>
|
|
64
|
+
): Promise<void> {
|
|
65
|
+
try {
|
|
66
|
+
const explainResult = await explainCallback();
|
|
67
|
+
|
|
68
|
+
if (!usesIndex(explainResult)) {
|
|
69
|
+
throw new MongoDBError(
|
|
70
|
+
ErrorCodes.ForbiddenCollscan,
|
|
71
|
+
getIndexCheckErrorMessage(database, collection, operation)
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (error instanceof MongoDBError && error.code === ErrorCodes.ForbiddenCollscan) {
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// If explain itself fails, log but do not prevent query execution
|
|
80
|
+
// This avoids blocking normal queries in special cases (e.g., permission issues)
|
|
81
|
+
console.warn(`Index check failed to execute explain for ${operation} on ${database}.${collection}:`, error);
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,58 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import logger, { LogId } from "./logger.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { Server } from "./server.js";
|
|
8
|
-
import { packageInfo } from "./helpers/packageInfo.js";
|
|
9
|
-
import { Telemetry } from "./telemetry/telemetry.js";
|
|
10
|
-
import { createEJsonTransport } from "./helpers/EJsonTransport.js";
|
|
3
|
+
import logger, { LogId } from "./common/logger.js";
|
|
4
|
+
import { config } from "./common/config.js";
|
|
5
|
+
import { StdioRunner } from "./transports/stdio.js";
|
|
6
|
+
import { StreamableHttpRunner } from "./transports/streamableHttp.js";
|
|
11
7
|
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
apiBaseUrl: config.apiBaseUrl,
|
|
15
|
-
apiClientId: config.apiClientId,
|
|
16
|
-
apiClientSecret: config.apiClientSecret,
|
|
17
|
-
});
|
|
18
|
-
const mcpServer = new McpServer({
|
|
19
|
-
name: packageInfo.mcpServerName,
|
|
20
|
-
version: packageInfo.version,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
const telemetry = Telemetry.create(session, config);
|
|
24
|
-
|
|
25
|
-
const server = new Server({
|
|
26
|
-
mcpServer,
|
|
27
|
-
session,
|
|
28
|
-
telemetry,
|
|
29
|
-
userConfig: config,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const transport = createEJsonTransport();
|
|
8
|
+
async function main() {
|
|
9
|
+
const transportRunner = config.transport === "stdio" ? new StdioRunner(config) : new StreamableHttpRunner(config);
|
|
33
10
|
|
|
34
11
|
const shutdown = () => {
|
|
35
12
|
logger.info(LogId.serverCloseRequested, "server", `Server close requested`);
|
|
36
13
|
|
|
37
|
-
|
|
14
|
+
transportRunner
|
|
38
15
|
.close()
|
|
39
16
|
.then(() => {
|
|
40
|
-
logger.info(LogId.serverClosed, "server", `Server closed
|
|
17
|
+
logger.info(LogId.serverClosed, "server", `Server closed`);
|
|
41
18
|
process.exit(0);
|
|
42
19
|
})
|
|
43
|
-
.catch((
|
|
44
|
-
|
|
45
|
-
logger.error(LogId.serverCloseFailure, "server", `Error closing server: ${error.message}`);
|
|
20
|
+
.catch((error: unknown) => {
|
|
21
|
+
logger.error(LogId.serverCloseFailure, "server", `Error closing server: ${error as string}`);
|
|
46
22
|
process.exit(1);
|
|
47
23
|
});
|
|
48
24
|
};
|
|
49
25
|
|
|
50
|
-
process.
|
|
51
|
-
process.
|
|
52
|
-
process.
|
|
26
|
+
process.on("SIGINT", shutdown);
|
|
27
|
+
process.on("SIGABRT", shutdown);
|
|
28
|
+
process.on("SIGTERM", shutdown);
|
|
29
|
+
process.on("SIGQUIT", shutdown);
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
await transportRunner.start();
|
|
33
|
+
} catch (error: unknown) {
|
|
34
|
+
logger.info(LogId.serverCloseRequested, "server", "Closing server");
|
|
35
|
+
try {
|
|
36
|
+
await transportRunner.close();
|
|
37
|
+
logger.info(LogId.serverClosed, "server", "Server closed");
|
|
38
|
+
} catch (error: unknown) {
|
|
39
|
+
logger.error(LogId.serverCloseFailure, "server", `Error closing server: ${error as string}`);
|
|
40
|
+
}
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
53
44
|
|
|
54
|
-
|
|
55
|
-
} catch (error: unknown) {
|
|
45
|
+
main().catch((error: unknown) => {
|
|
56
46
|
logger.emergency(LogId.serverStartFailure, "server", `Fatal error running server: ${error as string}`);
|
|
57
47
|
process.exit(1);
|
|
58
|
-
}
|
|
48
|
+
});
|
package/src/server.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { Session } from "./session.js";
|
|
2
|
+
import { Session } from "./common/session.js";
|
|
3
3
|
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
4
4
|
import { AtlasTools } from "./tools/atlas/tools.js";
|
|
5
5
|
import { MongoDbTools } from "./tools/mongodb/tools.js";
|
|
6
|
-
import logger, {
|
|
6
|
+
import logger, { LogId, LoggerBase, McpLogger, DiskLogger, ConsoleLogger } from "./common/logger.js";
|
|
7
7
|
import { ObjectId } from "mongodb";
|
|
8
8
|
import { Telemetry } from "./telemetry/telemetry.js";
|
|
9
|
-
import { UserConfig } from "./config.js";
|
|
9
|
+
import { UserConfig } from "./common/config.js";
|
|
10
10
|
import { type ServerEvent } from "./telemetry/types.js";
|
|
11
11
|
import { type ServerCommand } from "./telemetry/types.js";
|
|
12
12
|
import { CallToolRequestSchema, CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
13
13
|
import assert from "assert";
|
|
14
|
+
import { ToolBase } from "./tools/tool.js";
|
|
14
15
|
|
|
15
16
|
export interface ServerOptions {
|
|
16
17
|
session: Session;
|
|
@@ -21,9 +22,10 @@ export interface ServerOptions {
|
|
|
21
22
|
|
|
22
23
|
export class Server {
|
|
23
24
|
public readonly session: Session;
|
|
24
|
-
|
|
25
|
+
public readonly mcpServer: McpServer;
|
|
25
26
|
private readonly telemetry: Telemetry;
|
|
26
27
|
public readonly userConfig: UserConfig;
|
|
28
|
+
public readonly tools: ToolBase[] = [];
|
|
27
29
|
private readonly startTime: number;
|
|
28
30
|
|
|
29
31
|
constructor({ session, mcpServer, userConfig, telemetry }: ServerOptions) {
|
|
@@ -35,6 +37,8 @@ export class Server {
|
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
async connect(transport: Transport): Promise<void> {
|
|
40
|
+
await this.validateConfig();
|
|
41
|
+
|
|
38
42
|
this.mcpServer.server.registerCapabilities({ logging: {} });
|
|
39
43
|
|
|
40
44
|
this.registerTools();
|
|
@@ -63,9 +67,17 @@ export class Server {
|
|
|
63
67
|
return existingHandler(request, extra);
|
|
64
68
|
});
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
const loggers: LoggerBase[] = [];
|
|
71
|
+
if (this.userConfig.loggers.includes("mcp")) {
|
|
72
|
+
loggers.push(new McpLogger(this.mcpServer));
|
|
73
|
+
}
|
|
74
|
+
if (this.userConfig.loggers.includes("disk")) {
|
|
75
|
+
loggers.push(await DiskLogger.fromPath(this.userConfig.logPath));
|
|
76
|
+
}
|
|
77
|
+
if (this.userConfig.loggers.includes("stderr")) {
|
|
78
|
+
loggers.push(new ConsoleLogger());
|
|
79
|
+
}
|
|
80
|
+
logger.setLoggers(...loggers);
|
|
69
81
|
|
|
70
82
|
this.mcpServer.server.oninitialized = () => {
|
|
71
83
|
this.session.setAgentRunner(this.mcpServer.server.getClientVersion());
|
|
@@ -90,7 +102,7 @@ export class Server {
|
|
|
90
102
|
this.emitServerEvent("stop", Date.now() - closeTime, error);
|
|
91
103
|
};
|
|
92
104
|
|
|
93
|
-
await this.
|
|
105
|
+
await this.mcpServer.connect(transport);
|
|
94
106
|
}
|
|
95
107
|
|
|
96
108
|
async close(): Promise<void> {
|
|
@@ -130,12 +142,15 @@ export class Server {
|
|
|
130
142
|
}
|
|
131
143
|
}
|
|
132
144
|
|
|
133
|
-
this.telemetry.emitEvents([event]);
|
|
145
|
+
this.telemetry.emitEvents([event]).catch(() => {});
|
|
134
146
|
}
|
|
135
147
|
|
|
136
148
|
private registerTools() {
|
|
137
|
-
for (const
|
|
138
|
-
new
|
|
149
|
+
for (const toolConstructor of [...AtlasTools, ...MongoDbTools]) {
|
|
150
|
+
const tool = new toolConstructor(this.session, this.userConfig, this.telemetry);
|
|
151
|
+
if (tool.register(this)) {
|
|
152
|
+
this.tools.push(tool);
|
|
153
|
+
}
|
|
139
154
|
}
|
|
140
155
|
}
|
|
141
156
|
|
|
@@ -174,6 +189,35 @@ export class Server {
|
|
|
174
189
|
}
|
|
175
190
|
|
|
176
191
|
private async validateConfig(): Promise<void> {
|
|
192
|
+
const transport = this.userConfig.transport as string;
|
|
193
|
+
if (transport !== "http" && transport !== "stdio") {
|
|
194
|
+
throw new Error(`Invalid transport: ${transport}`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const telemetry = this.userConfig.telemetry as string;
|
|
198
|
+
if (telemetry !== "enabled" && telemetry !== "disabled") {
|
|
199
|
+
throw new Error(`Invalid telemetry: ${telemetry}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (this.userConfig.httpPort < 1 || this.userConfig.httpPort > 65535) {
|
|
203
|
+
throw new Error(`Invalid httpPort: ${this.userConfig.httpPort}`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (this.userConfig.loggers.length === 0) {
|
|
207
|
+
throw new Error("No loggers found in config");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const loggerTypes = new Set(this.userConfig.loggers);
|
|
211
|
+
if (loggerTypes.size !== this.userConfig.loggers.length) {
|
|
212
|
+
throw new Error("Duplicate loggers found in config");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
for (const loggerType of this.userConfig.loggers as string[]) {
|
|
216
|
+
if (loggerType !== "mcp" && loggerType !== "disk" && loggerType !== "stderr") {
|
|
217
|
+
throw new Error(`Invalid logger: ${loggerType}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
177
221
|
if (this.userConfig.connectionString) {
|
|
178
222
|
try {
|
|
179
223
|
await this.session.connectToMongoDB(this.userConfig.connectionString, this.userConfig.connectOptions);
|