import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import type { Tool } from '../../../shared/models/tool.model.js'; import type { Resource } from '../../../shared/models/resource.model.js'; import type { ServerInstanceConfig } from '../../config/config.schema.js'; import type { ServerRuntimeConfig } from '../../../shared/models/server.model.js'; import type { ServerStatus } from './types.js'; /** * Manages MCP (Model Context Protocol) server connections and provides a unified interface * for tool and resource operations across multiple connected servers. * * This service handles the complete lifecycle of MCP server connections including: * - Establishing connections via various transport protocols (stdio, SSE, HTTP) * - Managing client instances and transport layers * - Caching tools and resources for performance optimization * - Providing both composite key-based and server name-based access patterns * - Handling connection events and error recovery * - Supporting bidirectional communication for tool execution * * The manager uses ToolCache for both composite key-level and server name-level * operations to optimize different access patterns while ensuring data consistency. * * @example * ```typescript * const manager = new McpConnectionManager(); * await manager.connect('my-server', 0, serverConfig); * const tools = await manager.getTools('my-server', 0); * const result = await manager.callTool('my-server', 0, 'tool-name', { param: 'value' }); * ``` */ export declare class McpConnectionManager { private clients; private transports; private serverStatus; private _toolCache; private resourceCache; private serverNameToCompositeKeys; constructor(); /** * Establishes a connection to an MCP server using the specified configuration. * * This method handles the complete connection process including transport creation, * client initialization, validation, and automatic tool/resource discovery. * It supports multiple transport protocols (stdio, SSE, streamable-http, http) * and provides comprehensive error handling with proper status tracking. * * For bidirectional transports (stdio, streamable-http, http), it automatically * fetches and caches available tools and resources upon successful connection. * SSE transports are unidirectional and skip this step for performance reasons. * * The method publishes SERVER_CONNECTED and SERVER_STATUS_CHANGE events upon * successful connection, and SERVER_STATUS_CHANGE events with error details * on failure. * * @param {string} serverName - Server name * @param {number} serverIndex - Instance index * @param {ServerRuntimeConfig & Partial} server - Server configuration containing * connection details, transport type, and instance-specific parameters * @returns {Promise} True if connection succeeds, false if it fails * @throws {Error} If server ID is missing or required configuration is invalid * * @example * ```typescript * const serverConfig = { * id: 'my-server-1', * type: 'stdio' as const, * command: 'npx my-mcp-server', * name: 'My MCP Server' * }; * const success = await manager.connect('My MCP Server', 0, serverConfig); * if (success) { * console.log('Connected successfully'); * } * ``` */ connect(serverName: string, serverIndex: number, server: ServerRuntimeConfig & Partial): Promise; /** * Connects to a streamable-http-local MCP server. * * This method handles the unique lifecycle of locally-launched HTTP servers: * the transport internally delegates process management to ProcessLauncher * (spawn → waitForReady → HTTP connect), and ConnectionManager treats it * as a distinct connection path from connect(). */ connectLocalHttp(serverName: string, serverIndex: number, server: ServerRuntimeConfig & Partial): Promise; /** * Gets retry configuration from system settings. */ private getRetryConfig; /** * Validates server configuration before connection. */ private validateServerConfig; /** * Logs connection attempt information. */ private logConnectionAttempt; /** * Initializes server status to starting state. */ private initializeServerStatus; /** * Gets server info by ID from hub manager. */ private getServerInfo; /** * Creates transport and sets up all callbacks. */ private initializeTransport; /** * Creates Client and connects to transport. */ private establishClientConnection; /** * Registers client, transport, and updates name mappings. */ private registerConnection; /** * Updates server status to connected state. */ private updateConnectedStatus; /** * Publishes connection events. */ private publishConnectionEvents; /** * Refreshes server tools and resources (only for bidirectional transports). * * @param skipResources - Skip resources/list request when server doesn't support resources capability */ private refreshServerResources; /** * Sends logging/setLevel request to downstream server to start receiving log notifications. * This is a best-effort request — servers that don't support logging will silently ignore it. */ private requestLoggingFromServer; /** * Handles the OAuth authorization flow for Streamable HTTP servers. * Starts a local callback server, waits for the user to complete auth in the browser, * then finishes the auth on the transport. * * @returns true if OAuth was handled successfully, false otherwise */ private handleOAuthFlow; /** * Handles connection error with logging and retry delay. */ private handleConnectionError; /** * Handles final failure after all retries exhausted. */ private handleFinalFailure; /** * Disconnects from an MCP server and cleans up all associated resources. * * This method performs a graceful shutdown by closing the client connection, * closing the transport layer, and removing all cached data including tools, * resources, and status information. It also updates the server name-level * tool cache to maintain consistency across multiple instances of the same server. * * The method publishes SERVER_DISCONNECTED and SERVER_STATUS_CHANGE events * upon completion and handles any errors during the disconnection process * without throwing exceptions. * * @param {string} serverName - Server name * @param {number} serverIndex - Instance index * @returns {Promise} Resolves when disconnection is complete * * @example * ```typescript * await manager.disconnect('my-server', 0); * console.log('Server disconnected'); * ``` */ disconnect(serverName: string, serverIndex: number): Promise; /** * Disconnects from all currently connected MCP servers concurrently. * * This method iterates through all active client connections and calls * disconnect() on each one, handling errors individually to ensure * that failure to disconnect from one server doesn't prevent disconnection * from others. All disconnections are performed in parallel for efficiency. * * @returns {Promise} Resolves when all disconnection attempts complete * * @example * ```typescript * await manager.disconnectAll(); * console.log('All servers disconnected'); * ``` */ disconnectAll(): Promise; /** * Refreshes the tool cache for a specific server by fetching the latest tool list. * * This method queries the connected MCP server for its current set of available tools, * updates both the composite key-level and server name-level caches, and maintains * accurate tool counts in the server status. It handles server name resolution * to ensure proper caching across multiple instances of the same server. * * @param {string} serverName - Server name * @param {number} serverIndex - Instance index * @returns {Promise} Array of updated tools with server context * @throws {Error} If the server is not connected or tool listing fails * * @example * ```typescript * const tools = await manager.refreshTools('my-server', 0); * console.log(`Found ${tools.length} tools`); * ``` */ refreshTools(serverName: string, serverIndex: number): Promise; /** * Refreshes the resource cache for a specific server by fetching available resources. * * This method queries the connected MCP server for its current set of available resources, * handling servers that don't support the resources functionality gracefully by returning * an empty array. It updates the resource cache and maintains accurate resource counts * in the server status. * * The method specifically handles "Method not found" errors (MCP error code -32601) * which indicate that the server doesn't implement the resources protocol, treating * this as a normal case rather than an error. * * @param {string} serverName - Server name * @param {number} serverIndex - Instance index * @returns {Promise} Array of available resources, empty if unsupported * @throws {Error} If the server is not connected or resource listing fails unexpectedly * * @example * ```typescript * const resources = await manager.refreshResources('my-server', 0); * console.log(`Found ${resources.length} resources`); * ``` */ refreshResources(serverName: string, serverIndex: number): Promise; /** * Retrieves the current connection status for a specific server instance. * * This method provides access to the server's operational state including connection * status, error information, tool/resource counts, and process details. * * @param {string} serverName - Server name * @param {number} serverIndex - Instance index * @returns {ServerStatus | undefined} Current status object or undefined if not found * * @example * ```typescript * const status = manager.getStatus('my-server', 0); * if (status?.connected) { * console.log('Server is connected'); * } * ``` */ getStatus(serverName: string, serverIndex: number): ServerStatus | undefined; /** * Retrieves cached tools for a specific server instance. * * This method returns the currently cached tool list for the specified server, * which may be empty if tools haven't been refreshed yet or if the server * doesn't provide any tools. The method includes logging for debugging purposes. * * @param {string} serverName - Server name * @param {number} serverIndex - Instance index * @returns {Tool[]} Array of cached tools, empty if none available * * @example * ```typescript * const tools = manager.getTools('my-server', 0); * console.log(`Server has ${tools.length} tools`); * ``` */ getTools(serverName: string, serverIndex: number): Tool[]; /** * Retrieves cached resources for a specific server instance. * * This method returns the currently cached resource list for the specified server, * which may be empty if resources haven't been refreshed yet, if the server doesn't * support resources, or if the server doesn't provide any resources. The method * includes logging for debugging purposes. * * @param {string} serverName - Server name * @param {number} serverIndex - Instance index * @returns {Resource[]} Array of cached resources, empty if none available * * @example * ```typescript * const resources = manager.getResources('my-server', 0); * console.log(`Server has ${resources.length} resources`); * ``` */ getResources(serverName: string, serverIndex: number): Resource[]; /** * Reads content from a specific resource URI on a connected MCP server. * * This method delegates the resource reading operation to the underlying MCP client, * providing direct access to server-provided resources through their URIs. * * @param {string} serverName - Server name * @param {number} serverIndex - Instance index * @param {string} uri - Resource URI to read (e.g., "file:///path/to/file") * @returns {Promise} Resource content as returned by the server * @throws {Error} If the server is not connected or resource reading fails * * @example * ```typescript * const content = await manager.readResource('my-server', 0, 'hub://config/settings.json'); * console.log('Resource content:', content); * ``` */ readResource(serverName: string, serverIndex: number, uri: string): Promise; /** * Retrieves all cached tools from all connected server instances. * * This method aggregates tools from all composite key-level caches into a single array, * providing a unified view of all available tools across all connected servers. * The returned tools include server context information for proper identification. * * @returns {Tool[]} Array of all cached tools from all connected servers * * @example * ```typescript * const allTools = manager.getAllTools(); * console.log(`Total tools available: ${allTools.length}`); * ``` */ getAllTools(): Tool[]; /** * Retrieves all tool cache entries as composite key to tools mapping. * * This method returns the raw tool cache structure as an array of [compositeKey, tools] tuples, * providing direct access to the internal caching mechanism for debugging or advanced use cases. * * @returns {[string, Tool[]][]} Array of [compositeKey, tools] tuples representing the cache * * @example * ```typescript * const cacheEntries = manager.getToolCacheEntries(); * cacheEntries.forEach(([compositeKey, tools]) => { * console.log(`Server ${compositeKey} has ${tools.length} tools`); * }); * ``` */ getToolCacheEntries(): [string, Tool[]][]; /** * Resolves a server name to its corresponding composite key for a specific instance index. * * This method provides lookup from server names (as defined in configuration) * to composite keys used internally for connection management. * * @param {string} name - Server name as defined in the configuration * @param {number} index - Instance index * @returns {string | undefined} Corresponding composite key or undefined if not found * * @example * ```typescript * const compositeKey = manager.getCompositeKeyByName('my-mcp-server', 0); * if (compositeKey) { * const status = manager.getStatus(compositeKey); * } * ``` */ getCompositeKeyByName(name: string, index: number): string | undefined; /** * Retrieves the MCP client instance for a server by its name and index. * * This method resolves a composite key and returns the corresponding * MCP client instance, providing direct access to the underlying SDK client for * advanced operations that aren't covered by the manager's high-level methods. * * @param {string} name - Server name as defined in the configuration * @param {number} index - Instance index * @returns {Client | undefined} MCP client instance or undefined if not connected * * @example * ```typescript * const client = manager.getClient('my-mcp-server', 0); * if (client) { * // Use direct client methods for advanced operations * const result = await client.listPrompts(); * } * ``` */ getClient(name: string, index: number): Client | undefined; /** * Calls a tool on a connected server using the server name and index. * * The method is wrapped in OpenTelemetry tracing for observability and includes * comprehensive error handling with proper logging. * * @param {string} serverName - Server name * @param {number} serverIndex - Instance index * @param {string} toolName - Name of the tool to execute * @param {Record} args - Arguments to pass to the tool * @returns {Promise} Tool execution result as returned by the server * @throws {Error} If server is not connected or tool execution fails * * @example * ```typescript * const result = await manager.callTool('my-server', 0, 'list-files', { * directory: '/home/user' * }); * console.log('Tool result:', result); * ``` */ callTool(serverName: string, serverIndex: number, toolName: string, args: Record): Promise; /** * Retrieves cached tools for a server using its name instead of instance ID. * * This method resolves a server name to its composite key and returns the corresponding * cached tool list, providing a convenient way to access tools when working with * server names rather than instance IDs. * * @param {string} name - Server name as defined in the configuration * @returns {Tool[]} Array of cached tools, empty if none available or not connected * * @example * ```typescript * const tools = manager.getToolsByName('my-mcp-server'); * console.log(`Server has ${tools.length} tools`); * ``` */ getToolsByName(name: string): Tool[]; /** * Retrieves cached resources for a server using its name instead of instance ID. * * This method resolves a server name to its composite key and returns the corresponding * cached resource list, providing a convenient way to access resources when working with * server names rather than instance IDs. * * @param {string} name - Server name as defined in the configuration * @returns {Resource[]} Array of cached resources, empty if none available or not connected * * @example * ```typescript * const resources = manager.getResourcesByName('my-mcp-server'); * console.log(`Server has ${resources.length} resources`); * ``` */ getResourcesByName(name: string): Resource[]; /** * Retrieves a specific tool by name from a server's cached tools. * * This method searches the server name-level tool cache for a tool with the specified name, * providing efficient lookup without needing to iterate through all tools manually. * * @param {string} serverName - Server name as defined in the configuration * @param {string} toolName - Exact name of the tool to find * @returns {Tool | undefined} Tool object if found, undefined otherwise * * @example * ```typescript * const tool = manager.getTool('my-mcp-server', 'list-files'); * if (tool) { * console.log('Tool description:', tool.description); * } * ``` */ getTool(serverName: string, toolName: string): Tool | undefined; /** * Retrieves all cached resources grouped by server name. * * This method aggregates resources from all server instances and groups them by their * corresponding server names, providing a structured view of all available resources * across the system organized by server origin. * * @returns {Record} Object mapping server names to resource arrays * * @example * ```typescript * const allResources = manager.getAllResources(); * Object.entries(allResources).forEach(([serverName, resources]) => { * console.log(`Server ${serverName} has ${resources.length} resources`); * }); * ``` */ getAllResources(): Record; /** * Retrieves cached tools for a specific server name from the server name-level cache. * * This method provides access to the server name-level tool cache, which aggregates * tools from all instances of the same server name. It's optimized for scenarios * where you need to work with server names rather than individual instance IDs. * * @param {string} serverName - Server name as defined in the configuration * @returns {Tool[]} Array of cached tools for the specified server name * * @example * ```typescript * const tools = manager.getToolsByServerName('my-mcp-server'); * console.log(`Server has ${tools.length} tools across all instances`); * ``` */ getToolsByServerName(serverName: string): Tool[]; /** * Gets the status of the first connected instance for a server name. * This is a backward compatibility method for code that expects getStatusByName. * * @param name - Server name * @returns ServerStatus or undefined if not connected */ getStatusByName(name: string): ServerStatus | undefined; /** * Gets all connected instance indexes for a server. * @param serverName - Server name * @returns Array of connected instance indexes, empty if none connected */ getConnectedIndexes(serverName: string): number[]; /** * Gets the composite key of the first connected instance for a server name. * This is a backward compatibility method for code that expects getServerIdByName. * * @param name - Server name * @returns Composite key or undefined if no instance is connected */ getServerIdByName(name: string): string | undefined; /** * Retrieves all cached tools from all servers using the server name-level cache. * * This method aggregates tools from the server name-level cache, providing a unified * view of all available tools optimized for search operations and scenarios where * server name context is more relevant than individual instance IDs. * * @returns {Tool[]} Array of all cached tools from all servers * * @example * ```typescript * const allTools = manager.getAllToolsByServerName(); * console.log(`Total tools available: ${allTools.length}`); * ``` */ getAllToolsByServerName(): Tool[]; /** * Backward compatibility: direct access to the underlying toolCache Map. * This is maintained for backward compatibility with code that accesses * mcpConnectionManager.toolCache directly. * * @deprecated Use the dedicated methods like getTools(), setTools(), etc. instead */ get toolCache(): Map; } export declare const mcpConnectionManager: McpConnectionManager; //# sourceMappingURL=connection-manager.d.ts.map