MCP: Advanced Topics | Lesson 06「The STDIO transport」(全文ナレッジ)
動画 9分28秒(本コース最長級) / 講師: Stephen Grider(コース講師) / 文字起こし: mlx_whisper large-v3-turbo / 2026-07-03
日本語ナレッジ(要点整理)
- トランスポート=JSON メッセージを実際にクライアント⇄サーバー間で動かす仕組み。JSON 自体は HTTP でも WebSocket でも(極端な話ハガキでも)運べる。MCP 仕様で「何で運ぶか」を指すのが transport。
- stdio トランスポートの仕組み:
- クライアントが MCP サーバーをサブプロセスとして起動する(=プロセスのハンドルを持つ)
- クライアント→サーバー:サーバーの stdin に書き込む
- サーバー→クライアント:サーバーが stdout に書き込み、クライアントがそれを監視する
- 決定的な長所:クライアントもサーバーも、いつでもどちらからでも通信を開始できる
- 唯一の大きな欠点:クライアントとサーバーが同一マシン上でしか使えない
- デモ:
FastMCP(name="Demo Server") + add ツール1本だけの極小サーバーを uv run server.py で起動し、別クライアントを作らずターミナルから直接 JSON を貼り付けて対話する(ターミナル入力=そのプロセスの stdin、画面出力=stdout)。
- 接続初期化は必ず3メッセージ(MCP 仕様の規定):
1. initialize request(クライアント→サーバー・最初は必ずこれ)
2. initialize result(サーバー→クライアント・即返る)
3. initialized notification(クライアント→サーバー・通知なので応答なし)
- この3通の後で初めて call tool request や prompt listing request が実行できる。
- デモの
tools/call(add, a=5, b=3, _meta.progressToken 付き)には応答が3連で返った:①notifications/message(ログ・info "Preparing to add...")②notifications/progress(80.0/100.0)③call tool result(content text "8")。①②はサーバー→クライアントの通知。
- トランスポートが処理すべき4シナリオ:
1. クライアント→サーバーの起点リクエスト → stdio では「stdin に書く」
2. サーバー→クライアントの応答 → 「stdout に書く」
3. サーバー→クライアントの起点リクエスト(例:sampling の create message request) → 「stdout に書く」
4. クライアント→サーバーの応答 → 「stdin に書く」
- 結論:stdio は4シナリオ全部を自明に満たす=どちら側からでも任意時点で通信を開始できるのが素晴らしい点。streamable HTTP ではこれが成り立たない場面がある(サーバーが起点リクエストをクライアントに送れないケースがある)——次回以降の核心。
実務ポイント(このレッスンから持ち帰るもの)
- stdio サーバーはターミナルから素手でデバッグできる:
uv run server.py → JSON-RPC を1行ずつ貼るだけ。クライアント実装なしでサーバー単体の挙動(初期化・ツール呼び出し・通知)を確認できる。
- 初期化3点セットの JSON はそのままコピペで使える(画面転記・下記本文 [2:36] 参照):
initialize(id:1)→ 返答確認 → notifications/initialized → 以後 tools/call 等。自作サーバーのスモークテスト定型。
_meta: {"progressToken": ...} を付けると progress notification が返る。ログは ctx.info() → notifications/message、進捗は ctx.report_progress(80, 100) → notifications/progress。通知には id が無く、応答も不要。
- stdout はプロトコル専用チャネルという理解が本質(メッセージ=stdout に書かれた JSON)。このデモの
print() 群は「人間がクライアント」だから成立している。実クライアント相手の stdio サーバーで stdout に非 JSON を print すると壊れるので、ログは stderr / ctx.info() に出す。
- 「4シナリオ」チェックリストはあらゆるトランスポート評価のレンズ:特にシナリオ3(サーバー起点リクエスト=sampling / roots / elicitation が依存)を運べるかが streamable HTTP 理解の焦点になる。
本文(時系列・日本語逐語+画面差し込み)
[0:00] 少し前に話したとおり、クライアントとサーバーは、メッセージと呼ぶ JSON オブジェクトを交換して通信します。
[0:07] さて、JSON というもの自体は、クライアントとサーバーの間で実にさまざまな方法で送ることができます。
[0:13] たとえば HTTP リクエストでも、WebSocket でも。
[0:18] 極端な話、JSON をハガキに書いて誰かに送り、その人に手でサーバーへ打ち込んでもらうことだってできます。
[0:25] つまり、JSON を送受信する方法は本当にたくさんあるのです。
[0:29] MCP 仕様では、クライアントとサーバーの間で実際に JSON を動かすために使うものをトランスポートと呼びます。
[0:37] MCP サーバーやクライアントを開発し始めの頃に非常によく使われるのが、標準入出力(standard IO)トランスポートです。
🖥 [0:37〜1:29] 画面: スライド「'Stdio' transport」
text
'Stdio' transport
・Client launches the MCP server as a subprocess
・Client sends messages to the MCP Server using the server's 'stdin'
・Server responds by writing to 'stdout'
・Critical: either the server or the client can send a message at any time!
・Only appropriate when the client and server are running on the same machine
右図:MCP Client → [stdin](Client sends message to server)/[stdout]→ MCP Client(Server sends message to client)、下に MCP Server
[0:43] このトランスポートの考え方は、クライアントがサーバーを別プロセスとして起動するというものです。
[0:48] そうすることで、クライアントはそのプロセスのハンドルを持ちます。
[0:52] そしてクライアントは、サーバーの標準入力(stdin)チャネルにメッセージを書き込むことでサーバーへ送信でき、
[0:57] サーバーの標準出力(stdout)チャネルを監視することでメッセージを受信できます。
[1:02] 標準入出力トランスポートの本当に良いところは、クライアント側からでもサーバー側からでも、通信を非常に簡単に開始できることです。
[1:11] 言い換えると、任意の時点で、クライアントは stdin に書くことでサーバーへメッセージを送れますし、
[1:16] サーバーは stdout に書くことでクライアントへ返答できます。
[1:20] しかし標準入出力トランスポートには1つ大きな欠点があります。それは、クライアントとサーバーが同じ物理マシンで動いているときにしか使えないことです。
[1:29] 標準入出力トランスポートをよりよく理解してもらうために、簡単なデモをお見せします。私はとても小さな MCP サーバーを用意しました。
[1:34] 上のほうに、状況を理解しやすくするための print 文がいくつかありますが、それを除けば、このサーバーには大したものはありません。
🖥 [1:34〜2:03] 画面: VS Code server.py(transport-stdio リポジトリ)——サーバーの本体はこれだけ(左のターミナルには uv run server.py を入力済み)
```python
from mcp.server.fastmcp import FastMCP, Context
import asyncio
mcp = FastMCP(name="Demo Server", log_level="ERROR")
@mcp.tool()
async def add(a: int, b: int, ctx: Context) -> int:
await ctx.info("Preparing to add...")
await asyncio.sleep(2)
await ctx.report_progress(80, 100)
return a + b
if name == "main":
mcp.run(transport="stdio")
```
「上のほうの print 文」は後続フレームで確認できる(7〜17行目に挿入されている版):
```python
print("=== MCP STDIO Transport Demo ===")
print("Example messages:")
print(
'{"jsonrpc": "2.0", "method": "initialize", "params": {"pr…'
)
print('{"jsonrpc": "2.0", "method":"notifications/initialized"…')
print(
'{"jsonrpc": "2.0", "method": "tools/call", "params": {"_m…'
)
print("\n" + "=" * 50 + "\n")
```
[1:42] サーバーを作り、ツールを1つだけ定義し、標準入出力トランスポートでサーバーを起動しているだけです。
[1:47] さて、標準入出力トランスポートを使ってこのサーバーに接続するクライアントを作ることもできますが、
[1:52] 別個のクライアントを一切作らずに、ターミナルから直接サーバーに接続することもできます。どういう意味か、お見せしましょう。
[2:03] ここで uv run server.py を実行すると、あのサーバーが起動します。
[2:07] これでサーバーは stdin を待ち受け、送信メッセージがあれば stdout に書き出す状態になりました。
[2:12] ところで、ご存じないかもしれませんが、ターミナルでは、プログラムを実行中に下の部分に何かを打ち込むと、その実行中プログラムの stdin に書き込んでいることになります。
🖥 [2:12〜2:29] 画面: ターミナル——「下に打ち込めば実行中プログラムの stdin に入る」ことの実演として、サーバー出力の ===== 区切り線の下にランダムな文字列(lkasjdflkasjfdlkajsfdl)をそのまま打鍵してみせている(この直後 [2:32] にサーバーを再起動してから JSON 貼り付けデモに入る)
[2:22] つまり、実際にこの下に JSON メッセージを貼り付けて実行すれば、それはサーバーへの入力として受け取られるのです。
[2:29] それでは簡単なデモをやってみます。
[2:32] まずサーバーをサッと再起動します。
[2:36] それから、上にあるこの最初の例のメッセージをコピーして、ここに貼り付けます。
🖥 [2:36] 画面: ターミナル——サーバーが起動時に print した「Example messages:」(コピペ用サンプル3通)
```text
Example messages:
{"jsonrpc": "2.0", "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "demo-client", "version": "1.0.0"}}, "id": 1}
{"jsonrpc": "2.0", "method":"notifications/initialized"}
{"jsonrpc": "2.0", "method": "tools/call", "params": {"_meta": {"progressToken": "abc123"}, "name": "add", "arguments": {"a": 5, "b": 3}}, "id": 3}
==================================================
```
[2:42] Enter を押すと、ほぼ瞬時に応答が返ってきます。
🖥 [2:42〜2:54] 画面: ターミナル——1通目(initialize request)を貼り付け → 即座に initialize result が返る
text
{"jsonrpc": "2.0", "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "demo-client", "version": "1.0.0"}}, "id": 1}
{"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":"Demo Server","version":"1.9.3"}}}
[2:47] ここで私はメッセージを stdin に書き込み、stdout 上の出力メッセージがそこに見えている、というわけです。
[2:54] 次に、もう1通メッセージを送ります。
🖥 [2:54〜3:02] 画面: ターミナル——2通目 {"jsonrpc": "2.0", "method":"notifications/initialized"} を貼り付け(ハイライト表示)→ 応答なし
[2:58] はい、送りました。
[2:59] 今回は何の応答も表示されません。
[3:02] そして最後に、もう1通メッセージを実行します。
🖥 [3:02〜3:17] 画面: ターミナル——3通目(tools/call)を貼り付け → 応答3連
text
{"jsonrpc": "2.0", "method": "tools/call", "params": {"_meta": {"progressToken": "abc123"}, "name": "add", "arguments": {"a": 5, "b": 3}}, "id": 3}
{"method":"notifications/message","params":{"level":"info","data":"Preparing to add..."},"jsonrpc":"2.0"}
{"method":"notifications/progress","params":{"progressToken":"abc123","progress":80.0,"total":100.0},"jsonrpc":"2.0"}
{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"8"}],"isError":false}}
[3:08] これを実行すると、すぐに応答が1つ、その後もう1つ、さらにもう1つと返ってきます。
[3:13] 合計で3つのオブジェクトです。
[3:14] 1つ目、2つ目、3つ目。
[3:18] さて、これらのメッセージを貼り付けながら私が実際に何をしていたのかを理解するために、いくつか図をお見せします。
[3:23] はい、こちらに戻ってきました。
[3:25] 左側に「MCP クライアント」とラベルを付けたものがありますが、実際にはこれはターミナルでメッセージを貼り付けている私自身です。
[3:31] メッセージを貼り付けることで、私は MCP サーバーの stdin に書き込んでいます。
[3:35] サーバーは与えられたメッセージを処理し、場合によっては結果を stdout に print するだけの形で送り返します。それが私のターミナルに直接表示されるのです。
[3:44] 私が最初に送り込んだメッセージは、initialize request と呼ばれるものでした。
🖥 [3:44〜4:40] 画面: シーケンス図「MCP Client ⇄ MCP Server」
text
Initialize Request ──────────────▶
◀──────────── Initialize Result
Initialized Notification ─────────▶
Notification, no result comes back
[3:48] ここで少し背景を説明させてください。
[3:50] クライアントが最初にサーバーへ接続するとき、MCP 仕様は「3種類のメッセージを順番にやり取りしなければならない」と定めています。
[3:58] 一番最初のメッセージは、必ず initialize request でなければなりません。
[4:02] 繰り返しますが、それが最初に私がここに貼り付けたものです。
[4:05] あれが initialize request でした。
[4:08] リクエスト型のメッセージを送ったのだから、リザルトが返ってくると期待します。
[4:12] まさにそのとおりのことが起きました。
[4:14] initialize result と呼ばれるものが返ってきました。あのテキストがそれです。
[4:20] さらに MCP 仕様は、これらの最初のメッセージを交換した後、クライアントからサーバーへ initialized notification も送らなければならない、と定めています。
[4:27] 思い出してください、通知(notification)は応答を必要としません。
[4:33] 私はあそこで initialized notification を送りました。そして見てのとおり、
[4:39] 即座の応答は何も返ってきませんでした。繰り返しますが、それは単に通知が応答を必要としないからです。
[4:43] この3つのメッセージを交換し終えると、MCP サーバーへの接続は初期化済み(initialized)と見なされます。
[4:49] そしてその時点から、call tool request でも prompt listing request でも、やりたいことを何でも実行できるようになります。
🖥 [4:49〜5:20] 画面: フルセッションのシーケンス図(スライド版・実行結果とは通知の内訳が異なる)
text
Initialize Request ──▶ / ◀── Initialize Result
Initialized Notification ──▶(Notification, no result comes back)
Tool Call Request ──▶
◀── Logging Message Notification
◀── Logging Message Notification
◀── Tool Call Result
[5:02] 私の場合は、見てのとおり call tool request を送りました。一番下のあれです。
[5:09] 引数 5 と 3 で add ツールを呼び出そうとしました。
[5:15] さて、私が add ツールを作ったときの作りとして、いくつかのログを送り返してから、最終的に call tool result を返すようにしてあります。
[5:21] ログを見てみると——実際には、あの図に出ているものから少し変えてあります。まず message notification、つまりログ出力が返ってきました。あそこから来ています。私のログ文です。
🖥 [5:21〜5:48] 画面: ターミナル——応答3連の精読(notifications/message の行をハイライト)
text
{"method":"notifications/message","params":{"level":"info","data":"Preparing to add..."},"jsonrpc":"2.0"} ← ①ログ通知
{"method":"notifications/progress","params":{"progressToken":"abc123","progress":80.0,"total":100.0},"jsonrpc":"2.0"} ← ②進捗通知
{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"8"}],"isError":false}} ← ③call tool result(8)
[5:31] 次に progress(進捗)が返ってきました。あそこの progress の更新表示です。
[5:37] これらは両方とも、サーバーからクライアントへ送られている通知です。
[5:42] そして最後に、call tool response があそこに返ってきました。
[5:44] その中には 3 足す 5 の計算結果が入っています。8 が見えますね。
[5:48] さて、標準入出力トランスポートの実例を見たところで、このトランスポートまわりで指摘しておきたい本当に重要な考え方がいくつかあります。streamable HTTP トランスポートを見始めるときに、非常に大事になってくるものです。
[6:03] まず、少し前にこの図をお見せしました。この図を見せたのは、クライアントからサーバーへ送られることを意図したメッセージ型と、サーバーからクライアントへ送られることを意図した型があると理解してもらうためでした。
🖥 [6:03〜6:15] 画面: Lesson 05 のまとめ図を再掲(クライアント起点ペア4種/サーバー起点ペア Create Message・List Roots/通知 Initialized・Cancelled・Progress・Logging、「Notifications don't require a response」)
[6:15] この図から本当に理解してほしかったもう1つのことは、特に左上のこれらのメッセージには、クライアントがサーバーとの通信を開始しているとイメージできる場面がある、ということです。
[6:24] つまりクライアントが「私はリクエストを送る。応答が返ってくることを期待する」と言っている。
[6:34] 同様に、MCP サーバーの側が最初のリクエストを送り出して、応答が返ることを期待する場面もあります。
[6:39] それが例えば create message request——sampling を開始するのに使われるものです。
[6:45] つまりサーバーはこのリクエストをクライアントへ送り出し、何らかのリザルトが返ってくることを期待する必要があります。
[6:51] これをもう少し明確な言い方にすると、こういうことです。標準入出力トランスポートのような各種トランスポートには、処理できなければならないシナリオが実は4つあります。
🖥 [6:51〜7:26] 画面: スライド「How can we implement each of these with stdio?」——4シナリオ
text
How can we implement each of these with stdio?
┌ Initial request from Client → Server ┐
┌ Response from Server → Client ┐
┌ Initial request from Server → Client ┐
┌ Response from Client → Server ┐
右図:MCP Client/stdin・stdout/MCP Server(stdio 図の再掲)
[6:57] ①クライアントからサーバーへの開始(起点リクエスト)を処理できること。②サーバーからクライアントへ応答を送れること。
[7:11] ③サーバーがクライアントへ起点リクエストを送れること。④同様に、クライアントが応答を返せること。
[7:22] では、この4つのシナリオをすべて順に見て、標準入出力トランスポートでどう実装するかを考えましょう。
[7:26] まず、クライアントからサーバーへの起点リクエスト。
🖥 [7:26〜7:45] 画面: シナリオ①をハイライト——クライアント吹き出し「I need to send a message to the server!」+「Write to stdin」ラベル
[7:31] このシナリオは、クライアントが何かをサーバーへ送りたいとき——たとえば call tool request のようなもの——ならいつでも該当します。
[7:36] これを標準入出力トランスポートで実装するには、stdin に書くだけでいい。MCP サーバーはそのメッセージを受け取り、処理して、うまくいけば応答を組み立てます。
[7:46] 応答ができたら、stdout にメッセージを書くだけで応答します。(=シナリオ②)
[7:52] 次に3つ目のシナリオ、サーバーからクライアントへ送られる起点リクエストです。
🖥 [7:52〜8:12] 画面: シナリオ③をハイライト——サーバー吹き出し「I need to send a message to the client」+「Write to stdout」ラベル
[7:58] これは、たとえばサーバーが sampling をやりたい場面です。それにはサーバーがクライアントへ何らかの起点メッセージを送る必要があります。
[8:06] サーバーがクライアントへ起点リクエストを送る必要があるときは、stdout に書くだけでいい。
[8:12] そして同様に、応答するには、クライアントは stdin に書くだけでいいのです。(=シナリオ④)
🖥 [8:12〜8:23] 画面: シナリオ④をハイライト——クライアント吹き出し「I need to respond to the message I just got」+「Write to stdin」ラベル
[8:18] さて、この数分間の話と、いま見せた一連の図は、おそらく少し混乱させたと思います。
[8:27] 「起点リクエストだの応答だの、この話は一体何なんだ?」と思っているでしょう。
[8:33] ポイントはこうです。この話全体の目的は、標準入出力トランスポートが本当に素晴らしいのは、任意の時点でクライアントからでもサーバーからでも通信を開始できるからだ、と理解してもらうことです。
[8:44] どちらの側も、いつでもリクエストを送って、応答が返ることを期待できる。
[8:49] そして肝心なのはここです。streamable HTTP トランスポートでは、これが成り立たなくなります。
🖥 [8:49〜9:11] 画面: 4シナリオのスライドで「Initial request from Server → Client」(シナリオ③)を再びハイライト——streamable HTTP で問題になるのはまさにこの行
[8:54] streamable HTTP トランスポートがこの状況を許さないシナリオがあるのです。
[9:02] サーバーがクライアントへ起点リクエストを送れないケースがある。
[9:06] それが streamable HTTP トランスポートについて理解しにくい、厄介なところです。
[9:12] それでは、ここで一旦区切りにします。戻ってきたら HTTP トランスポートを見始めます。
[9:17] そしてこの特定のシナリオを目にして、「なるほど、確かにここには少し厄介なものがあるな」と、自分の MCP サーバーを開発するときに必ず理解しておくべきことを確認していきます。
英語逐語(ASR全文)
As we discussed a moment ago, clients and servers communicate by exchanging JSON objects that we refer to as messages. Now, JSON in general can be transmitted between a client and a server in a wide variety of different ways. For example, we can make a HTTP request. We could use WebSockets. We could even write out a postcard with some JSON and then send it to someone else and have them manually type that JSON into a server. So there really are a tremendous number of ways to send and receive JSON. In the MCP spec, the thing that we use to actually move JSON between a client and a server is referred to as the transport. When you are initially developing an MCP server or a client, a very commonly used transport is the standard IO transport. The idea with this transport is that our client is going to launch a server as a separate process. By doing so, the client has a handle on that process. And the client can send messages into the server by writing them into the server's standard end channel. and it can receive messages by watching the server's standard out channel. Something that is really nice about the standard IO transport is that communication between the client or the server can be very easily initiated on either side. So in other words, at any point in time, the client can communicate or send a message off to the server by writing to standard in, and the server can communicate back to the client by writing to standard out. But the standard IO transport also has one big downside, and that is that we can only make use this transport when the client and the server are running on the same physical machine. To help you better understand the standard IO transport, let me give you a quick demonstration. I put together a very small MCP server. I've got some print statements up here at the top just to help you understand what's going on, but besides those print statements, the server doesn't really have a whole lot to it. I'm creating a server, I'm defining one single tool, and then starting the server up with a standard IO transport. Now I could create a client to connect to the server using the standard IO transport, but I can also just connect to the server directly from my terminal without creating any distinct separate client. Let me show you what I mean by that. If I run uvrun server.py right here, it's going to start up that server. And now that server is going to be listening to standard in and then writing any outgoing messages to standard out. Well, in my terminal, in case you don't know, whenever I run a program, if I type anything down here, I am writing to standard in of this running program. So I can actually paste in JSON messages down here at the bottom, execute them, and they will be received as input to the server. So let me give you a quick demonstration of that. I'm going to restart the server really quickly. And then I'm going to copy this first example message up here. I'm going to paste it right here. And it's going to occur almost instantly when I hit enter, I'm going to immediately get a response back. So I've written to standard in right here with a message, and I am seeing a output message on standard out right there. I'm then going to send another message. Here we go. And this time around, I'm not going to see any response. And then finally, I'm going to run one more message down here. And when I run this one, I'll immediately get back one response and then another response and another response after that. So three objects in total. There's one, there's two, and there's three. So let me show you a couple diagrams to help you understand what I'm really doing as I paste these different messages in. Okay, so back over here. On the left-hand side, I've got what I've labeled my MCP client, but really it's just me at my terminal pasting messages in. By pasting those messages in, I'm writing to standard in of the MCP server. The server is then going to process these given messages and then possibly send a result back by just printing it to standard out, which I see directly printed at my terminal. The first message that I sent in was something called an initialized request. Let me just give you a little bit of backstory here. Whenever a client first connects to the server, the MCP spec says that we must send a sequence of three different messages back and forth. The very first message must always be an initialized request. And again, that is what I initially pasted in right here. That was initialized request. Because I sent in a request type message, I would expect to get back a result. And that's exactly what happened. I got back something referred to as a initialized result. So that was that text right there. Then the NCP spec also says that after exchanging these initial messages, we must then also send a initialized notification from the client to the server. As a reminder, notifications do not require a response. So I did send in that initialized notification right there. And as we noticed, we didn't get any immediate response back. Again, that's just because notifications do not require a response. Once we have exchanged these three messages, our connection to the MCP server is considered to be initialized. And at that point on, we can then run call tool requests or run prompt listing requests, whatever else we want to do. So in my case, as you saw, I sent in a call tool request. That was the last one down here. I attempted to call the add tool with arguments of five and three. Now the way that I put together the add tool, it is set up to send back a couple of different logs and then eventually a call tool result. So if I look through the logs, I actually changed it from what you see in that diagram. First, I got a message notification, so a login statement that's coming from right there. There's my login statement. I then got a progress statement. So there's the progress update right there. Those are both notifications being sent from the server to the client. And then finally, I got my call tool response right there. And inside of it is the calculated result of adding three plus five. I see eight. So now that we have seen an example of the standard IO transport, there are some really critical ideas that I want to point out around this transport in particular that are going to be very relevant or very important to understand as we start to take a look at the streamable HTTP transport. First, I showed you this diagram a little bit ago, and I showed you this diagram to help you understand that there are some message types that are intended to be sent from the client to the server and some types that are meant to be sent from the server to the client. The other thing that I really wanted you to understand from this diagram is that there are some instances, specifically with these messages on the top left-hand side, where we can kind of imagine that the client is initiating communication with the server. So in other words, the client is saying, I am making a request and I expect to get back a response. Likewise, there are some situations where the MCP server is sending the initial request off and expects to get back a response. So that would be like the create message request, which is what is used to initiate sampling. So the server needs to send off this request to the client and expects to get back some kind of result. Now to put that in slightly more clear terms, here's what I really mean to indicate with that. There are really four different scenarios with these different transports, like the standard IO transport, that we need to be able to handle. We need to be able to handle the initiation or kind of a initial request from the client to the server, and the transport needs to be able to handle sending a response from the server to the client. Also, the server needs to be able to send an initial request to the client, and then likewise, the client needs to be able to respond. So I want to walk through all these four different scenarios and think about how we would implement them with a standard IO transport. So first is an initial request from the client to the server. So the scenario here would be anytime the client wants to send something off to the server, like maybe a call to a request or something like that. To implement this with a standard IO transport, all we have to do is write to standard in, and the NCP server will receive that message, process it, and then hopefully formulate a response. Once it has a response, it would respond by just writing a message to standard out. Now the third scenario would be where we have an initial request to be sent from the client to the server. So this would be where maybe the server wants to do some sampling, and that's going to require the server to send some kind of initial message off to the client. Whenever the server needs to send an initial request to the client, all it has to do is write to standard out. And then likewise, to respond, all the client has to do is write to standard in. All right, now I know that the last couple of minutes in this video, and the sequence of diagrams I just went over, are probably a little bit confusing. And you're probably thinking, what is this about initial requests and responses and whatnot? Well, here's the point. The whole point of all this is to help you understand that the standard IO transport is really fantastic because at any point in time, the client or the server can initiate communication. Either one can send a request at any point in time and expect to get back a response. Here's the key thing. That is not going to be the case with a streamable HTTP transport. There are some scenarios where the streamable HTTP transport does not allow for this situation. There are some cases where the server cannot send some initial request off to the client. And that's the tricky thing to understand about the streamable HTTP transport. So now we're going to take a pause right here, come back, we're going to start to take a look at the HTTP transport, and we're going to see this particular scenario and understand that, yeah, there's something a little bit tricky about this that you definitely need to understand when you are developing your own MCP servers.
(注:ASR の「initialized request / initialized result」=正しくは initialize request / initialize result(画面図は Initialize Request / Initialize Result)。「NCP spec / NCP server」=MCP。「uvrun server.py」=uv run server.py。「login statement」=logging statement。「Now the third scenario would be where we have an initial request to be sent from the client to the server」は言い間違い/誤認識で、文脈・画面ともサーバー→クライアントの起点リクエストが正。「adding three plus five. I see eight」——引数は a=5, b=3。)