Skip to main content
Glama

Web Proxy MCP Server

by mako10k
tool-handlers.js14.6 kB
/** * Web Proxy MCP Tool Handlers * Implements the actual functionality for each MCP tool */ import { validateToolArgs } from './tool-definitions.js'; export class ToolHandlers { constructor(proxyServer, targetManager, browserSetup, trafficAnalyzer, sslManager = null) { this.proxyServer = proxyServer; this.targetManager = targetManager; this.browserSetup = browserSetup; this.trafficAnalyzer = trafficAnalyzer; this.sslManager = sslManager; } /** * Handle tool call * @param {string} name - Tool name * @param {Object} args - Tool arguments * @returns {Object} Tool result */ async handleTool(name, args = {}) { // Validate arguments const validation = validateToolArgs(name, args); if (!validation.valid) { return { error: validation.error, isError: true }; } try { // Route to appropriate handler if (name.startsWith('proxy_target_') || name.includes('_target')) { return await this._handleTargetTool(name, args); } else if (name.startsWith('proxy_server_') || name.includes('_server')) { return await this._handleServerTool(name, args); } else if (name.startsWith('ssl_')) { return await this._handleSSLTool(name, args); } else if (name.includes('setup') || name.includes('pac')) { return await this._handleSetupTool(name, args); } else if (name.includes('traffic') || name.includes('har')) { return await this._handleTrafficTool(name, args); } else if (name.includes('config')) { return await this._handleConfigTool(name, args); } else if (name.includes('analyze') || name.includes('metrics')) { return await this._handleAnalysisTool(name, args); } return { error: `Unknown tool: ${name}`, isError: true }; } catch (error) { return { error: error.message, isError: true, stack: error.stack }; } } /** * Handle SSL management tools * @private */ async _handleSSLTool(name, args) { if (!this.sslManager) { return { error: "SSL Manager not available", isError: true }; } switch (name) { case 'ssl_create_ca': const caResult = await this.sslManager.createCA( args.caName, { description: args.description, overwrite: args.overwrite, subject: args.subject } ); return { content: [{ type: "text", text: `✅ Certificate Authority created: ${caResult.caName}\n\n📁 CA Directory: ${caResult.caDir}\n🔑 CA Certificate: ${caResult.caCertPath}\n\n${caResult.installationInstructions}` }] }; case 'ssl_list_cas': const cas = await this.sslManager.listCAs(); const caList = cas.map(ca => `• ${ca.name} ${ca.current ? '(current)' : ''} - ${ca.exists ? '✅ Available' : '❌ Missing'}\n Created: ${ca.created || 'Unknown'}\n Description: ${ca.description || 'No description'}` ).join('\n\n'); return { content: [{ type: "text", text: `🔒 Available Certificate Authorities\n\n${caList || 'No CAs found'}` }] }; case 'ssl_switch_ca': const switchResult = await this.sslManager.switchCA(args.caName); return { content: [{ type: "text", text: `🔄 Switched to CA: ${switchResult.caName}\n📁 CA Directory: ${switchResult.caDir}` }] }; case 'ssl_get_ca_certificate': const caCert = await this.sslManager.getCACertificate(); return { content: [{ type: "text", text: `📜 CA Certificate\n\n📁 Certificate Path: ${caCert.certPath}\n\n${caCert.installationInstructions}` }] }; case 'ssl_generate_certificate': const certResult = await this.sslManager.generateServerCertificate( args.domain, args.altNames ); return { content: [{ type: "text", text: `📜 Generated certificate for: ${certResult.domain}\n\n🔑 Private Key: ${certResult.keyPath}\n📄 Certificate: ${certResult.certPath}\n🏷️ Alt Names: ${certResult.altNames.join(', ')}` }] }; case 'ssl_ca_status': const status = this.sslManager.getCAStatus(); return { content: [{ type: "text", text: `🔒 SSL Manager Status\n\n${JSON.stringify(status, null, 2)}` }] }; default: return { error: `Unknown SSL tool: ${name}`, isError: true }; } } /** * Handle target management tools * @private */ async _handleTargetTool(name, args) { switch (name) { case 'proxy_add_target': const added = this.targetManager.addTarget( args.domain, args.description, { enabled: args.enabled, captureHeaders: args.captureHeaders, captureBody: args.captureBody } ); return { content: [{ type: "text", text: `Target added: ${args.domain}\nStatus: ${added ? 'success' : 'already exists'}\nMonitored domains: ${this.targetManager.getStats().enabled}` }] }; case 'proxy_remove_target': const removed = this.targetManager.removeTarget(args.domain); return { content: [{ type: "text", text: `Target removed: ${args.domain}\nStatus: ${removed ? 'success' : 'not found'}\nRemaining domains: ${this.targetManager.getStats().enabled}` }] }; case 'proxy_list_targets': const targets = this.targetManager.listTargets(args.status); const targetList = targets.map(t => `• ${t.domain} (${t.status}) - ${t.description || 'No description'}` ).join('\n'); return { content: [{ type: "text", text: `📋 Proxy Targets (${targets.length})\n\n${targetList || 'No targets configured'}\n\nStats: ${JSON.stringify(this.targetManager.getStats(), null, 2)}` }] }; case 'proxy_update_target': const updates = {}; if ('enabled' in args) updates.enabled = args.enabled; if ('description' in args) updates.description = args.description; if ('captureHeaders' in args) updates.captureHeaders = args.captureHeaders; if ('captureBody' in args) updates.captureBody = args.captureBody; const updated = this.targetManager.updateTarget(args.domain, updates); return { content: [{ type: "text", text: `Target updated: ${args.domain}\nStatus: ${updated ? 'success' : 'not found'}\nUpdates: ${JSON.stringify(updates, null, 2)}` }] }; default: return { error: `Unknown target tool: ${name}`, isError: true }; } } /** * Handle server control tools * @private */ async _handleServerTool(name, args) { switch (name) { case 'proxy_start_server': if (this.proxyServer.isRunning()) { return { content: [{ type: "text", text: `Proxy server is already running on ${this.proxyServer.getAddress()}` }] }; } await this.proxyServer.start(args.port, args.host, { enableSSLBumping: args.enableSSLBumping }); const serverStatus = this.proxyServer.getStatus(); return { content: [{ type: "text", text: `🚀 Proxy server started!\n\nAddress: ${this.proxyServer.getAddress()}\nPAC URL: ${this.proxyServer.getAddress()}/proxy.pac\nCA Certificate: ${this.proxyServer.getAddress()}/ca.crt\nSSL Bumping: ${serverStatus.sslBumpingEnabled ? 'ENABLED' : 'DISABLED'}\nMonitoring: ${this.targetManager.getStats().enabled} domains${serverStatus.sslBumpingEnabled ? '\n\n⚠️ SSL Bumping is active - install CA certificate for HTTPS interception!' : ''}` }] }; case 'proxy_stop_server': if (!this.proxyServer.isRunning()) { return { content: [{ type: "text", text: "Proxy server is not running" }] }; } await this.proxyServer.stop(); return { content: [{ type: "text", text: "✅ Proxy server stopped" }] }; case 'proxy_server_status': const status = this.proxyServer.getStatus(); const stats = this.targetManager.getStats(); return { content: [{ type: "text", text: `📊 Proxy Server Status\n\n${JSON.stringify({ ...status, targetStats: stats, trafficEntries: this.trafficAnalyzer ? this.trafficAnalyzer.getEntryCount() : 0 }, null, 2)}` }] }; default: return { error: `Unknown server tool: ${name}`, isError: true }; } } /** * Handle setup and configuration tools * @private */ async _handleSetupTool(name, args) { switch (name) { case 'proxy_generate_setup': const setup = await this.browserSetup.generateAllSetups( args.proxyHost, args.proxyPort ); const quickGuide = this.browserSetup.generateQuickSetup( args.proxyHost, args.proxyPort ); return { content: [{ type: "text", text: `✅ Browser setup scripts generated!\n\n${quickGuide}\n\nGenerated files:\n${Object.entries(setup.files).map(([type, file]) => `• ${file.filename} - ${file.description}`).join('\n')}` }] }; case 'proxy_get_pac_file': const pacContent = this.targetManager.generatePacFile( args.proxyHost, args.proxyPort ); return { content: [{ type: "text", text: `📄 PAC File Content:\n\n\`\`\`javascript\n${pacContent}\n\`\`\`` }] }; default: return { error: `Unknown setup tool: ${name}`, isError: true }; } } /** * Handle traffic analysis tools * @private */ async _handleTrafficTool(name, args) { if (!this.trafficAnalyzer) { return { error: "Traffic analyzer not available", isError: true }; } switch (name) { case 'proxy_get_traffic_log': const entries = this.trafficAnalyzer.getEntries({ domain: args.domain, method: args.method, limit: args.limit, since: args.since ? new Date(args.since) : undefined }); const logText = entries.map(entry => `[${entry.timestamp}] ${entry.method} ${entry.url} -> ${entry.statusCode} (${entry.responseTime}ms)` ).join('\n'); return { content: [{ type: "text", text: `📈 Traffic Log (${entries.length} entries)\n\n${logText || 'No traffic captured'}` }] }; case 'proxy_export_har': const harFile = await this.trafficAnalyzer.exportHAR({ domain: args.domain, since: args.since ? new Date(args.since) : undefined, filename: args.filename }); return { content: [{ type: "text", text: `📁 HAR file exported: ${harFile.filename}\nEntries: ${harFile.entryCount}\nSize: ${harFile.fileSize} bytes` }] }; case 'proxy_clear_traffic_log': if (!args.confirm) { return { error: "Confirmation required to clear traffic log", isError: true }; } const cleared = this.trafficAnalyzer.clearEntries(args.domain); return { content: [{ type: "text", text: `🗑️ Traffic log cleared\nEntries removed: ${cleared}\nRemaining: ${this.trafficAnalyzer.getEntryCount()}` }] }; default: return { error: `Unknown traffic tool: ${name}`, isError: true }; } } /** * Handle configuration management tools * @private */ async _handleConfigTool(name, args) { switch (name) { case 'proxy_import_config': const imported = await this.targetManager.importFromFile( args.filepath, args.merge ); return { content: [{ type: "text", text: `📥 Configuration imported from ${args.filepath}\nTargets imported: ${imported.imported}\nTotal targets: ${this.targetManager.getStats().total}` }] }; case 'proxy_export_config': const exported = await this.targetManager.exportToFile( args.filepath, args.includeTrafficLog && this.trafficAnalyzer ? { trafficLog: this.trafficAnalyzer.getAllEntries() } : undefined ); return { content: [{ type: "text", text: `📤 Configuration exported to ${exported.filepath}\nTargets: ${exported.targetCount}\nFile size: ${exported.fileSize} bytes` }] }; default: return { error: `Unknown config tool: ${name}`, isError: true }; } } /** * Handle analysis tools * @private */ async _handleAnalysisTool(name, args) { switch (name) { case 'proxy_analyze_traffic': if (!this.trafficAnalyzer) { return { error: "Traffic analyzer not available", isError: true }; } const analysis = this.trafficAnalyzer.analyzeTraffic({ domain: args.domain, timeframe: args.timeframe, groupBy: args.groupBy }); return { content: [{ type: "text", text: `📊 Traffic Analysis (${args.timeframe})\n\n${JSON.stringify(analysis, null, 2)}` }] }; case 'proxy_get_performance_metrics': const metrics = this.proxyServer.getMetrics(); if (args.reset) { this.proxyServer.resetMetrics(); } return { content: [{ type: "text", text: `⚡ Performance Metrics\n\n${JSON.stringify(metrics, null, 2)}${args.reset ? '\n\n✅ Metrics reset' : ''}` }] }; default: return { error: `Unknown analysis tool: ${name}`, isError: true }; } } }

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/mako10k/mcp-web-proxy'

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