Skip to main content
Glama
index.ts6.8 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; // Import configuration and utilities import { config } from './config/index.js'; import { logger } from './utils/logger.js'; import { setupGlobalErrorHandlers } from './utils/errors.js'; import { resourceManager } from './utils/resource-manager.js'; // Import all available tools import { fileSystemTools } from './tools/filesystem.js'; import { databaseTools } from './tools/database.js'; import { webDevTools } from './tools/webdev.js'; import { backendTools } from './tools/backend.js'; import { apiTools } from './tools/api.js'; import { aiTools } from './tools/ai.js'; import { cacheTools } from './tools/cache.js'; import { containerTools } from './tools/containers.js'; import { deploymentTools } from './tools/deployment.js'; import { gitTools } from './tools/git.js'; import { messageQueueTools } from './tools/messagequeue.js'; import { monitoringTools } from './tools/monitoring.js'; import { securityTools } from './tools/security.js'; import { testingTools } from './tools/testing.js'; // Setup global error handlers setupGlobalErrorHandlers(); class SoftwareEngineerMCPServer { private server: Server; private allTools: Map<string, any>; constructor() { this.server = new Server( { name: 'software-engineer-mcp', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // Combine all tool collections this.allTools = new Map(); // Add all tool collections const toolCollections = [ fileSystemTools, databaseTools, webDevTools, backendTools, apiTools, aiTools, cacheTools, containerTools, deploymentTools, gitTools, messageQueueTools, monitoringTools, securityTools, testingTools ]; // Merge all tools into allTools map for (const toolCollection of toolCollections) { for (const [key, value] of toolCollection) { this.allTools.set(key, value); } } this.setupHandlers(); } private setupHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => { const tools = Array.from(this.allTools.values()).map(tool => { // Check if it's a new class-based tool or old style if ('inputSchema' in tool && 'name' in tool && 'description' in tool) { return { name: tool.name, description: tool.description, inputSchema: tool.inputSchema, }; } // Fallback for any tools not yet migrated return { name: tool.name || 'unknown', description: tool.description || 'No description', inputSchema: tool.inputSchema || { type: 'object' } }; }); logger.info('Listing available tools', { count: tools.length }); return { tools }; }); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; const requestId = `req_${Date.now()}_${Math.random()}`; logger.setContext({ requestId, toolName: name }); logger.info('Tool request received', { args: this.sanitizeForLogging(args) }); const tool = this.allTools.get(name); if (!tool) { logger.error('Unknown tool requested', { name }); throw new Error(`Unknown tool: ${name}`); } try { // Execute tool (works for both new and old style) const result = await tool.execute(args); logger.info('Tool execution successful', { toolName: name }); return { content: [ { type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result, null, 2), }, ], }; } catch (error) { logger.error('Tool execution failed', error as Error); throw new Error(`Error executing tool ${name}: ${error instanceof Error ? error.message : String(error)}`); } finally { logger.clearContext(); } }); // Note: MCP doesn't support custom endpoints like health/check // Health check needs to be implemented as a tool if needed } private sanitizeForLogging(data: any): any { // Remove sensitive fields from logs if (!data || typeof data !== 'object') return data; const sanitized = { ...data }; const sensitiveFields = ['password', 'token', 'secret', 'key', 'apiKey']; for (const field of sensitiveFields) { if (field in sanitized) { sanitized[field] = '[REDACTED]'; } } return sanitized; } async run() { try { const transport = new StdioServerTransport(); await this.server.connect(transport); logger.info('MCP Software Engineer Server started', { totalTools: this.allTools.size, tools: Array.from(this.allTools.keys()), config: config.getSafeConfig() }); // Log to stderr for visibility console.error('Software Engineer MCP Server running on stdio'); console.error(`Total tools loaded: ${this.allTools.size}`); console.error('Available tools:', Array.from(this.allTools.keys()).join(', ')); // Setup periodic resource monitoring setInterval(() => { const usage = resourceManager.getUsage(); logger.metric('resource_usage', usage.memoryMB, 'MB', { type: 'memory', processes: usage.processes, connections: usage.connections }); // Warn if resources are high if (usage.memoryMB > config.getNumber('MAX_MEMORY_MB') * 0.8) { logger.warn('High memory usage detected', usage); } }, 30000); // Every 30 seconds } catch (error) { logger.error('Failed to start server', error as Error); throw error; } } } // Graceful shutdown handler async function shutdown() { logger.info('Shutdown signal received'); try { await resourceManager.cleanup(); logger.info('Cleanup completed, exiting'); process.exit(0); } catch (error) { logger.error('Error during shutdown', error as Error); process.exit(1); } } process.on('SIGTERM', shutdown); process.on('SIGINT', shutdown); // Start the server const server = new SoftwareEngineerMCPServer(); server.run().catch(error => { logger.error('Server crashed', error); console.error('Server crashed:', error); process.exit(1); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Rajawatrajat/mcp-software-engineer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server