|
1 | 1 | import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
2 | 2 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
3 |
| -import logger, { LogId, McpLogger } from "./logger.js"; |
4 |
| -import { TimeoutManager } from "./timeoutManager.js"; |
| 3 | +import logger, { LogId, LoggerBase, McpLogger } from "./logger.js"; |
| 4 | +import { ManagedTimeout, setManagedTimeout } from "./managedTimeout.js"; |
5 | 5 |
|
6 | 6 | export class SessionStore {
|
7 | 7 | private sessions: {
|
8 | 8 | [sessionId: string]: {
|
9 |
| - mcpServer: McpServer; |
| 9 | + logger: LoggerBase; |
10 | 10 | transport: StreamableHTTPServerTransport;
|
11 |
| - abortTimeout: TimeoutManager; |
12 |
| - notificationTimeout: TimeoutManager; |
| 11 | + abortTimeout: ManagedTimeout; |
| 12 | + notificationTimeout: ManagedTimeout; |
13 | 13 | };
|
14 | 14 | } = {};
|
15 | 15 |
|
@@ -39,54 +39,61 @@ export class SessionStore {
|
39 | 39 | return;
|
40 | 40 | }
|
41 | 41 |
|
42 |
| - session.abortTimeout.reset(); |
| 42 | + session.abortTimeout.restart(); |
43 | 43 |
|
44 |
| - session.notificationTimeout.reset(); |
| 44 | + session.notificationTimeout.restart(); |
45 | 45 | }
|
46 | 46 |
|
47 | 47 | private sendNotification(sessionId: string): void {
|
48 | 48 | const session = this.sessions[sessionId];
|
49 | 49 | if (!session) {
|
| 50 | + logger.warning( |
| 51 | + LogId.streamableHttpTransportSessionCloseNotificationFailure, |
| 52 | + "sessionStore", |
| 53 | + `session ${sessionId} not found, no notification delivered` |
| 54 | + ); |
50 | 55 | return;
|
51 | 56 | }
|
52 |
| - const logger = new McpLogger(session.mcpServer); |
53 |
| - logger.info( |
| 57 | + session.logger.info( |
54 | 58 | LogId.streamableHttpTransportSessionCloseNotification,
|
55 | 59 | "sessionStore",
|
56 | 60 | "Session is about to be closed due to inactivity"
|
57 | 61 | );
|
58 | 62 | }
|
59 | 63 |
|
60 | 64 | setSession(sessionId: string, transport: StreamableHTTPServerTransport, mcpServer: McpServer): void {
|
61 |
| - if (this.sessions[sessionId]) { |
| 65 | + const session = this.sessions[sessionId]; |
| 66 | + if (session) { |
62 | 67 | throw new Error(`Session ${sessionId} already exists`);
|
63 | 68 | }
|
64 |
| - const abortTimeout = new TimeoutManager(async () => { |
65 |
| - const logger = new McpLogger(mcpServer); |
66 |
| - logger.info( |
67 |
| - LogId.streamableHttpTransportSessionCloseNotification, |
68 |
| - "sessionStore", |
69 |
| - "Session closed due to inactivity" |
70 |
| - ); |
| 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 | + ); |
71 | 76 |
|
72 |
| - await this.closeSession(sessionId); |
| 77 | + await this.closeSession(sessionId); |
| 78 | + } |
73 | 79 | }, this.idleTimeoutMS);
|
74 |
| - const notificationTimeout = new TimeoutManager( |
| 80 | + const notificationTimeout = setManagedTimeout( |
75 | 81 | () => this.sendNotification(sessionId),
|
76 | 82 | this.notificationTimeoutMS
|
77 | 83 | );
|
78 |
| - this.sessions[sessionId] = { mcpServer, transport, abortTimeout, notificationTimeout }; |
| 84 | + this.sessions[sessionId] = { logger: new McpLogger(mcpServer), transport, abortTimeout, notificationTimeout }; |
79 | 85 | }
|
80 | 86 |
|
81 | 87 | async closeSession(sessionId: string, closeTransport: boolean = true): Promise<void> {
|
82 |
| - if (!this.sessions[sessionId]) { |
| 88 | + const session = this.sessions[sessionId]; |
| 89 | + if (!session) { |
83 | 90 | throw new Error(`Session ${sessionId} not found`);
|
84 | 91 | }
|
85 |
| - this.sessions[sessionId].abortTimeout.clear(); |
86 |
| - this.sessions[sessionId].notificationTimeout.clear(); |
| 92 | + session.abortTimeout.cancel(); |
| 93 | + session.notificationTimeout.cancel(); |
87 | 94 | if (closeTransport) {
|
88 | 95 | try {
|
89 |
| - await this.sessions[sessionId].transport.close(); |
| 96 | + await session.transport.close(); |
90 | 97 | } catch (error) {
|
91 | 98 | logger.error(
|
92 | 99 | LogId.streamableHttpTransportSessionCloseFailure,
|
|
0 commit comments