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

243 lines 11.8 kB
import { BaseToolHandler } from '../base-handler.js'; /** * Handler for Next.js runtime monitoring tools (middleware, server actions) */ export class NextJSRuntimeHandler extends BaseToolHandler { nextjsEngine; constructor(nextjsEngine) { super(); this.nextjsEngine = nextjsEngine; } tools = [ { name: 'nextjs_middleware_monitor', description: 'Monitor Next.js middleware performance including execution time, affected routes, and memory usage.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'nextjs_server_actions', description: 'Monitor Server Actions including invocations, payload sizes, execution time, and revalidations.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } } ]; async handle(toolName, args, sessions) { const session = sessions.get(args.sessionId); if (!session) { throw new Error(`Debug session ${args.sessionId} not found`); } // Validate this is a Next.js app if (session.framework !== 'nextjs' && session.framework !== 'next' && !(session.framework === 'react' && session.isNextJS)) { throw new Error('This tool only works with Next.js applications'); } switch (toolName) { case 'nextjs_middleware_monitor': return this.monitorMiddleware(args, session); case 'nextjs_server_actions': return this.monitorServerActions(args, session); default: throw new Error(`Unknown Next.js runtime tool: ${toolName}`); } } async monitorMiddleware(args, session) { try { const analysis = await this.nextjsEngine.getMiddlewareAnalysis(); // Check if no middleware found if (!analysis || analysis.affectedRoutes === 0 || analysis.executionTime === '0ms') { return { content: [{ type: 'text', text: '⚡ **Next.js Middleware Monitor**\n\n' + '❌ No middleware detected.\n\n' + 'Next.js middleware allows you to run code before requests are completed.\n' + 'To add middleware:\n\n' + '1. Create `middleware.ts` in your project root\n' + '2. Export a `middleware` function\n' + '3. Define matcher patterns or use conditional logic\n\n' + '```typescript\n' + 'export function middleware(request: NextRequest) {\n' + ' // Your middleware logic\n' + '}\n\n' + 'export const config = {\n' + ' matcher: \'/api/:path*\'\n' + '}\n' + '```' }] }; } let content = '⚡ **Next.js Middleware Monitor**\n\n'; // Performance metrics content += '**Performance Metrics:**\n'; content += `- **Execution Time:** ${analysis.executionTime}\n`; content += `- **Affected Routes:** ${analysis.affectedRoutes}\n`; content += `- **Memory Usage:** ${analysis.memoryUsage}\n\n`; // Matcher patterns if (analysis.matchers && analysis.matchers.length > 0) { content += '**Matcher Patterns:**\n'; analysis.matchers.forEach((matcher) => { content += `- \`${matcher}\`\n`; }); content += '\n'; } // Warnings if (analysis.warnings && analysis.warnings.length > 0) { content += '**⚠️ Warnings:**\n'; analysis.warnings.forEach((warning) => { content += `- ${warning}\n`; }); content += '\n'; } // Performance analysis const execTime = parseFloat(analysis.executionTime); if (execTime > 100) { content += '**🔴 Performance Issues:**\n'; content += '- Middleware execution time exceeds 100ms\n'; content += '- This will delay all matched requests\n'; content += '- Consider optimizing middleware logic\n\n'; } else if (execTime > 50) { content += '**🟡 Performance Warning:**\n'; content += '- Middleware execution time is above 50ms\n'; content += '- Monitor for further degradation\n\n'; } // Recommendations content += '**💡 Recommendations:**\n'; content += '- Keep middleware logic minimal and fast\n'; content += '- Avoid heavy computations or external API calls\n'; content += '- Use specific matchers to limit execution scope\n'; content += '- Consider edge runtime for better performance\n'; if (analysis.affectedRoutes > 100) { content += '- High number of affected routes - ensure this is intentional\n'; } return { content: [{ type: 'text', text: content.trim() }] }; } catch (error) { throw new Error(`Failed to monitor middleware: ${error instanceof Error ? error.message : String(error)}`); } } async monitorServerActions(args, session) { try { const monitor = await this.nextjsEngine.getServerActionMonitor(); // Check if no server actions detected if (monitor.totalInvocations === 0) { return { content: [{ type: 'text', text: '🎯 **Next.js Server Actions Monitor**\n\n' + '❌ No server actions detected.\n\n' + 'Server Actions allow you to run server-side code directly from your components.\n' + 'To use Server Actions:\n\n' + '1. Add `"use server"` directive at the top of your action file\n' + '2. Define async functions that will run on the server\n' + '3. Call them from Client Components\n\n' + '```typescript\n' + '// app/actions.ts\n' + '"use server"\n\n' + 'export async function createUser(formData: FormData) {\n' + ' const name = formData.get("name");\n' + ' // Server-side logic here\n' + ' revalidatePath("/users");\n' + '}\n' + '```' }] }; } let content = '🎯 **Next.js Server Actions Monitor**\n\n'; // Summary metrics content += '**Summary:**\n'; content += `- **Total Invocations:** ${monitor.totalInvocations}\n`; content += `- **Average Execution:** ${monitor.avgExecutionTime}ms\n`; content += `- **Largest Payload:** ${(monitor.largestPayload / 1024).toFixed(1)}KB\n\n`; // Recent invocations if (monitor.invocations.length > 0) { content += '**Recent Invocations:**\n\n'; // Show last 10 invocations const recentInvocations = monitor.invocations.slice(-10).reverse(); recentInvocations.forEach(invocation => { content += `**\`${invocation.action}\`**\n`; content += `- Duration: ${invocation.duration}ms\n`; content += `- Payload: ${(invocation.payloadSize / 1024).toFixed(1)}KB\n`; if (invocation.revalidations && invocation.revalidations.length > 0) { content += `- Revalidated: ${invocation.revalidations.join(', ')}\n`; } if (invocation.error) { content += `- ❌ Error: ${invocation.error}\n`; } content += '\n'; }); } // Performance analysis const performanceIssues = []; if (monitor.avgExecutionTime > 1000) { performanceIssues.push('Long execution time detected (>1s average)'); } if (monitor.largestPayload > 1024 * 1024) { // 1MB performanceIssues.push(`Large payload detected (${(monitor.largestPayload / (1024 * 1024)).toFixed(1)}MB)`); } // Check for frequent errors const errorCount = monitor.invocations.filter(i => i.error).length; const errorRate = monitor.totalInvocations > 0 ? (errorCount / monitor.totalInvocations) * 100 : 0; if (errorRate > 10) { performanceIssues.push(`High error rate: ${errorRate.toFixed(1)}%`); } if (performanceIssues.length > 0) { content += '**🔴 Performance Issues:**\n'; performanceIssues.forEach(issue => { content += `- ${issue}\n`; }); content += '\n'; } // Recommendations content += '**💡 Recommendations:**\n'; if (monitor.avgExecutionTime > 500) { content += '- Consider optimizing database queries in server actions\n'; content += '- Use caching for frequently accessed data\n'; } if (monitor.largestPayload > 512 * 1024) { // 512KB content += '- Reduce payload sizes by paginating results\n'; content += '- Consider streaming responses for large data sets\n'; } if (errorRate > 5) { content += '- Add better error handling and validation\n'; content += '- Log errors for debugging\n'; } // Check for missing revalidations const actionsWithoutRevalidation = monitor.invocations.filter(i => !i.error && (!i.revalidations || i.revalidations.length === 0)).length; if (actionsWithoutRevalidation > monitor.totalInvocations * 0.5) { content += '- Consider adding revalidatePath() or revalidateTag() to update cached data\n'; } return { content: [{ type: 'text', text: content.trim() }] }; } catch (error) { throw new Error(`Failed to monitor server actions: ${error instanceof Error ? error.message : String(error)}`); } } } //# sourceMappingURL=nextjs-runtime-handler.js.map