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