Skip to main content
Glama
generic-session-manager.ts4.67 kB
/** * Generic Session Manager * * Reusable file-based session management for MCP tools * Provides CRUD operations with persistent storage * * Usage: * const manager = new GenericSessionManager<MySessionData>('myprefix', args); * const session = manager.createSession({ myData: 'value' }); */ import * as fs from 'fs'; import * as path from 'path'; import { randomUUID } from 'crypto'; import { getAndValidateSessionDirectory } from './session-utils'; /** * Generic session structure * T is the type of data stored in the session */ export interface GenericSession<T = any> { sessionId: string; createdAt: string; updatedAt: string; data: T; } /** * Generic session manager with file-based storage */ export class GenericSessionManager<T = any> { private prefix: string; private sessionDir: string; private sessionsPath: string; /** * Create a new session manager * @param prefix - Prefix for session IDs and directory (e.g., 'proj', 'pattern', 'test') */ constructor(prefix: string) { this.prefix = prefix; this.sessionDir = getAndValidateSessionDirectory(true); this.sessionsPath = path.join(this.sessionDir, `${prefix}-sessions`); // Create sessions directory if it doesn't exist if (!fs.existsSync(this.sessionsPath)) { fs.mkdirSync(this.sessionsPath, { recursive: true }); } } /** * Create a new session * Pattern: {prefix}-{timestamp}-{uuid} */ createSession(initialData: T = {} as T): GenericSession<T> { const sessionId = `${this.prefix}-${Date.now()}-${randomUUID().substring(0, 8)}`; const now = new Date().toISOString(); const session: GenericSession<T> = { sessionId, createdAt: now, updatedAt: now, data: initialData, }; this.saveSession(session); return session; } /** * Get an existing session */ getSession(sessionId: string): GenericSession<T> | null { try { const sessionFile = path.join(this.sessionsPath, `${sessionId}.json`); if (!fs.existsSync(sessionFile)) { return null; } const sessionData = fs.readFileSync(sessionFile, 'utf8'); return JSON.parse(sessionData) as GenericSession<T>; } catch (error) { console.error(`Failed to load session ${sessionId}:`, error); return null; } } /** * Update session data (merges with existing data) */ updateSession(sessionId: string, newData: Partial<T>): GenericSession<T> | null { const session = this.getSession(sessionId); if (!session) { return null; } session.data = { ...session.data, ...newData }; session.updatedAt = new Date().toISOString(); this.saveSession(session); return session; } /** * Replace session data entirely */ replaceSession(sessionId: string, newData: T): GenericSession<T> | null { const session = this.getSession(sessionId); if (!session) { return null; } session.data = newData; session.updatedAt = new Date().toISOString(); this.saveSession(session); return session; } /** * Delete a session */ deleteSession(sessionId: string): boolean { try { const sessionFile = path.join(this.sessionsPath, `${sessionId}.json`); if (!fs.existsSync(sessionFile)) { return false; } fs.unlinkSync(sessionFile); return true; } catch (error) { console.error(`Failed to delete session ${sessionId}:`, error); return false; } } /** * List all sessions (returns session IDs) */ listSessions(): string[] { try { if (!fs.existsSync(this.sessionsPath)) { return []; } return fs .readdirSync(this.sessionsPath) .filter((file) => file.endsWith('.json')) .map((file) => file.replace('.json', '')); } catch (error) { console.error('Failed to list sessions:', error); return []; } } /** * Clear all sessions (useful for testing) */ clearAllSessions(): void { try { if (!fs.existsSync(this.sessionsPath)) { return; } const sessions = fs.readdirSync(this.sessionsPath); for (const file of sessions) { if (file.endsWith('.json')) { fs.unlinkSync(path.join(this.sessionsPath, file)); } } } catch (error) { console.error('Failed to clear sessions:', error); } } /** * Save session to file */ private saveSession(session: GenericSession<T>): void { const sessionFile = path.join(this.sessionsPath, `${session.sessionId}.json`); fs.writeFileSync(sessionFile, JSON.stringify(session, null, 2), 'utf8'); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vfarcic/dot-ai'

If you have feedback or need assistance with the MCP directory API, please join our Discord server