nikkie-ftnextの日記

イベントレポートや読書メモを発信

MCPサーバとクライアントのstdio transportは何をしている? MCPサーバのPythonスクリプトに一連のJSONを送ってツール一覧を得るまで

(2025/04/27 追記) この記事のupdate版がこちらです

シェルで一連のJSONを送るよりも、MCPサーバを起動して標準入力で送る方が実行できるリクエストが多いです(特にtools/call

(追記終わり)


はじめに

七尾百合子さん、お誕生日 17日目 おめでとうございます! nikkieです。

久しぶりのMCPの話題です。

目次

MCPサーバは一体何をやっている?

Quickstartに沿ってお天気のMCPサーバを作りました。

modelcontextprotocol.io

作る中で試しに、MCPサーバのスクリプトPython処理系で実行してみたのですが、何も起こりません

% uv run weather.py  # Ctrl+C連打で抜けます

しかしMCPクライアントにMCPサーバのスクリプトを渡すと動きます。

% uv run client.py ../weather/weather.py

一体何をやっているのでしょうか? 私、気になります!

結論:stdio transportを覗き見

この記事の結論です。

% echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"bash-client","version":"1.0.0"}}}' | uv run weather.py
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"experimental":{},"prompts":{"listChanged":false},"resources":{"subscribe":false,"listChanged":false},"tools":{"listChanged":false}},"serverInfo":{"name":"weather","version":"1.3.0"}}}
% uv run weather.py <<EOF
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"bash-client","version":"1.0.0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
EOF
[04/03/25 22:24:05] INFO     Processing request of type            server.py:534
                             ListToolsRequest
{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"get_alerts","description":"Get weather alerts for a US state.\n\n    Args:\n        state: Two-letter US state code (e.g. CA, NY)\n    ","inputSchema":{"properties":{"state":{"title":"State","type":"string"}},"required":["state"],"title":"get_alertsArguments","type":"object"}},{"name":"get_forecasts","description":"Get weather forecasts for a location.\n\n    Args:\n        latitude: Latitude of the location\n        longitude: Longitude of the location\n    ","inputSchema":{"properties":{"latitude":{"title":"Latitude","type":"number"},"longitude":{"title":"Longitude","type":"number"}},"required":["latitude","longitude"],"title":"get_forecastsArguments","type":"object"}}]}}

お天気MCPサーバのtool一覧が取得できました!

今の理解:MCPサーバにはクライアントからJSONが送られる

MCPのpython-sdkをClaude Codeにチャットしながら少し読みました。

https://modelcontextprotocol.io/llms-full.txt もFetchさせた上で

このリポジトリにはstdio transportのMCP serverの実装があります。JSON RPCを使うようですが、toolの一覧を取得するためにサーバ・クライアント間でどのような通信が行われているか示してください

パイプラインでクライアントからサーバの呼び出しはbashのコマンドで再現できるのでしょうか?できる場合は例を示してください

全文はこちらに控えました
https://gist.github.com/ftnext/fdefed4500e3eddf08ccc4e9f44111a2

Claude Codeでのセッションと上記覗き見を元に、ドキュメントを見ていきます。

MCPではクライアントとサーバのtransportには2つあります。
https://modelcontextprotocol.io/docs/concepts/architecture#transport-layer

  • Stdio transport
  • HTTP with SSE transport

All transports use JSON-RPC 2.0 to exchange messages.

JSON-RPCを使っているとのこと。
だからMCPサーバにJSONを送るわけですね!

stdio transportの仕様1を見ていくと
https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio

  • The client launches the MCP server as a subprocess.
  • The server receives JSON-RPC messages on its standard input (stdin) and writes responses to its standard output (stdout).

体験したものが言語化されているように思われます。

また、なぜ3つのJSONを順番に送ったかの説明がライフサイクルにありました

spec.modelcontextprotocol.io

  • initialize
  • notifications/initialized
  • tools/list

ここを読み込んでいけば、JSONを送ってtoolを呼び出すこともできそうです!

終わりに

MCPサーバを実装したPythonスクリプトを処理系で実行しても何も起こらなかったために、クライアントとMCPはどのような通信をしているかが気になりました。
Claude Codeを使ってMCP Python SDKソースコードを読み、一連のJSONを送ってサーバからリストの一覧を取得できました。

MCPサーバはPythonに限らず、TypeScriptやDockerイメージでの提供とバリエーション豊富ですが、stdio transportはこの記事で見たのと共通ととらえています。
stdio transportを理解する一歩目は踏み出せました!


  1. 執筆時点で最新の仕様は2025-03-26ですが、素振りは1つ前の2024-11-05だったので、素振りと同じバージョンを見ています