第4章 デバッグの作法 — 見えない通信を覗く

📖 MCPサーバーを作って学ぶ AIに道具を持たせる入門 — はじめに・目次 ← 目次に戻る 第3章では、console.log 1行でサーバーをわざと壊しました。この章では、壊れているのがどこなのかを突き止める手順を身につけます。この教材でいちばん実用的な章です。


📱 Claude ではこう見える 🟢

MCPサーバーが動かないとき、Claude Desktop の画面はこうなります。

  • サーバーの名前が、そもそも一覧に出てこない
  • 名前は出るのに、ツールが0個
  • ツールはあるのに、Claude が 「私はメモを読めません」 と言う
  • 頼むと 「エラーが発生しました」 とだけ言われる

共通しているのは——画面には理由が書いていないということです。

これは Claude が不親切なわけではありません。第1章で見たとおり、あなたのサーバーは画面のないプログラムとして裏でこっそり起動しています。Claude Desktop から見えるのは「繋がらなかった」という結果だけで、あなたのコードの中で何が起きたかは、Claude Desktop も知らないのです。

🔍 だからこの章でやることは、たった1つです。 「見えない通信を、見えるところまで引きずり出す」。

そのために、上から順に試す4つの段階を用意しました。この順番には理由があります。下の段階ほど調べるのが面倒なので、面倒でない方から潰していくのです。


🤔 なぜ「順番」が大事なのか 🟢

初心者がいちばんよくやる失敗は、いきなり難しいところを疑うことです。

  • 「Claude Desktop の設定が悪いのかな」→ 設定ファイルを何度も書き換える
  • 「MCPの仕様が変わったのかな」→ ネットを何時間も検索する
  • 「AIに聞こう」→ AIもあなたのパソコンの中を見られないので、当てずっぽうを返してくる

ところが実際の原因は、そもそもプログラムがビルドされていなかったとか、ファイルのパスが1文字違っていたとか、そういうものが大半です。

切り分けとは「犯人の範囲を半分にする」こと

デバッグは、推理ではなく消去法です。関係する部品はこれだけあります。

[あなたのコード] → [Node.js] → [MCPの通信] → [Claude Desktop] → [AIの判断]
      ①              ①            ②              ③              ④

左から順に確かめていけば、「ここまでは正常」という線がどんどん右に伸びていきます。止まったところが犯人です。番号は、次から説明する4つの段階に対応しています。

💡 「動かない」は情報量ゼロです。 「Inspector までは繋がるが Claude Desktop からは見えない」まで絞れれば、それはもうほぼ答えです(設定ファイルか再起動が怪しい、と分かる)。


🛠 段階① サーバーは単体で起動するか 🟢

いちばん最初にやること。例外なく、必ずここから。

ターミナル(Windows なら PowerShell)を開いて、サーバーのフォルダに移動し、Claude Desktop を経由せずに、直接起動します。

node build/index.js

たったこれだけです。何が分かるのでしょうか。

正常なとき

カーソルが点滅したまま、何も起きません。

Weather MCP Server running on stdio

こんな1行だけが出て、プロンプトが戻ってこない——これが正解です。びっくりしないでください。

なぜなら、サーバーは今「標準入力から MCP のメッセージが来るのを待っている」状態だからです。誰も話しかけてこないので、黙って待っている。これは正常に起動できた証拠です。

💡 出ている1行は console.error で書いたものです(第3章でやりましたね)。stderr(標準エラー出力)に出しているので、通信の邪魔をしません。

終わるときは Ctrl + C を押してください。

落ちるとき

一方、こうなったらここが犯人です。Claude Desktop の設定を見に行く必要は、まだありません。

出るもの 意味 対処
Error: Cannot find module '/…/build/index.js' ビルドしていない/パスが違う npm run build を実行。build/ フォルダができたか目で確認
Cannot find module '@modelcontextprotocol/sdk/…' import に .js が付いていない …/server/mcp.js のように拡張子 .js を必ず付ける
Cannot find package '…' インストール漏れ npm install をやり直す
SyntaxError: … コードの書き間違い 表示された行番号を見る
ReferenceError: … is not defined 変数名のタイプミス 同上
何も出ずにすぐプロンプトが戻る main() が即終了している await server.connect(transport) を書き忘れていないか

⚠️ node build/index.js が動かないのに、Claude Desktop で動くことは絶対にありません。 ここが通らないうちに先へ進むのは、時間の無駄です。

🔧 手で会話してみる(余裕がある人だけ)

さらに深く見たい人へ。待ち受け状態のサーバーに、キーボードから直接 MCP のメッセージを打ち込むこともできます。

node build/index.js を実行して待ち受け状態にしたまま、次の1行を貼り付けて Enter を押します(1行で打つのがポイントです)。

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"tenuki","version":"1.0.0"}}}

JSON がずらっと返ってくれば、あなたのサーバーは MCP として喋れています

これが「見えない通信」の正体です。ただの文字列のやりとり。魔法は1つもありません。

💡 ふだんこれを手打ちする必要はありません。それを画面付きでやってくれるのが、次の Inspector です。


🛠 段階② MCP Inspector で繋がるか 🟢

段階①を通ったら、次は MCP Inspector(インスペクター) です。公式が用意しているMCPサーバー専用の検査ツールで、公式ドキュメントも「まずここに来い(first stop)」と書いています。

インストールは不要です。ターミナルで次を実行します。

npx @modelcontextprotocol/inspector node /絶対パス/build/index.js
  • npx … インストールせずにパッケージを実行するコマンド
  • @modelcontextprotocol/inspector … 検査ツール本体
  • 続く node /絶対パス/build/index.js検査したいサーバーの起動コマンドをそのまま渡す

しばらくするとブラウザが開き、検査画面が出ます。左側で接続の設定をして、Connect を押すと繋がります。

⚠️ ここでも絶対パスで書くのが安全です。相対パスは「今どのフォルダにいるか」で意味が変わってしまいます。

Inspector の見どころ

画面には次のものがあります。上のタブを左から順に押していくだけで、健康診断になります。

場所 何が見える ここを見て分かること
Server connection pane(接続パネル) トランスポートの選択、起動コマンドと環境変数の編集 繋がるかどうかenv の渡し忘れもここで試せる
Tools タブ ツールの一覧、それぞれの説明文と入力スキーマ ツールが登録できているか。説明文が意図どおりか
Resources タブ リソースの一覧、MIMEタイプや説明、中身 第7章で使います。今は空でOK
Prompts タブ プロンプトの一覧、引数と説明、生成されるメッセージのプレビュー 同上。第7章で使います
Notifications pane(通知パネル) サーバーから届いたログと通知がぜんぶ出る sendLoggingMessage で出したログの確認場所

★ ツールを手で実行してみる

Inspector の本当の価値はここです。

Tools タブでツール名をクリックすると、引数の入力欄が出ます。値を打って実行ボタンを押すと、返ってきた結果がそのまま表示されます

つまり——AIを一切通さずに、自分の道具だけをテストできるのです。

第2章の天気サーバーなら、get_alertsstate: "CA" と入れて実行してみてください。カリフォルニア州の警報が返ってくれば、あなたのツールは完璧に動いています

これが分かると、切り分けが一気にラクになります。

Inspector で動く + Claude で動かない = あなたのコードは無実。犯人は設定か再起動。 Inspector でも動かない = 犯人はあなたのコード。Claude Desktop を触るのはまだ早い。

コードを直したときの手順

Inspector を開いたまま直しても、反映されません。毎回この順で回してください。

  1. コードを直す
  2. npm run build(ここを忘れる人が本当に多い)
  3. Inspector で Disconnect → Connect(再接続)
  4. もう一度ツールを実行

💡 開発中は Claude Desktop より Inspector のほうが速いです。 Claude Desktop は変更のたびに完全終了・再起動が要りますが、Inspector は再接続だけ。作っている間は Inspector、仕上げに Claude Desktop、と使い分けてください。


🛠 段階③ Claude Desktop のログを読む 🟢

段階②まで通ったのに Claude Desktop で動かない——ここまで来て、はじめて Claude Desktop 側を疑います。

Claude Desktop は、MCPサーバーとのやりとりをログファイルに書き出しています。場所はここです。

  • macOS: ~/Library/Logs/Claude
  • Windows: %APPDATA%\Claude\logs

読むコマンドはこちらです。

macOS(ターミナル)

tail -n 20 -F ~/Library/Logs/Claude/mcp*.log
  • tail … ファイルの末尾を見るコマンド(ログは新しいものが下に付く)
  • -n 20 … 直近20行を表示
  • -F表示したまま、新しい行が来たら流し続ける(これが便利)
  • mcp*.logmcp で始まるログファイルをまとめて見る

Windows(PowerShell)

type "$env:AppData\Claude\logs\mcp*.log"

使い方のコツ

ログを流したまま、Claude Desktop を再起動するのがいちばん効きます。

  1. ターミナルで上の tail コマンドを実行して、そのまま置いておく
  2. Claude Desktop を完全終了して起動し直す
  3. ターミナルに、サーバーを起動しようとしている様子がリアルタイムで流れる

ここに、あなたが console.error で書いたメッセージも出てきます。「見えないはずの通信」が、はじめて目に見えるようになる瞬間です。

ログに記録されるのは、公式ドキュメントによると次のものです。

  • サーバーとの接続イベント(繋ごうとした・成功した・失敗した)
  • 設定の問題
  • 実行時のエラー
  • やりとりされたメッセージ

ログでよく見つかるもの

ログに出るもの 原因
spawn node ENOENT commandnode が見つからない。which node で調べたフルパスを書く
Cannot find module '/…' args のパスが違う/ビルドしていない
Unexpected token Invalid JSON stdout に余計な文字が混ざった(=第3章の console.log
Server disconnected / transport closed サーバーが起動直後に落ちた。段階①に戻る
設定ファイルの読み込みエラー claude_desktop_config.jsonカンマや括弧のミス

💡 JSONのミスは全員やります。 カンマの付け忘れ、末尾の余計なカンマ、\ の書き方。設定ファイルを VS Code で開くと、間違っている箇所に赤い波線が出ます。保存前に必ず見てください。


🛠 段階④ Chrome DevTools で中を覗く 🔧

ここは応用です。読み飛ばして構いません。 段階③までで、原因の9割以上は見つかります。

Claude Desktop は Electron(中身は Chromium=Chrome と同じ描画エンジン)でできているため、ブラウザの開発者ツールを開けます。ただし既定では封印されているので、まず鍵を開けます

macOS

echo '{"allowDevTools": true}' > ~/Library/Application\ Support/Claude/developer_settings.json

Windows(PowerShell)

'{"allowDevTools": true}' | Set-Content "$env:AppData\Claude\developer_settings.json"
  • echo '…' … 文字列を出力する
  • > … その出力をファイルに書き込む(既にあれば上書き)
  • パスの Application\ Support\スペースをそのまま扱うための印。消さないでください

書き終えたら Claude Desktop を再起動し、次のキーを押します。

  • macOS: Command + Option + I
  • Windows: Ctrl + Alt + I

💡 DevTools のウィンドウは2つ開きます(本体の画面用と、タイトルバー用)。仕様なので驚かないでください。

見るところは2つです。

  • Console パネル … Claude Desktop 側(=クライアント側)で起きたエラー
  • Network パネル … やりとりされたメッセージの中身と、通信のタイミング

サーバー側ではなくクライアント側の異常を疑うときの最終手段、という位置づけです。


⚠️ ハマりどころ 🟢

「動かない」の4類型と、その対処

「動かない」と一言で言っても、症状によって見るべき場所がまったく違います。まずどの型かを判定してください。

① 繋がらない(サーバーが一覧に出ない)

症状:Claude Desktop のコネクタ一覧に、そもそもサーバー名が出てこない。

疑うこと 確かめ方
ビルドしていない build/index.js が実際にあるか目で見る → npm run build
パスが相対パスになっている 絶対パスにする。stdio サーバーの作業ディレクトリは未定義(macOS では / のことがある)
node が見つからない which node(Windows は where node)のフルパスを command に書く
設定ファイルの JSON が壊れている VS Code で開いて赤い波線を探す
設定ファイルの置き場所が違う macOS: ~/Library/Application Support/Claude/claude_desktop_config.json / Windows: %AppData%\Claude\claude_desktop_config.json
再起動していない ウィンドウを閉じるだけでは足りません。完全終了して起動し直す
起動直後に落ちている 段階①node build/index.js)へ

⚠️ 設定を変えたときも、コードを直したときも、完全終了・再起動が必要です。 公式ドキュメントにも「closing the window is not enough(ウィンドウを閉じるだけでは不十分)」と明記されています。

② 繋がるが、ツールが出てこない

症状:サーバー名は出る。でもツールが0個。

疑うこと 確かめ方
ツールの登録コードが実行される前に connect している registerToolserver.connect() より前に書く
ツール登録自体でエラーが出ている Inspector の Tools タブを見る。ここが空なら Claude 以前の問題
zod のバージョン違い この教材は zod@3 です。v4 が混ざると書き方が違って登録に失敗します
inputSchema の形が違う zod フィールドを並べた素のオブジェクトで書く(z.object(...) で包まない)
ビルドが古い 直したのに npm run build していない

③ ツールはあるが、AIが呼んでくれない ★

症状:Inspector でも Claude の一覧でもツールは見えている。手で実行すればちゃんと動く。なのに、頼んでも Claude が使ってくれない。

これはバグではありません。 そして——これはデバッグの問題ですらありません。

思い出してください。AIがあなたの道具について知っているのは、あなたが書いた「説明文」だけです。コードは1文字も読んでいません。

つまりこの症状は、あなたの説明文が、AIに伝わっていないということです。

疑うこと 直し方
description が短すぎる・曖昧 いつ使う道具なのかを書く。「メモを検索する」→「ユーザーの個人メモ(Markdownファイル)を全文検索して、該当ファイル名と抜粋を返す」
引数に .describe() が無い 全フィールドに必ず付ける。AIはここを見て何を入れるか決めます
道具のできる範囲が書いていない 第2章の天気サーバーがまさにこれです。get_alerts の説明は “Two-letter state code”——アメリカの州しか受け付けない。だから「東京の天気」では呼ばれません
ツール名が意味不明 doIt ではなく search_notes名前も説明文の一部です
他のツールと役割がかぶっている どちらを選べばいいかAIが迷います(第12章で扱います)

💡 切り分けの言い方を覚えてください。Inspector で手動実行すると動く。でもAIが呼んでくれない」——これは100%説明文の問題です。コードをいじっても直りません。 逆に「AIは呼んでくれるが、結果が変」なら、犯人はコードの中身です。

この「説明文が全て」という話は、この教材の通奏低音です。第5章で、説明文を書き換えるだけで呼ばれ方が変わるのを実験してもらいます。

④ 呼ぶと落ちる

症状:AIがツールを呼ぶ。そこで「エラーが発生しました」となる、あるいはサーバーごと切断される。

疑うこと 直し方
ツールの中で例外を throw している throw せず、説明文をテキストで返す{ content: [{ type: "text", text: "ファイルが見つかりませんでした: memo.md" }] }
環境変数が渡っていない stdio で起動されたサーバーは環境変数をごく一部しか引き継ぎません。設定ファイルの env キーで明示的に渡す
ファイルパスが相対パス 作業ディレクトリは未定義。絶対パス
権限がない ファイルの読み書き権限、chmod 755 build/index.js
console.log が紛れ込んでいる 第3章の罠。そのツールを呼んだ瞬間に通信が乱れます(完全に止まることも、その行だけ捨てられて動いているように見えることもあります)

⚠️ 「エラーは throw せず、テキストで返す」は、この教材で何度も出てくる原則です。 throw するとAIには「失敗した」としか伝わりません。テキストで理由を返せば、AIがそれを読んで次の手を考えられます。道具は、AIに向かって喋れるのです。

🔧 もう1つ、稀に出るもの

接続時に -32602(Invalid params) というエラーコードが出ることがあります。これは JSON-RPC の「引数が不正」を表す標準コードで、いろいろな場面で出ます。よくある原因の1つは、クライアントが宣言していない機能をサーバーが使おうとしたケースです。初心者のうちは深追い不要ですが、見かけたら「機能のすり合わせ(capability negotiation)で失敗している」と覚えておいてください。


🛠 ログをどう設計するか 🟢

ここまでは「壊れてから調べる」話でした。最後に、壊れたときに調べやすくしておく話をします。

何を記録すべきか

公式ドキュメントは、記録しておくべき出来事として次を挙げています。

記録するもの なぜ 書き方の例
起動したこと 「そもそも起動したのか」が最初の分かれ目 console.error("Memo MCP Server running on stdio")
設定値の読み込み パスや環境変数の間違いが一発で分かる console.error("NOTES_DIR =", notesDir)
ツールが呼ばれたこと AIが呼んだのか、呼んでいないのかが分かる console.error("[tool] search_notes query=", query)
エラーが起きたこと 原因そのもの console.error("[error] search_notes:", err)
🔧 処理にかかった時間 「遅い」の原因を探すとき 開始と終了の時刻を出す

ツール呼び出しのログは、とくに効きます。 ③型(AIが呼んでくれない)か④型(呼ぶと落ちる)かを、ログを見るだけで一瞬で判定できるからです。ログに [tool] の行が出ていなければ、AIはそもそも呼んでいません。

どこに出すか

第3章でやったとおり、トランスポートによって安全な出し先が違います

トランスポート stdout(console.log stderr(console.error
stdio 絶対禁止。通信が壊れます ✅ 安全。ホストがログとして拾います
Streamable HTTP(第8章) ✅ 問題なし ⚠️ 出せるが、クライアントには届きません

どちらでも使える方法もあります。

await server.server.sendLoggingMessage({
  level: "info",
  data: "Server started successfully",
});

⚠️ この方法を使うには、サーバーを作るときに capabilities: { logging: {} } を宣言しておく必要があります。宣言していないと、エラーも例外も出ないまま、黙って何も送りません第3章参照)。

これは MCP の正式なログ通知です。ログの重さは RFC 5424 の8段階debug から emergency まで)で指定でき、クライアントが logging/setLevel で「これ以上重いものだけ送って」と調整できます。送ったログは Inspector の Notifications パネルに出ます。

💡 まずは console.error で十分です。sendLoggingMessage は、HTTPでも動かすようになったら(第8章)思い出してください。

⚠️ 機密情報をログに出さない

これは必ず守ってください。 ログは、原因を探すためにあちこちにコピペされるものです。GitHub の issue に貼ったり、AIに読ませたり。

出してはいけないものは次のとおりです。

  • APIキー・トークン・パスワード
  • メモやファイルの中身そのもの(あなたの個人的な文章です)
  • 氏名・住所・メールアドレスなどの個人情報
  • 絶対パスの丸ごと(ユーザー名が入っていることがあります)

やり方は簡単です。中身ではなく「量」や「結果」を書く

// ❌ 悪い例:メモの中身が丸ごとログに残る
console.error("[tool] read_note:", content);

// ✅ 良い例:何が起きたかは分かるが、中身は漏れない
console.error("[tool] read_note:", filename, `(${content.length} chars)`);
// ❌ 悪い例
console.error("API key:", process.env.API_KEY);

// ✅ 良い例
console.error("API key:", process.env.API_KEY ? "set" : "MISSING");

「あるかどうか」だけログに出せば、デバッグには足ります。 値そのものは要りません。

💡 これは第9章(安全)の予告でもあります。自分のパソコンの中だから安全——ではありません。ログは外に出ていきます。


🤖 AIに頼むなら 🟢

AIに聞く前に、どこで壊れているか掴んでから聞く

これがこの章のいちばんの持ち帰りです。

AIコーディングツールは強力ですが、あなたのパソコンの中を見ることができません。ファイルがビルドされているかも、Claude Desktop が再起動されたかも、ログに何が出ているかも、AIは1つも知らないのです。

だから「MCPサーバーが動きません」とだけ聞くと、AIは当てずっぽうの一般論を返してきます。そして、そのとおりに直しても直らない。あなたは「AIは役に立たない」と思い、AIは的外れな提案を続ける。時間だけが溶けます

段階①〜③を先に回してから聞くと、質問がこう変わります。

「MCPサーバーが動きません。直して」

「MCPサーバーが Claude Desktop に出てきません。切り分け済みの情報は以下です。 node build/index.js は正常に起動する(Memo MCP Server running on stdio と出て待ち受け状態) npx @modelcontextprotocol/inspector では繋がり、Tools タブに search_notes が出る。手動実行も成功 ~/Library/Logs/Claude/mcp*.log にはこう出ている:(ログを貼る) claude_desktop_config.json はこうなっている:(設定を貼る。ただしAPIキーは伏せる) ・Claude Desktop は完全終了して再起動済み」

下の聞き方をすると、AIはほぼ一発で当ててきます。切り分けは、AIへの通訳作業でもあるのです。

💡 貼るときは伏せる。 さっきの「機密情報をログに出さない」がここで効いてきます。ログや設定をAIに貼るのは日常茶飯事だからです。

症状を伝えるときの型

先ほどの4類型を、そのまま言葉にすると伝わります。

AIへの言い方
① 繋がらない 「サーバーが一覧に出てきません。ログにはこう出ています」
② ツールが出ない 「サーバーは繋がりますが、ツールが0個です。Inspector でも空です」
③ 呼ばれない 「Inspector で手動実行すると動きますが、Claudeが呼んでくれません。説明文を改善したいです」
④ 落ちる 「ツールを呼ぶと落ちます。エラーはこれです:(貼る)」

とくに③は、「説明文を良くしたい」と最初に言うのがコツです。そう言わないと、AIはコードを直そうとしてしまいます。直すべきはコードではなく、日本語(または英語)のほうなのです。

古い書き方に注意

第1章でも触れましたが、MCPは動きの速い分野です。AIはデバッグ手順についても古い情報を出すことがあります。とくに——

  • 廃止された繋ぎ方(古いHTTPのやり方)を前提にした手順
  • 昔のSDKのAPI名を使ったログの出し方

なので、こう添えてください。

「MCPの公式ドキュメント(modelcontextprotocol.io)の最新の手順で」

そして、Inspector の使い方やログの場所は、この章に書いてあるとおりが公式の最新です。迷ったらここに戻ってきてください。


📗 ことばメモ

ことば よみ 意味
切り分け きりわけ 原因のありそうな範囲を、順番に消していく調べ方
MCP Inspector エムシーピー インスペクター 公式のMCPサーバー検査ツール。AIを通さずツールを手で実行できる
stdout ひょうじゅんしゅつりょく/標準出力 プログラムの出力の口。stdio では MCP の通信路そのもの。ログを書いてはいけない
stderr ひょうじゅんエラーしゅつりょく/標準エラー出力 エラー用の出力の口。stdio ではログを書いてよい場所
tail -F テイル ファイルの末尾を表示し、新しい行が来たら流し続けるコマンド
DevTools デブツールズ ブラウザの開発者ツール。Claude Desktop は Electron(中身は Chromium)なので開ける
sendLoggingMessage MCP の正式なログ通知。トランスポートを問わず使える
RFC 5424 ログの重さを8段階で決めた標準。debugemergency
JSON-RPC ジェイソン アールピーシー MCP が中で使っている、メッセージのやりとりの決まりごと
-32602 JSON-RPC の「引数が不正(Invalid params)」を表す標準エラーコード

➡️ 次へ

道具は揃いました。壊れても、もう怖くありません。

  • 段階①:ターミナルで直接起動する
  • 段階②:Inspector で繋いで、手で実行する
  • 段階③:Claude Desktop のログを流したまま再起動する
  • 段階④:DevTools を開く(応用)

そして「動かない」を4つの型に分けて、それぞれ見るところを決めました。とくに③「ツールはあるが呼ばれない」は説明文の問題——これが、次から効いてきます。

第5章 自分の道具を作りはじめる — メモを検索する から、いよいよあなた自身のサーバーを作ります。天気サーバーは他人の完成品でしたが、ここからは違います。自分で書けば、必ず一度は動かなくなります。そのときにこの章へ戻ってきてください。戻ってこられる場所がある——それが、この2章を先にやった理由です。

関連ページ