It Receives the Screen — With None of It in the Client

5 min
GoalFourth in the mcp_client course. Read the screen definition from the server and hand it to a runtime. This file holds not one line about what the desk looks like — and that is checked.

Through part 3 the client knew what to show because we wrote it here. Now we do not.

Three lines

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

In a Flutter host this goes on to MCPUIRuntime.initialize(screen). The course sample stays plain Dart so anyone can run it, and confirms only that it arrived and that it is a screen.

What is absent

Things this file does not contain:

  • a widget tree
  • colours and font sizes
  • button labels
  • which button calls which tool

All of it is in the document the server gave. The client is plumbing that receives that document and hands it to a runtime.

So when the server changes the screen, the client does nothing. Just as server part 4 changed fontSize from 88 to 120 without stopping the server, this side does not rebuild.

546 bytes

One screen is 546 bytes. Six lines.

That the number looks small is the point. When moving a screen is cheap, moving it becomes the default. If every change means shipping an app, the screen belongs inside the app; if it means fetching one document, it belongs outside.

Verification — it fails if the screen is in the client

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"

One occurrence of fontSize in bin/step4.dart and it fails.

The server side has the same check — server part 4 fails if the screen is in the server code. Both sides have to be free of it for this structure to hold. If either one holds it, it is just a hardcoded app.

Run it yourself

dart run bin/step4.dart
bash verify.sh

Edit ../course-server/ui/desk.json and run again — the new size prints. The client was not touched.

What to take

  1. readResource → jsonDecode → runtime, three lines
  2. No screen in the client — no widgets, no colours, no labels
  3. Check both sides — neither server nor client may hold the screen

Next

Stop asking whether the value changed.

Run the sample

cd course-client
dart pub get
dart run bin/step4.dart