把画面做成资源 — 不是代码,是服务端交出来的文档
5 分钟目标MCP 服务端课程第四篇。服务端把画面当成一个文件拿着,再交出去。改了文件,下一次连接就变了,不用重编译也不用重装——前提是每次请求都去读它。
到目前为止服务端答的是值。现在它答 一块画面。
画面就是一个文件
{ "type": "page", "title": "Desk",
"content": { "type": "center",
"child": { "type": "linear", "direction": "vertical", "spacing": 14, "alignment": "center", "children": [
{ "type": "text", "text": "WAITING", "style": { "fontSize": 16, "letterSpacing": 4, "color": "#6b7280" } },
{ "type": "text", "text": "{{waiting}}", "style": { "fontSize": 88, "fontWeight": "bold", "color": "#111827" } },
{ "type": "button", "label": "Admit one", "onTap": { "type": "tool", "tool": "desk.admit", "params": { "count": 1 } } } ] } } }六行。值落在 {{waiting}} 的位置,按钮调用第三篇做的那个工具。
服务端把它交出来
server.addResource(
uri: 'ui://desk',
name: 'Desk screen',
description: 'The desk screen, served as a document',
mimeType: 'application/json',
handler: (uri, params) async => ReadResourceResult(contents: [
ResourceContentInfo(
uri: 'ui://desk',
mimeType: 'application/json',
text: File(_screenPath).readAsStringSync(),
)
]),
);ResourcesCapability 也要打开。
capabilities: ServerCapabilities(
tools: ToolsCapability(listChanged: true),
resources: ResourcesCapability(listChanged: true),
),每次请求都读,这才是要点
readAsStringSync() 在处理器里面。启动时读一次放进变量当然更快,但这里没那么做。
一旦拿住,每改一次画面就得重启服务端。 那一刻,这一篇主张的事——改了文件就是另一个应用——就成了假的。
/// Read fresh on every request, deliberately. A screen cached at boot is a
/// screen you have to restart the server to change, and then the claim above
/// stops being true.等性能真的成为问题时可以缓存,但 必须靠检测文件变化来失效。只是拿住,等于把这项能力丢掉。
有什么不同
画面一旦出了代码,就是这样:
| 在代码里时 | 作为文档交出来时 | |
|---|---|---|
| 改字号 | 构建 → 发布 → 安装 | 文件里一行 |
| 客户端种类 | 每种各实现一遍 | 都接同一份文档来画 |
| 加一块画面 | 改应用 | 多一条资源 |
校验 —— 画面在代码里就失败
这一篇最容易变成谎话的地方只有一个:把画面放在代码里,文里却写「服务端交出来的」。 光看响应分不出来。
ask step4 '{"jsonrpc":"2.0","id":2,"method":"resources/read","params":{"uri":"ui://desk"}}'
grep -q 'ui://desk' captures/s4.txt || die "resource not served"
grep -q 'page' captures/s4.txt || die "served document is not a screen"
# The claim is that the screen is not in the code.
grep -q 'fontSize' bin/step4.dart && die "step4: the screen is inside the code"服务端代码里出现一次 fontSize 就失败。
step4 ui://desk served from ui/desk.json (6 lines), not from the code自己跑一遍
dart run bin/step4.dart
bash verify.sh把 ui/desk.json 里的 fontSize 从 88 改成 120 再问一次,回来的就是改过的文档。服务端一直没关。
可以带走的
addResource+ capability — 两个都要,否则不出现在清单里- 在处理器里面读 — 一缓存就不再是免安装
- 禁止画面进代码的检查 — 这个主张唯一可能作假的地方
下一篇
现在的等待人数是个变量。进程一死就没了。要让它留下来。
运行示例
makemind-academy/course_server/git clone https://github.com/makemind-academy/course_server cd course_server dart pub get dart run bin/step4.dart