mcp-server-skills について
Next.js App RouterプロジェクトでMCPサーバーを構成するための開発ガイドです。MCPルート、Server Actions、Web UIのテストでツールロジックとZodスキーマを再利用します。
主な機能
- 01Zodスキーマとツールロジックの共有
- 02軽量なMCPルートの接続
- 03Server Actionsでロジックを再利用
- 04HTTP・SSEトランスポート対応
- 05Web UIからのテスト
活用シーン
- 01Next.jsアプリでのMCPサーバー構築
- 02UIとMCPの入力検証の統一
- 03Server Actionsを使ったツール動作のテスト
MCP 対応
MCPハンドラーを使い、HTTPまたはSSE経由でツールを公開する構成を説明します。mcp-remoteを使ってClaude Desktopクライアントをルートに接続する方法も扱います。
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ gocallum/ nextjs16-agent-skills --skill mcp-server-skillsインストール後、Claude Code で/mcp-server-skillsを入力して読み込まれたか確認します。
詳細
リンク
- 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
フォルダー構成(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 testing
目標: route.ts は最小限に保ちます。ロジックと Zod スキーマは lib/* に配置し、MCP ハンドラーとサーバーアクションの両方が単一の信頼できる情報源を共有するようにします。
共有 Zod スキーマとツール定義
// 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;
再利用可能なサーバーアクション(Web UI + テスト)
// 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 を支え、レスポンスの一貫性を保ちます。
軽量な MCP ルート
// 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 };
パターンの主なポイント
- ルートは
createMcpHandlerの接続のみを行い、ビジネスロジックを直接記述しません。 server.toolは共有ツールスキーマと説明を使用し、共有ロジックを呼び出します。basePathはフォルダー構成に合わせます(例:/api/[transport])。- SSE/HTTP トランスポートで動作し、必要に応じて stdio を別途追加できます。
Claude Desktop の設定(mcp-remote)
{
"mcpServers": {
"rolldice": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:3000/api/mcp"]
}
}
}
ベストプラクティス
- 単一の信頼できる情報源 — スキーマとロジックは
lib/*に配置し、MCP ツールとサーバーアクションの両方からインポートします。 - まずは検証 — 入力には Zod を使用し、同じスキーマを UI と MCP で再利用します。
- route.ts は軽量に保つ — ハンドラーの接続、ログ記録、トランスポート設定のみを行います。
- レスポンスを共有 — ツールと UI で
{ success, result | error }の形式を標準化します。 - Vercel に適した構成 — 状態を持つグローバル変数を避け、必要に応じて
maxDurationとruntimeを設定します。 - 複数のトランスポート — HTTP/SSE 用に
/api/[transport]を公開し、必要に応じて stdio のエントリーポイントを追加します。 - ローカルテスト — Web UI からサーバーアクションを呼び出し、MCP のレスポンスとの同期を確認します。
コメント
Markdown 対応