Skip to main content
Glama

Watchtower DAP Windows Debugging

by rlaksana
http-debug.ts13 kB
import { z } from 'zod'; import { Logger } from '../server/logger'; import { MetricsCollector } from '../server/metrics'; import { NetMvcAdapter } from '../adapters/netmvc-adapter'; import { DapHttpRequestDebugRequest, DapHttpRequestDebugResponse, } from '../schemas/netmvc-tools.schemas'; /** * dap.debugHttpRequest tool implementation * * Handles HTTP request/response debugging for .NET MVC applications * with detailed inspection of request lifecycle, routing, and response generation */ export class HttpDebugTool { private logger: Logger; private metrics: MetricsCollector; private adapter: NetMvcAdapter; constructor() { this.logger = new Logger('dap.debugHttpRequest'); this.metrics = MetricsCollector.getInstance(); this.adapter = new NetMvcAdapter(); } /** * Execute HTTP request debugging */ async execute(args: any): Promise<DapHttpRequestDebugResponse> { this.metrics.startTimer('dap.debugHttpRequest.tool'); this.metrics.increment('dap.debugHttpRequest.count'); try { // Validate input const validatedArgs = this.validateArgs(args); this.logger.debug('Debugging HTTP request', { method: validatedArgs.method, path: validatedArgs.path, requestId: validatedArgs.requestId, }); // Process HTTP request debugging const debugResult = await this.debugHttpRequest(validatedArgs); this.logger.info('HTTP request debugging completed', { requestId: debugResult.requestId, method: validatedArgs.method, path: validatedArgs.path, }); this.metrics.stopTimer('dap.debugHttpRequest.tool'); return this.createSuccessResponse(debugResult); } catch (error) { this.logger.error('HTTP request debugging failed:', error); this.metrics.increment('dap.debugHttpRequest.error.count'); this.metrics.stopTimer('dap.debugHttpRequest.tool'); return this.createErrorResponse((error as Error).message); } } /** * Validate input arguments */ private validateArgs(args: any): DapHttpRequestDebugRequest['arguments'] { const schema = z.object({ requestId: z.string().optional(), method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']), path: z.string(), queryString: z.string().optional(), headers: z.record(z.string()).optional(), body: z.string().optional(), cookies: z.record(z.string()).optional(), session: z.record(z.any()).optional(), user: z.record(z.any()).optional(), routeData: z.record(z.any()).optional(), controller: z.string().optional(), action: z.string().optional(), modelState: z.record(z.any()).optional(), form: z.record(z.any()).optional(), files: z.record(z.any()).optional(), culture: z.string().optional(), acceptedLanguages: z.array(z.string()).optional(), isAjax: z.boolean().optional(), isLocal: z.boolean().optional(), protocol: z.string().optional(), scheme: z.string().optional(), host: z.string().optional(), originalUrl: z.string().optional(), }); return schema.parse(args); } /** * Process HTTP request debugging */ private async debugHttpRequest(args: DapHttpRequestDebugRequest['arguments']): Promise<any> { // Mock HTTP request processing const httpRequest = { requestId: args.requestId || `req_${Date.now()}`, timestamp: Date.now(), method: args.method, path: args.path, fullPath: args.path + (args.queryString ? `?${args.queryString}` : ''), // Request parsing headers: this.parseHeaders(args.headers || {}), cookies: args.cookies || {}, session: args.session || {}, user: args.user || {}, // ASP.NET Core specific routeData: args.routeData || this.extractRouteData(args.path), controller: args.controller || this.extractController(args.path), action: args.action || this.extractAction(args.path), // Request lifecycle tracking processingStart: Date.now(), middleware: [], filters: [], modelBinding: {}, modelValidation: args.modelState || {}, // Response generation viewData: {}, tempData: {}, viewBag: {}, // Response info response: { statusCode: 200, contentType: 'text/html', headers: {}, body: null, isRedirect: false, redirectUrl: null, }, // Performance metrics processingTime: 0, databaseQueries: [], externalCalls: [], // Request context culture: args.culture || 'en-US', acceptedLanguages: args.acceptedLanguages || ['en-US'], isAjax: args.isAjax || false, isLocal: args.isLocal || false, protocol: args.protocol || 'https', scheme: args.scheme || 'https', host: args.host || 'localhost:5001', originalUrl: args.originalUrl || args.path, // Security authentication: { isAuthenticated: false, identity: null, principal: null, }, // Debug info debugInfo: { middlewareApplied: false, modelBound: false, validModelState: true, viewRendered: false, cacheHit: false, optimizationApplied: [], }, }; // Simulate request processing await this.simulateRequestProcessing(httpRequest); // Add to adapter tracking await this.adapter.debugHttpRequest(httpRequest); return { requestId: httpRequest.requestId, httpRequest, metrics: { processingTime: httpRequest.processingTime, databaseQueries: httpRequest.databaseQueries.length, externalCalls: httpRequest.externalCalls.length, memoryUsage: Math.random() * 50 + 10, // MB }, }; } /** * Parse HTTP headers */ private parseHeaders(headers: Record<string, string>): any { const parsed: any = {}; // Common headers to parse if (headers['content-type']) { parsed.contentType = headers['content-type']; } if (headers['content-length']) { parsed.contentLength = parseInt(headers['content-length']); } if (headers['user-agent']) { parsed.userAgent = headers['user-agent']; } if (headers['accept']) { parsed.accept = headers['accept']; } if (headers['accept-language']) { parsed.acceptLanguage = headers['accept-language']; } if (headers['accept-encoding']) { parsed.acceptEncoding = headers['accept-encoding']; } if (headers['authorization']) { parsed.authorization = '[REDACTED]'; } if (headers['cookie']) { parsed.cookies = headers['cookie']; } return parsed; } /** * Extract route data from path */ private extractRouteData(path: string): any { // Mock route data extraction for common MVC patterns const routePatterns = [ { pattern: '^/Home/Index$', controller: 'Home', action: 'Index' }, { pattern: '^/Home/About$', controller: 'Home', action: 'About' }, { pattern: '^/Users/Index$', controller: 'Users', action: 'Index' }, { pattern: '^/Users/Edit/\\d+$', controller: 'Users', action: 'Edit' }, { pattern: '^/Api/.*$', controller: 'Api', action: 'Index' }, ]; for (const route of routePatterns) { const regex = new RegExp(route.pattern); if (regex.test(path)) { return { controller: route.controller, action: route.action, area: null, routeName: `${route.controller}_${route.action}`, template: `/{controller}/{action}`, constraints: {}, dataTokens: {}, rawUrl: path, }; } } return { controller: 'Unknown', action: 'Unknown', area: null, routeName: 'Default', template: '/{controller}/{action}/{id?}', constraints: {}, dataTokens: {}, rawUrl: path, }; } /** * Extract controller from path */ private extractController(path: string): string { const route = this.extractRouteData(path); return route.controller; } /** * Extract action from path */ private extractAction(path: string): string { const route = this.extractRouteData(path); return route.action; } /** * Simulate ASP.NET Core request processing */ private async simulateRequestProcessing(httpRequest: any): Promise<void> { const startTime = Date.now(); // 1. Middleware pipeline simulation const middleware = [ { name: 'UseExceptionHandler', executed: true, duration: 5 }, { name: 'UseHsts', executed: true, duration: 2 }, { name: 'UseHttpsRedirection', executed: true, duration: 3 }, { name: 'UseStaticFiles', executed: true, duration: 10 }, { name: 'UseRouting', executed: true, duration: 8 }, { name: 'UseAuthentication', executed: true, duration: 15 }, { name: 'UseAuthorization', executed: true, duration: 12 }, { name: 'UseEndpoints', executed: true, duration: 20 }, ]; httpRequest.middleware = middleware; // 2. Filter pipeline simulation const filters = [ { name: 'ActionFilter', executed: true, duration: 5 }, { name: 'ResultFilter', executed: true, duration: 3 }, { name: 'ExceptionFilter', executed: false, duration: 0 }, ]; httpRequest.filters = filters; // 3. Model binding simulation httpRequest.modelBinding = { bound: true, model: { id: 123, name: 'John Doe', email: 'john.doe@example.com', createdAt: '2023-01-01T00:00:00Z', }, }; // 4. Model validation simulation httpRequest.modelValidation = { isValid: true, errors: [], warnings: [], }; // 5. Database queries simulation const databaseQueries = [ { id: `db_query_${Date.now()}_1`, text: 'SELECT * FROM Users WHERE Id = @p0', parameters: { '@p0': 123 }, executionTime: Math.random() * 10 + 1, connection: 'DefaultConnection', isAsync: true, }, { id: `db_query_${Date.now()}_2`, text: 'SELECT * FROM Products WHERE UserId = @p0', parameters: { '@p0': 123 }, executionTime: Math.random() * 15 + 5, connection: 'DefaultConnection', isAsync: true, }, ]; httpRequest.databaseQueries = databaseQueries; // 6. External calls simulation const externalCalls = [ { id: 'ext_call_1', service: 'UserService', operation: 'GetUser', url: 'https://api.example.com/users/123', method: 'GET', duration: Math.random() * 50 + 20, success: true, }, ]; httpRequest.externalCalls = externalCalls; // 7. Response generation simulation httpRequest.viewData = { pageTitle: 'User Profile', user: httpRequest.modelBinding.model, products: [], stats: { totalOrders: 5, totalSpent: 250.0, }, }; httpRequest.tempData = { successMessage: 'User profile updated successfully', notification: 'Welcome back, John!', }; httpRequest.viewBag = { metaTitle: 'User Profile - My Application', metaDescription: 'View and manage user profile information', }; // 8. Response setup httpRequest.response = { statusCode: 200, contentType: 'text/html', headers: { 'Content-Type': 'text/html; charset=utf-8', 'Content-Length': '4096', 'X-Powered-By': 'ASP.NET', 'X-Response-Time': `${Math.random() * 100 + 50}ms`, }, body: '<html><body>User profile page content...</body></html>', isRedirect: false, redirectUrl: null, }; // Calculate processing time httpRequest.processingTime = Date.now() - startTime; } /** * Create success response */ private createSuccessResponse(body: any): DapHttpRequestDebugResponse { return { type: 'response', seq: 1, command: 'debugHttpRequest', request_seq: 1, success: true, body: { success: true, requestId: body.requestId, message: 'HTTP request debug completed successfully', httpRequest: body.httpRequest, }, }; } /** * Create error response */ private createErrorResponse(message: string): DapHttpRequestDebugResponse { return { type: 'response', seq: 1, command: 'debugHttpRequest', request_seq: 1, success: false, message, body: { success: false, requestId: 'req_error_' + Date.now(), message: 'Failed to debug HTTP request', }, }; } } // Singleton instance export const httpDebugTool = new HttpDebugTool(); // Tool execution function export async function executeHttpDebug(args: any): Promise<DapHttpRequestDebugResponse> { return await httpDebugTool.execute(args); }

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/rlaksana/mcp-watchtower'

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