チップを作る会社はチップだけを売らない。チップと一緒に 評価ボードを出す。「うちのチップはこういうことができます」と手に握らせる小さな基板だ。
そのボードに画面を付けた瞬間、仕事が大きくなる。グラフィックスライブラリを載せ、フォントを入れ、タッチドライバを繋ぎ、レイアウトを組み、その全部をフラッシュに焼く。ボタンの位置ひとつ変えるのにまた焼く。だからたいていの評価ボードは 画面無しで出て行き、画面が要る顧客は別の会社を探す。
この記事はそれを違うやり方でやる。ボードに GUI を載せない。 代わりにボードが二つを差し出す — 自分にできることの一覧と、それを見せる画面の定義。描くのは外だ。
机の上の WeAct STM32H723 ボードで実際にやった。
ボードが差し出すもの
USB シリアルで繋いで問い合わせると、こう答える。
[serial] connected via serial_bridge /dev/cu.usbmodem365D395E33331 115200
[serial] tools: led.set, sys.info
[serial] resources: ui://app, ui://app/info, bundle://manifest.json
道具二つ、リソース三つ。 これがこのボードの表面の全部だ。
道具はこういう形をしている。
{"tools":[
{"name":"led.set","description":"Turn the on-board LED on or off",
"inputSchema":{"type":"object","properties":{"on":{"type":"boolean"}},"required":["on"]}},
{"name":"sys.info","description":"Report LED state and uptime",
"inputSchema":{"type":"object","properties":{}}}]}
led.set と sys.info。このボードはほかにもできることが多い — フラッシュを消し、クロックを変え、ブートローダに落ちられる。その能力は一覧に無く、一覧に無ければ呼ぶ名が無い。
画面もボードが持っている
ui://app を読むと画面定義が出てくる。
[serial] ui://app — 656 B, type "page", title "WeAct H723 MCP Node"
656 バイト。 画面ひとつでその程度だ。クライアントにはこのボード用の UI コードが一行も無い — 受け取って描く。

押せばボードが反応する
画面のボタンが led.set を呼ぶ。実際の往復だ。
[serial] led.set({"on":true}) -> "LED on" (1 ms)
[serial] sys.info({}) -> "LED=on uptime=205491208ms" (10 ms)
[serial] led.set({"on":false}) -> "LED off" (10 ms)
[serial] sys.info({}) -> "LED=off uptime=205491232ms" (11 ms)
[serial] uptime advanced 205491208 -> 205491232 ms
机の上のボードの LED が点いて消えた。 そして最後の行を見てほしい — uptime が 205491208 から 205491232 へ、24 ミリ秒前進している。あらかじめ入れておいた答えではなく、その瞬間ボードが数えていた値だ。録画した応答なら二度問えば同じ数字が出る。
往復は 1〜11 ミリ秒。UART の上だからだ。
同じクライアントが別のチップにも繋がる
これがこの構造の値打ちだ。同じコードで Wi-Fi 越しの ESP32 に繋いだ。
[tcp] connected via tcp_bridge mcp-esp32.local 6270
[tcp] tools: led.set, sys.info
[tcp] ui://app — 158 B, type "application", title "ESP32 MCP Node"
[tcp] application — initialRoute "/" -> ui://page/main
[tcp] ui://page/main — 1894 B
[tcp] led.set({"on":true}) -> "LED on" (89 ms)
[tcp] uptime advanced 67004328 -> 67004391 ms

別会社のチップ、別の伝送、同じクライアント。 変わったのはブリッジプログラムひとつだ。
そして二台のボードで画面の構造が違う。STM32 はページひとつ(type: "page"、656 B)を、ESP32 はルートを持つアプリケーション(type: "application"、158 B + ページ 1894 B)を差し出す。ボードが自分の画面の形を自分で決めている。
遅延は違う。UART が 1〜11 ms、Wi-Fi TCP が 17〜89 ms。桁が違い、その差が UI 設計を分ける — 一桁の側は「押せばすぐ」を期待していいが、数十ミリ秒の側は待ち状態を画面に描かねばならない。