使用 Spring AI 与 MCP Apps 构建交互式 AI 界面
人类与人工智能(AI)的典型交互方式是通过类似于 ChatGPT 或 Claude Desktop 的聊天界面。事实上,能够用自然语言与 AI 对话,或许是这项技术最令人惊叹的地方之一。它让人类能够以符合人类逻辑的方式与计算机交谈,而无需局限于由按钮、列表和文本框组成的传统界面。
尽管传统的用户界面(UI)不如聊天界面那样灵活流畅,但在某些场景下,它们依然是与应用程序进行交流的最佳且最自然的方式。例如,在地图上点击某个位置,就比试图用自然语言描述具体位置要精确自然得多。(除非你恰好知道该位置的经纬度。)
如果能兼顾两者的优点会怎样?如果你可以在与 AI 聊天时,在适当的时候调用更传统的 UI 界面呢?这正是 MCP Apps 带给我们的功能:在聊天界面中嵌入丰富的 UI 元素。其结果是一种混合体验,聊天与应用程序融为一体,允许用户不仅可以提问,还能在不离开聊天界面的情况下,主动与工具和工作流进行交互。
得益于 Spring AI 社区的贡献(特别感谢 Vadzim Shurmialiou 和 Alexandros Pappas 提交的拉取请求),现在使用 Spring AI 2.0.0-M3 创建作为 MCP 服务器一部分的富 UI 界面变得非常简单。在本文中,我们将动手实现这一功能。
MCP Apps 概览
从本质上讲,一个 MCP App 包含两个主要要素:
- 由 MCP 服务器提供的一个工具,该工具包含引用 HTML 资源的元数据。
- 由 MCP 服务器提供的一个 HTML 资源(包含 JavaScript 和 CSS),构成了 UI 本身。
UI 本身是一种特殊的 MCP 客户端,可以使用 JSON-RPC 与 MCP 服务器及其宿主助手进行通信。为了简化服务器交互,提供了一个 ext-apps.ts 模块,UI 可以利用它来调用工具、处理上下文变更、向宿主推送消息等。
为了演示如何使用 Spring AI 构建 MCP Apps,我们来创建一个简单但有趣的掷骰子示例。
初始化项目
创建包含 MCP App 的 MCP 服务器的第一步是创建一个 MCP 服务器。使用 Spring AI,首先可以使用 Spring Boot Initializr(通过 IDE 或访问 start.spring.io)来初始化一个包含 Spring MVC 和 Model Context Protocol Server 依赖的 Spring Boot 项目。
⚠️ 重要提示
项目初始化完成后,请确保 Spring AI 版本为 2.0.0-M3 或更高。正是从该版本开始,MCP 注解被合并到了 Spring AI 中,并增加了在工具和资源上指定元数据的能力——这对于开发 MCP Apps 至关重要。
对于 Gradle 构建的项目,你应该在 build.gradle 中看到以下代码块:
如果你使用 Maven,请查找类似如下的 <properties> 块:
项目初始化完成后,就可以定义应用程序的用户界面了。
定义用户界面
MCP App 的用户界面是一个标准的 HTML 文件,外加任何配套的 JavaScript 和/或 CSS。为了演示 MCP Apps,我们创建一个掷骰子 UI。以下 HTML 定义了该界面(位于 src/main/resources/app/dice-app.html):
HTML 代码虽然较多,但大部分用于定义 UI 的视觉元素以及 JavaScript 驱动的动画效果。其中 <script> 块的前几行对于创建 MCP Apps 至关重要。
首先是导入 ext-apps.ts 模块并创建 App 实例。App 实例用于与托管该 MCP App 的 AI 助手(如 Claude Desktop、MCP Jam 或 Goose)进行交互。
接下来是连接到助手宿主。连接成功后,它会调用 rollDice() 函数执行初始掷骰动作。
最后,updateContext() 函数利用 App 对象的 updateModelContext() 将掷骰结果发送给助手,从而更新其上下文。这会将掷骰结果注入聊天历史记录中,确保后续的聊天交互能够感知骰子的当前状态。
以下时序图有助于直观理解整个流程:
[LOADING...]
值得注意的是,HTML/JavaScript 视图还有其他与 MCP 服务器交互的方式。除了 updateModelContext(),还有两个有用的函数:sendMessage() 和 callServerTool()。sendMessage() 允许你注入一条消息,就像用户自己输入的一样;而 callServerTool() 则允许从 UI 调用 MCP 服务器上的工具。
创建 MCP 服务器
使用 Spring AI 开发 MCP 服务器,需要创建一个包含 @McpTool 和 @McpResource 注解方法的 Bean。对于 MCP App,你需要两个方法:一个用 @McpResource 注解的方法来提供 HTML UI,一个用 @McpTool 注解的方法来关联 MCP App。
首先,定义 @McpResource 注解的方法:
DiceApp 类标注了 @Service 以便被自动扫描。由于 HTML UI 从 unpkg.com 加载 ext-apps.ts,我们需要设置内容安全策略(CSP),通过 CspMetaProvider 将 ui.csp.resourceDomains 设置为允许访问 https://unpkg.com。
接下来添加工具方法:
rollTheDice() 方法通过 metaProvider 关联了 UI 资源。最后,在 application.properties 中添加配置:
我们推荐使用 streamable HTTP 传输协议。
运行 MCP App
你可以像运行任何 Spring Boot 应用程序一样启动它:
启动后,在你的 MCP 客户端(如 MCP Jam 或 Claude Desktop)中配置使用 http://localhost:3001/mcp。
如果使用 Claude Desktop,由于其尚不支持 Streamable HTTP 传输,你需要使用 mcp-remote 进行代理:
配置完成后,在聊天中输入“Roll the dice”。授予权限后,你将看到掷骰子界面出现在聊天框中。
结论
开发 MCP App 意味着构建一个包含 @McpResource(提供 UI)和 @McpTool(触发应用)的 MCP 服务器。Spring AI 通过简化元数据配置,使这一过程变得非常直观。
MCP App 打破了 LLM 仅限于文本交互的局限,为在聊天中直接实现丰富、响应式的 UI 开辟了无限可能。你打算如何利用 MCP Apps 创造更具交互性的 AI 体验呢?
资源
- MCP Apps GitHub 仓库:Dice Roller MCP App
- MCP Apps:MCP Apps 文档