@ai-mapping/mcp-nextjs-dev
Version:
MCP server for managing Next.js development processes with AI tools
226 lines • 7.6 kB
JavaScript
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