UNPKG

@ai-mapping/mcp-nextjs-dev

Version:

MCP server for managing Next.js development processes with AI tools

226 lines 7.6 kB
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z } from 'zod'; import { StateManager } from './managers/state-manager.js'; import { ProcessManager } from './managers/process-manager.js'; const stateManager = StateManager.getInstance(); const processManager = ProcessManager.getInstance(); const server = new McpServer({ name: 'mcp-nextjs-dev', version: '1.0.0', }); async function startNextJsProcess(projectPath, script) { let port = 3000; if (script) { const portMatch = script.match(/--port\s+(\d+)/); if (portMatch && portMatch[1]) { port = parseInt(portMatch[1], 10); } } const options = { projectPath, port, turbo: false, ...(script ? { script } : {}), }; const result = await processManager.startNextJsProcess(options); return { processId: result.processId, serverUrl: result.serverUrl, message: `Next.js development server started on port ${result.port}`, }; } function getFilteredLogs(params) { const logs = stateManager.getLogs(params); return { entries: logs.entries, total: logs.total, serverRunning: logs.serverRunning, }; } async function stopNextJsProcess(force, timeout) { return await processManager.stopNextJsProcess(force, timeout); } function getServerStatus() { const processInfo = processManager.getProcessInfo(); const status = stateManager.getStatus(); if (processInfo.isRunning && processInfo.pid !== undefined) { status.processId = processInfo.pid; } return status; } function registerNextJsTools(server) { server.tool('nextjs_dev_start', { projectPath: z.string().optional().default('.'), script: z.string().optional().describe('Script command to run (default: "pnpm run dev"). Include port in the command, e.g., "pnpm run dev -- --port 3001"'), }, async ({ projectPath, script }) => { try { const result = await startNextJsProcess(projectPath, script); return { content: [ { type: 'text', text: JSON.stringify({ success: true, processId: result.processId, serverUrl: result.serverUrl, message: result.message, }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error', }, null, 2), }, ], isError: true, }; } }); server.tool('nextjs_get_logs', { lines: z.number().max(1000).optional().default(50), filter: z.string().optional(), level: z.enum(['error', 'warn', 'info', 'all']).optional().default('all'), since: z.number().optional(), }, ({ lines, filter, level, since }) => { try { const logs = getFilteredLogs({ lines, filter, level, since, }); return { content: [ { type: 'text', text: JSON.stringify({ success: true, logs: logs.entries, totalLines: logs.total, serverRunning: logs.serverRunning, }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error', }, null, 2), }, ], isError: true, }; } }); server.tool('nextjs_get_status', {}, async () => { try { const status = await Promise.resolve(getServerStatus()); return { content: [ { type: 'text', text: JSON.stringify({ isRunning: status.isRunning, processId: status.processId, serverUrl: status.serverUrl, uptime: status.uptime, port: status.port, logCount: status.logCount, }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ isRunning: false, error: error instanceof Error ? error.message : 'Unknown error', }, null, 2), }, ], isError: true, }; } }); server.tool('nextjs_stop_server', { force: z.boolean().optional().default(false), timeout: z.number().optional().default(5), }, async ({ force, timeout }) => { try { const result = await stopNextJsProcess(force, timeout); return { content: [ { type: 'text', text: JSON.stringify({ success: true, wasRunning: result.wasRunning, message: result.message, }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error', }, null, 2), }, ], isError: true, }; } }); } export async function startServer() { try { registerNextJsTools(server); const transport = new StdioServerTransport(); await server.connect(transport); process.on('SIGINT', () => { processManager.cleanup(); process.exit(0); }); process.on('SIGTERM', () => { processManager.cleanup(); process.exit(0); }); console.error('MCP Server started successfully'); } catch (error) { console.error('Failed to start MCP server:', error); process.exit(1); } } export { server }; if (import.meta.url === `file://${process.argv[1]}`) { startServer().catch((error) => { console.error('Server error:', error); process.exit(1); }); } //# sourceMappingURL=server.js.map