MCPサーバーを繋ごうとして「startup incomplete」と表示され、止まっていませんか。これはOpenAI Codex特有の表示にすぎず、正体は各ツールに共通する「initializeハンドシェイクが完了しなかった」状態です。本記事はMCPを使う初〜中級の開発者向けに、文言ではなく「初期化のどこで止まったか」で原因を切り分け、Codex・Claude Code・Cursorなどで同じ手順で直す方法を公式情報を根拠に整理します(確認日:2026年6月14日)。
MCPの「startup incomplete」とは何か(initializeハンドシェイクが完了しない状態)

「MCP startup incomplete」という完全一致の文言は、実はOpenAI Codexが出すステータス表示です。まずこの表示が何を意味し、他のツールではどう見えるのかを整理します。
結論:表示はツールごとに違うが、根本原因は1つに集約できる
- startup incomplete = Codexの表示
- 正体 = initialize未完(全ツール共通)
- 確認:手元でコマンド直実行
- 原因:パス・stdout汚染・timeout・version
最初に、この記事全体の結論をまとめておきます。startup incompleteは「initializeの往復が成立する前に打ち切られた(参考)」状態です。Codex特有の表示(参考)ですが、他のクライアントでも同じ根本原因で起こります。本記事は「initializeのどこで止まったか」で切り分け、ツール共通の対処法を示します。
まずは設定のcommandとargsをターミナルで実行し、サーバー側とクライアント側のどちらに原因があるかを切り分けてください。表示されている文言がCodexの「startup incomplete」でも、Claude Codeの「failed」でも、Cursorの「Loading tools」のままでも、確認する場所と直し方はほぼ共通です。本記事では、まず症状の正体を押さえ、次にログとエラー文言から原因を逆引きし、最後に原因別の対処と環境別(Windows / Mac / Linux)の確認点までを順にたどります。
initializeの3ステップが、startup incompleteの発生箇所を決める
では「initializeが完了しない」とは、通信のどの段階を指すのでしょうか。MCPの初期化は3つのステップで成り立っています。
initializeの3ステップ
クライアント(CodexやClaude)がサーバーにinitializeリクエストを送ります。サーバーが応答します。最後にクライアントがnotifications/initializedでサーバーに受信完了を通知します。
この3ステップが揃って、はじめてクライアントとサーバーの運用が開始されます。startup incompleteが発生するのは、この往復のどこかが完走しない状態です。
この往復が成立する前に打ち切られると startup incomplete になる
サーバープロセスが落ちる、またはクライアント側で応答が読み込めない場合があります。設定のcommandやargsが誤っていれば、サーバーが正しく起動しません。
仕様は初期化のエラーを3種(バージョン不一致、capability折衝の失敗、タイムアウト)と明記しており、これらで往復が中断されるとstartup incompleteが表示されます。
Codex・Claude Code・Cursor・VS Code・Claude Desktopで見え方が違う理由
handshaking with MCP server failed: connection closed: initialize response — Codex Issues #6020(参考)
ツールごとの見え方の違いを把握しておくと、切り分けがしやすくなります。
Codex・Claude Code・Cursor・VS Code・Claude Desktopでの見え方
同じ障害でも、ツールによって画面上の言葉はまったく違います。
- Codexは「startup incomplete」や「failed to start」
- Claude Codeは接続パネルで「failed」
- CursorはツールバーやMCP欄が「Loading tools」のまま進まない
- VS CodeはChatビューにエラーが出る
- Claude Desktopではコネクタのアイコンそのものが表示されない
文言は別物ですが、起きていることは一つで、すべてinitializeの往復が完了していない同じ状態を指しています。
表示が違っても確認すべき場所は共通
ここで注意したいのは、表示文言の違いに引きずられて「これは自分の使っているツール固有の不具合だ」と決めつけてしまうことです。実際にはinitializeが完了していないという原因が共通しているため、調べる場所と直し方も共通します。
表示の言葉から原因を推測する前に、次章で説明する「設定のコマンドを手元でそのまま実行する」切り分けを行ってください。どのツールを使っていても、これが最初の一歩になります。
原因を切り分ける(initializeのどこで打ち切られたかを特定する)

原因を当てずっぽうで設定変更する前に、まず障害がサーバー側にあるのかクライアント側にあるのかを切り分けます。公式が推奨する最短の手順は「設定のコマンドを手元でそのまま実行する」ことです。
まず手元でコマンドを直接実行し、MCP Inspectorで単体テストする
切り分けの第一歩は、設定ファイルをいじることではありません。
設定のコマンドをそのままターミナルで打つ
最初にやるべきことは、設定ファイルに書いたcommandとargsをそのままコピーして、ターミナルで手元で起動してみることです。ここで落ちるなら、原因はクライアントではなくサーバー側にあります。
公式のデバッグガイド(参考)は、実行ファイルのパス誤り・必要ファイルの欠落・権限の問題を起動失敗の主な原因に挙げ、commandは絶対パスで指定するよう助言しています。逆に手元では問題なく起動するのにツール経由で繋がらないなら、疑うべきはクライアント側の設定の書き方や、実行する環境の差です。当てずっぽうで設定を変える前に、この一手で原因がどちら側にあるかを先に確定させてください。
MCP Inspectorで単体テストする
手元のターミナルでは起動するのに、クライアント経由だと繋がらない。そんなときの次の一手がMCP Inspectorです。Inspectorはトランスポートの種類に依存せず、stdioでもHTTPでもサーバーを直接叩いてテストできる公式のツールです。
これを使うと、特定のクライアント(CodexやCursorなど)を介さずにサーバー単体の応答を確認できるため、問題がサーバーの実装そのものにあるのか、それとも特定クライアントの設定や扱い方にあるのかを切り分けられます。クライアントごとに表示が違って判断に迷うときほど、まず素のサーバーがどう応答するかを見るのが近道です。
やりがちな遠回り:先に設定を書き換えてしまう
やりがちな遠回りが、原因を特定しないまま設定ファイルを書き換え始めてしまうことです。サーバー側の依存パッケージが足りない、といった根本の問題が残っているのに、commandやenvをあれこれ変えると、解決しないまま設定だけが複雑になり、後から見て何が効いているのか分からなくなります。
遠回りを避けるには、「手元でコマンドを実行する → ログを確認する → プロセスが動いているか確認する → MCP Inspector で単体テストする → プロトコルやcapabilityの互換を確認する」という順序を守り、原因を一カ所に局在させてから対処に入るのが確実です。
クライアント別にログをどこで見るか(横断一覧)
手元で起動するのにツール上で失敗する場合は、各クライアントのログを読みます。
Claude Code(CLI)とClaude Desktopのログ
Claude Codeでは、claude mcp listでサーバーの状態を確認します。⏸ Pending approvalや✗ Rejectedで接続が確立できていません。対話中は/mcpで現在の状態を確認できます。
Claude DesktopはmacOS(~/Library/Logs/Claude)とWindows(%APPDATA%\Claude\logs)でログ場所が異なります。mcp.logは接続全般、mcp-server-<NAME>.logはそのサーバーのstderr出力を記録します。
VS CodeとCursorのログ
VS CodeはコマンドパレットからMCP: List Serversを選び、対象サーバーのShow Outputでログを確認します。ローカルサーバーは初回に信頼確認のダイアログが表示され、これを許可しないとそもそも起動されないため、「設定したのに動かない」原因が信頼の未確認だったというケースもあります。
Cursorは出力(Output)パネルのドロップダウンからMCPを選ぶと関連ログが見られます。ツール一覧がLoading toolsと表示されたまま進まない場合は、初期化が完了しておらず未接続だと考えてください。表示が止まっているだけで成功しているように錯覚しやすいので、ここで止まっていないかを確認しておくと、後の切り分けが速くなります。
設定変更後は完全終了して再起動する
設定ファイルやサーバーのコードを変更したら、アプリを完全に終了してから再起動してください。ウィンドウを閉じただけだと、バックグラウンドにプロセスが残って設定が再読み込みされず、「直したのに直らない」という錯覚に陥ります。
Claude Desktopはウィンドウを閉じるだけでは終了しないことがあるため特に注意が必要で、メニューから明示的に終了させてください。Cursorも環境変数(env)を変更した場合は再起動が必要です。直したつもりの変更が反映されているか不安なときは、まず完全終了と再起動を試してからログを読み直すと、無駄な切り分けを減らせます。
ログのエラー文言から原因を逆引きする
手元実行でサーバーが正常に動作し、クライアント側のログを確認できたら、そのログに含まれるエラー文言を下表と照らし合わせて原因を特定します。MCPのinitialize往復がどの段階で失敗しているか、エラー出力から逆引きできるようにまとめました。これにより、問題がサーバーの起動段階か、クライアントの通信段階かが明確になります。
| エラー文言(症状) | 疑う原因(初期化のどの段階か) | 対処の方向 |
|---|---|---|
| connection closed: initialize response | 初期化応答が読めない(stdout汚染、プロセス異常終了) | サーバーがstdoutにログやデバッグ出力を出していないか確認する |
| timed out after 60 seconds | 起動タイムアウト(応答待機が長い) | タイムアウト値を延ばす(MCP_TIMEOUT、startup_timeout_sec) |
| Permission denied (os error 13) | 実行権限不足またはコマンドが見つからない | commandを絶対パスに修正し、実行権限を確認する |
| missing field type | JSON設定の必須フィールド欠落 | 設定ファイルの構文と必須フィールドを検証する |
| Unsupported protocol version(-32602) | プロトコルバージョン不一致 | クライアント・サーバーのMCP仕様バージョン(参考)を整合させる |
| Server does not support completions(required capability) | capability折衝失敗(サーバーが要求機能を備えない) | 要求するcapabilityをサーバーが実装しているか確認する |
この表が次章「原因別の対処」の目次になります。ログから該当するエラー文言を見つけたら、その行の「対処の方向」に示された方法で、順を追って確認していくことで、根本原因へたどり着けます。
原因別の対処法と環境別(Win/Mac/Linux)の確認点
逆引き表で原因のあたりが付いたら、ここから具体的に直していきます。頻度の高い順に、パスと権限、env、ランタイム、stdout汚染、タイムアウト、Windows特有、そして「実は壊れていない」ケースを確認してください。
コマンド/パス・実行権限・env/認証を直す
もっとも多いのは、サーバーを起動する前段でつまずくパターンです。
commandは絶対パスにし、実行権限を確認する
もっとも基本的な確認は、commandを絶対パスにし、その実行ファイルが本当に実行できるかを見ることです。パスが正しく解決できないと「spawn claude ENOENT」のようなエラー(参考)が出ます。ENOENTは「そのファイルが見つからない」という意味で、相対パスやPATHの通っていないコマンドを指定したときに起こります。
一方「Permission denied (os error 13)」(参考)は、ファイルは見つかっているものの実行権限がない、あるいはランチャーから起動できない状態を示すサインです。まずは設定のcommandとargsをそのままターミナルで打ってみて、起動するパスに直し、必要なら実行権限を付与してください。
stdioは環境変数を限定継承しかしない
見落としやすいのが環境変数の扱いです。stdioで起動するMCPサーバーは、環境変数の一部しか自動的には引き継ぎません(参考)。ふだんシェルで使えているからといって、APIキーや認証トークン、パス関連の変数がサーバーにそのまま渡るとは限りません。
手元のターミナルでは起動するのにクライアント経由だと落ちる、という場合はこれが原因のことがあります。サーバーが必要とするキーや変数は、設定ファイルのenvセクションに明示的に書いて渡してください。値をハードコードしたくなければ、起動元の環境から確実に渡る形にしておくのが安全です。
リモートサーバーの認証(401/403)
リモート(HTTP/SSE)のサーバーに繋ぐ場合は、認証でつまずくことがあります。401 Unauthorized や 403 Forbidden が返るのは、認証が必要だというサインです。Claude Codeなら、対話中に/mcpを開いてOAuthで認可すると接続できることがあります。
ここで注意したいのは、設定に静的なAuthorizationヘッダを書いてもサーバー側に拒否される場合があり、しかもClaude Codeはその拒否時にOAuthへ自動的にフォールバックしないため、表示はfailedのまま止まる点です。トークンを直書きして弾かれているなら、OAuthによる認可フローに切り替えて繋ぎ直してください。
stdoutの汚染とトランスポート種別を確認する
サーバーは起動しているのに「connection closed」になる場合、この原因が濃厚です。
ローカルMCPサーバーはstdoutにログを出してはいけません。stdoutはJSON-RPCプロトコル通信専用です。
ログをstdoutに出さない
stdioで通信するMCPサーバーは、標準出力(stdout)をJSON-RPCのやり取り専用に使います。ここにconsole.log()やprint()、起動時のバナー、デバッグ出力が1行でも混じると、クライアントが受け取るメッセージにJSONでない文字列が紛れ込み、応答が壊れます。
その結果、initializeの応答が読めず「connection closed」として接続が打ち切られます。サーバーは正常に動いているつもりでも、出力を1行汚しただけで初期化に失敗するわけです。公式のデバッグガイドも、ローカルサーバーはstdoutにログを出してはいけないと明記しています。ログはすべてstderrに回してください。
stderrに逃がす仕組み
なぜ1行で壊れるのかというと、プロトコルのデコーダはstdoutを1メッセージずつJSONとして解釈するため、非JSONの行が混ざるとそこで解析が破綻し、initializeの応答にたどり着けなくなるからです。
対処はシンプルで、出力先を標準エラー出力(stderr)に変えるだけです。stderrに出したメッセージはホストアプリ側が自動でキャプチャしてくれるため、ログを失うこともありません。Node.jsならconsole.error()、Pythonなら標準エラーへの出力に切り替える、といった形でstdoutを汚さないようにします。
トランスポート種別の不一致にも注意
stdoutを汚していないのに接続が閉じる場合は、トランスポート種別の不一致も疑ってください。Claude Codeではtransport typeとしてhttp(streamable-http)・sse(非推奨)・stdio・wsが選べますが、サーバーがHTTPで待ち受けているのに設定がstdioになっている、といったずれがあると、そもそも噛み合わずに接続が成立しません。
サーバーの実装がどのトランスポートを想定しているかを確認し、設定側のtypeをそれに合わせてください。古いsseは非推奨のため、新規に組むならhttpかstdioを選ぶのが無難です。
タイムアウトとバージョン/capability不一致に対処する
応答が遅い、あるいは応答はあるのに弾かれる場合の対処です。
起動タイムアウトを延ばす(ツール別の設定)
サーバーの起動に時間がかかって途中で打ち切られるなら、起動タイムアウトを延ばすのが対処です。設定方法はツールごとに違います。
Claude Codeは環境変数MCP_TIMEOUTで起動タイムアウトを設定でき、たとえばMCP_TIMEOUT=10000とすると10秒(単位はミリ秒)に延ばせます。サーバー起動後のツール実行にかかる時間は、別途MCP_TOOL_TIMEOUTで制御します。Codexの場合はconfig.tomlのstartup_timeout_sec(参考)で調整します。実際に「timed out after 60 seconds」というエラー文言とともに、この値を調整するよう促されるケースが報告されています。ただしデフォルトの秒数はツールやバージョンによって異なるため、ここでは具体的な既定値を断定しません。
バージョン/capability不一致を疑う
応答は返るのに「failed」になる場合、プロトコルバージョン不一致は-32602 Unsupported protocol version(参考)です。「Server does not support completions」(参考)のようなエラーは、要求capabilityがサーバーにない場合です。いずれも初期化段階でエラーコードが返るため、ドキュメントで宣言capabilityを確認しましょう。
数値を鵜呑みにしない(断定回避)
このエラーを扱う記事の多くは、「起動タイムアウトのデフォルトは10秒」「動作には最小◯◯以上のNode.jsが必要」といった数値を、出典を示さずに断定しています。しかしこうした値はツールの種類やバージョン、OSによって変わりうるもので、鵜呑みにすると古い前提のまま設定をいじってしまいます。
本記事では公式ドキュメントやエラー文言で裏が取れた数値だけを使い、裏の取れないものは「例として」にとどめています。読者の側でも、見かけた秒数やバージョン要件をそのまま信じるのではなく、自分の環境とツールのバージョンで実際に確認してから設定することをお勧めします。
Windows特有の対処とJSON設定の確認
Windows環境では特有のつまずきがあります。
- node –versionでランタイム確認
- commandをcmd /cでラップ
- envにAPPDATA実値を設定
- JSON構文を検証ツールでチェック
cmd /c でnpxをラップする
Windowsでまず引っかかりやすいのが、npxやnpmで起動するサーバーです。これらはWindows上では.cmdバッチとして実装されているため、設定にそのままnpxと書いて直接spawnしようとすると、実行ファイルとして起動できず失敗します。
対処は、commandを"cmd"にして、argsの先頭に"/c"を入れ、本来の起動コマンドをその後ろに続ける形でラップすることです。具体的にはcommand: "cmd", args: ["/c", "npx", "@server/tool"]のように書きます。Mac/Linuxではこのラップは不要なので、OSによって設定を出し分ける必要がある点も覚えておいてください。
${APPDATA} ENOENT とランタイム確認
もうひとつWindows特有なのが、パスに${APPDATA}が絡んでENOENTが出るケースです。これは公式ドキュメントにも記載があり、設定のenvにAPPDATAの実値を入れることで解消できます。env: { "APPDATA": "C:\\Users\\{user}\\AppData" }のように、自分の環境の実際のパスを指定してください。
Mac/Linuxでは、commandを絶対パスにする・実行権限をchmod +xで付ける・node --versionでランタイムが入っているか確認する(参考)、といった点を押さえておけば十分です。多くのMCPサーバーはNode.jsを前提とするため、まずランタイムの有無を確認するのが近道です。
JSON設定の構文ミス・必須フィールド欠落
OSを問わず怖いのが、設定JSONの構文ミスです。カンマの付け忘れや余分なカンマ、括弧の閉じ忘れがあると、設定ファイル全体が読み込めず、登録していたすべてのMCPサーバーが無言で起動に失敗します。1つのサーバーだけ追加したつもりが全部動かなくなった、というときは構文を疑ってください。
さらに、構文は正しくても必須フィールドが欠けていると「missing field type」のようなエラー(参考)になります。typeのような必須キーを書き忘れていないか確認しましょう。設定を編集したら、保存前にJSONの検証ツールで構文をチェックしておくと、こうした無言の失敗を防げます。
「failed表示でも実は動いている」場合がある(false positive)
ここまで試しても直らない時、そもそも本当に壊れているのかを疑ってみてください。
stderrの起動確認を誤認していないか確認する
stderrに出したメッセージはホストが自動でキャプチャします。クライアントが「failed」と表示していても、サーバーが起動して動いているのに、その起動確認文をエラーと誤認しているだけかもしれません。
ログに「Server stderr: …」と続いて起動成功のメッセージが見えたら、failed表示は偽陽性(false positive)です。確認方法は単純。failed扱いのツールを実際に呼び出し、動くか試してください。
表示と実態がずれる回帰もある
表示が実態とずれるのは、クライアント側の誤検知だけが理由とは限りません。Codexでは、サーバーの起動失敗や警告を画面に出さずに隠してしまう回帰(once動いていた挙動が壊れる不具合)が報告されています(参考)。こうした回帰があると、「failed」と出ているのに実は動いている逆のパターンだけでなく、表示と実際の状態が食い違うこと自体が起こり得ます。
ただし、これはツールのバージョンに依存する話で、すべての環境で起きると断定はできません。だからこそ、表示の言葉を最終的な判断材料にするのではなく、まず該当のツールを実際に呼び出して動くかどうかで確かめる姿勢が大切です。
解決しない場合の確認チェックリストと公式の確認先
判断を決める前に、次のポイントを上から順に確認してください。ひとつでも引っかかるところがあれば、いったん立ち止まって見直す判断も大切です。
- 設定のcommand+argsを手元でそのまま実行して起動するか確認した(落ちるならサーバー側)
- MCP Inspectorでサーバー単体をテストした
- クライアントのログ(Claude Desktopならmcp*.log)でエラー文言を確認した
- commandを絶対パスにし、実行権限を確認した
- 必要なAPIキー・環境変数を設定のenvに明示した
- サーバーがstdoutにログを出していないか確認した(stderrへ逃がした)
- 起動タイムアウトを延ばした(Claude CodeはMCP_TIMEOUT、Codexはstartup_timeout_sec)
- Windowsではnpxをcmd /cでラップし、${APPDATA}のENOENTを確認した
- JSON設定の構文と必須フィールドを検証ツールでチェックした
- 実際にツールを呼び、failedが誤検知(false positive)でないか確認した
- 設定変更後にクライアントを完全終了して再起動した
よくある質問
「MCP startup incomplete」はCodex専用のエラーですか?
完全一致の文言はCodexの表示ですが、正体はAIコーディングツール共通の「initializeハンドシェイクが完了しない」状態です。Claude CodeやCursorなどでは表示文言が違うだけで、原因と対処は共通します。
サーバーは起動しているのに「connection closed」になります。なぜですか?
stdoutにログやバナーが混じってJSON-RPC通信を壊している可能性が高いです。ローカルサーバーはログをstderrに出す必要があります。トランスポート種別の不一致でも接続が閉じます。
タイムアウトはどこで延ばせますか?
Claude Codeは環境変数MCP_TIMEOUT(例:MCP_TIMEOUT=10000で10秒)で起動タイムアウトを設定します。Codexはconfig.tomlのstartup_timeout_secで調整します。デフォルトの秒数はツールやバージョンで異なります。
Windowsでnpxを使うサーバーが起動しません。
npxは.cmdバッチのため、Windowsではcommandを”cmd”、argsを[“/c”,”npx”, …]のようにラップしてください。パスに${APPDATA}が絡むENOENTが出る場合は、設定のenvにAPPDATAの実値を入れます。
関連記事と公式情報の確認先・更新履歴
本記事と同じAIコーディングツールのエラー対処は、AIコーディングツールのエラー・設定データベースにまとめています。Claude CodeやCodexのMCP設定、認証エラー、タイムアウト関連の記事と合わせて読むと、自分の環境に近いケースが見つかりやすくなります。設定を直してもMCPが繋がらないときは、まず公式の一次情報で現在の仕様を確認してください。
公式の確認先は、MCP公式デバッグガイド、initializeライフサイクルを定めたMCP仕様、Claude CodeのMCPドキュメントです。仕様や既定値は更新されることがあるため、数値や設定キーは必ず最新の公式ページで照合してください。

コメント