/**
 * Simple MCP manager for Pi Agent version.
 * Manages connections to multiple MCP servers.
 */
import { createMcpClient } from './client-factory.js';
import { log } from '../utils/logger.js';
export class McpManager {
    servers = new Map();
    listeners = [];
    /**
     * Initialize manager with config
     */
    initialize(config) {
        const mcpServers = config.mcpServers || {};
        // Remove servers no longer in config
        for (const [name] of this.servers) {
            if (!(name in mcpServers)) {
                this.disconnectServer(name);
                this.servers.delete(name);
            }
        }
        // Add/update servers
        for (const [name, serverConfig] of Object.entries(mcpServers)) {
            const existing = this.servers.get(name);
            // Skip if unchanged and already connected
            if (existing &&
                JSON.stringify(existing.config) === JSON.stringify(serverConfig) &&
                existing.status === 'connected') {
                continue;
            }
            // Disconnect existing if config changed
            if (existing && existing.client) {
                existing.client.disconnect().catch(() => { });
            }
            // Create new state
            this.servers.set(name, {
                name,
                config: serverConfig,
                status: serverConfig.disabled ? 'disabled' : 'connecting',
                tools: [],
            });
            // Connect if not disabled
            if (!serverConfig.disabled) {
                this.connectServer(name).catch(error => {
                    log.error(`Failed to connect MCP server ${name}:`, error);
                });
            }
        }
        this.notifyListeners();
    }
    /**
     * Connect to a specific server
     */
    async connectServer(name) {
        const state = this.servers.get(name);
        if (!state) {
            throw new Error(`MCP server ${name} not found`);
        }
        if (state.status === 'disabled') {
            throw new Error(`MCP server ${name} is disabled`);
        }
        try {
            state.status = 'connecting';
            this.notifyListeners();
            const client = createMcpClient(name, state.config);
            await client.connect();
            const tools = await client.listTools();
            state.client = client;
            state.tools = tools;
            state.status = 'connected';
            state.error = undefined;
            log.info(`MCP server ${name} connected with ${tools.length} tools`);
            this.notifyListeners();
        }
        catch (error) {
            state.status = 'error';
            state.error = error instanceof Error ? error.message : String(error);
            log.error(`Failed to connect MCP server ${name}:`, error);
            this.notifyListeners();
            throw error;
        }
    }
    /**
     * Disconnect from a server
     */
    async disconnectServer(name) {
        const state = this.servers.get(name);
        if (!state || !state.client)
            return;
        try {
            await state.client.disconnect();
        }
        catch (error) {
            // Ignore disconnect errors
        }
        state.client = undefined;
        state.status = 'disconnected';
        this.notifyListeners();
    }
    /**
     * Call a tool on a server
     */
    async callTool(serverName, toolName, params) {
        const state = this.servers.get(serverName);
        if (!state || !state.client) {
            throw new Error(`MCP server ${serverName} not connected`);
        }
        if (!state.client.isConnected()) {
            throw new Error(`MCP server ${serverName} is not connected`);
        }
        try {
            return await state.client.callTool(toolName, params);
        }
        catch (error) {
            log.error(`MCP tool call failed ${serverName}.${toolName}:`, error);
            throw error;
        }
    }
    /**
     * Get all server states
     */
    getServerStates() {
        return Array.from(this.servers.values());
    }
    /**
     * Get tools from all connected servers
     */
    getAllTools() {
        const tools = [];
        for (const state of this.servers.values()) {
            if (state.status === 'connected' && state.tools.length > 0) {
                for (const tool of state.tools) {
                    tools.push({ server: state.name, tool });
                }
            }
        }
        return tools;
    }
    /**
     * Subscribe to server state changes
     */
    subscribe(listener) {
        this.listeners.push(listener);
        // Initial notification
        listener(this.getServerStates());
        return () => {
            const index = this.listeners.indexOf(listener);
            if (index !== -1) {
                this.listeners.splice(index, 1);
            }
        };
    }
    /**
     * Notify all listeners
     */
    notifyListeners() {
        const states = this.getServerStates();
        for (const listener of this.listeners) {
            try {
                listener(states);
            }
            catch (error) {
                log.error('MCP listener error:', error);
            }
        }
    }
}
// Singleton instance
let managerInstance = null;
export function getMcpManager() {
    if (!managerInstance) {
        managerInstance = new McpManager();
    }
    return managerInstance;
}
//# sourceMappingURL=manager.js.map