Skip to main content
Glama

Watchtower DAP Windows Debugging

by rlaksana
aspnet-eval.ts17.9 kB
import { z } from 'zod'; import { Logger } from '../server/logger'; import { MetricsCollector } from '../server/metrics'; import { NetMvcAdapter } from '../adapters/netmvc-adapter'; import { DapAspNetEvaluationRequest, DapAspNetEvaluationResponse, } from '../schemas/netmvc-tools.schemas'; /** * dap.evaluateAspNet tool implementation * * Handles ASP.NET Core specific expression evaluation with: * - HttpContext evaluation * - ViewBag and ViewData inspection * - Model state validation * - Session and TempData access * - Configuration evaluation * - DbContext query inspection */ export class AspNetEvalTool { private logger: Logger; private metrics: MetricsCollector; private adapter: NetMvcAdapter; constructor() { this.logger = new Logger('dap.evaluateAspNet'); this.metrics = MetricsCollector.getInstance(); this.adapter = new NetMvcAdapter(); } /** * Execute ASP.NET Core expression evaluation */ async execute(args: any): Promise<DapAspNetEvaluationResponse> { this.metrics.startTimer('dap.evaluateAspNet.tool'); this.metrics.increment('dap.evaluateAspNet.count'); try { // Validate input const validatedArgs = this.validateArgs(args); this.logger.debug('Evaluating ASP.NET Core expression', { expression: validatedArgs.expression, frameId: validatedArgs.frameId, context: validatedArgs.context, }); // Process ASP.NET evaluation const evalResult = await this.evaluateAspNetExpression(validatedArgs); this.logger.info('ASP.NET evaluation completed', { expression: validatedArgs.expression, resultType: evalResult.type, variablesReference: evalResult.variablesReference, }); this.metrics.stopTimer('dap.evaluateAspNet.tool'); return this.createSuccessResponse(evalResult); } catch (error) { this.logger.error('ASP.NET evaluation failed:', error); this.metrics.increment('dap.evaluateAspNet.error.count'); this.metrics.stopTimer('dap.evaluateAspNet.tool'); return this.createErrorResponse((error as Error).message); } } /** * Validate input arguments */ private validateArgs(args: any): DapAspNetEvaluationRequest['arguments'] { const schema = z.object({ expression: z.string(), frameId: z.number().optional(), context: z.enum(['hover', 'watch', 'repl', 'clipboard']).default('repl'), ASPNETSpecific: z.boolean().default(true), }); return schema.parse(args); } /** * Process ASP.NET Core expression evaluation */ private async evaluateAspNetExpression( args: DapAspNetEvaluationRequest['arguments'] ): Promise<any> { // Use the adapter for ASP.NET specific evaluation const result = await this.adapter.evaluateAspNetExpression(args as any); // Enhance the result with ASP.NET specific information const enhancedResult = { ...result, ASPNETSpecific: { httpContext: this.generateHttpContextInfo(), controllerContext: this.generateControllerContextInfo(), routeData: this.generateRouteDataInfo(), viewData: this.generateViewDataInfo(), tempData: this.generateTempDataInfo(), session: this.generateSessionInfo(), configuration: this.generateConfigurationInfo(), dbContext: this.generateDbContextInfo(), identity: this.generateIdentityInfo(), }, }; return enhancedResult; } /** * Generate HttpContext information */ private generateHttpContextInfo(): any { return { requestId: `req_${Date.now()}`, requestIdShort: Date.now().toString().slice(-6), method: 'GET', path: '/api/users/123', queryString: '?include=orders&limit=10', scheme: 'https', host: 'localhost:5001', userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', contentType: 'application/json', contentLength: 256, isAjax: false, isLocal: true, protocol: 'HTTPS/1.1', remoteIpAddress: '127.0.0.1', remotePort: 54321, connectionId: 'CON_123456', traceIdentifier: `0HLTFV6TTT0P:00000001`, features: { IHttpConnectionFeature: { connectionId: 'CON_123456' }, IHttpActivityFeature: { traceIdentifier: '0HLTFV6TTT0P:00000001' }, IHttpResponseBodyFeature: { buffering: false }, }, }; } /** * Generate Controller Context information */ private generateControllerContextInfo(): any { return { controllerName: 'UsersController', controllerType: 'MyApp.Controllers.UsersController', actionName: 'GetUserById', actionDescriptor: { methodInfo: 'System.Threading.Tasks.Task<IActionResult> GetUserById(int id)', routeValues: { id: '123' }, filters: [], endpointMetadata: [], }, areaName: null, routeData: { values: { controller: 'Users', action: 'GetUserById', id: '123' }, dataTokens: {}, template: 'api/users/{id}', }, modelState: { isValid: true, validationState: 0, // Valid errors: [], }, actionContext: { actionDescriptor: { displayName: 'GetUserById', name: 'GetUserById', filterPipeline: [], methodInfo: { name: 'GetUserById', returnType: 'System.Threading.Tasks.Task<IActionResult>', parameters: [{ name: 'id', parameterType: 'System.Int32' }], }, endpointMetadata: [], }, routeData: { values: { controller: 'Users', action: 'GetUserById', id: '123' }, }, httpContext: { request: { method: 'GET', path: '/api/users/123', headers: {}, }, }, }, }; } /** * Generate Route Data information */ private generateRouteDataInfo(): any { return { router: 'Microsoft.AspNetCore.Routing.RouteCollection', currentRoute: { routeName: 'Users_GetUserById', template: 'api/users/{id}', defaults: { controller: 'Users', action: 'GetUserById' }, constraints: { id: '\\\\d+' }, dataTokens: {}, inlineConstraints: [], }, routeValues: { controller: 'Users', action: 'GetUserById', id: '123', }, dataTokens: {}, inheritedRouteData: [], }; } /** * Generate ViewData information */ private generateViewDataInfo(): any { return { model: { id: 123, name: 'John Doe', email: 'john.doe@example.com', createdAt: '2023-01-01T00:00:00Z', updatedAt: '2023-12-01T00:00:00Z', isActive: true, profile: { firstName: 'John', lastName: 'Doe', bio: 'Software developer', avatarUrl: 'https://example.com/avatar.jpg', }, orders: [ { id: 1, total: 99.99, date: '2023-11-01T00:00:00Z' }, { id: 2, total: 149.99, date: '2023-11-15T00:00:00Z' }, ], }, pageTitle: 'User Profile - John Doe', pageDescription: 'View and manage user profile information', metaTags: { title: 'User Profile - John Doe', description: 'View and manage user profile information', keywords: 'user profile, account settings, personal information', }, breadcrumbs: [ { name: 'Home', url: '/' }, { name: 'Users', url: '/users' }, { name: 'John Doe', url: '/users/123', isActive: true }, ], flashMessages: [ { type: 'success', message: 'Profile updated successfully' }, { type: 'info', message: 'Welcome back, John!' }, ], }; } /** * Generate TempData information */ private generateTempDataInfo(): any { return { keep: { successMessage: true, notification: true, }, discard: { oldData: true, }, items: { successMessage: 'User profile updated successfully', notification: 'Welcome back, John!', alert: 'Your session will expire in 15 minutes', redirectUrl: '/users/profile', formModel: { id: 123, name: 'John Doe', email: 'john.doe@example.com', }, }, keys: ['successMessage', 'notification', 'alert', 'redirectUrl', 'formModel'], peek: { successMessage: 'User profile updated successfully', notification: 'Welcome back, John!', }, }; } /** * Generate Session information */ private generateSessionInfo(): any { return { sessionId: `sess_${Date.now()}`, sessionToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', isAvailable: true, isReadOnly: false, timeout: 30, // minutes idleTimeout: 20, // minutes maxIdleTimeout: 60, // minutes sessionID: 'sess_1234567890', cookie: { name: '.AspNetCore.Session', value: 'CfDJ8H...etc...', path: '/', domain: 'localhost', secure: true, httpOnly: true, sameSite: 'Lax', expires: new Date(Date.now() + 1800000), // 30 minutes from now }, items: { userId: 123, username: 'john.doe', email: 'john.doe@example.com', role: 'User', permissions: ['read', 'write'], preferences: { theme: 'dark', language: 'en-US', notifications: true, }, lastActivity: '2023-12-01T10:30:00Z', loginCount: 42, createdAt: '2023-01-01T00:00:00Z', }, keys: [ 'userId', 'username', 'email', 'role', 'permissions', 'preferences', 'lastActivity', 'loginCount', 'createdAt', ], }; } /** * Generate Configuration information */ private generateConfigurationInfo(): any { return { configuration: { applicationName: 'MyApp', environment: 'Development', version: '1.0.0', logging: { level: 'Information', providers: [ { name: 'Console', enabled: true }, { name: 'Debug', enabled: true }, { name: 'File', enabled: false }, ], }, databases: { default: { provider: 'SqlServer', connectionString: 'Server=(localdb)\\\\mssqllocaldb;Database=MyDb;Trusted_Connection=True;', timeout: 30, commandTimeout: 30, maxPoolSize: 100, minPoolSize: 5, }, secondary: { provider: 'PostgreSQL', connectionString: 'Host=localhost;Database=MyDb;Username=user;Password=pass;', timeout: 30, }, }, security: { jwt: { issuer: 'MyApp', audience: 'MyAppUsers', secret: 'your-secret-key-here', expiration: '01:00:00', validateIssuer: true, validateAudience: true, validateLifetime: true, }, password: { minLength: 8, requireDigit: true, requireLowercase: true, requireUppercase: true, requireNonalphanumeric: true, }, }, features: { enableSwagger: true, enableSignalR: false, enableHealthChecks: true, enableMetrics: true, }, }, configurationSources: [ { name: 'appsettings.json', path: 'appsettings.json', }, { name: 'appsettings.Development.json', path: 'appsettings.Development.json', }, { name: 'Environment Variables', path: 'ASPNETCORE_*', }, { name: 'User Secrets', path: 'secrets.json', }, ], reloadable: true, cachedValues: { databaseConnection: 'cached_connection_string', jwtSecret: 'cached_jwt_secret', featureFlags: ['swagger', 'healthchecks'], }, }; } /** * Generate DbContext information */ private generateDbContextInfo(): any { return { dbContextType: 'MyApp.Data.ApplicationDbContext', databaseProvider: 'Microsoft.EntityFrameworkCore.SqlServer', databaseName: 'MyDatabase', connectionId: 'DefaultConnection', configuration: { commandTimeout: 30, maxBatchSize: 42, minBatchSize: 1, useRelationalNulls: true, querySplittingBehavior: 'SplitQuery', changeTracker: { autoDetectChangesEnabled: true, queryTrackingBehavior: 'TrackAll', lazyLoadingEnabled: true, dataAnnotationsEnabled: true, }, }, changeTracking: { hasChanges: false, changeCount: 0, trackedEntities: 0, autoDetectChanges: true, validateOnSaveEnabled: true, }, entities: { users: { entryType: 'MyApp.Models.User', state: 'Unchanged', isLoaded: true, isModified: false, properties: { id: { originalValue: 123, currentValue: 123, isModified: false }, name: { originalValue: 'John Doe', currentValue: 'John Doe', isModified: false }, email: { originalValue: 'john.doe@example.com', currentValue: 'john.doe@example.com', isModified: false, }, createdAt: { originalValue: '2023-01-01T00:00:00Z', currentValue: '2023-01-01T00:00:00Z', isModified: false, }, }, }, orders: { entryType: 'MyApp.Models.Order', state: 'Unchanged', isLoaded: true, isModified: false, properties: { id: { originalValue: 1, currentValue: 1, isModified: false }, userId: { originalValue: 123, currentValue: 123, isModified: false }, total: { originalValue: 99.99, currentValue: 99.99, isModified: false }, createdAt: { originalValue: '2023-11-01T00:00:00Z', currentValue: '2023-11-01T00:00:00Z', isModified: false, }, }, }, }, queries: { lastQuery: 'SELECT * FROM Users WHERE Id = @p0', activeQueries: [ { id: 'query_1', sql: 'SELECT u.* FROM Users u WHERE u.Id = @p0', parameters: { '@p0': 123 }, startTime: Date.now(), duration: 15, isAsync: true, connection: 'DefaultConnection', }, ], }, }; } /** * Generate Identity information */ private generateIdentityInfo(): any { return { isAuthenticated: true, authenticationType: 'Bearer', name: 'john.doe@example.com', userId: '123', userName: 'john.doe', email: 'john.doe@example.com', roles: ['User'], claims: [ { type: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name', value: 'john.doe@example.com', }, { type: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier', value: '123', }, { type: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress', value: 'john.doe@example.com', }, { type: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role', value: 'User' }, { type: 'custom/userId', value: '123' }, { type: 'custom/username', value: 'john.doe' }, ], authenticationProperties: { token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', issuedUtc: new Date(), expiresUtc: new Date(Date.now() + 3600000), isPersistent: false, isRefreshTokenAvailable: true, }, principal: { identity: { isAuthenticated: true, authenticationType: 'Bearer', name: 'john.doe@example.com', userId: '123', }, claims: [ { type: 'name', value: 'john.doe@example.com' }, { type: 'email', value: 'john.doe@example.com' }, { type: 'role', value: 'User' }, ], properties: { token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', expires: new Date(Date.now() + 3600000), }, }, }; } /** * Create success response */ private createSuccessResponse(body: any): DapAspNetEvaluationResponse { return { type: 'response', seq: 1, command: 'evaluateAspNet', request_seq: 1, success: true, body: { result: body.result, type: body.type, presentationHint: body.presentationHint, variablesReference: body.variablesReference, namedVariables: body.namedVariables, indexedVariables: body.indexedVariables, ASPNETSpecific: body.ASPNETSpecific, }, }; } /** * Create error response */ private createErrorResponse(message: string): DapAspNetEvaluationResponse { return { type: 'response', seq: 1, command: 'evaluateAspNet', request_seq: 1, success: false, message, body: { result: '', type: 'error', presentationHint: { kind: 'error' }, variablesReference: 0, ASPNETSpecific: {}, }, }; } /** * Generate ASP.NET stack trace */ } // Singleton instance export const aspNetEvalTool = new AspNetEvalTool(); // Tool execution function export async function executeAspNetEval(args: any): Promise<DapAspNetEvaluationResponse> { return await aspNetEvalTool.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