Skip to content

Commit 6ae0492

Browse files
authored
Merge branch 'main' into telemetry-2
2 parents 0e6bd02 + 78db85b commit 6ae0492

File tree

15 files changed

+384
-255
lines changed

15 files changed

+384
-255
lines changed

.github/dependabot.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "npm"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
- package-ecosystem: "github-actions"
8+
directory: "/"
9+
schedule:
10+
interval: "weekly"

.github/workflows/codeql.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: "CodeQL Advanced"
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
pull_request:
7+
branches: ["main"]
8+
schedule:
9+
- cron: "35 4 * * 4"
10+
11+
jobs:
12+
analyze:
13+
name: Analyze (${{ matrix.language }})
14+
runs-on: ubuntu-latest
15+
permissions:
16+
security-events: write
17+
packages: read
18+
actions: read
19+
contents: read
20+
21+
strategy:
22+
fail-fast: false
23+
matrix:
24+
language:
25+
- actions
26+
- javascript-typescript
27+
steps:
28+
- name: Checkout repository
29+
uses: actions/checkout@v4
30+
- name: Initialize CodeQL
31+
uses: github/codeql-action/init@v3
32+
with:
33+
languages: ${{ matrix.language }}
34+
- name: Perform CodeQL Analysis
35+
uses: github/codeql-action/analyze@v3
36+
with:
37+
category: "/language:${{matrix.language}}"

src/errors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export enum ErrorCodes {
22
NotConnectedToMongoDB = 1_000_000,
3-
InvalidParams = 1_000_001,
3+
MisconfiguredConnectionString = 1_000_001,
44
}
55

66
export class MongoDBError extends Error {

src/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
#!/usr/bin/env node
22

33
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4-
import logger from "./logger.js";
5-
import { mongoLogId } from "mongodb-log-writer";
4+
import logger, { LogId } from "./logger.js";
65
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
76
import { config } from "./config.js";
87
import { Session } from "./session.js";
@@ -29,6 +28,6 @@ try {
2928

3029
await server.connect(transport);
3130
} catch (error: unknown) {
32-
logger.emergency(mongoLogId(1_000_004), "server", `Fatal error running server: ${error as string}`);
31+
logger.emergency(LogId.serverStartFailure, "server", `Fatal error running server: ${error as string}`);
3332
process.exit(1);
3433
}

src/logger.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,29 @@
11
import fs from "fs/promises";
2-
import { MongoLogId, MongoLogManager, MongoLogWriter } from "mongodb-log-writer";
2+
import { mongoLogId, MongoLogId, MongoLogManager, MongoLogWriter } from "mongodb-log-writer";
33
import redact from "mongodb-redact";
44
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
55
import { LoggingMessageNotification } from "@modelcontextprotocol/sdk/types.js";
66

77
export type LogLevel = LoggingMessageNotification["params"]["level"];
88

9+
export const LogId = {
10+
serverStartFailure: mongoLogId(1_000_001),
11+
serverInitialized: mongoLogId(1_000_002),
12+
13+
atlasCheckCredentials: mongoLogId(1_001_001),
14+
15+
telemetryDisabled: mongoLogId(1_002_001),
16+
telemetryEmitFailure: mongoLogId(1_002_002),
17+
telemetryEmitStart: mongoLogId(1_002_003),
18+
telemetryEmitSuccess: mongoLogId(1_002_004),
19+
20+
toolExecute: mongoLogId(1_003_001),
21+
toolExecuteFailure: mongoLogId(1_003_002),
22+
toolDisabled: mongoLogId(1_003_003),
23+
24+
mongodbConnectFailure: mongoLogId(1_004_001),
25+
} as const;
26+
927
abstract class LoggerBase {
1028
abstract log(level: LogLevel, id: MongoLogId, context: string, message: string): void;
1129

src/server.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import { Session } from "./session.js";
33
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
44
import { AtlasTools } from "./tools/atlas/tools.js";
55
import { MongoDbTools } from "./tools/mongodb/tools.js";
6-
import logger, { initializeLogger } from "./logger.js";
7-
import { mongoLogId } from "mongodb-log-writer";
6+
import logger, { initializeLogger, LogId } from "./logger.js";
87
import { ObjectId } from "mongodb";
98
import { Telemetry } from "./telemetry/telemetry.js";
109
import { UserConfig } from "./config.js";
@@ -23,7 +22,7 @@ export class Server {
2322
public readonly session: Session;
2423
private readonly mcpServer: McpServer;
2524
private readonly telemetry: Telemetry;
26-
private readonly userConfig: UserConfig;
25+
public readonly userConfig: UserConfig;
2726
private readonly startTime: number;
2827

2928
constructor({ session, mcpServer, userConfig }: ServerOptions) {
@@ -71,7 +70,7 @@ export class Server {
7170
this.session.sessionId = new ObjectId().toString();
7271

7372
logger.info(
74-
mongoLogId(1_000_004),
73+
LogId.serverInitialized,
7574
"server",
7675
`Server started with transport ${transport.constructor.name} and agent runner ${this.session.agentRunner?.name}`
7776
);
@@ -135,6 +134,32 @@ export class Server {
135134
}
136135

137136
private registerResources() {
137+
this.mcpServer.resource(
138+
"config",
139+
"config://config",
140+
{
141+
description:
142+
"Server configuration, supplied by the user either as environment variables or as startup arguments",
143+
},
144+
(uri) => {
145+
const result = {
146+
telemetry: this.userConfig.telemetry,
147+
logPath: this.userConfig.logPath,
148+
connectionString: this.userConfig.connectionString
149+
? "set; no explicit connect needed, use switch-connection tool to connect to a different connection if necessary"
150+
: "not set; before using any mongodb tool, you need to call the connect tool with a connection string",
151+
connectOptions: this.userConfig.connectOptions,
152+
};
153+
return {
154+
contents: [
155+
{
156+
text: JSON.stringify(result),
157+
uri: uri.href,
158+
},
159+
],
160+
};
161+
}
162+
);
138163
if (this.userConfig.connectionString) {
139164
this.mcpServer.resource(
140165
"connection-string",

src/session.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver";
22
import { ApiClient, ApiClientCredentials } from "./common/atlas/apiClient.js";
33
import { Implementation } from "@modelcontextprotocol/sdk/types.js";
4+
import EventEmitter from "events";
45

56
export interface SessionOptions {
67
apiBaseUrl?: string;
78
apiClientId?: string;
89
apiClientSecret?: string;
910
}
1011

11-
export class Session {
12+
export class Session extends EventEmitter<{
13+
close: [];
14+
}> {
1215
sessionId?: string;
1316
serviceProvider?: NodeDriverServiceProvider;
1417
apiClient: ApiClient;
@@ -18,6 +21,8 @@ export class Session {
1821
};
1922

2023
constructor({ apiBaseUrl, apiClientId, apiClientSecret }: SessionOptions = {}) {
24+
super();
25+
2126
const credentials: ApiClientCredentials | undefined =
2227
apiClientId && apiClientSecret
2328
? {
@@ -49,6 +54,8 @@ export class Session {
4954
console.error("Error closing service provider:", error);
5055
}
5156
this.serviceProvider = undefined;
57+
58+
this.emit("close");
5259
}
5360
}
5461
}

src/telemetry/telemetry.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { Session } from "../session.js";
22
import { BaseEvent, CommonProperties } from "./types.js";
33
import { config } from "../config.js";
4-
import logger from "../logger.js";
5-
import { mongoLogId } from "mongodb-log-writer";
4+
import logger, { LogId } from "../logger.js";
65
import { ApiClient } from "../common/atlas/apiClient.js";
76
import { MACHINE_METADATA } from "./constants.js";
87
import { EventCache } from "./eventCache.js";
@@ -61,7 +60,7 @@ export class Telemetry {
6160

6261
await this.emit(events);
6362
} catch {
64-
logger.debug(mongoLogId(1_000_002), "telemetry", `Error emitting telemetry events.`);
63+
logger.debug(LogId.telemetryEmitFailure, "telemetry", `Error emitting telemetry events.`);
6564
}
6665
}
6766

@@ -89,20 +88,20 @@ export class Telemetry {
8988
const allEvents = [...cachedEvents, ...events];
9089

9190
logger.debug(
92-
mongoLogId(1_000_003),
91+
LogId.telemetryEmitStart,
9392
"telemetry",
9493
`Attempting to send ${allEvents.length} events (${cachedEvents.length} cached)`
9594
);
9695

9796
const result = await this.sendEvents(this.session.apiClient, allEvents);
9897
if (result.success) {
9998
this.eventCache.clearEvents();
100-
logger.debug(mongoLogId(1_000_004), "telemetry", `Sent ${allEvents.length} events successfully`);
99+
logger.debug(LogId.telemetryEmitSuccess, "telemetry", `Sent ${allEvents.length} events successfully`);
101100
return;
102101
}
103102

104-
logger.warning(
105-
mongoLogId(1_000_005),
103+
logger.debug(
104+
LogId.telemetryEmitFailure,
106105
"telemetry",
107106
`Error sending event to client: ${result.error instanceof Error ? result.error.message : String(result.error)}`
108107
);

0 commit comments

Comments
 (0)