「Next.js MCP server」で検索すると、同じ名前を共有する2つの異なる役割にたどり着きます。1つは、開発中のNext.jsアプリの内部をコーディングエージェントに把握させたいというもの。ページ上のエラー、ルート、ビルドの問題などです。もう1つは、自分のNext.jsアプリをMCP serverに変えて、ClaudeやChatGPTがサイトの提供するツールを呼び出せるようにしたいというものです。私たちが読んだほとんどのページは片方だけを扱ってもう片方を曖昧にしたままで、しかも多くが2つ目の役割についてライブラリの古いバージョンを示しています。
このガイドでは両方を扱います。以下のコマンドとコードサンプルはすべて、2026年11月14日にmacOS上で、Next.js 16.4.6、next-devtools-mcp 0.4.0、mcp-handler 2.4.0、@modelcontextprotocol/server 2.4.0、zod 4.6.7を使って実行しました。結果がドキュメントと異なった箇所では、その旨を明記します。
どちらが必要ですか?
| やりたいこと | 使うもの | 実行場所 | AI が得られるもの |
|---|---|---|---|
| 開発中のアプリを Claude Code、Cursor、Codex にデバッグさせたい | 組み込みの /_next/mcp と next-devtools-mcp |
自分のマシン、next dev のみ |
リアルタイムのエラー、ルート、ログ、コンパイルチェック、バージョンに一致したドキュメント |
| 自社プロダクトのツール(検索、注文、ドキュメント)を AI アプリに提供したい | mcp-handler を使った独自ルート |
アプリがデプロイされている場所 | 自分で書いたツールのみ |
| 両方 | 両方、競合しません |
迷ったら、おそらく最初の選択肢です。コマンド 1 つで済み、コードは不要です。
Part 1: コーディングエージェントを実行中の Next.js アプリに接続する
Next.js 16 が /_next/mcp で公開するもの
Next.js 16 以降、next dev は /_next/mcp で MCP リクエストに応答します。これはデフォルトで有効です。curl で tools/list を送ったところ、9 つのツールが返ってきました:
| ツール | 返す内容 | 必要なもの |
|---|---|---|
get_errors |
現在のエラー: next.config の検証、ブラウザのランタイムエラー、ソースマップ付きのビルドエラー |
ランタイムエラーにはブラウザで開いているページ |
get_logs |
ブラウザコンソールとサーバー出力を含む開発ログファイルのパス | |
get_page_metadata |
現在のページレンダリングに寄与したもの | ブラウザで開いているページ |
get_project_metadata |
プロジェクトのパスと開発サーバーの URL | |
get_routes |
appRouter と pagesRouter でグループ化されたすべてのルート。動的セグメントは [param] として表示 |
|
get_server_action_by_id |
Server Action のソースファイルとエクスポート名 | |
get_compilation_issues |
すべてのルートにわたる resolve エラー、モジュールの欠落、transform エラー | Turbopack |
compile_route |
リクエストせずに 1 つのルートをコンパイル | Turbopack |
get_request_insights |
最近のリクエストのタイムライン、fetch、キャッシュの挙動 | experimental.requestInsights |
サーバーは自身を「Next.js MCP Server」バージョン 0.2.0 と名乗っていました。2 ページのテストアプリでは、get_routes は作成したとおり / と /api/mcp を返しました。
コンパイル系のツールは地味な収穫です。3 つのファイルを編集したばかりのエージェントは、コードが半分しかできていない状態で next build 全体を開始する代わりに、実行中の開発サーバーにコンパイルできるかどうかを尋ねられます。
頼る前に知っておくべき制限が 2 つあります。まず開発時のみ存在します。同じアプリをビルドして next start を実行したところ、/_next/mcp は 404 を返しました。次に Next.js 16 が必要です。15 ではそのパスに何もありません。npx @next/codemod@latest upgrade latest がツール自体が提案するアップグレード方法です。
無効にするには、next.config で experimental.mcpServer を false に設定します。
next-devtools-mcp をインストールする
エージェントは /_next/mcp と直接通信しません。next-devtools-mcp パッケージは、実行中の開発サーバーを見つけて呼び出しを転送する小さな stdio サーバーです。バージョン 0.4.0 以降は 4 つのツールを持つ薄いコネクタです:
nextjs_indexは実行中の Next.js 開発サーバーと、それぞれが公開するツールを一覧表示します。nextjs_callはportとtoolNameを指定して、サーバー上のツールの 1 つを実行します。nextjs_docsは、インストール済みの Next.js 内のnode_modules/next/dist/docs/にあるドキュメントへエージェントを導き、回答がバージョンと一致するようにします。browser_evalは、実際のブラウザでページを確認するためにagent-browserCLI へエージェントを導きます。
Node.js 20.19 以降が必要です。クライアントを選んでください:
Claude Code
claude mcp add next-devtools npx next-devtools-mcp@latest
Codex
codex mcp add next-devtools -- npx next-devtools-mcp@latest
Windows 11 では、README によると Codex は .codex/config.toml に env = { SystemRoot="C:\\Windows", PROGRAMFILES="C:\\Program Files" } と startup_timeout_ms = 20_000 も必要です。
Gemini CLI
gemini mcp add next-devtools npx next-devtools-mcp@latest
現在のプロジェクトだけでなくすべてのプロジェクトにインストールするには、-s user を追加します。
VS Code with Copilot
code --add-mcp '{"name":"next-devtools","command":"npx","args":["-y","next-devtools-mcp@latest"]}'
Cursor、または JSON ファイルを読む任意のクライアント
{
"mcpServers": {
"next-devtools": {
"command": "npx",
"args": ["-y", "next-devtools-mcp@latest"]
}
}
}
プロジェクトルートの .mcp.json に置けば git 経由でチームと共有でき、Cursor だけで使うなら ~/.cursor/mcp.json に置きます。
すべてのエージェントに一度に
npx add-mcp next-devtools-mcp@latest
add-mcp はマシン上で見つけたすべてのコーディングエージェントにエントリを書き込みます。
動作を確認する
まず開発サーバーを起動します。次に、get_errors と get_page_metadata はライブのブラウザセッションから読み取るため、作業中のページをブラウザで開きます。そして、実行中のアプリだけが知っていることをエージェントに尋ねます:
- 「アプリに今どんなエラーがありますか?」
- 「ルートを一覧にして、どれが動的か教えてください。」
- 「
/blog/[slug]はコンパイルできますか?」
Claude Code では、nextjs_index の呼び出しに続いて toolName: "get_errors" を指定した nextjs_call が表示されます。エージェントが代わりにファイルを読んで答えるなら、接続されていません。
エージェントなしでエンドポイントを確認することもできます:
curl -s -X POST http://localhost:3000/_next/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
ツールの一覧が返れば Next.js は正常で、問題があるとすればエージェントと next-devtools-mcp の間です。
遭遇したこと: 別ポートの開発サーバー
テストアプリはポート 3000 が使用中だったため、ポート 3417 で動いていました。nextjs_index はそれを見つけられませんでした。代わりに、たまたま 3000 で動いていた別のプロジェクトを見つけました。
パッケージのソースを読むと理由がわかりました。macOS と Linux では、next-devtools-mcp 0.4.0 はまず正確に next-server という名前のプロセスを探します。私たちの Mac ではプロセス名が next-server (v16.4.6) なのでこのマッチは失敗し、パッケージはポート 3000 から 3010 のプローブにフォールバックしました。それ以外のポートの開発サーバーは見えません。
修正は簡単です。nextjs_call はポートを直接受け取るので、渡したとたん 3417 で動作しました:
{ "port": 3417, "toolName": "get_routes" }
複数のプロジェクトを動かしている場合やカスタムポートを使っている場合は、エージェントに一度「開発サーバーはポート 3417 です」と伝えてください。そのポートでツールを呼び出します。プロジェクトを 3000 から 3010 の範囲に収めておくのも問題を避ける方法です。
パート2: Next.js アプリ内に独自の MCP server を構築する
ここでは別の意味になります。あなたの Next.js アプリが、Claude、Cursor、ChatGPT から URL で接続できるものになるということです。典型的なツールは、コンテンツの検索、データベースの参照、サポートチケットの作成のようなアクションです。
Vercel の mcp-handler がプロトコル部分を担います。サーバー定義を素の (Request) => Response 関数に変換するもので、これはまさに Next.js の Route Handler がエクスポートする形です。
バージョン 2 では大きく変わりました
ほとんどのチュートリアルはまだバージョン 1 を扱っており、Redis、SSE エンドポイント、[transport] 動的ルートを前提としています。バージョン 2 はよりシンプルで、古いスニペットはそのままでは動きません。
| mcp-handler 1.x | mcp-handler 2.x | |
|---|---|---|
| SDK パッケージ | @modelcontextprotocol/sdk 1.x |
@modelcontextprotocol/server 2.x |
| zod | 3 | 4.2 以降 |
| Node.js | 20 以降 | |
| トランスポート | Streamable HTTP と SSE | Streamable HTTP のみ、ステートレス |
| Redis | SSE に必要 | 使用しない |
| ルーティングオプション | basePath、maxDuration、redisUrl など |
削除済み: 任意のルートにハンドラーをマウントする |
1.x を使い続ける場合は、@modelcontextprotocol/sdk を 1.26.0 以降に保ってください。mcp-handler の README は、それ以前の SDK バージョンにセキュリティ脆弱性があると指摘しています。
インストール
npm install mcp-handler@^2 @modelcontextprotocol/server@^2 zod@^4
ルート
app/api/mcp/route.ts を作成します。これは AI クライアントにブログ記事の検索を提供するものです。配列はデータベースや CMS に置き換えてください。
import { createMcpHandler } from "mcp-handler";
import { z } from "zod";
const posts = [
{ slug: "edge-caching", title: "Caching at the edge", body: "How we cache HTML at the edge for 10 minutes." },
{ slug: "image-sizes", title: "Picking image sizes", body: "Three widths cover most layouts." },
];
const handler = createMcpHandler(
(server) => {
server.registerTool(
"search_posts",
{
title: "Search posts",
description: "Find blog posts whose title or body contains the query.",
inputSchema: z.object({ query: z.string().min(2) }),
},
async ({ query }) => {
const q = query.toLowerCase();
const hits = posts.filter((p) => `${p.title} ${p.body}`.toLowerCase().includes(q));
return {
content: [{ type: "text", text: hits.length ? hits.map((p) => `${p.title} (/blog/${p.slug})`).join("\n") : "No posts found." }],
};
},
);
},
{ serverInfo: { name: "my-blog", version: "1.0.0" } },
);
export { handler as GET, handler as POST };
/api/mcp はあくまで慣例です。ハンドラーはパスを参照しないため、app/mcp/route.ts でも問題なく動作します。選んだルートの完全な URL をクライアントに渡してください。
serverInfo を設定してください。これがないと、私たちのサーバーはクライアントに対して「mcp-typescript server on vercel」と名乗り、ユーザーにはクライアントのサーバー一覧にそう表示されます。
curl でテストする
npm run dev を実行した状態で、次の 3 つのリクエストで一連のやり取りが完結します。私たちは上のルートに対して実行しました。
curl -s -X POST http://localhost:3000/api/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'
応答は "serverInfo":{"name":"my-blog","version":"1.0.0"} を含む 1 つの server-sent event として返ってきました。ボディを {"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}} に置き換えると、JSON Schema 付きの search_posts が確認できます。ツールを実行するには次のボディを使います。
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"search_posts","arguments":{"query":"edge"}}}
結果は Caching at the edge (/blog/edge-caching) でした。ルートへの素の GET は 405 を返しましたが、これは想定どおりです。バージョン 2 はステートレスで、開いたままにする長寿命のストリームが存在しません。
curl ではなくクリック操作で確認したい場合は、MCP Inspector も使えます。npx @modelcontextprotocol/inspector を実行し、Streamable HTTP トランスポートで http://localhost:3000/api/mcp に接続してください。
クライアントを接続する
Streamable HTTP に対応したクライアントは URL で接続します。
Claude Code
claude mcp add --transport http my-blog http://localhost:3000/api/mcp
Cursor (~/.cursor/mcp.json)
{
"mcpServers": {
"my-blog": { "url": "http://localhost:3000/api/mcp" }
}
}
VS Code (.vscode/mcp.json)
{
"servers": {
"my-blog": { "type": "http", "url": "http://localhost:3000/api/mcp" }
}
}
Claude Desktop はリモートサーバーを Settings › Connectors から読み込みます。claude_desktop_config.json でローカル URL を使う場合は、mcp-remote でブリッジします。
{
"mcpServers": {
"my-blog": { "command": "npx", "args": ["-y", "mcp-remote", "http://localhost:3000/api/mcp"] }
}
}
デプロイ後は、localhost の URL を https://your-app.vercel.app/api/mcp のような実際の URL に置き換えてください。サーバーを登録していただければ、私たちの設定ビルダーが 15 のクライアント向けにこれらのスニペットを生成します。
デプロイ前に保護する
デプロイされたルートは公開されます。URL を見つけた人は誰でもあなたのツールを呼び出せるため、認証はデプロイの後ではなく前に追加してください。
withMcpAuth はハンドラーをラップします。以下は私たちがテストしたバージョンで、環境変数から取得した 1 つの共有トークンを使っています。
import { createMcpHandler, withMcpAuth } from "mcp-handler";
// createMcpHandler(...) as above
const verifyToken = async (_req: Request, bearerToken?: string) => {
if (!bearerToken || bearerToken !== process.env.MCP_TOKEN) return undefined;
return { token: bearerToken, clientId: "team", scopes: ["posts:read"] };
};
const authed = withMcpAuth(handler, verifyToken, { required: true });
export { authed as GET, authed as POST };
required: true が重要です。これがないと、有効なトークンを持たないリクエストもそのまま通ってしまいます。これがある場合、認証なしの呼び出しは次のように返りました。
HTTP/1.1 401 Unauthorized
www-authenticate: Bearer error="invalid_token", error_description="No authorization provided", resource_metadata="http://localhost:3417/.well-known/oauth-protected-resource"
そして Authorization: Bearer <token> を付けた同じ呼び出しは 200 を返しました。
この resource_metadata リンクは、OAuth 対応クライアントがサインイン先を見つけるためのものです。app/.well-known/oauth-protected-resource/route.ts から配信します。
import { metadataCorsOptionsRequestHandler, protectedResourceHandler } from "mcp-handler";
const handler = protectedResourceHandler({ authServerUrls: ["https://auth.example.com"] });
const corsHandler = metadataCorsOptionsRequestHandler();
export { handler as GET, corsHandler as OPTIONS };
これは {"resource":"http://localhost:3417","authorization_servers":["https://auth.example.com"]} を返しました。authServerUrls は実際の ID プロバイダーを指すようにしてください。実際のユーザーを扱う場合は、共有トークンをそのプロバイダーのトークン検証に置き換え、ルートごとに requiredScopes を確認してください。現在の仕様リビジョン 2026-07-28 では、クライアント登録が Dynamic Client Registration から Client ID Metadata Documents に移行します。この作業は認可サーバー側で行うもので、Next.js のルートを変更する必要はありません。
ツール内では、検証済みの ID は ctx.http?.authInfo にあります。これにより、ツールは呼び出し元のアカウントで結果を絞り込めます。
問題と対処法
| 表示される内容 | 原因 | 対処法 |
|---|---|---|
next-devtools-mcp からの [error] No server info found |
Next.js 16 の開発サーバーが起動していない、またはポート 3000〜3010 の範囲外にある | npm run dev を起動します。別のポートを使う場合は、nextjs_call 用のポートをエージェントに伝えます |
next-devtools-mcp/dist に対する ERR_MODULE_NOT_FOUND |
npx のキャッシュが古い | npx のキャッシュをクリアしてクライアントを再起動します |
/_next/mcp の 404 |
Next.js 15 以前、next start、または experimental.mcpServer: false |
アップグレードするか、next dev を使うか、フラグを削除します |
| エージェントがファイルから回答するだけで、ツールを呼び出さない | クライアントがサーバーを読み込んでいない | クライアントを再起動して MCP の一覧を確認します。Claude Code では /mcp を実行します |
GET /api/mcp の 405 |
mcp-handler 2 では正常な動作 | 対処は不要です。クライアントは POST を使用します |
WWW-Authenticate ヘッダー付きの 401 |
required: true を指定した withMcpAuth でトークンがない |
Authorization: Bearer ... を送信するか、クライアントの OAuth フローでサインインします |
古いチュートリアルのコードが redisUrl や basePath で失敗する |
mcp-handler 1 向けに書かれている | これらのオプションを削除し、任意の場所にルートをマウントします |
| 新規プロジェクトで「The module was automatically converted to an EcmaScript module」が出る | npm init が package.json に "type": "commonjs" を追加した |
type フィールドを削除します。モジュールの扱いは Next.js が行います |
最後の項目では、空のテストプロジェクトで 5 分を費やしました。create-next-app ではこの問題は発生しません。
ディレクトリ内の Next.js MCP サーバー
2026年11月14日時点で、HostedMCP カタログには名前に Next.js を含むアクティブなサーバーが19件あり、そのうち4件がインデックス規則を通過しました。本ガイドで重要な2件は次のとおりです。
| サーバー | スター数 | チェックスコア | 概要 |
|---|---|---|---|
| vercel/next-devtools-mcp | 836 | 89 | パート1のコネクター |
| vercel-labs/mcp-handler | 699 | 86 | パート2のライブラリ |
スター数は最後のリフレッシュ時点の GitHub の値です。チェックスコアは、リポジトリ、ライセンス、メンテナンス、サプライチェーン、ツール説明を自動レビューした結果で、根拠は各サーバーのチェックレポートに記載しています。残り17件のほとんどはスター数の少ないスターターテンプレートか単機能ツールです。インストールする前に、同じ方法で確認してください。
セキュリティに関する注意
dev エンドポイントは開発専用ですが、プライベートではありません。next dev の実行中は、そのポートに到達できるあらゆるプロセスがプロジェクトのパス、ルート、ログの場所を読み取れます。環境にシークレットを保持している間は、開発サーバーを共有ネットワークアドレスにバインドしないでください。
自前のルートは、デプロイした日から公開 API です。すべてのツールをエンドポイントと同じように扱ってください。スキーマで入力を検証し、呼び出し元が見てよいものだけを返し、ツールの説明にシークレットや内部 URL を決して書かないでください。モデルがそれらの説明を読み、ツールを一覧する人も読むからです。リスクは MCP セキュリティガイド で順を追って説明しています。
次に読むべきもの
ルートの背景にあるプロトコルの詳細を知りたい場合は、MCP server の構築方法で、素の TypeScript と Python を使って MCP server を構築する方法を解説しています。サーバーが公開されたらリポジトリを送信してください。HostedMCP がクライアントごとのインストールスニペットとともに掲載し、チェックを実行します。