MCP Apps —— 把「带 UI 资源的 MCP 工具」接进 AG-UI 的事件流与前端代理通道。
clj-agent-mcp分层与 genui 那次一致,判据也一样:协议认不认。
| 归谁 | 什么 |
|---|---|
clj-agent-mcp(独立模块) | JSON-RPC 信封、双时代握手、两种传输、tools/list、tools/call、工具接入 |
| 本 ns(agui) | 带 UI 的工具出结果时补一条 AG-UI activity 事件;前端那块 iframe 发起调用时的代理白名单 |
activity 消息、replace: true、forwardedProps.__proxiedMCPRequest 都是
CopilotKit 前端的约定,不是 MCP 协议的东西——所以它们在这儿,而不在协议模块里。
(require '[im.ttalk.agent.mcp.tools :as mcp-tools] ;; 协议侧:把工具接进来
'[im.ttalk.agent.agui.mcp :as agui-mcp]) ;; 前端侧:UI 那半边
(let [spec (mcp-tools/with-tools base-spec servers)
apps (agui-mcp/app-tools (:tools spec))]
(rt/runtime {:agent-fn (tools/agent-fn spec)
:event-transform (agui-mcp/event-transform {:apps apps :servers servers})}))
**MCP Apps** —— 把「带 UI 资源的 MCP 工具」接进 AG-UI 的事件流与前端代理通道。
## 这里**只剩前端约定**,协议栈在 `clj-agent-mcp`
分层与 genui 那次一致,判据也一样:**协议认不认**。
| 归谁 | 什么 |
|---|---|
| `clj-agent-mcp`(独立模块) | JSON-RPC 信封、双时代握手、两种传输、`tools/list`、`tools/call`、工具接入 |
| 本 ns(agui) | 带 UI 的工具出结果时补一条 **AG-UI activity 事件**;前端那块 iframe 发起调用时的**代理白名单** |
activity 消息、`replace: true`、`forwardedProps.__proxiedMCPRequest` 都是
**CopilotKit 前端**的约定,不是 MCP 协议的东西——所以它们在这儿,而不在协议模块里。
## 装
```clojure
(require '[im.ttalk.agent.mcp.tools :as mcp-tools] ;; 协议侧:把工具接进来
'[im.ttalk.agent.agui.mcp :as agui-mcp]) ;; 前端侧:UI 那半边
(let [spec (mcp-tools/with-tools base-spec servers)
apps (agui-mcp/app-tools (:tools spec))]
(rt/runtime {:agent-fn (tools/agent-fn spec)
:event-transform (agui-mcp/event-transform {:apps apps :servers servers})}))
```AG-UI activity 消息的类型标签。前端按它挑 renderer。
AG-UI activity 消息的类型标签。前端按它挑 renderer。
(app-tools tools)工具表里哪些是带 UI 的 → {工具名 {:resource-uri … :server-id …}}。
工具表里哪些是**带 UI 的** → `{工具名 {:resource-uri … :server-id …}}`。
(event-transform {:keys [apps servers]})runtime 的 :event-transform:带 UI 的工具出结果时,补一条 activity 快照。
前端收到它就去把 resourceUri 指向的界面拉起来(replace: true = 每次结果
整块换掉)。只认带 UI 的工具——普通 MCP 工具就是普通工具,不该多出一块界面。
:apps 由 app-tools 算出来(装配期就知道,不必每轮再问 server)。
`runtime` 的 `:event-transform`:带 UI 的工具出结果时,补一条 activity 快照。 前端收到它就去把 `resourceUri` 指向的界面拉起来(`replace: true` = 每次结果 整块换掉)。**只认带 UI 的工具**——普通 MCP 工具就是普通工具,不该多出一块界面。 `:apps` 由 `app-tools` 算出来(装配期就知道,不必每轮再问 server)。
UI 代理只允许这四个方法。上游同款白名单——那块界面跑在浏览器里, 不能让它随便调 server 的任何东西。
UI 代理**只允许这四个方法**。上游同款白名单——那块界面跑在浏览器里, 不能让它随便调 server 的任何东西。
(proxy-request servers {:keys [serverId serverHash method params]})前端那块 MCP UI 发起的调用(forwardedProps.__proxiedMCPRequest)。
servers 是你配的那几个;按 serverId 或 serverHash 找到是哪一个——
前端不知道 url,它只有这两个引用。
连接由 mcp.client 负责(含双时代判定),本函数只做路由 + 白名单。
前端那块 MCP UI 发起的调用(`forwardedProps.__proxiedMCPRequest`)。 `servers` 是你配的那几个;按 `serverId` 或 `serverHash` 找到是哪一个—— **前端不知道 url**,它只有这两个引用。 连接由 `mcp.client` 负责(含双时代判定),本函数只做**路由 + 白名单**。
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |