UNPKG

mcp-use

Version:

A utility library for integrating Model Context Protocol (MCP) with LangChain, Zod, and related tools. Provides helpers for schema conversion, event streaming, and SDK usage.

168 lines (167 loc) 5.87 kB
/** * Observability callbacks manager for MCP-use. * * This module provides a centralized manager for handling observability callbacks * from various platforms (Langfuse, Laminar, etc.) in a clean and extensible way. */ import { logger } from '../logging.js'; export class ObservabilityManager { customCallbacks; availableHandlers = []; handlerNames = []; initialized = false; verbose; constructor(config = {}) { this.customCallbacks = config.customCallbacks; this.verbose = config.verbose ?? false; } /** * Collect all available observability handlers from configured platforms. */ async collectAvailableHandlers() { if (this.initialized) { return; } // Import handlers lazily to avoid circular imports try { const { langfuseHandler, langfuseInitPromise } = await import('./langfuse.js'); // Wait for initialization to complete const initPromise = langfuseInitPromise(); if (initPromise) { await initPromise; } const handler = langfuseHandler(); if (handler) { this.availableHandlers.push(handler); this.handlerNames.push('Langfuse'); logger.debug('ObservabilityManager: Langfuse handler available'); } } catch { logger.debug('ObservabilityManager: Langfuse module not available'); } // Future: Add more platforms here... this.initialized = true; } /** * Get the list of callbacks to use. * @returns List of callbacks - either custom callbacks if provided, or all available observability handlers. */ async getCallbacks() { // If custom callbacks were provided, use those if (this.customCallbacks) { logger.debug(`ObservabilityManager: Using ${this.customCallbacks.length} custom callbacks`); return this.customCallbacks; } // Otherwise, collect and return all available handlers await this.collectAvailableHandlers(); if (this.availableHandlers.length > 0) { logger.debug(`ObservabilityManager: Using ${this.availableHandlers.length} handlers`); } else { logger.debug('ObservabilityManager: No callbacks configured'); } return this.availableHandlers; } /** * Get the names of available handlers. * @returns List of handler names (e.g., ["Langfuse", "Laminar"]) */ async getHandlerNames() { if (this.customCallbacks) { // For custom callbacks, try to get their class names return this.customCallbacks.map(cb => cb.constructor.name); } await this.collectAvailableHandlers(); return this.handlerNames; } /** * Check if any callbacks are available. * @returns True if callbacks are available, False otherwise. */ async hasCallbacks() { const callbacks = await this.getCallbacks(); return callbacks.length > 0; } /** * Add a callback to the custom callbacks list. * @param callback The callback to add. */ addCallback(callback) { if (!this.customCallbacks) { this.customCallbacks = []; } this.customCallbacks.push(callback); logger.debug(`ObservabilityManager: Added custom callback: ${callback.constructor.name}`); } /** * Clear all custom callbacks. */ clearCallbacks() { this.customCallbacks = []; logger.debug('ObservabilityManager: Cleared all custom callbacks'); } /** * Flush all pending traces to observability platforms. * Important for serverless environments and short-lived processes. */ async flush() { // Flush Langfuse traces const callbacks = await this.getCallbacks(); for (const callback of callbacks) { if ('flushAsync' in callback && typeof callback.flushAsync === 'function') { await callback.flushAsync(); } } logger.debug('ObservabilityManager: All traces flushed'); } /** * Shutdown all handlers gracefully (for serverless environments). */ async shutdown() { // Flush before shutdown await this.flush(); // Shutdown other callbacks const callbacks = await this.getCallbacks(); for (const callback of callbacks) { // Check if the callback has a shutdown method (like Langfuse) if ('shutdownAsync' in callback && typeof callback.shutdownAsync === 'function') { await callback.shutdownAsync(); } else if ('shutdown' in callback && typeof callback.shutdown === 'function') { await callback.shutdown(); } } logger.debug('ObservabilityManager: All handlers shutdown'); } /** * String representation of the ObservabilityManager. */ toString() { const names = this.handlerNames; if (names.length > 0) { return `ObservabilityManager(handlers=${names.join(', ')})`; } return 'ObservabilityManager(no handlers)'; } } // Singleton instance for easy access let defaultManager = null; /** * Get the default ObservabilityManager instance. * @returns The default ObservabilityManager instance (singleton). */ export function getDefaultManager() { if (!defaultManager) { defaultManager = new ObservabilityManager(); } return defaultManager; } /** * Create a new ObservabilityManager instance. * @param config Configuration options * @returns A new ObservabilityManager instance. */ export function createManager(config = {}) { return new ObservabilityManager(config); }