OverviewHistoryStatsSecurity
npx skills add ...
Documentation
SKILL.md
npx skills add gocallum/nextjs16-agent-skills --skill mcp-server-skills
Pattern for building MCP servers in Next.js with mcp-handler, shared Zod schemas, and reusable server actions.
npx skills add gocallum/nextjs16-agent-skills --skill mcp-server-skills
Goal: Keep route.ts minimal. Put logic + Zod schemas in lib/* so both the MCP handler and server actions share a single source of truth.
Server actions call the same logic as the MCP handler and power the web UI, keeping responses aligned.
Pattern highlights
createMcpHandler; no business logic inline.server.tool consumes the shared tool schema/description and calls shared logic.basePath should align with the folder (e.g., /api/[transport]).lib/*; both MCP tools and server actions import them.{ success, result | error } shapes for tools and UI.maxDuration and runtime if needed./api/[transport] for HTTP/SSE; add stdio entrypoint when required.// app/actions/mcp-actions.ts
"use server";
import { rollDice as rollDiceCore, rollDiceTool } from "@/lib/dice";
export async function rollDice(sides: number) {
try {
const result = rollDiceCore(sides);
return { success: true, result: { content: [result] } };
} catch {
return {
success: false,
error: { code: -32602, message: "Invalid parameters: sides must be >= 2" },
};
}
}
export async function listTools() {
return {
success: true,
result: {
tools: [
{
name: rollDiceTool.name,
description: rollDiceTool.description,
inputSchema: {
type: "object",
properties: { sides: { type: "number", minimum: 2 } },
required: ["sides"],
},
},
],
},
};
}// app/api/[transport]/route.ts
import { createMcpHandler } from "mcp-handler";
import { rollDice, rollDiceTool } from "@/lib/dice";
const handler = createMcpHandler(
(server) => {
server.tool(
rollDiceTool.name,
rollDiceTool.description,
rollDiceTool.schema,
async ({ sides }) => ({ content: [rollDice(sides)] }),
);
},
{}, // server options
{
basePath: "/api", // must match folder path
maxDuration: 60,
verboseLogs: true,
},
);
export { handler as GET, handler as POST };{
"mcpServers": {
"rolldice": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:3000/api/mcp"]
}
}
}