mcp-server-skills
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLinks
链接
- Model Context Protocol: https://modelcontextprotocol.io/
- mcp-handler (HTTP): https://www.npmjs.com/package/mcp-handler
- Reference implementation (Roll Dice): https://github.com/gocallum/rolldice-mcpserver
- Claude Desktop + mcp-remote bridge: https://www.npmjs.com/package/mcp-remote
- Model Context Protocol: https://modelcontextprotocol.io/
- mcp-handler (HTTP): https://www.npmjs.com/package/mcp-handler
- 参考实现(掷骰子): https://github.com/gocallum/rolldice-mcpserver
- Claude Desktop + mcp-remote 桥接工具: https://www.npmjs.com/package/mcp-remote
Folder Structure (Next.js App Router)
文件夹结构(Next.js App Router)
app/
api/[transport]/route.ts # One handler for all transports (e.g., /api/mcp)
actions/mcp-actions.ts # Server actions reusing the same logic/schemas
lib/
dice.ts | tools.ts # Zod schemas, tool definitions, pure logic
components/ # UI that calls server actions for web testingGoal: Keep minimal. Put logic + Zod schemas in so both the MCP handler and server actions share a single source of truth.
route.tslib/*app/
api/[transport]/route.ts # 处理所有传输方式的统一处理器(例如:/api/mcp)
actions/mcp-actions.ts # 复用相同逻辑/模式的服务器操作
lib/
dice.ts | tools.ts # Zod模式、工具定义、纯逻辑
components/ # 调用服务器操作进行Web测试的UI组件目标: 保持尽可能简洁。将逻辑和Zod模式放在目录下,让MCP处理器和服务器操作共享单一数据源。
route.tslib/*Shared Zod Schema + Tool Definition
共享Zod模式与工具定义
ts
// lib/dice.ts
import { z } from "zod";
export const diceSchema = z.number().int().min(2);
export function rollDice(sides: number) {
const validated = diceSchema.parse(sides);
const value = 1 + Math.floor(Math.random() * validated);
return { type: "text" as const, text: `🎲 You rolled a ${value}!` };
}
export const rollDiceTool = {
name: "roll_dice",
description: "Rolls an N-sided die",
schema: { sides: diceSchema },
} as const;ts
// lib/dice.ts
import { z } from "zod";
export const diceSchema = z.number().int().min(2);
export function rollDice(sides: number) {
const validated = diceSchema.parse(sides);
const value = 1 + Math.floor(Math.random() * validated);
return { type: "text" as const, text: `🎲 You rolled a ${value}!` };
}
export const rollDiceTool = {
name: "roll_dice",
description: "Rolls an N-sided die",
schema: { sides: diceSchema },
} as const;Reusable Server Actions (Web UI + Tests)
可复用服务器操作(Web UI与测试)
ts
// 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"],
},
},
],
},
};
}Server actions call the same logic as the MCP handler and power the web UI, keeping responses aligned.
ts
// 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"],
},
},
],
},
};
}服务器操作调用与MCP处理器相同的逻辑,为Web UI提供支持,确保响应一致。
Lightweight MCP Route
轻量级MCP路由
ts
// 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 };Pattern highlights
- Route only wires ; no business logic inline.
createMcpHandler - consumes the shared tool schema/description and calls shared logic.
server.tool - should align with the folder (e.g.,
basePath)./api/[transport] - Works for SSE/HTTP transports; stdio can be added separately if needed.
ts
// 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)] }),
);
},
{}, // 服务器选项
{
basePath: "/api", // 必须与文件夹路径匹配
maxDuration: 60,
verboseLogs: true,
},
);
export { handler as GET, handler as POST };方案亮点
- 路由仅负责连接;无内联业务逻辑。
createMcpHandler - 使用共享的工具模式/描述,并调用共享逻辑。
server.tool - 应与文件夹路径对齐(例如:
basePath)。/api/[transport] - 支持SSE/HTTP传输方式;若需要可单独添加stdio入口。
Claude Desktop Config (mcp-remote)
Claude Desktop配置(mcp-remote)
jsonc
{
"mcpServers": {
"rolldice": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:3000/api/mcp"]
}
}
}jsonc
{
"mcpServers": {
"rolldice": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:3000/api/mcp"]
}
}
}Best Practices
最佳实践
- Single source of truth — schemas + logic in ; both MCP tools and server actions import them.
lib/* - Validation first — use Zod for inputs and reuse the same schema for UI + MCP.
- Keep route.ts light — only handler wiring, logging, and transport config.
- Shared responses — standardize shapes for tools and UI.
{ success, result | error } - Vercel-friendly — avoid stateful globals; configure and
maxDurationif needed.runtime - Multiple transports — expose for HTTP/SSE; add stdio entrypoint when required.
/api/[transport] - Local testing — hit server actions from the web UI to ensure MCP responses stay in sync.
- 单一数据源 — 模式与逻辑放在中;MCP工具和服务器操作均从这里导入。
lib/* - 优先验证 — 使用Zod处理输入,并为UI和MCP复用相同的模式。
- 保持route.ts轻量化 — 仅包含处理器连接、日志记录和传输配置。
- 共享响应格式 — 为工具和UI标准化的结构。
{ success, result | error } - 适配Vercel — 避免有状态的全局变量;必要时配置和
maxDuration。runtime - 多传输方式 — 暴露以支持HTTP/SSE;需要时添加stdio入口点。
/api/[transport] - 本地测试 — 从Web UI调用服务器操作,确保MCP响应保持同步。