/** * The daemon's session table: one StreamableHTTPServerTransport + one WorkflowServer per * MCP session, keyed by the spec's Mcp-Session-Id. * * Liveness is connection presence, not recent traffic: a live client always holds an open * connection (the standalone GET stream, or an in-flight POST), and the kernel closes those * sockets when the client process dies. Idle eviction therefore only collects sessions with * zero open connections that also went quiet — dead clients that never sent the spec's * DELETE. Eviction closes the transport; runs are unaffected (they live in the per-project * manager), and a wrongly-evicted client re-initializes on the spec's 404. * * Connections and REQUESTS are tracked separately: the standalone GET stream is a connection * but not work, while an in-flight POST is both. A superseded (lame-duck) daemon uses the * distinction to migrate sessions that have nothing in flight — closing such a session costs * the client nothing but a transparent re-initialize on the successor — while never cutting a * request that is being processed. */ import type { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node"; import type { WorkflowServer } from "../server.js"; export interface SessionRecord { sessionId: string; transport: NodeStreamableHTTPServerTransport; server: WorkflowServer; lastActivityAt: number; openConnections: number; /** Requests (POSTs) currently being processed on this session. */ inflightRequests: number; } export declare class SessionRegistry { private readonly sessions; add(record: Omit & { inflightRequests?: number; }): void; get(sessionId: string): SessionRecord | undefined; delete(sessionId: string): void; touch(sessionId: string, now?: number): void; connectionOpened(sessionId: string): void; connectionClosed(sessionId: string): void; /** A request (POST) started being processed on the session. */ requestStarted(sessionId: string): void; /** The request's response finished (or its connection closed). */ requestFinished(sessionId: string): void; /** Requests being processed right now, across every session. */ inflightCount(): number; get size(): number; values(): SessionRecord[]; /** Close (and thereby unregister, via transport.onclose) every idle dead-client session. */ evictIdle(ttlMs: number, now?: number): string[]; /** * Close every session with NO request in flight — the lame-duck migration: the client's * next frame (or its standalone GET stream ending) makes it re-initialize on the successor. */ evictDrainable(): string[]; closeAll(): Promise; } //# sourceMappingURL=session-registry.d.ts.map