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
297 lines • 14.3 kB
JavaScript
import { BaseToolHandler } from '../base-handler.js';
import { SessionDebugFixes } from '../session-debug-fixes.js';
import { SessionStabilityManager } from '../session-stability-manager.js';
import * as fmt from './nextjs-formatter-utils.js';
/**
* Handler for Next.js core information tools (page info, config, app router)
*/
export class NextJSCoreInfoHandler extends BaseToolHandler {
nextjsEngine;
constructor(nextjsEngine) {
super();
this.nextjsEngine = nextjsEngine;
}
tools = [
{
name: 'nextjs_page_info',
description: 'Get information about current Next.js page including rendering type (SSR/SSG/ISR/RSC) and data fetching methods.',
inputSchema: {
type: 'object',
properties: {
sessionId: { type: 'string', description: 'Debug session ID' }
},
required: ['sessionId']
}
},
{
name: 'nextjs_config',
description: 'Get comprehensive Next.js configuration including version, router type, build mode, and experimental features.',
inputSchema: {
type: 'object',
properties: {
sessionId: { type: 'string', description: 'Debug session ID' }
},
required: ['sessionId']
}
},
{
name: 'nextjs_app_router_info',
description: 'Get App Router information including current route, params, search params, layout nesting, parallel routes, and intercepted routes.',
inputSchema: {
type: 'object',
properties: {
sessionId: { type: 'string', description: 'Debug session ID' }
},
required: ['sessionId']
}
}
];
async handle(toolName, args, sessions) {
let session;
try {
// Enhanced session validation with detailed debugging
SessionDebugFixes.validateSessionStorage(args.sessionId, sessions);
session = this.getSession(args.sessionId, sessions);
// P0 FIX: Enhanced session health validation with auto-recovery
const healthResult = await SessionStabilityManager.validateSessionWithRecovery(session, sessions, { timeoutMs: 5000, maxRetries: 2 });
if (!healthResult.isHealthy) {
return SessionStabilityManager.createRecoveryErrorResponse(args.sessionId, new Error('Session validation failed after recovery attempts'), true);
}
// Use recovered session if recovery occurred
session = healthResult.session;
}
catch (error) {
return SessionDebugFixes.createDetailedErrorResponse(error, 'NextJS Core Info', args.sessionId);
}
// Framework validation should throw directly (not wrapped in detailed response)
this.validateNextJSSession(session);
try {
switch (toolName) {
case 'nextjs_page_info':
return this.getPageInfo(args, session);
case 'nextjs_config':
return this.getConfig(args, session);
case 'nextjs_app_router_info':
return this.getAppRouterInfo(args, session);
default:
throw new Error(`Unknown Next.js core info tool: ${toolName}`);
}
}
catch (error) {
// Only wrap handler execution errors, not validation errors
return SessionDebugFixes.createDetailedErrorResponse(error, 'NextJS Core Info', args.sessionId);
}
}
validateNextJSSession(session) {
const { framework, isNextJS } = session;
if (framework !== 'nextjs' && framework !== 'next' && !(framework === 'react' && isNextJS)) {
throw new Error('This tool only works with Next.js applications');
}
}
async getPageInfo(args, session) {
try {
// Use safe page info extraction
const safeInfo = await SessionDebugFixes.safePageInfoExtraction(session.page);
const info = await this.nextjsEngine.getPageInfo(session);
// Merge safe extraction with engine results
const mergedInfo = {
path: safeInfo.pathname || info?.path || 'Unknown',
renderingType: info?.renderingType || 'Unknown',
url: safeInfo.url || session.url || 'Unknown',
title: safeInfo.title || 'Unknown',
...info,
...safeInfo
};
const sections = [
'📄 **Next.js Page Information**',
'',
fmt.formatKeyValue('Path', mergedInfo.path),
fmt.formatKeyValue('URL', mergedInfo.url),
fmt.formatKeyValue('Title', mergedInfo.title),
fmt.formatKeyValue('Rendering Type', `${mergedInfo.renderingType} (${fmt.RENDERING_DESCRIPTIONS[mergedInfo.renderingType] || 'Unknown'})`),
''
];
// Data fetching
if (info.dataFetchingMethods?.length > 0) {
sections.push(...fmt.formatSection('**Data Fetching Methods:**', fmt.formatList(info.dataFetchingMethods)));
}
else if (info.dataFetching?.length > 0) {
// Handle alternate property name
sections.push(...fmt.formatSection('**Data Fetching:**', fmt.formatList(info.dataFetching)));
}
// Router type for App Router
if (info.isAppRouter) {
sections.push('**Router:** App Router');
}
// Server component indicator
if (info.isServerComponent) {
sections.push('**Component Type:** Server Component');
}
// Has layout
if (info.hasLayout !== undefined) {
sections.push(fmt.formatKeyValue('Has Layout', info.hasLayout ? 'Yes' : 'No'));
}
// Metadata and performance
sections.push(...fmt.formatMetadata(info.metadata));
sections.push(...fmt.formatPerformance(info.performance));
// Recommendations
const recommendations = [];
if (info.renderingType === 'CSR' && !info.hasLayout) {
recommendations.push('Consider using SSG or SSR for better SEO and initial load performance');
}
if (info.performance?.lcp > 2500) {
recommendations.push('LCP is above 2.5s threshold. Optimize largest content paint');
}
if (!info.metadata?.description) {
recommendations.push('Add meta description for better SEO');
}
sections.push(...fmt.formatRecommendations(recommendations));
return this.createTextResponse(sections.join('\n').trim());
}
catch (error) {
throw new Error(`Failed to get page information: ${error instanceof Error ? error.message : String(error)}`);
}
}
async getConfig(args, session) {
try {
const config = await this.nextjsEngine.getConfig();
if (!config) {
return this.createTextResponse('❌ **Next.js Configuration**\n\nCould not retrieve Next.js configuration.');
}
const sections = ['🔧 **Next.js Configuration**', ''];
// Basic info
if (config.version)
sections.push(fmt.formatKeyValue('Version', config.version));
sections.push(fmt.formatKeyValue('Router Type', config.rendering), fmt.formatKeyValue('Build Mode', config.buildMode || 'Unknown'), '');
// Configuration details
const configItems = [];
// React Strict Mode - show enabled/disabled
if (config.config?.reactStrictMode) {
configItems.push('React Strict Mode: Enabled');
}
else {
configItems.push('React Strict Mode: Disabled');
}
// Other config items
configItems.push(...fmt.formatConfigItems(config.config, [
['poweredByHeader', 'X-Powered-By header', true],
['compress', 'Compression'],
['swcMinify', 'SWC Minification']
]));
// Experimental features
if (config.config?.experimental) {
configItems.push(...fmt.formatConfigItems(config.config.experimental, [
['appDir', 'App Directory: Enabled (experimental)'],
['serverActions', 'Server Actions'],
['ppr', 'Partial Prerendering']
]));
}
if (configItems.length > 0) {
sections.push(...fmt.formatSection('**Configuration:**', fmt.formatList(configItems)));
}
// Additional configs
this.addImageConfig(sections, config.config?.images);
sections.push(...fmt.formatConfigItems(config.config, [
['basePath', '- Base Path'],
['assetPrefix', '- Asset Prefix']
]));
if (config.config?.i18n) {
const locales = config.config.i18n.locales?.join(', ') || config.config.i18n.defaultLocale;
sections.push(`- i18n: Enabled (${locales})`);
}
// Count configurations
sections.push(...fmt.formatList(fmt.formatCountItems(config.config, [
['redirects', 'Redirects'],
['rewrites', 'Rewrites'],
['headers', 'Custom Headers']
])));
// Note: webpack configuration detection not available in enhanced engine
// Recommendations
const recommendations = this.getConfigRecommendations(config);
sections.push(...fmt.formatRecommendations(recommendations));
return this.createTextResponse(sections.join('\n').trim());
}
catch (error) {
throw new Error(`Failed to get Next.js config: ${error instanceof Error ? error.message : String(error)}`);
}
}
addImageConfig(sections, images) {
if (!images)
return;
sections.push('- Image Optimization:');
if (images.domains?.length > 0)
sections.push(` - Allowed domains: ${images.domains.join(', ')}`);
if (images.deviceSizes)
sections.push(` - Device sizes: ${images.deviceSizes.join(', ')}`);
if (images.imageSizes)
sections.push(` - Image sizes: ${images.imageSizes.join(', ')}`);
}
getConfigRecommendations(config) {
const recommendations = [];
if (!config.config?.reactStrictMode && config.buildMode === 'development') {
recommendations.push('Enable React Strict Mode for better development experience');
}
if (config.version) {
const versionParts = config.version.split('.').map(Number);
if (versionParts[0] < 13) {
recommendations.push('Consider upgrading to Next.js 13+ for App Router and improved performance');
}
}
if (!config.config?.images?.domains) {
recommendations.push('Configure image domains for optimized external images');
}
return recommendations;
}
async getAppRouterInfo(args, session) {
try {
const info = await this.nextjsEngine.getAppRouterInfo();
if (!info) {
return this.createTextResponse('🚦 **Next.js App Router Information**\n\n' +
'❌ This application is using Pages Router, not App Router.\n\n' +
'App Router is available in Next.js 13.4+ and provides:\n' +
'- React Server Components\n- Nested layouts\n- Improved data fetching\n' +
'- Built-in loading and error states\n\n' +
'To migrate to App Router, create an `app` directory in your project root.');
}
const sections = [
'🚦 **Next.js App Router Information**',
'',
fmt.formatKeyValue('Current Route', info.currentRoute || 'Unknown'),
''
];
// Route params and search params
sections.push(...fmt.formatParams(info.params, 'Route Parameters'));
sections.push(...fmt.formatParams(info.searchParams, 'Search Parameters'));
// Additional info
sections.push(fmt.formatKeyValue('Layout Nesting', `${info.layoutNesting} level${info.layoutNesting !== 1 ? 's' : ''}`));
const routeInfo = [
[info.parallelRoutes, 'Parallel Routes'],
[info.routeGroups, 'Route Groups'],
[info.dynamicSegments, 'Dynamic Segments']
];
routeInfo.forEach(([data, label]) => {
if (data && data.length > 0) {
sections.push(fmt.formatKeyValue(label, data.join(', ')));
}
});
if (info.interceptedRoutes > 0) {
sections.push(fmt.formatKeyValue('Intercepted Routes', info.interceptedRoutes));
}
// Recommendations
const recommendations = this.getAppRouterRecommendations(info);
sections.push(...fmt.formatRecommendations(recommendations));
return this.createTextResponse(sections.join('\n').trim());
}
catch (error) {
throw new Error(`Failed to get App Router information: ${error instanceof Error ? error.message : String(error)}`);
}
}
getAppRouterRecommendations(info) {
return [
...(info.layoutNesting > 5 ? ['Deep layout nesting detected. Consider flattening for better performance'] : []),
...(info.parallelRoutes?.length > 3 ? ['Many parallel routes detected. Ensure they\'re necessary for UX'] : []),
...(!info.routeGroups?.length ? ['Consider using route groups to organize related routes'] : [])
];
}
}
//# sourceMappingURL=nextjs-core-info-handler.js.map