MCPサーバーに接続できないときの切り分け手順 — 設定・起動・認証・ツール表示の4層で原因を絞る
MCPサーバーに接続できないときの切り分け手順。設定ファイル・プロセス起動・認証・ツール表示の4層を上から潰す進め方と、stdioとリモートで違うエラーの出方を扱います。
MCPサーバーにつながらないときは、4つの層を上から順に潰すと原因が一意に決まります。この順序が最短です。
接続できないときに確かめる4つの層
- 1
設定ファイルが読まれているか
サーバー名が一覧に出るかどうか。出なければ、書いた場所か構文の問題です。
- 2
サーバーのプロセスが起動しているか
設定した起動コマンドが、手で実行しても動くかどうか。
- 3
認証が通っているか
リモートサーバーが401か403を返していないかどうか。
- 4
ツールが会話から見えているか
接続済みなのに、ツールが読み込まれていないだけではないかどうか。
逆から入ると遠回りになります。ツールが呼ばれない理由をモデル側の問題だと考えて調べ続け、実は設定を書いたファイルが読まれていなかった、という着地もあります。まず claude mcp list を打ち、そこに名前が出るかどうかで①と②以降を分けます。
症状から入る層を決める
最初に見るのは3つのコマンドの出力だけです。症状と入り口の対応は次のようになります。
| 見えている症状 | 疑う層 | 最初に見るもの |
|---|---|---|
| 一覧にサーバー名が出ない | 疑う層設定ファイル | 最初に見るものclaude mcp list |
| 名前は出るが接続していない | 疑う層プロセス起動 | 最初に見るもの起動コマンドを手で実行 |
| 「認証が必要」と出る / 毎回ログインを求められる | 疑う層認証 | 最初に見るもの/mcp |
| 接続済みなのにツールが呼ばれない | 疑う層ツール表示 | 最初に見るもの/mcp のツール数 |
claude mcp list は設定済みサーバーの一覧と接続状態を出します。個別に踏み込むなら claude mcp get <name> で、そのサーバーがどのスコープに定義されていて、いまどういう状態かまで確認できます。
claude mcp list # 一覧と接続状態
claude mcp get github # 個別サーバーのスコープと状態
claude doctor # インストールと設定ファイルの検証(読み取りのみ)追加コマンドの構文やスコープの選び方そのものに迷いがある場合は、Claude CodeへのMCPサーバー追加手順をまとめた設定ガイドが対応します。ここから先は、追加までは済んでいる前提で進めます。
「Pending approval」は失敗ではなく未承認
v2.1.286で、作業用の空フォルダーに存在しないパッケージを起動するstdioサーバーを --scope project で追加し、claude mcp get を打つと次のように出ました。
$ claude mcp add --scope project demo -- npx -y nonexistent-pkg-xyz
Added stdio MCP server demo with command: npx -y nonexistent-pkg-xyz to project config
$ claude mcp get demo
demo:
Scope: Project config (shared via .mcp.json)
Status: ⏸ Pending approval (run `claude` to approve)
Type: stdio
Command: npx
Args: -y nonexistent-pkg-xyz存在しないパッケージを指定したのに、Added と出て、状態も「接続失敗」ではなく「承認待ち」です。承認前のprojectサーバーには接続を試みないので、パスが間違っていても、この段階では何も起きません。「追加できた」はコマンドが設定を書き込めたという意味でしかなく、起動できる保証は含みません。
承認は、そのフォルダーで claude を対話モードで起動して行います。v2.1.196からは、信頼していないフォルダーで承認の設定が無視されます。対象は、リポジトリにコミットされた .claude/settings.json の enableAllProjectMcpServers と enabledMcpjsonServers です。クローンしたばかりのリポジトリで承認待ちが消えないときは、ワークスペースの信頼ダイアログを一度通しているかを見ます。ユーザーの ~/.claude/settings.json や管理設定、--settings で渡した設定にある承認は、未信頼のフォルダーでも有効です。
存在しない名前を渡したときの出力も、切り分けに使えます。
$ claude mcp get nothere
No MCP server named "nothere". Configured servers: github, claude.ai Gmail, ...終了コードは1で、メッセージには読み込まれているサーバー名が全部並びます(上は一部だけ表示)。綴りの間違いはここで見つかります。claude.aiのコネクタも同じ一覧に入るため、コネクタが読み込まれているかの確認にも使えます。なお、WebSocketサーバーは claude mcp list には出ないので、claude mcp get <name> か /mcp で見ます。
第1層: 設定ファイルが読まれているか
一覧に名前が出ないなら、書いた場所か構文のどちらかです。まず押さえたいのは、MCPサーバーの定義を settings.json には書かないという点。保存先は2系統に分かれます。
| スコープ | 保存先 | チーム共有 |
|---|---|---|
| local(既定) | 保存先~/.claude.json | チーム共有しない |
| project | 保存先プロジェクトルートの .mcp.json | チーム共有する |
| user | 保存先~/.claude.json | チーム共有しない |
permissionsやHooksを置く settings.json にMCPの定義を書いても、エラーにならずそのまま無視されます。設定ファイルの系統全体はClaude Codeの設定ファイル完全ガイドで扱っています。
構文側で踏みやすいのは次の4つです。
- 起動コマンドの前の
--: サーバー自身のフラグは、必ず--の後ろに置きます。実際の出力は次の項で示します - 環境変数の展開失敗:
.mcp.jsonで${VAR}を参照した変数が未設定で、デフォルト値もない場合、設定自体は読み込まれますが、claude mcp listに未設定変数の警告が出て、${VAR}の文字列がそのまま使われます。認証情報がこの状態だと接続は失敗するため、${VAR:-default}でデフォルトを与えるか変数を設定します - 予約名:
workspaceは内部用に予約されています。claude mcp addは拒否し、手書きの設定ファイルにある場合は読み込み時にスキップされます - 未承認:
.mcp.json由来のprojectスコープは初回利用前に承認が必要で、未承認のあいだは一覧に「⏸ Pending approval」と出ます。選び直すならclaude mcp reset-project-choicesを実行します
-- を忘れたときの実際のエラー
v2.1.286で、-- の有無だけを変えて追加を試した結果です。
$ claude mcp add -s project s3 npx server --port 8080
error: unknown option '--port'
$ claude mcp add -s project s4 -e KEY=v npx server
error: missing required argument 'commandOrUrl'
$ claude mcp add -s project s5 -e KEY=v -- npx server --port 8080
Added stdio MCP server s5 with command: npx server --port 8080 to project config1行目は、サーバーに渡したい --port をClaude Code自身のオプションとして読み取ろうとして落ちています。2行目は、-e が複数の値を受け取る形式なので npx server まで環境変数として飲み込み、起動コマンドが残らなくなった状態です。3行目のように -- を挟むと、意図どおり書き込まれました。.mcp.json の command は npx、args は server --port 8080 の3要素、env は KEY です。
追加の実行時に拒否されるのは救いで、エラーが出ないまま間違った形で保存される失敗のほうが厄介です。--env の位置にも触れておきます。公式の例は、名前の後ろ・-- の前に --env を置く形です。claude mcp add example --env API_KEY=your-key -- npx -y @example/mcp-server がその例です。v2.1.286では -- の無い claude mcp add s2 npx server --env KEY=value でも環境変数として解釈されました。-- で区切っておけば、サーバー側のフラグと取り違えられません。
値に紛れる空白
トークンを貼り付けたときに末尾の改行が入ると、認証だけが通らなくなります。対象は command、url、args の各要素と、env と headers のキーと値です。見えない前後の空白があると、Leading or trailing whitespace in: headers.Authorization のようにフィールド名だけを示して警告します。値そのものは表示されません。空白は自動では取り除かれず、書かれたまま使われるので、設定ファイルを直す必要があります。
同じ名前が複数のスコープにあるとき
同じ名前が複数スコープにあるときの優先順位は、local → project → user → プラグイン提供 → Claude.aiコネクタの順です。優先されたスコープの定義が丸ごと使われ、フィールド単位ではマージされません。「projectの定義をベースにlocalでトークンだけ差し替える」は成立せず、片方が丸ごと勝ちます。
「チームでは動くのに自分の環境だけ別のエンドポイントを向いている」という症状は、この優先順位で別の定義が読まれていると起こります。エンドポイントが異なる定義が複数スコープにあると、claude mcp list と /mcp に警告が出ます。/doctor が同じ警告を出すようになったのはv2.1.110です。OAuthのサインイン状態はエンドポイントごとに保存されるため、別の定義が読み込まれるプロジェクトでは、同じ名前でも改めてログインが必要になります。
第2層: サーバーのプロセスが起動しているか
この層はstdio、つまりローカルで子プロセスとして起動するサーバー固有の問題です。まず疑うのは command と args のパスで、確かめ方は単純です。設定に書いたコマンドを、そのままターミナルで手で実行します。
npx -y airtable-mcp-server
node ./tools/mcp-server.js手で叩いて起動しないなら、Claude Code側から起動しても結果は同じです。パスの相対基準がずれている場合は、stdioサーバーへ自動で渡される環境変数 CLAUDE_PROJECT_DIR を使い、${CLAUDE_PROJECT_DIR:-.}/tools/mcp-server.js のように書くと作業ディレクトリに依存しなくなります。この変数はサーバーのプロセスの環境に入るもので、Claude Code自身の環境にはありません。そのため command や args で参照するときは、:-. のようなデフォルトを付けておきます。
手元では動くのにClaude Codeからは失敗する場合、疑う先は3つです。
- 起動が遅い: サーバーの起動タイムアウトは既定30,000ミリ秒です。
MCP_TIMEOUT=60000 claudeのように延ばして起動します - 標準出力の汚染: 自作サーバーが
console.logでプロトコル外の行を標準出力に書くと、通信の邪魔になります。v2.1.105のリグレッションで、そうした行が1行出ただけで接続が切れる状態になり、v2.1.110で直っています。直ったあとでも、ログはconsole.errorに寄せるほうが安全です - 環境変数の欠落: 手元のシェルには通っているAPIキーが、
--envや.mcp.jsonのenvに書かれていないケースです
第3層: 認証が通っているか
リモートサーバーが401か403を返すと、Claude Codeはそのサーバーを「認証が必要」とマークし、/mcp のパネルに表示します。セッション内で /mcp を実行してブラウザーでログインすれば接続され、取得したトークンは保存されて自動更新されます。Datadog MCP ServerはOAuthとPAT/SAT認証を使い分けられ、接続手順にtoolsetsでの絞り込み方をまとめています。TavilyのMCPサーバーもAPIキー方式とOAuth方式の両方に対応しており、Tavily MCP検索サーバー接続ガイドで使い分けを扱っています。
/mcpログインまで進めない、あるいは進んでも状態が残らないケースは3つに分かれます。
動的クライアント登録に非対応のサーバー。「Incompatible auth server: does not support dynamic client registration」というエラーで止まります。サーバー側の開発者ポータルでOAuthアプリを登録し、--client-id と --client-secret、登録済みリダイレクトURIと一致する --callback-port を付けて追加し直します。
認証ヘッダーとOAuthの取り合い。headers.Authorization を設定したサーバーがそのヘッダーを拒否すると、Claude CodeはOAuthへフォールバックせず接続失敗として報告します。トークンがMCPエンドポイントで有効かを確かめるか、OAuthを使うならヘッダー設定を消します。末尾の改行が混ざっていないかも、前節の警告で確認できます。
リモートサーバーの url や headers では、ANTHROPIC_API_KEY や NPM_TOKEN のような認証情報の変数は展開されず、空として読まれます。警告は出ないまま Bearer だけが送られ、サーバーが401で拒否して接続失敗になります。
claude.ai側のコネクタが出てこない。この場合はアクティブな認証方法を確認します。コネクタが読み込まれるのはClaude.aiサブスクリプションで認証しているときだけで、ANTHROPIC_API_KEY やBedrock / Vertex経由の認証では読み込まれません。
一度認証したのに毎回ログインを求められる類の症状は、更新で解消している可能性が高い領域です。MCPのOAuth経路をまとめて修正したv2.1.118では、/mcp メニューの認証アクション欠落、expires_in 省略時の毎時再認証、macOSキーチェーンの競合などが同時に塞がれています。
第4層: 接続済みなのにツールが呼ばれない
/mcp で接続済みと出ているのにClaudeがツールを使わないなら、接続の問題ではありません。ツールが見えていないか、呼ぶ判断がされていないかのどちらかです。
最初に /mcp でそのサーバーのツール数を見ます。0ならサーバー側がツールを公開できていません。まず /mcp からReconnectを選びます。0のままなら claude --debug=mcp で起動し、サーバーの標準エラー出力を ~/.claude/debug/<session-id>.txt のデバッグログで読みます。数が出ているなら、次の3点を確認します。
ツール数が出ているのに呼ばれないときの3点
モデルと接続先
ツール検索は既定で有効で、MCPのツールは遅延され、必要になったときに見つかる仕組みです。
tool_referenceブロックに対応するモデル(Sonnet 4.5 / Haiku 4.5 / Opus 4.5以降)が前提で、ANTHROPIC_BASE_URLがファーストパーティ以外のホストを指していると、既定で無効になります。常時読み込みの指定
特定のサーバーを毎回すべて読ませたい場合は、そのサーバー定義に
alwaysLoad: trueを付けます。v2.1.121で追加されたオプションです。ENABLE_TOOL_SEARCH=falseで全サーバーを事前読み込みに戻す方法もあります。ツール名での指名
「GitHubのissueを見て」ではなく
mcp__github__list_issuesのようにツール名で指名します。呼ばれない原因が認識側にあるのか接続側にあるのかを分けられます。
出力側で切れている場合も、見え方はよく似ています。ツール出力が10,000トークンを超えると警告が出て、既定25,000トークンの上限(MAX_MCP_OUTPUT_TOKENS)を超える結果は打ち切られます。大きなスキーマやログを返すサーバーでは、上限を引き上げてから起動する手があります。警告のしきい値は固定で、上限だけが変えられます。
stdioとリモートではエラーの出方がどう違うか
同じ「つながらない」でも、トランスポートによって失敗の現れ方が違います。ここを知っていると、症状を見た時点で調べる層を絞れます。
トランスポート別の失敗の出方
stdio(ローカル)
起動の時点で一気に失敗します。主な原因はパス誤り、環境変数、標準出力の汚染です。自動再接続はなく、確認は起動コマンドを手で実行するところから始めます。
HTTP(リモート)
追加は成功し、実際に応答を受ける段で止まります。疑うのは認証、ネットワーク、エンドポイント違いです。指数バックオフで最大5回再接続し、確認は /mcp の認証状態から始めます。
追加が成功するのは、stdioもリモートも同じです。前掲の実機例では、存在しないパッケージでも Added と出ました。違うのは止まる場所で、stdioは起動の時点、リモートは応答を受ける段になります。一覧に名前が並んでいても、接続できている証拠にはなりません。切り分けの順序を層で固定するのは、この理由からです。
起動時の初回接続は、HTTP / SSEのサーバーに限って一時的なエラーなら最大3回まで再試行されます(v2.1.121で追加)。対象は5xx応答、接続拒否、タイムアウトです。認証エラーとnot-found(エンドポイントのURL違い)は、設定を変えないと直らないため再試行されません。ネットワークが安定しない環境での「たまに繋がらない」は再試行の範囲に収まることがあり、URLの綴り違いや認証の失敗は1回で失敗扱いになります。ただし headersHelper が Authorization ヘッダーの唯一の供給元のときは、認証エラーでも再試行されます。WebSocketサーバーの初回接続も再試行されません。
セッション中に切れた場合は、5回の再接続に失敗すると MCP server "<name>" disconnected · open /mcp to reconnect という通知が出ます。/mcp から手動でやり直せます。ターミナルではv2.1.284以降、/mcp reconnect all で全サーバーをまとめて再試行できます。
それでも切り分かないとき
ログを見る手が残っています。デバッグログは既定で無効なので、claude --debug で起動するか、セッションの途中で /debug を打ってその時点から記録を始めます。ファイルに落とすなら --debug-file です。
claude --debug
claude --debug-file /tmp/claude.logもう一つ効くのが、自分の環境ではなくバージョンを疑うことです。MCPの接続まわりは修正が続いている領域で、症状がそのまま過去の修正項目に一致することがあります。SSE / HTTPの接続が応答途中で落ちたときの無限ハングはv2.1.110で、stdioのツール実行中にEscを押すとサーバー接続そのものが閉じるリグレッションはv2.1.120で、それぞれ解消しました。claude update を先に走らせてから再現を取ると、調査自体が不要になることもあります。
MCPに限らずClaude Code全般の詰まりどころは起動失敗から権限まで10種のエラーと対処をまとめた記事に並べてあります。そもそもMCPがどういう層で何を運んでいるのかを掴み直したいときはMCPの仕組みと採用状況の解説が土台になります。
まとめ
層の順序を覚えるより、ふだんから claude mcp get <name> の出力を読む習慣のほうが効きます。「承認待ち」「認証が必要」「接続失敗」は、それぞれ別の層の話です。原因の見当が付かないまま設定を書き換えると、直った理由も分からないまま次の環境で再発します。層を1つずつ確定させた記録が残っていれば、チームの誰かが同じ症状を踏んだときに再利用できます。Claude Code全体の機能とMCPの位置付けを見渡したい場合はClaude Codeの全体像が起点になります。