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
JavaScript
/**
* 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