画面を受け取る — クライアントに画面がひとつも無い状態で

5 分
目標MCP クライアント講座 4 編目。サーバーから画面定義を読んでランタイムに渡す。このファイルにはデスクがどんな形かというコードが一行も無い — そしてそれが検査される。

3 編目までクライアントが何を見せるかは 我々がここに書いたから 分かっていた。今回は書かない。

三行

final read = await client.readResource('ui://desk');
final text = read.contents.first.text!;
final screen = jsonDecode(text) as Map<String, dynamic>;
ui://desk — 546 B, 6 lines, type "page", title "Desk"
nothing about this screen is written in the client

Flutter のホストならここから MCPUIRuntime.initialize(screen) へ渡る。講座のサンプルは誰でも回せるよう純粋な Dart に留め、届いたことと、それが画面であること までを確かめる。

何が無いのか

このファイルに無いものだ。

  • ウィジェットツリー
  • 色・文字の大きさ
  • ボタンのラベル
  • どのボタンがどの道具を呼ぶか

全部サーバーが渡した文書の中にある。クライアントは その文書を受け取ってランタイムに渡す配管 だ。

だからサーバーが画面を直してもクライアントは何もしなくていい。サーバー 4 編目で fontSize を 88 から 120 に変えてもサーバーを落とさなかったように、こちら側も作り直さない。

546 バイト

画面ひとつが 546 バイト。6 行だ。

この数字が小さく見えることが要点である。画面を運ぶ費用が小さければ、運ぶことが既定になる。 毎回アプリを配らねばならないなら画面はアプリの中にあるのが正しく、文書ひとつ受け取るだけなら外にあるのが正しい。

検証 — クライアントに画面があれば失敗

run step4 > captures/s4.txt || die "step4: failed"
grep -q 'type "page"' captures/s4.txt || die "what arrived is not a screen"
grep -q 'fontSize' bin/step4.dart && die "step4: the screen is inside the client"

bin/step4.dart に fontSize が一度でも出れば失敗する。

サーバー側にも同じ検査がある — サーバー 4 編目はサーバーのコードに画面があれば失敗する。両方が画面を持っていないこと で初めてこの構造が成立する。どちらかが持っていれば、それはただのハードコードされたアプリだ。

自分で動かす

dart run bin/step4.dart
bash verify.sh

../course-server/ui/desk.json を直してもう一度回せば、変わった大きさが出る。クライアントは触っていない。

持ち帰るもの

  1. readResource → jsonDecode → ランタイム の三行
  2. クライアントに画面が無い — ウィジェットも色もラベルも
  3. 両側の検査 — サーバーとクライアント両方が画面を持たないかを見る

次の編

値が変わったかを問うのをやめる。

サンプルを実行する

makemind-academy/course_client/
git clone https://github.com/makemind-academy/course_client
cd course_client
dart pub get
(cd course-server && dart pub get)
dart run bin/step4.dart
GitHub で開く →