UNPKG

agile-planner-mcp-server

Version:

Serveur MCP pour la génération d'artefacts agiles (backlogs, features, user stories) avec IA - compatible Windsurf, Claude et Cursor

173 lines (152 loc) 5.8 kB
/** * Express server pour Agile Planner MCP Server * Permet d'exposer les fonctionnalités via une API REST */ const express = require('express'); const path = require('path'); // Import du routeur MCP qui contient la logique métier const mcpRouter = require('./lib/mcp-router'); // Gestion robuste des dépendances optionnelles let swaggerUi, YAML; /** * Charge une dépendance de façon sécurisée * @param {string} moduleName - Nom du module à charger * @returns {Object|null} - Module chargé ou null si erreur */ function safeRequire(moduleName) { try { return require(moduleName); } catch (error) { console.warn(`Module ${moduleName} non disponible: ${error.message}`); return null; } } // Charger les dépendances optionnelles swaggerUi = safeRequire('swagger-ui-express'); YAML = safeRequire('yamljs'); // Afficher un message selon la disponibilité if (swaggerUi && YAML) { console.log('Documentation Swagger UI disponible. Accès sur /api-docs.'); } else { console.warn('Swagger UI ou YAMLJS non disponibles. La documentation API ne sera pas exposée.'); console.warn('Pour activer la documentation, exécutez: npm install swagger-ui-express yamljs --save'); } const app = express(); // Charger et exposer la documentation OpenAPI si les dépendances sont disponibles if (swaggerUi && YAML) { try { const openapiDocument = YAML.load(path.join(__dirname, '../openapi/openapi.yaml')); app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(openapiDocument)); console.log('Documentation OpenAPI chargée avec succès.'); } catch (error) { console.error('Erreur lors du chargement de la documentation OpenAPI:', error.message); // Ajouter une route informative en cas d'erreur de chargement app.get('/api-docs', (req, res) => { res.status(500).send('Documentation OpenAPI non disponible. Vérifiez le fichier openapi.yaml.'); }); } } // Middleware pour le parsing JSON des requêtes app.use(express.json()); // Endpoint MCP pour générer un backlog app.post('/mcp/generateBacklog', express.json(), async (req, res) => { try { console.log('Reçu une demande de génération de backlog:', req.body); // Adapter les paramètres HTTP pour le format attendu par le handler MCP const args = { projectName: req.body.projectName, projectDescription: req.body.projectDescription, outputPath: req.body.outputPath || '.agile-planner-backlog' }; // Appeler la logique réelle de génération en réutilisant le handler MCP const result = await mcpRouter.handleToolsCall({ params: { name: 'generateBacklog', arguments: args } }); // Vérifier si une erreur est présente dans la réponse (format JSON-RPC) if (result.error) { return res.status(400).json({ status: 'error', message: result.error.message, details: result.error.data }); } // Renvoyer le résultat au format REST approprié res.json({ status: 'success', backlog: result.result, outputPath: args.outputPath }); } catch (error) { console.error('Erreur lors de la génération du backlog:', error); res.status(500).json({ status: 'error', message: error.message, stack: process.env.NODE_ENV === 'development' ? error.stack : undefined }); } }); app.post('/mcp/generateFeature', express.json(), async (req, res) => { try { console.log('Reçu une demande de génération de fonctionnalité:', req.body); // Adapter les paramètres HTTP pour le format attendu par le handler MCP const args = { featureDescription: req.body.featureDescription, businessValue: req.body.businessValue, complexityLevel: req.body.complexityLevel, epicId: req.body.epicId, backlogDir: req.body.backlogDir || '.agile-planner-backlog', outputPath: req.body.outputPath || '.agile-planner-backlog' }; // Appeler la logique réelle de génération en réutilisant le handler MCP const result = await mcpRouter.handleToolsCall({ params: { name: 'generateFeature', arguments: args } }); // Vérifier si une erreur est présente dans la réponse (format JSON-RPC) if (result.error) { return res.status(400).json({ status: 'error', message: result.error.message, details: result.error.data }); } // Renvoyer le résultat au format REST approprié res.json({ status: 'success', feature: result.result, outputPath: args.outputPath }); } catch (error) { console.error('Erreur lors de la génération de la fonctionnalité:', error); res.status(500).json({ status: 'error', message: error.message, stack: process.env.NODE_ENV === 'development' ? error.stack : undefined }); } }); // Ajouter un middleware pour gérer les erreurs app.use((err, req, res, _next) => { console.error('Erreur non gérée:', err); res.status(500).json({ status: 'error', message: 'Une erreur interne est survenue', details: process.env.NODE_ENV === 'development' ? err.message : undefined, stack: process.env.NODE_ENV === 'development' ? err.stack : undefined }); }); // Démarrer le serveur const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`API MCP Server running on http://localhost:${PORT}`); console.log(`Swagger UI: http://localhost:${PORT}/api-docs`); console.log(`Endpoints disponibles: - POST /mcp/generateBacklog - POST /mcp/generateFeature `); });