UNPKG

bc-webclient-mcp

Version:

Model Context Protocol (MCP) server for Microsoft Dynamics 365 Business Central via WebUI protocol. Enables AI assistants to interact with BC through the web client protocol, supporting Card, List, and Document pages with full line item support and server

172 lines 5.39 kB
/** * Connection Manager - Session Pooling for BC MCP Tools * * Manages BC WebSocket sessions across multiple tool invocations. * Enables multi-step workflows (read → edit → write → save) by maintaining * session state between tool calls. * * Key Features: * - Single session per environment (baseUrl + tenant + user) * - Form registry tracks open pages per session * - TTL-based auto-cleanup (15 min idle timeout) * - Thread-safe session access * * Based on GPT-5 Pro analysis in WRITE_TOOLS_ANALYSIS.md */ import type { BCPageConnection } from './bc-page-connection.js'; import type { Result } from '../core/result.js'; import type { BCError } from '../core/errors.js'; /** * Information about an open BC form within a session. */ export interface FormInfo { readonly formId: string; readonly pageId: string; readonly caption: string; readonly listControlPath?: string; readonly quickFilterPath?: string; readonly openedAt: Date; } /** * Configuration for creating a BC session. */ export interface SessionConfig { readonly baseUrl: string; readonly username: string; readonly password: string; readonly tenantId: string; } /** * Result of getting or creating a session. */ export interface SessionResult { readonly sessionId: string; readonly connection: BCPageConnection; readonly isNewSession: boolean; } /** * Singleton manager for BC WebSocket session pooling. * * Maintains a pool of BC sessions keyed by environment (baseUrl + tenant + user). * Each session tracks open forms and their metadata. * * Usage: * ```typescript * const manager = ConnectionManager.getInstance(); * const { sessionId, connection } = await manager.getOrCreateSession(config); * * // Later, in another tool: * const connection = manager.getSession(sessionId); * ``` */ export declare class ConnectionManager { private static instance; private readonly sessions; private readonly SESSION_TTL; private readonly cleanupTimers; /** * Private constructor - use getInstance() instead. */ private constructor(); /** * Get the singleton instance of ConnectionManager. */ static getInstance(): ConnectionManager; /** * Get or create a BC session for the given environment. * * If a session already exists for this environment and is not expired, * it will be reused. Otherwise, a new session is created. * * @param config - Session configuration (baseUrl, username, password, tenantId) * @returns SessionResult with sessionId and connection */ getOrCreateSession(config: SessionConfig): Promise<Result<SessionResult, BCError>>; /** * Get an existing session by sessionId. * * @param sessionId - Session ID to retrieve * @returns BCPageConnection if found and not expired, null otherwise */ getSession(sessionId: string): BCPageConnection | null; /** * Find session ID by connection instance. * * Used by global dialog listening in BCPageConnection to track dialogs * against the correct session. * * @param connection - Connection instance to find (accepts any IBCConnection) * @returns Session ID if found, null otherwise */ getSessionIdByConnection(connection: unknown): string | null; /** * Register an open form in the session's form registry. * * This allows tools to check if a page is already open before * attempting to open it again. * * @param sessionId - Session ID * @param pageId - BC Page ID * @param formInfo - Form information (formId, caption, etc.) */ registerForm(sessionId: string, pageId: string, formInfo: Omit<FormInfo, 'openedAt'>): void; /** * Get form info from session's form registry. * * @param sessionId - Session ID * @param pageId - BC Page ID * @returns FormInfo if page is open in this session, null otherwise */ getForm(sessionId: string, pageId: string): FormInfo | null; /** * Check if a page is already open in a session. * * @param sessionId - Session ID * @param pageId - BC Page ID * @returns true if page is open, false otherwise */ isPageOpen(sessionId: string, pageId: string): boolean; /** * Close a specific session by sessionId. * * @param sessionId - Session ID to close */ closeSessionById(sessionId: string): Promise<void>; /** * Close all sessions (for shutdown). */ closeAllSessions(): Promise<void>; /** * Get statistics about current sessions. */ getStats(): { totalSessions: number; sessions: Array<{ sessionId: string; environment: string; openForms: number; ageMinutes: number; }>; }; /** * Generate environment key for session lookup. */ private getEnvironmentKey; /** * Check if a session has expired based on TTL. */ private isExpired; /** * Schedule automatic cleanup for a session after TTL expires. */ private scheduleCleanup; /** * Close session by environment key. */ private closeSessionByEnvKey; /** * Generate a unique session ID. */ private generateSessionId; } //# sourceMappingURL=connection-manager.d.ts.map