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

mongodb-js / mongodb-mcp-server / 14622981460

23 Apr 2025 04:14PM UTC coverage: 75.182% (-3.2%) from 78.42%
14622981460

Pull #87

github

blva
address comment for category and update emit tool to get tool result object
Pull Request #87: feat: core telemetry functionality

100 of 188 branches covered (53.19%)

Branch coverage included in aggregate %.

53 of 92 new or added lines in 8 files covered. (57.61%)

18 existing lines in 4 files now uncovered.

624 of 775 relevant lines covered (80.52%)

39.15 hits per line

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

37.25
/src/telemetry/telemetry.ts
1
import { Session } from "../session.js";
2
import { BaseEvent } from "./types.js";
3
import config from "../config.js";
18✔
4
import logger from "../logger.js";
18✔
5
import { mongoLogId } from "mongodb-log-writer";
18✔
6
import { ApiClient } from "../common/atlas/apiClient.js";
7
import { MACHINE_METADATA } from "./constants.js";
18✔
8
import { EventCache } from "./eventCache.js";
18✔
9

10
type EventResult = {
11
    success: boolean;
12
    error?: Error;
13
};
14

15
type CommonProperties = {
16
    device_id: string;
17
    mcp_server_version: string;
18
    mcp_server_name: string;
19
    mcp_client_version?: string;
20
    mcp_client_name?: string;
21
    platform: string;
22
    arch: string;
23
    os_type: string;
24
    os_version?: string;
25
    session_id?: string;
26
};
27

28
export class Telemetry {
18✔
29
    private readonly commonProperties: CommonProperties;
30

31
    constructor(
32
        private readonly session: Session,
522✔
33
        private readonly eventCache: EventCache = EventCache.getInstance()
522✔
34
    ) {
35
        this.commonProperties = {
522✔
36
            ...MACHINE_METADATA,
37
        };
38
    }
39

40
    /**
41
     * Checks if telemetry is currently enabled
42
     * This is a method rather than a constant to capture runtime config changes
43
     *
44
     * Follows the Console Do Not Track standard (https://consoledonottrack.com/)
45
     * by respecting the DO_NOT_TRACK environment variable
46
     */
47
    private static isTelemetryEnabled(): boolean {
48
        // Check if telemetry is explicitly disabled in config
49
        if (config.telemetry === "disabled") {
176✔
50
            return false;
176✔
51
        }
52

NEW
53
        const doNotTrack = process.env.DO_NOT_TRACK;
×
NEW
54
        if (doNotTrack) {
×
NEW
55
            const value = doNotTrack.toLowerCase();
×
56
            // Telemetry should be disabled if DO_NOT_TRACK is "1", "true", or "yes"
NEW
57
            if (value === "1" || value === "true" || value === "yes") {
×
NEW
58
                return false;
×
59
            }
60
        }
61

NEW
62
        return true;
×
63
    }
64

65
    /**
66
     * Emits events through the telemetry pipeline
67
     * @param events - The events to emit
68
     */
69
    public async emitEvents(events: BaseEvent[]): Promise<void> {
70
        try {
176✔
71
            if (!Telemetry.isTelemetryEnabled()) {
176✔
72
                logger.debug(mongoLogId(1_000_000), "telemetry", "Telemetry is disabled, skipping events.");
176✔
73
                return;
176✔
74
            }
75

NEW
76
            await this.emit(events);
×
77
        } catch {
NEW
78
            logger.debug(mongoLogId(1_000_002), "telemetry", `Error emitting telemetry events.`);
×
79
        }
80
    }
81

82
    /**
83
     * Gets the common properties for events
84
     * @returns Object containing common properties for all events
85
     */
86
    public getCommonProperties(): CommonProperties {
87
        return {
176✔
88
            ...this.commonProperties,
89
            mcp_client_version: this.session.agentRunner?.version,
90
            mcp_client_name: this.session.agentRunner?.name,
91
            session_id: this.session.sessionId,
92
        };
93
    }
94

95
    /**
96
     * Attempts to emit events through authenticated and unauthenticated clients
97
     * Falls back to caching if both attempts fail
98
     */
99
    private async emit(events: BaseEvent[]): Promise<void> {
NEW
100
        const cachedEvents = this.eventCache.getEvents();
×
NEW
101
        const allEvents = [...cachedEvents, ...events];
×
102

NEW
103
        logger.debug(
×
104
            mongoLogId(1_000_003),
105
            "telemetry",
106
            `Attempting to send ${allEvents.length} events (${cachedEvents.length} cached)`
107
        );
108

NEW
109
        const result = await this.sendEvents(this.session.apiClient, allEvents);
×
NEW
110
        if (result.success) {
×
NEW
111
            this.eventCache.clearEvents();
×
NEW
112
            logger.debug(mongoLogId(1_000_004), "telemetry", `Sent ${allEvents.length} events successfully`);
×
NEW
113
            return;
×
114
        }
115

NEW
116
        logger.warning(
×
117
            mongoLogId(1_000_005),
118
            "telemetry",
119
            `Error sending event to client: ${result.error instanceof Error ? result.error.message : String(result.error)}`
×
120
        );
NEW
121
        this.eventCache.appendEvents(events);
×
122
    }
123

124
    /**
125
     * Attempts to send events through the provided API client
126
     */
127
    private async sendEvents(client: ApiClient, events: BaseEvent[]): Promise<EventResult> {
NEW
128
        try {
×
NEW
129
            await client.sendEvents(events);
×
NEW
130
            return { success: true };
×
131
        } catch (error) {
NEW
132
            return {
×
133
                success: false,
134
                error: error instanceof Error ? error : new Error(String(error)),
×
135
            };
136
        }
137
    }
138
}
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