@mrtkrcm/acp-claude-code
Version:
ACP (Agent Client Protocol) bridge for Claude Code
138 lines • 5.74 kB
JavaScript
import { createLogger } from './logger.js';
export class McpConnectionManager {
connections = new Map();
connectionStats = new Map();
connectionConfigs = new Map();
healthCheckInterval;
logger;
constructor() {
this.logger = createLogger('MCP-Manager');
this.startHealthChecking();
}
/**
* Register an MCP server configuration for connection pooling
*/
async registerServer(config) {
this.connectionConfigs.set(config.name, config);
this.connectionStats.set(config.name, {
totalCalls: 0,
failedCalls: 0,
avgResponseTime: 0,
lastUsed: 0,
isHealthy: true,
});
// Initialize connection pool
const poolSize = config.maxConnections || 3;
const connections = [];
for (let i = 0; i < poolSize; i++) {
try {
// Note: This would need to be implemented based on actual MCP SDK interfaces
// const connection = await this.createConnection(config);
// connections.push(connection);
}
catch (error) {
this.logger.warn(`Failed to create MCP connection for ${config.name}: ${error}`);
}
}
this.connections.set(config.name, connections);
this.logger.info(`Registered MCP server: ${config.name} with ${connections.length} connections`);
}
/**
* Execute MCP tool with connection pooling and retry logic
*/
async executeToolWithPooling(serverName, toolName, args, options = {}) {
const connections = this.connections.get(serverName);
const stats = this.connectionStats.get(serverName);
if (!connections || connections.length === 0) {
throw new Error(`No available connections for MCP server: ${serverName}`);
}
const startTime = Date.now();
const { timeout = 30000, retries = 2 } = options;
let lastError = null;
for (let attempt = 0; attempt <= retries; attempt++) {
// Round-robin connection selection
const connectionIndex = stats.totalCalls % connections.length;
const connection = connections[connectionIndex];
try {
stats.totalCalls++;
stats.lastUsed = Date.now();
// Execute with timeout
const result = await Promise.race([
this.executeWithConnection(connection, toolName, args),
new Promise((_, reject) => setTimeout(() => reject(new Error('Tool execution timeout')), timeout))
]);
// Update performance stats
const duration = Date.now() - startTime;
stats.avgResponseTime = (stats.avgResponseTime + duration) / 2;
return result;
}
catch (error) {
lastError = error;
stats.failedCalls++;
if (attempt === retries) {
this.logger.error(`MCP tool execution failed after ${retries + 1} attempts: ${lastError.message}`);
}
else {
this.logger.warn(`MCP tool attempt ${attempt + 1} failed, retrying: ${lastError.message}`);
await new Promise(resolve => setTimeout(resolve, 1000 * (attempt + 1)));
}
}
}
throw lastError || new Error('Tool execution failed');
}
async executeWithConnection(connection, toolName, args) {
// This would need to be implemented based on actual MCP SDK interfaces
// return await connection.callTool({ name: toolName, arguments: args });
throw new Error('Not implemented - requires actual MCP SDK integration');
}
/**
* Get connection statistics for monitoring
*/
getStats() {
return Object.fromEntries(this.connectionStats.entries());
}
/**
* Health check all connections
*/
startHealthChecking() {
this.healthCheckInterval = setInterval(async () => {
for (const [serverName, connections] of this.connections.entries()) {
const stats = this.connectionStats.get(serverName);
if (!stats)
continue;
let healthyConnections = 0;
for (const connection of connections) {
try {
// Implement health check based on actual MCP SDK
// const isHealthy = await this.checkConnectionHealth(connection);
const isHealthy = true; // Placeholder
if (isHealthy)
healthyConnections++;
}
catch (error) {
this.logger.warn(`Health check failed for ${serverName}: ${error}`);
}
}
stats.isHealthy = healthyConnections > 0;
if (!stats.isHealthy) {
this.logger.error(`MCP server ${serverName} is unhealthy`);
}
}
}, 30000); // Check every 30 seconds
}
destroy() {
if (this.healthCheckInterval) {
clearInterval(this.healthCheckInterval);
}
for (const connections of this.connections.values()) {
for (const connection of connections) {
// Close connections
// await connection.close();
}
}
this.connections.clear();
this.connectionStats.clear();
}
}
export const globalMcpManager = new McpConnectionManager();
//# sourceMappingURL=mcp-connection-manager.js.map