1. はじめに:設定を書くだけでなぜToolを使えるのか
公開されているMCPサーバーのREADMEを見ると、設定ファイルへcommandとargsを追加するだけで利用できるように見えます。しかし、それだけでは次の疑問が残ります。
- 「サーバー」なのに、なぜURLやポート番号がないのか
command、args、envは何を表しているのか- 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についての解説はこちらの記事を参照してください。
2. 今回構築するもの
完成後の処理経路は次のようになります。
ユーザー
↓ 指示
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を使います。
// 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製です。まず実行環境と検証用ディレクトリを準備します。
node --version
npx --version
mkdir -p ~/mcp-demo次にServerを起動します。
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の資料も確認してください。
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/username/mcp-demo"
]
}
}
}これは概念的に、次のようなプロセス起動を表しています。
spawn("npx", [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/username/mcp-demo"
]);5.1 command・args・Server名
filesystem:Client上で接続を識別する名前command:実行するプログラム。この例ではnpxargs:commandへ順番に渡す引数の配列
argsはシェルコマンド全体を1本の文字列にするのではなく、引数ごとに分けます。空白を含むパスも1つの配列要素として扱います。
5.2 絶対パスを使う理由
GUIアプリから起動されたServerの作業ディレクトリは、ターミナルで試したときと同じとは限りません。./mcp-demoや~/mcp-demoではなく、次のような絶対パスを指定します。
"/Users/username/mcp-demo"npxが見つからない場合は、which npxまたはWindowsのwhere npxで実体を調べ、Clientの仕様に応じて絶対パスを指定します。Windowsでは公式Filesystem Serverの例のように、commandをcmd、argsの先頭を["/c", "npx", ...]とする必要がある場合もあります。
保存後はClaude Desktopをウィンドウだけ閉じるのではなく、完全に終了して再起動します。公式ローカル接続ガイドでも、設定の再読込とServer起動のため完全な再起動が案内されています。
6. MCPサーバーが認識されるまでの通信フロー
設定を読み込んだClientでは、概ね次の処理が行われます。
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です。簡略化すると次のようになります。
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": {
"name": "example-client",
"version": "1.0.0"
}
}
}Serverは合意するプロトコルバージョン、toolsやresourcesなどのCapability、serverInfoを応答します。Clientがそのバージョンを扱えなければ、接続を終了すべきとされています。成功後、Clientは初期化完了を通知します。
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}MCP lifecycle仕様では、初期化を最初の対話とし、バージョン互換性、Capability、実装情報を交換するよう定めています。例のバージョンは記事執筆時点の仕様を示すもので、実際にはClientとServerが対応する値で交渉します。
6.2 tools/list:利用可能なToolを発見する
初期化後、ClientはTool一覧を要求できます。
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}Serverは各Toolのname、description、inputSchemaなどを返します。入力スキーマは、必要な引数や型を表す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へ次のように依頼します。
mcp-demoディレクトリにhello.txtを作成してください。
内容は「Hello, MCP!」にしてください。実行結果としては以下のようになりMCPが呼ばれていることがわかります。

作成されたファイルの中身
cat ~/mcp-demo/hello.txt
Hello, MCP!モデルがFilesystem Serverのwrite_fileを選ぶと、MCP Clientは概念的に次のリクエストを送ります。
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "write_file",
"arguments": {
"path": "/Users/username/mcp-demo/hello.txt",
"content": "Hello, MCP!"
}
}
}処理全体は次の順序です。
ユーザーの指示
↓
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で子プロセスの環境変数を渡せます。
{
"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に末尾カンマ、クォート不足、括弧の不一致がないか
- 正しい設定ファイルを編集したか
mcpServers、command、argsの型が正しいか- Clientを完全に終了して再起動したか
Server名自体がUIに現れない場合は、この層を疑います。
9.2 同じコマンドを手動実行できるか
設定と同じ内容をターミナルで試します。
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では次のように追跡できます。
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実行結果を確認できます。
npx -y @modelcontextprotocol/inspector \
npx -y @modelcontextprotocol/server-filesystem \
/Users/username/mcp-demoInspectorで動くのにClaude Desktopで動かないなら、Server本体よりもClient設定、環境、承認状態を疑えます。Inspectorでも接続できないなら、Server起動またはMCPプロトコル側を調べます。
9.6 4段階で分類する
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が子プロセスへ渡す環境変数になります。
起動後はstdinとstdoutでJSON-RPCを交換し、initializeでバージョンとCapabilityを確認します。Clientはtools/listでToolを発見し、モデルが利用を選ぶとtools/callを送ります。AIモデルではなく、HostとMCP Clientが接続や実行を管理します。
問題が起きたら、設定、プロセス起動、initialize、tools/list、tools/callの順に切り分けてください。特に、絶対パス、環境変数、stdoutへの不要なログは、stdio接続で最初に確認したいポイントです。