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

mongodb-js / mongodb-mcp-server / 16779406063

06 Aug 2025 02:11PM UTC coverage: 81.424% (-0.4%) from 81.781%
16779406063

Pull #420

github

web-flow
Merge cc01ac54e into a35d18dd6
Pull Request #420: chore: allow logging unredacted messages MCP-103

679 of 874 branches covered (77.69%)

Branch coverage included in aggregate %.

161 of 291 new or added lines in 16 files covered. (55.33%)

7 existing lines in 4 files now uncovered.

3485 of 4240 relevant lines covered (82.19%)

63.42 hits per line

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

54.72
/src/common/sessionStore.ts
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";
2✔
4
import { ManagedTimeout, setManagedTimeout } from "./managedTimeout.js";
2✔
5

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

16
    constructor(
2✔
17
        private readonly idleTimeoutMS: number,
2✔
18
        private readonly notificationTimeoutMS: number
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
            logger.warning({
×
NEW
51
                id: LogId.streamableHttpTransportSessionCloseNotificationFailure,
×
NEW
52
                context: "sessionStore",
×
NEW
53
                message: `session ${sessionId} not found, no notification delivered`,
×
NEW
54
            });
×
55
            return;
×
56
        }
×
NEW
57
        session.logger.info({
×
NEW
58
            id: LogId.streamableHttpTransportSessionCloseNotification,
×
NEW
59
            context: "sessionStore",
×
NEW
60
            message: "Session is about to be closed due to inactivity",
×
NEW
61
        });
×
UNCOV
62
    }
×
63

64
    setSession(sessionId: string, transport: StreamableHTTPServerTransport, mcpServer: McpServer): 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]) {
×
NEW
71
                this.sessions[sessionId].logger.info({
×
NEW
72
                    id: LogId.streamableHttpTransportSessionCloseNotification,
×
NEW
73
                    context: "sessionStore",
×
NEW
74
                    message: "Session closed due to inactivity",
×
NEW
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] = { logger: new McpLogger(mcpServer), transport, abortTimeout, notificationTimeout };
2✔
85
    }
2✔
86

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

108
    async closeAllSessions(): Promise<void> {
2✔
109
        await Promise.all(Object.keys(this.sessions).map((sessionId) => this.closeSession(sessionId)));
2✔
110
    }
2✔
111
}
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