@houmak/minerva-mcp-server
Version:
Minerva Model Context Protocol (MCP) Server for Microsoft 365 and Azure integrations
225 lines (224 loc) • 8.38 kB
JavaScript
import { logger } from '../logger.js';
export class ConnectorFramework {
connectors = new Map();
configs = new Map();
executionHistory = [];
/**
* Enregistrer un connecteur
*/
async registerConnector(connector) {
logger.info('Registering connector', { name: connector.name, version: connector.version });
try {
// Valider le connecteur
const validation = await this.validateConnector(connector);
if (!validation.isValid) {
throw new Error(`Connector validation failed: ${validation.errors.join(', ')}`);
}
this.connectors.set(connector.name, connector);
logger.info('Connector registered successfully', { name: connector.name });
}
catch (error) {
logger.error('Failed to register connector', { name: connector.name, error: error instanceof Error ? error.message : String(error) });
throw error;
}
}
/**
* Exécuter un connecteur
*/
async executeConnector(name, params) {
logger.info('Executing connector', { name, params });
const startTime = Date.now();
try {
const connector = this.connectors.get(name);
if (!connector) {
throw new Error(`Connector '${name}' not found`);
}
// Valider les paramètres
if (!connector.validate(params)) {
throw new Error(`Invalid parameters for connector '${name}'`);
}
// Exécuter le connecteur
const data = await connector.execute(params);
const result = {
success: true,
data,
executionTime: Date.now() - startTime,
timestamp: new Date()
};
this.executionHistory.push(result);
logger.info('Connector executed successfully', { name, executionTime: result.executionTime });
return result;
}
catch (error) {
const result = {
success: false,
error: error instanceof Error ? error.message : String(error),
executionTime: Date.now() - startTime,
timestamp: new Date()
};
this.executionHistory.push(result);
logger.error('Connector execution failed', { name, error: error instanceof Error ? error.message : String(error) });
return result;
}
}
/**
* Lister tous les connecteurs
*/
async listConnectors() {
logger.info('Listing connectors');
const connectors = [];
for (const [name, connector] of this.connectors) {
connectors.push({
name,
version: connector.version,
description: connector.description,
enabled: true,
capabilities: connector.getCapabilities(),
lastUsed: this.getLastUsage(name)
});
}
logger.info('Connectors listed successfully', { count: connectors.length });
return connectors;
}
/**
* Valider un connecteur
*/
async validateConnector(connector) {
logger.info('Validating connector', { name: connector.name });
const errors = [];
const warnings = [];
// Vérifications de base
if (!connector.name || connector.name.trim() === '') {
errors.push('Connector name is required');
}
if (!connector.version || connector.version.trim() === '') {
errors.push('Connector version is required');
}
if (typeof connector.execute !== 'function') {
errors.push('Connector must have an execute method');
}
if (typeof connector.validate !== 'function') {
errors.push('Connector must have a validate method');
}
if (typeof connector.getCapabilities !== 'function') {
errors.push('Connector must have a getCapabilities method');
}
// Vérifier si le nom est unique
if (this.connectors.has(connector.name)) {
warnings.push(`Connector with name '${connector.name}' already exists and will be replaced`);
}
const result = {
isValid: errors.length === 0,
errors,
warnings
};
logger.info('Connector validation completed', { name: connector.name, isValid: result.isValid });
return result;
}
/**
* Configurer un connecteur
*/
async configureConnector(config) {
logger.info('Configuring connector', { name: config.name, type: config.type });
try {
this.configs.set(config.name, config);
logger.info('Connector configured successfully', { name: config.name });
}
catch (error) {
logger.error('Failed to configure connector', { name: config.name, error: error instanceof Error ? error.message : String(error) });
throw error;
}
}
/**
* Obtenir la configuration d'un connecteur
*/
async getConnectorConfig(name) {
return this.configs.get(name) || null;
}
/**
* Activer/désactiver un connecteur
*/
async setConnectorEnabled(name, enabled) {
logger.info('Setting connector enabled state', { name, enabled });
const config = this.configs.get(name);
if (config) {
config.enabled = enabled;
this.configs.set(name, config);
logger.info('Connector enabled state updated', { name, enabled });
}
else {
throw new Error(`Connector configuration not found: ${name}`);
}
}
/**
* Obtenir l'historique d'exécution
*/
async getExecutionHistory(limit = 50) {
return this.executionHistory.slice(-limit);
}
/**
* Obtenir les statistiques d'utilisation
*/
async getUsageStats() {
const stats = {
totalConnectors: this.connectors.size,
totalExecutions: this.executionHistory.length,
successfulExecutions: this.executionHistory.filter(r => r.success).length,
failedExecutions: this.executionHistory.filter(r => !r.success).length,
averageExecutionTime: this.calculateAverageExecutionTime(),
mostUsedConnectors: this.getMostUsedConnectors()
};
return stats;
}
/**
* Nettoyer l'historique d'exécution
*/
async clearExecutionHistory() {
logger.info('Clearing execution history');
this.executionHistory = [];
logger.info('Execution history cleared');
}
/**
* Obtenir les connecteurs par capacité
*/
async getConnectorsByCapability(capability) {
const connectors = await this.listConnectors();
return connectors.filter(c => c.capabilities.includes(capability));
}
/**
* Vérifier la disponibilité d'un connecteur
*/
async isConnectorAvailable(name) {
const connector = this.connectors.get(name);
const config = this.configs.get(name);
return connector !== undefined && config?.enabled === true;
}
/**
* Méthodes privées utilitaires
*/
getLastUsage(connectorName) {
const executions = this.executionHistory.filter(r => r.data?.connectorName === connectorName || r.data?.name === connectorName);
if (executions.length > 0) {
return executions[executions.length - 1].timestamp;
}
return undefined;
}
calculateAverageExecutionTime() {
if (this.executionHistory.length === 0) {
return 0;
}
const totalTime = this.executionHistory.reduce((sum, result) => sum + result.executionTime, 0);
return totalTime / this.executionHistory.length;
}
getMostUsedConnectors() {
const usageCount = {};
this.executionHistory.forEach(result => {
const connectorName = result.data?.connectorName || result.data?.name || 'unknown';
usageCount[connectorName] = (usageCount[connectorName] || 0) + 1;
});
return Object.entries(usageCount)
.map(([name, count]) => ({ name, count }))
.sort((a, b) => b.count - a.count)
.slice(0, 5);
}
}