Xでシェア

Writing / MCP

N° 09

MCPサーバーをAIクライアントに接続する方法:stdioの仕組みから設定・Tool実行まで解説

Filesystem MCP ServerをClaude Desktopへ接続するハンズオンを通して、command・args・envの意味、stdioによるプロセス間通信、initialize、tools/list、tools/callの流れを解説します。接続エラーをプロセス起動とMCP通信に分けて調査する方法も紹介します。

このガイドに含まれます

MCP完全ガイド

この記事を読むとできるようになること

  • stdio接続のプロセスとライフサイクルを説明できる
  • MCPサーバーをAIクライアントへ設定し、Tool実行を確認できる

1. はじめに:設定を書くだけでなぜToolを使えるのか

公開されているMCPサーバーのREADMEを見ると、設定ファイルへcommandargsを追加するだけで利用できるように見えます。しかし、それだけでは次の疑問が残ります。

  • 「サーバー」なのに、なぜURLやポート番号がないのか
  • commandargsenvは何を表しているのか
  • AIはどのようにToolの存在を知るのか
  • 「MCP server disconnected」と表示されたら、どこから調べるのか

答えの中心にあるのが、ローカルMCPサーバーで広く使われるstdio transportです。

stdio方式では、AIクライアントがMCPサーバーを子プロセスとして起動し、その標準入力と標準出力を通信路として使います。設定は単なるプラグイン一覧ではありません。「どのコマンドで子プロセスを起動し、どの引数を渡し、その標準入出力をMCPの通信路として使うか」を定義しています。

この記事ではClaude Desktopと公式のFilesystem MCP Serverを例に、手動起動、設定、初期化、Toolの検出・実行、環境変数、トラブルシューティングまでを扱います。基本原理はCodexやIDEなど、ほかのstdio対応クライアントでも共通です。ただし、設定場所や形式、承認UIはクライアントごとに異なります。

対象はローカルのstdio接続です。Streamable HTTPやOAuthを使うリモート接続は扱いません。

MCPについての解説はこちらの記事を参照してください。

WritingMCPMCPとは?API・Function Callingとの違いを初心者向けに図解MCP(Model Context Protocol)の役割を、REST APIやFunction Callingとの違いから初心者向けに解説します。Host・Client・Serverの関係、処理の流れ、MCPが向くケースと不要なケースを整理します。

2. 今回構築するもの

完成後の処理経路は次のようになります。

plaintext
ユーザー
  ↓ 指示
AIモデルを含むHost(Claude Desktopなど)
  ↓ Toolの選択
MCP Client
  ↓ stdin / stdoutによるJSON-RPC
Filesystem MCP Server
  ↓
許可されたローカルディレクトリ

MCPの公式アーキテクチャ解説では、登場要素を次のように分けています。

  • Host:AIアプリケーション全体。会話、モデル、権限、複数の接続を管理する
  • Client:特定のMCPサーバーとの接続を維持するコンポーネント
  • Server:Tool、Resource、Promptなどを公開するプログラム

通常、Hostは接続するMCPサーバーごとにClientを1つ作ります。「AIモデルがサーバーへ直接接続する」のではなく、Host内のMCP Clientが通信を担当する点が重要です。

3. stdioによるローカル連携とは

3.1 stdin・stdout・stderr

OS上で起動されたプロセスには、一般に次のストリームがあります。

  • stdin:プロセスが入力を受け取る標準入力
  • stdout:通常の出力を送る標準出力
  • stderr:ログや診断情報を送る標準エラー出力

stdio方式では、MCP ClientがMCP Serverを子プロセスとして起動します。ClientからServerへのJSON-RPCメッセージはServerのstdinへ送られ、Serverからのメッセージはstdoutから読み取られます。

MCP 2025-11-25のtransport仕様では、メッセージはUTF-8のJSON-RPCで、改行によって区切られると定められています。したがってServerは、MCPメッセージではない文字列をstdoutへ書いてはいけません。ログにはstderrを使います。

javascript
// NG: stdoutを汚し、JSON-RPCを壊す可能性がある
console.log("Server started");

// OK: 診断ログはstderrへ送る
console.error("Server started");

stderrへの出力は必ずしも障害を意味しません。Clientはそれを記録、転送、または無視できます。

3.2 Streamable HTTPとの違い

観点

stdio

Streamable HTTP

主な構成

ローカルプロセス間連携

ネットワーク越しの接続

接続先

Clientが起動した子プロセス

HTTPエンドポイント

URL・ポート

基本的に不要

必要

通信経路

stdin・stdout

HTTP POST、必要に応じてSSE

Serverの起動

Clientが起動

独立して稼働

認証情報

環境変数など

HTTP認証やOAuthなど

stdioでも「Client」と「Server」という役割は存在しますが、HTTPサーバーをlocalhostで待ち受ける仕組みではありません。同じマシン上の2プロセスがパイプで通信します。

4. Filesystem MCP Serverを手動で起動する

4.1 事前準備

Filesystem MCP ServerはNode.js製です。まず実行環境と検証用ディレクトリを準備します。

bash
node --version
npx --version
mkdir -p ~/mcp-demo

次にServerを起動します。

bash
npx -y @modelcontextprotocol/server-filesystem ~/mcp-demo

各部分の意味は次のとおりです。

  • npx:npmパッケージが提供するコマンドを実行する
  • -y:パッケージ取得時などの確認へ自動的に同意する
  • @modelcontextprotocol/server-filesystem:起動するnpmパッケージ
  • ~/mcp-demo:アクセスを許可するディレクトリ

ここで~をホームディレクトリへ展開しているのはシェルです。後述するJSONのargsではシェルを経由しないことがあるため、~ではなく絶対パスを使います。

Filesystem MCP Serverの公式READMEによると、このServerはファイルの読み書き、ディレクトリ操作、検索、メタデータ取得などのToolを公開します。アクセス先はコマンドライン引数、またはClientが対応している場合はMCP Rootsで制限されます。必要以上に広いディレクトリを許可しないでください。

4.2 何も表示されなくても異常とは限らない

起動後、画面が止まったように見えることがあります。stdio Serverは通常の対話型CLIではなく、stdinからMCPメッセージが届くのを待っています。

Ctrl+Cで終了でき、例外が表示されていなければ、少なくともプロセス起動までは成功している可能性があります。ただし、これだけではinitializeやTool実行の成功までは確認できません。プロトコルレベルの確認には、後述するMCP Inspectorを使います。

5. AIクライアントへ登録する

Claude Desktopの設定ファイルを開き、次のように登録します。macOSでは設定画面のDeveloperセクションから開けるほか、通常は~/Library/Application Support/Claude/claude_desktop_config.jsonにあります。Windowsでは%APPDATA%\Claude\claude_desktop_config.jsonです。場所やUIは将来変更される可能性があるため、利用中のClientの資料も確認してください。

claude_desktop_config.jsonjson
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/username/mcp-demo"
      ]
    }
  }
}

これは概念的に、次のようなプロセス起動を表しています。

javascript
spawn("npx", [
  "-y",
  "@modelcontextprotocol/server-filesystem",
  "/Users/username/mcp-demo"
]);

5.1 command・args・Server名

  • filesystem:Client上で接続を識別する名前
  • command:実行するプログラム。この例ではnpx
  • argscommandへ順番に渡す引数の配列

argsはシェルコマンド全体を1本の文字列にするのではなく、引数ごとに分けます。空白を含むパスも1つの配列要素として扱います。

5.2 絶対パスを使う理由

GUIアプリから起動されたServerの作業ディレクトリは、ターミナルで試したときと同じとは限りません。./mcp-demo~/mcp-demoではなく、次のような絶対パスを指定します。

json
"/Users/username/mcp-demo"

npxが見つからない場合は、which npxまたはWindowsのwhere npxで実体を調べ、Clientの仕様に応じて絶対パスを指定します。Windowsでは公式Filesystem Serverの例のように、commandcmdargsの先頭を["/c", "npx", ...]とする必要がある場合もあります。

保存後はClaude Desktopをウィンドウだけ閉じるのではなく、完全に終了して再起動します。公式ローカル接続ガイドでも、設定の再読込とServer起動のため完全な再起動が案内されています。

6. MCPサーバーが認識されるまでの通信フロー

設定を読み込んだClientでは、概ね次の処理が行われます。

plaintext
1. 設定ファイルを読み込む
2. commandとargsでServerを子プロセスとして起動する
3. Serverのstdin・stdoutへパイプを接続する
4. initializeリクエストを送る
5. プロトコルバージョンとCapabilityを確認する
6. notifications/initializedを送る
7. tools/listでTool定義を取得する
8. Tool情報をHostとAIモデルが利用できる形に登録する

6.1 initialize:接続条件をそろえる

最初のやり取りはinitializeです。簡略化すると次のようになります。

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

Serverは合意するプロトコルバージョン、toolsresourcesなどのCapability、serverInfoを応答します。Clientがそのバージョンを扱えなければ、接続を終了すべきとされています。成功後、Clientは初期化完了を通知します。

json
{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}

MCP lifecycle仕様では、初期化を最初の対話とし、バージョン互換性、Capability、実装情報を交換するよう定めています。例のバージョンは記事執筆時点の仕様を示すもので、実際にはClientとServerが対応する値で交渉します。

6.2 tools/list:利用可能なToolを発見する

初期化後、ClientはTool一覧を要求できます。

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list"
}

Serverは各ToolのnamedescriptioninputSchemaなどを返します。入力スキーマは、必要な引数や型を表すJSON Schemaです。Clientはこの情報をHostへ登録し、AIモデルが「どの操作を、どの引数で利用できるか」を判断できるようにします。

6.3 AIが直接プロセスを操作するわけではない

この流れを役割別に整理すると、次のようになります。

  • AIモデルは、Hostから渡されたTool定義を見て利用を判断する
  • Hostは権限確認やユーザー承認を行う
  • MCP Clientがtools/callをJSON-RPCとして送信する
  • MCP Serverが実際のファイル操作を実行する

つまり、モデル自身がnpxを起動したり、直接stdinへ書き込んだりするわけではありません。

7. AIからToolを呼び出す

接続後、Claude Desktopへ次のように依頼します。

plaintext
mcp-demoディレクトリにhello.txtを作成してください。
内容は「Hello, MCP!」にしてください。

実行結果としては以下のようになりMCPが呼ばれていることがわかります。

作成されたファイルの中身

plaintext
cat ~/mcp-demo/hello.txt
Hello, MCP!

モデルがFilesystem Serverのwrite_fileを選ぶと、MCP Clientは概念的に次のリクエストを送ります。

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "write_file",
    "arguments": {
      "path": "/Users/username/mcp-demo/hello.txt",
      "content": "Hello, MCP!"
    }
  }
}

処理全体は次の順序です。

plaintext
ユーザーの指示
  ↓
AIモデルがwrite_fileの利用を提案
  ↓
Hostが必要に応じてユーザー承認を求める
  ↓
MCP Clientがtools/callを送信
  ↓
Filesystem MCP Serverがファイルを書き込む
  ↓
Tool結果をJSON-RPCで返す
  ↓
AIモデルが結果をユーザーへ説明する

MCPのTools仕様は、Toolの発見にtools/list、実行にtools/callを使用すると定めています。また、実装にはToolの公開や呼び出しを明示し、ユーザーが拒否できる仕組みを持たせることが推奨されています。

8. envで環境変数を渡す

APIキーなどが必要なstdio Serverには、設定のenvで子プロセスの環境変数を渡せます。

claude_desktop_config.jsonjson
{
  "mcpServers": {
    "example": {
      "command": "npx",
      "args": [
        "-y",
        "example-mcp-server"
      ],
      "env": {
        "EXAMPLE_API_KEY": "your-api-key"
      }
    }
  }
}

Server側では、Node.jsならprocess.env.EXAMPLE_API_KEY、Pythonならos.environ["EXAMPLE_API_KEY"]などで参照できます。

GUIアプリから起動したプロセスには、ターミナルで設定した環境変数が同じように渡るとは限りません。公式デバッグガイドも、stdio Serverが自動継承する環境変数は限定され、プラットフォームに依存すると説明しています。必要な値はenvへ明示します。

一方、秘密情報をGit管理する設定ファイルへ直接書くのは避けてください。ClientがOSのキーチェーン、秘密情報ストア、環境変数参照などを提供している場合は、それを優先します。設定ファイルとログのアクセス権にも注意が必要です。

MCPの標準Authorization仕様は主にHTTP transport向けです。Authorization仕様では、stdio実装はHTTP向けフローではなく環境から認証情報を取得する方針が示されています。

9. 接続できない場合の切り分け方

「MCP server disconnected」だけを検索するより、失敗した段階を特定する方が早く原因へ近づけます。

9.1 設定を読み込めているか

最初に次を確認します。

  • JSONに末尾カンマ、クォート不足、括弧の不一致がないか
  • 正しい設定ファイルを編集したか
  • mcpServerscommandargsの型が正しいか
  • Clientを完全に終了して再起動したか

Server名自体がUIに現れない場合は、この層を疑います。

9.2 同じコマンドを手動実行できるか

設定と同じ内容をターミナルで試します。

bash
npx -y @modelcontextprotocol/server-filesystem \
  /Users/username/mcp-demo

ここで失敗するなら、MCPの初期化以前の問題です。Node.jsやnpxがない、PATHが異なる、パッケージを取得できない、ディレクトリが存在しない、権限がない、といった原因を確認します。

9.3 Clientのログを確認する

Claude DesktopのMCP関連ログは、macOSでは~/Library/Logs/Claude、Windowsでは%APPDATA%\Claude\logsに保存されると公式ガイドに記載されています。macOSでは次のように追跡できます。

bash
tail -n 20 -F ~/Library/Logs/Claude/mcp*.log

ログへAPIキー、個人情報、ファイル内容を残さないよう注意してください。

9.4 stdoutと環境変数を確認する

独自Serverなら、通常ログをstdoutへ出していないか確認します。1行の起動メッセージでもJSON-RPCのストリームを壊します。診断ログはstderrへ送ります。

API連携Serverなら、環境変数名、値、Client設定のenv、設定変更後の再起動を確認します。ターミナルで動くのにGUI Clientから失敗する場合は、PATHや環境変数の差が有力です。

9.5 MCP Inspectorで単体確認する

MCP Inspectorを使うと、AI Clientを介さずにstdio Serverへ接続し、Capability、Tool一覧、入力スキーマ、Tool実行結果を確認できます。

bash
npx -y @modelcontextprotocol/inspector \
  npx -y @modelcontextprotocol/server-filesystem \
  /Users/username/mcp-demo

Inspectorで動くのにClaude Desktopで動かないなら、Server本体よりもClient設定、環境、承認状態を疑えます。Inspectorでも接続できないなら、Server起動またはMCPプロトコル側を調べます。

9.6 4段階で分類する

plaintext
1. プロセスを起動できない
   → command、PATH、Node.js、引数、権限を確認

2. initializeに失敗する
   → stdout汚染、例外、バージョン、Capabilityを確認

3. tools/listに失敗する
   → tools Capability、Tool定義、JSON Schemaを確認

4. tools/callだけ失敗する
   → Tool名、arguments、許可ディレクトリ、実行権限を確認

この分類を使えば、「接続できない」という大きな問題を、OSプロセス、transport、MCP lifecycle、個別Toolの問題へ分解できます。

10. まとめ

stdio方式の設定は、AIクライアントへ子プロセスの起動方法を教えるものです。commandが実行プログラム、argsが引数、envが子プロセスへ渡す環境変数になります。

起動後はstdinstdoutでJSON-RPCを交換し、initializeでバージョンとCapabilityを確認します。Clientはtools/listでToolを発見し、モデルが利用を選ぶとtools/callを送ります。AIモデルではなく、HostとMCP Clientが接続や実行を管理します。

問題が起きたら、設定、プロセス起動、initializetools/listtools/callの順に切り分けてください。特に、絶対パス、環境変数、stdoutへの不要なログは、stdio接続で最初に確認したいポイントです。

次のステップ

MCPサーバーをStreamable HTTPでリモート化する方法:Python・SSE・Docker対応

stdio形式のMCPサーバーを、複数クライアントがURLで利用できるStreamable HTTPサービスへ移行します。Python SDKによる実装、セッション、JSONとSSE、Docker、Origin検証、CORS・TLS・認証の違いまで解説します。

次の記事を読む