UNPKG

ai-debug-local-mcp

Version:

🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh

616 lines (592 loc) 23.2 kB
/** * HTTP MCP Transport - V2 Stateless Architecture * * Handles HTTP-based Model Context Protocol communication for AI-Debug V2 * Provides reliable, stateless communication with automatic error recovery */ import * as http from 'http'; import * as url from 'url'; import { EventEmitter } from 'events'; export class HttpMcpTransport extends EventEmitter { server; config; isRunning = false; activeConnections = new Set(); constructor(port, config = {}) { super(); this.config = { port, host: config.host || '127.0.0.1', timeout: config.timeout || 30000, maxConnections: config.maxConnections || 100 }; this.server = http.createServer((req, res) => { this.handleRequest(req, res); }); this.setupServerHandlers(); } setupServerHandlers() { this.server.on('connection', (socket) => { socket.setTimeout(this.config.timeout); }); this.server.on('error', (error) => { console.error('❌ V2 HTTP Transport error:', error); this.emit('error', error); }); this.server.on('listening', () => { console.error(`🌐 V2 HTTP MCP Transport listening on ${this.config.host}:${this.config.port}`); this.emit('listening'); }); } async handleRequest(req, res) { this.activeConnections.add(req); try { // Set CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; } const parsedUrl = url.parse(req.url || '', true); const path = parsedUrl.pathname; switch (path) { case '/': await this.handleMCPRoot(req, res); break; case '/mcp': await this.handleMCPEndpoint(req, res); break; case '/.well-known/mcp': await this.handleMCPWellKnown(req, res); break; case '/v1/mcp': await this.handleMCPEndpoint(req, res); break; case '/register': await this.handleDynamicClientRegistration(req, res); break; case '/health': await this.handleHealthCheck(req, res); break; case '/status': await this.handleStatusRequest(req, res); break; case '/tools': await this.handleToolsRequest(req, res); break; case '/execute': await this.handleToolExecution(req, res); break; case '/suggest': await this.handleToolSuggestion(req, res); break; case '/discover': await this.handleToolDiscovery(req, res); break; case '/ai-guide': await this.handleAIGuide(req, res); break; default: this.sendNotFound(res); } } catch (error) { console.error('❌ V2 Request handling error:', error); this.sendError(res, 500, 'Internal Server Error'); } finally { this.activeConnections.delete(req); } } async handleHealthCheck(req, res) { const healthData = { status: 'healthy', timestamp: new Date().toISOString(), version: 'v2.0.0-stability', transport: 'http', connections: this.activeConnections.size }; this.sendJSON(res, 200, healthData); } async handleStatusRequest(req, res) { const statusData = { server: { running: this.isRunning, port: this.config.port, host: this.config.host, activeConnections: this.activeConnections.size, maxConnections: this.config.maxConnections }, transport: { type: 'http', version: '2.0.0', features: ['stateless', 'circuit-breakers', 'auto-recovery'] } }; this.sendJSON(res, 200, statusData); } async handleToolsRequest(req, res) { // Import AI discovery system const { AIToolDiscovery } = await import('../discovery/ai-tool-discovery.js'); const discovery = new AIToolDiscovery(); const parsedUrl = url.parse(req.url || '', true); const format = parsedUrl.query.format; if (format === 'ai-docs') { // Return AI-optimized documentation const aiDocs = discovery.generateAIDocumentation(); res.setHeader('Content-Type', 'text/markdown'); res.writeHead(200); res.end(aiDocs); return; } if (format === 'ai-metadata') { // Return structured metadata for AI models const allTools = discovery.getAllToolsForAI(); this.sendJSON(res, 200, { totalTools: allTools.length, aiOptimized: true, tools: allTools.map(tool => ({ name: tool.name, category: tool.metadata.category, purpose: tool.metadata.purpose, aiDescription: tool.metadata.aiDescription, triggers: tool.metadata.autoTriggerSignals, parameters: { required: tool.metadata.requiredParameters, optional: tool.metadata.optionalParameters }, examples: tool.metadata.aiUsageExamples })) }); return; } // Default response with enhanced information const toolsData = { available: true, count: 346, categories: ['session_management', 'visual_analysis', 'performance_analysis', 'interaction_testing'], message: 'AI-Debug V2 tools with AI-discovery support', aiFeatures: { autoDiscovery: true, intelligentSuggestions: true, contextAwareParameters: true, workflowRecommendations: true }, endpoints: { aiDocs: '/tools?format=ai-docs', aiMetadata: '/tools?format=ai-metadata', suggest: '/suggest', discover: '/discover' } }; this.sendJSON(res, 200, toolsData); } async handleToolExecution(req, res) { if (req.method !== 'POST') { this.sendError(res, 405, 'Method Not Allowed'); return; } let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', async () => { try { const requestData = JSON.parse(body); const startTime = Date.now(); // Convert HTTP request to MCP protocol format const mcpRequest = { jsonrpc: '2.0', id: Date.now().toString(), method: 'tools/call', params: { name: requestData.tool, arguments: requestData.params || {} } }; // Emit MCP request to be handled by the server const responsePromise = new Promise((resolve) => { this.emit('request', mcpRequest, (response) => { resolve(response); }); }); const mcpResponse = await responsePromise; const executionTime = Date.now() - startTime; // Convert MCP response to HTTP response format if (mcpResponse.error) { this.sendJSON(res, 500, { success: false, tool: requestData.tool || 'unknown', error: mcpResponse.error.message, timestamp: new Date().toISOString(), executionTime }); } else { const result = mcpResponse.result; const content = result.content?.[0]?.text || JSON.stringify(result); this.sendJSON(res, 200, { success: true, tool: requestData.tool || 'unknown', result: content, timestamp: new Date().toISOString(), executionTime }); } } catch (error) { this.sendError(res, 400, 'Invalid JSON or tool execution error: ' + error.message); } }); } sendJSON(res, statusCode, data) { res.setHeader('Content-Type', 'application/json'); res.writeHead(statusCode); res.end(JSON.stringify(data, null, 2)); } sendError(res, statusCode, message) { const errorData = { error: true, statusCode, message, timestamp: new Date().toISOString() }; this.sendJSON(res, statusCode, errorData); } async handleToolSuggestion(req, res) { const parsedUrl = url.parse(req.url || '', true); const userInput = parsedUrl.query.input; if (!userInput) { this.sendError(res, 400, 'Missing required parameter: input'); return; } try { const { AIToolDiscovery } = await import('../discovery/ai-tool-discovery.js'); const discovery = new AIToolDiscovery(); const suggestions = discovery.suggestToolsForInput(userInput); const workflows = discovery.suggestWorkflow(userInput); const delegationCheck = discovery.shouldAutoDelegate(userInput); this.sendJSON(res, 200, { input: userInput, suggestions, workflows, autoDelegate: delegationCheck, recommendation: delegationCheck.delegate ? `Consider using delegate_to_debug_agent with agentType: ${delegationCheck.agentType}` : 'Standard tool workflow recommended', timestamp: new Date().toISOString(), aiOptimized: true }); } catch (error) { this.sendError(res, 500, 'Error generating suggestions'); } } async handleToolDiscovery(req, res) { const parsedUrl = url.parse(req.url || '', true); const category = parsedUrl.query.category; const signal = parsedUrl.query.signal; try { const { AIToolDiscovery } = await import('../discovery/ai-tool-discovery.js'); const discovery = new AIToolDiscovery(); if (category) { // Return tools by category const allTools = discovery.getAllToolsForAI(); const categoryTools = allTools.filter(tool => tool.metadata.category === category); this.sendJSON(res, 200, { category, tools: categoryTools, count: categoryTools.length }); } else if (signal) { // Return tools that respond to specific signals const suggestions = discovery.suggestToolsForInput(signal); this.sendJSON(res, 200, { signal, matchingTools: suggestions, count: suggestions.length }); } else { // Return discovery overview const allTools = discovery.getAllToolsForAI(); const categories = [...new Set(allTools.map(tool => tool.metadata.category))]; this.sendJSON(res, 200, { totalTools: allTools.length, categories, discoveryFeatures: [ 'Intelligent tool suggestions based on user input', 'Auto-trigger signal detection', 'Workflow recommendations', 'Context-aware parameter suggestions', 'AI-optimized documentation' ], usage: { suggestions: '/suggest?input=your_user_request', byCategory: '/discover?category=category_name', bySignal: '/discover?signal=keyword' } }); } } catch (error) { this.sendError(res, 500, 'Error in tool discovery'); } } async handleMCPRoot(req, res) { // MCP HTTP root endpoint - provides server metadata const metadata = { name: 'ai-debug-v2', version: '2.0.0-stability', description: 'AI-Debug V2 - Revolutionary Debugging Platform with AI Discovery', capabilities: { tools: true, resources: false, prompts: false, sub_agents: true, ai_discovery: true }, endpoints: { mcp: '/mcp', 'v1/mcp': '/v1/mcp', register: '/register', 'well-known': '/.well-known/mcp', tools: '/tools', health: '/health', status: '/status' }, transport: 'http', protocol: 'mcp/2024-11-05' }; this.sendJSON(res, 200, metadata); } async handleMCPWellKnown(req, res) { // Well-known MCP discovery endpoint const discovery = { mcp: { endpoints: { primary: 'http://localhost:8080/mcp', v1: 'http://localhost:8080/v1/mcp' }, server: { name: 'ai-debug-v2', version: '2.0.0-stability' }, capabilities: ['tools'], auth: { type: 'none' } } }; this.sendJSON(res, 200, discovery); } async handleDynamicClientRegistration(req, res) { // Dynamic Client Registration endpoint for OAuth-like flows if (req.method !== 'POST') { this.sendError(res, 405, 'Method Not Allowed'); return; } let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', async () => { try { const registrationRequest = JSON.parse(body); // Generate a client registration response const clientRegistration = { client_id: `ai-debug-client-${Date.now()}`, client_name: registrationRequest.client_name || 'AI Debug Client', grant_types: ['client_credentials'], token_endpoint_auth_method: 'none', registration_client_uri: `http://localhost:8080/client/${Date.now()}`, registration_access_token: `token-${Date.now()}`, mcp_endpoints: { primary: 'http://localhost:8080/mcp', tools: 'http://localhost:8080/tools' } }; this.sendJSON(res, 201, clientRegistration); } catch (error) { this.sendError(res, 400, 'Invalid registration request'); } }); } async handleMCPEndpoint(req, res) { // Main MCP endpoint for protocol communication if (req.method === 'POST') { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', async () => { try { const mcpRequest = JSON.parse(body); // Emit request event for dual-mode server to handle this.emit('request', mcpRequest, (mcpResponse) => { this.sendJSON(res, 200, mcpResponse); }); } catch (error) { this.sendError(res, 400, 'Invalid MCP request'); } }); } else { // GET request for MCP capabilities const capabilities = { jsonrpc: '2.0', result: { protocolVersion: '2024-11-05', capabilities: { tools: { listChanged: false } }, serverInfo: { name: 'ai-debug-v2', version: '2.0.0-stability' } } }; this.sendJSON(res, 200, capabilities); } } // Method removed - MCP requests now handled by dual-mode server via event emission convertParametersToSchema(required, optional = []) { const properties = {}; [...required, ...optional].forEach(param => { properties[param.name] = { type: param.type === 'array' ? 'array' : 'string', description: param.description }; }); return properties; } async handleAIGuide(req, res) { const aiGuide = ` # AI-Debug V2 - AI Integration Guide ## For AI Models: How to Use AI-Debug Tools Effectively ### 🎯 Core Principle AI-Debug V2 is designed to be completely discoverable by AI models. You don't need explicit user instructions - the tools can analyze user intent and suggest appropriate actions. ### 🚀 Quick Start for AI Models 1. **Always start with tool discovery**: \`GET /tools?format=ai-metadata\` - Get all tools with AI-friendly descriptions 2. **Analyze user intent**: \`GET /suggest?input=user_request\` - Get tool suggestions based on user input 3. **Execute suggested workflow**: Follow the suggested tool sequence with recommended parameters ### 🧠 AI-Friendly Features #### Auto-Discovery - Tools include \`autoTriggerSignals\` - keywords that indicate when to use them - \`useWhenUser\` conditions help identify appropriate scenarios - Example usage patterns for common requests #### Intelligent Parameter Suggestions - Required parameters clearly marked with AI hints - Example values provided for all parameters - Context-aware parameter extraction from user input #### Workflow Recommendations - Pre-defined sequences for common debugging scenarios - Integration tips for tool combinations - Expected outcomes for each workflow ### 📋 Common AI Usage Patterns #### Pattern 1: User wants to debug a website \`\`\` User: "Can you help debug my slow website at https://example.com?" AI Response: 1. Detect signals: "debug", "slow", "website", URL 2. Suggest tools: inject_debugging → run_audit → take_screenshot 3. Execute workflow with extracted URL \`\`\` #### Pattern 2: User wants visual analysis \`\`\` User: "How does my homepage look?" AI Response: 1. Detect signals: "look", "homepage", visual request 2. Suggest tools: inject_debugging → take_screenshot 3. Capture and analyze visual state \`\`\` #### Pattern 3: User wants to test functionality \`\`\` User: "Test if my contact form works" AI Response: 1. Detect signals: "test", "form", "works" 2. Suggest workflow: inject_debugging → take_screenshot → simulate_user_action → take_screenshot 3. Execute interaction testing sequence \`\`\` ### 🔍 Discovery Endpoints for AI Models - \`/tools?format=ai-docs\` - Markdown documentation optimized for AI - \`/tools?format=ai-metadata\` - Structured JSON with all tool metadata - \`/suggest?input=user_request\` - Get tool suggestions for user input - \`/discover?category=category_name\` - Browse tools by category - \`/ai-guide\` - This comprehensive guide ### 💡 Best Practices for AI Models 1. **Always use tool discovery first** - Don't assume you know available tools 2. **Analyze user intent with /suggest** - Get confidence scores and reasoning 3. **Follow recommended workflows** - Pre-tested sequences for optimal results 4. **Use provided examples** - Real usage patterns for accurate implementation 5. **Check integration tips** - Understand tool compatibility and sequencing ### 🎉 Success Indicators You're using AI-Debug effectively when: - ✅ You discover and use tools without explicit user instructions - ✅ You suggest appropriate tool sequences based on user intent - ✅ You provide meaningful analysis and recommendations - ✅ You handle edge cases gracefully with troubleshooting guidance The goal is seamless debugging assistance where the AI model understands user needs and uses appropriate tools automatically. `; res.setHeader('Content-Type', 'text/markdown'); res.writeHead(200); res.end(aiGuide); } sendNotFound(res) { this.sendError(res, 404, 'Not Found'); } async start() { return new Promise((resolve, reject) => { if (this.isRunning) { resolve(); return; } this.server.listen(this.config.port, this.config.host, () => { this.isRunning = true; resolve(); }); this.server.on('error', reject); }); } async stop() { return new Promise((resolve, reject) => { if (!this.isRunning) { resolve(); return; } // Close all active connections for (const connection of this.activeConnections) { connection.destroy(); } this.activeConnections.clear(); this.server.close((error) => { if (error) { reject(error); } else { this.isRunning = false; console.error('🛑 V2 HTTP MCP Transport stopped'); resolve(); } }); }); } getConnectionCount() { return this.activeConnections.size; } isTransportRunning() { return this.isRunning; } } //# sourceMappingURL=http-mcp-transport.js.map