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

mongodb-js / mongodb-mcp-server / 16790782045

06 Aug 2025 11:09PM UTC coverage: 81.233% (-0.07%) from 81.298%
16790782045

Pull #425

github

web-flow
Merge 7712da066 into 53ac631ea
Pull Request #425: fix: remove global logger MCP-103

681 of 881 branches covered (77.3%)

Branch coverage included in aggregate %.

158 of 207 new or added lines in 17 files covered. (76.33%)

6 existing lines in 2 files now uncovered.

3522 of 4293 relevant lines covered (82.04%)

58.12 hits per line

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

57.14
/src/common/sessionStore.ts
1
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
2
import { LogId, LoggerBase } from "./logger.js";
2✔
3
import { ManagedTimeout, setManagedTimeout } from "./managedTimeout.js";
2✔
4

5
export class SessionStore {
2✔
6
    private sessions: {
2✔
7
        [sessionId: string]: {
8
            logger: LoggerBase;
9
            transport: StreamableHTTPServerTransport;
10
            abortTimeout: ManagedTimeout;
11
            notificationTimeout: ManagedTimeout;
12
        };
13
    } = {};
2✔
14

15
    constructor(
2✔
16
        private readonly idleTimeoutMS: number,
2✔
17
        private readonly notificationTimeoutMS: number,
2✔
18
        private readonly logger: LoggerBase
2✔
19
    ) {
2✔
20
        if (idleTimeoutMS <= 0) {
2!
21
            throw new Error("idleTimeoutMS must be greater than 0");
×
22
        }
×
23
        if (notificationTimeoutMS <= 0) {
2!
24
            throw new Error("notificationTimeoutMS must be greater than 0");
×
25
        }
×
26
        if (idleTimeoutMS <= notificationTimeoutMS) {
2!
27
            throw new Error("idleTimeoutMS must be greater than notificationTimeoutMS");
×
28
        }
×
29
    }
2✔
30

31
    getSession(sessionId: string): StreamableHTTPServerTransport | undefined {
2✔
32
        this.resetTimeout(sessionId);
6✔
33
        return this.sessions[sessionId]?.transport;
6✔
34
    }
6✔
35

36
    private resetTimeout(sessionId: string): void {
2✔
37
        const session = this.sessions[sessionId];
6✔
38
        if (!session) {
6!
39
            return;
×
40
        }
×
41

42
        session.abortTimeout.restart();
6✔
43

44
        session.notificationTimeout.restart();
6✔
45
    }
6✔
46

47
    private sendNotification(sessionId: string): void {
2✔
48
        const session = this.sessions[sessionId];
×
49
        if (!session) {
×
NEW
50
            this.logger.warning({
×
51
                id: LogId.streamableHttpTransportSessionCloseNotificationFailure,
×
52
                context: "sessionStore",
×
53
                message: `session ${sessionId} not found, no notification delivered`,
×
54
            });
×
55
            return;
×
56
        }
×
57
        session.logger.info({
×
58
            id: LogId.streamableHttpTransportSessionCloseNotification,
×
59
            context: "sessionStore",
×
60
            message: "Session is about to be closed due to inactivity",
×
61
        });
×
62
    }
×
63

64
    setSession(sessionId: string, transport: StreamableHTTPServerTransport, logger: LoggerBase): void {
2✔
65
        const session = this.sessions[sessionId];
2✔
66
        if (session) {
2!
67
            throw new Error(`Session ${sessionId} already exists`);
×
68
        }
×
69
        const abortTimeout = setManagedTimeout(async () => {
2✔
70
            if (this.sessions[sessionId]) {
×
71
                this.sessions[sessionId].logger.info({
×
72
                    id: LogId.streamableHttpTransportSessionCloseNotification,
×
73
                    context: "sessionStore",
×
74
                    message: "Session closed due to inactivity",
×
75
                });
×
76

77
                await this.closeSession(sessionId);
×
78
            }
×
79
        }, this.idleTimeoutMS);
2✔
80
        const notificationTimeout = setManagedTimeout(
2✔
81
            () => this.sendNotification(sessionId),
2✔
82
            this.notificationTimeoutMS
2✔
83
        );
2✔
84
        this.sessions[sessionId] = {
2✔
85
            transport,
2✔
86
            abortTimeout,
2✔
87
            notificationTimeout,
2✔
88
            logger,
2✔
89
        };
2✔
90
    }
2✔
91

92
    async closeSession(sessionId: string, closeTransport: boolean = true): Promise<void> {
2✔
93
        const session = this.sessions[sessionId];
2✔
94
        if (!session) {
2!
95
            throw new Error(`Session ${sessionId} not found`);
×
96
        }
×
97
        session.abortTimeout.cancel();
2✔
98
        session.notificationTimeout.cancel();
2✔
99
        if (closeTransport) {
2✔
100
            try {
2✔
101
                await session.transport.close();
2✔
102
            } catch (error) {
2!
NEW
103
                this.logger.error({
×
104
                    id: LogId.streamableHttpTransportSessionCloseFailure,
×
105
                    context: "streamableHttpTransport",
×
106
                    message: `Error closing transport ${sessionId}: ${error instanceof Error ? error.message : String(error)}`,
×
107
                });
×
108
            }
×
109
        }
2✔
110
        delete this.sessions[sessionId];
2✔
111
    }
2✔
112

113
    async closeAllSessions(): Promise<void> {
2✔
114
        await Promise.all(Object.keys(this.sessions).map((sessionId) => this.closeSession(sessionId)));
2✔
115
    }
2✔
116
}
2✔
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