@todo-for-ai/mcp
Version:
Model Context Protocol server for Todo for AI task management system with Streamable HTTP transport. Provides AI assistants with access to task management, project information, and feedback submission capabilities through modern HTTP-based communication.
116 lines • 3.93 kB
JavaScript
/**
* Session management for HTTP transport
*/
import { randomUUID } from 'node:crypto';
import { logger } from '../logger.js';
export class HttpSessionManager {
sessions = new Map();
sessionTimeout;
cleanupInterval;
constructor(sessionTimeout = 300000) {
this.sessionTimeout = sessionTimeout;
this.startCleanupTimer();
}
createSession() {
const sessionId = randomUUID();
const now = new Date();
const sessionInfo = {
id: sessionId,
createdAt: now,
lastActivity: now,
isActive: true
};
this.sessions.set(sessionId, sessionInfo);
logger.debug('[SESSION_MANAGER] Session created', {
sessionId,
totalSessions: this.sessions.size,
createdAt: now.toISOString()
});
return sessionId;
}
getSession(sessionId) {
const session = this.sessions.get(sessionId);
if (!session) {
logger.debug('[SESSION_MANAGER] Session not found', { sessionId });
return null;
}
// Check if session is expired
const now = new Date();
const timeSinceLastActivity = now.getTime() - session.lastActivity.getTime();
if (timeSinceLastActivity > this.sessionTimeout) {
logger.debug('[SESSION_MANAGER] Session expired', {
sessionId,
timeSinceLastActivity,
sessionTimeout: this.sessionTimeout
});
this.removeSession(sessionId);
return null;
}
return session;
}
updateActivity(sessionId) {
const session = this.sessions.get(sessionId);
if (session) {
session.lastActivity = new Date();
logger.debug('[SESSION_MANAGER] Session activity updated', {
sessionId,
lastActivity: session.lastActivity.toISOString()
});
}
}
removeSession(sessionId) {
const session = this.sessions.get(sessionId);
if (session) {
session.isActive = false;
this.sessions.delete(sessionId);
logger.debug('[SESSION_MANAGER] Session removed', {
sessionId,
totalSessions: this.sessions.size
});
}
}
cleanupExpiredSessions() {
const now = new Date();
let cleanedCount = 0;
for (const [sessionId, session] of this.sessions.entries()) {
const timeSinceLastActivity = now.getTime() - session.lastActivity.getTime();
if (timeSinceLastActivity > this.sessionTimeout) {
this.removeSession(sessionId);
cleanedCount++;
}
}
if (cleanedCount > 0) {
logger.info('[SESSION_MANAGER] Cleaned up expired sessions', {
cleanedCount,
remainingSessions: this.sessions.size,
sessionTimeout: this.sessionTimeout
});
}
}
getActiveSessions() {
return Array.from(this.sessions.values()).filter(session => session.isActive);
}
startCleanupTimer() {
// Run cleanup every minute
this.cleanupInterval = setInterval(() => {
this.cleanupExpiredSessions();
}, 60000);
logger.debug('[SESSION_MANAGER] Cleanup timer started', {
intervalMs: 60000,
sessionTimeout: this.sessionTimeout
});
}
destroy() {
if (this.cleanupInterval) {
clearInterval(this.cleanupInterval);
this.cleanupInterval = undefined;
}
// Mark all sessions as inactive
for (const session of this.sessions.values()) {
session.isActive = false;
}
this.sessions.clear();
logger.info('[SESSION_MANAGER] Session manager destroyed');
}
}
//# sourceMappingURL=manager.js.map