Ohhnews

分类导航

$ cd ..
Baeldung原文

使用Spring AI在MCP服务器中嵌入HTML UI

#mcp服务器#spring ai#html ui#claude desktop#交互式ui

1. 概述

MCP(模型上下文协议)服务器是现代人工智能处理与开发的基础。因此,掌握如何配置一个 MCP 服务器并将其集成到项目中显得至关重要。

在本教程中,我们将学习如何使用 Spring AI 构建一个 MCP 服务器,并将其连接到 Claude Desktop 这样的人工智能工具。首先,我们创建一个简单的 hello-world 工具,使用 MCP Inspector 进行测试,然后将其作为自定义连接器注册到 Claude Desktop。

基础搭建完成后,我们将更进一步,暴露一个丰富的交互式 HTML UI——一个随机挑选今日运动的幸运大转盘。在实现过程中,我们将看到 Spring AI 的 @McpTool@McpResource 注解如何让工具将页面内嵌在聊天中,并将结果反馈回对话中。

2. 创建 MCP 服务器

模型上下文协议 (MCP) 为 Claude Code 或 Claude Desktop 等人工智能助手提供了一种标准化方式,使其能够在模型认为合适时调用某些自定义功能。MCP 服务器是一个轻量级后端,通过工具资源提示暴露这些功能。

让我们从创建一个简单的 hello-world MCP 服务器开始。首先,在 pom.xml 中添加 spring-ai-starter-mcp-server-webmvc 依赖:

$ xml
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>

此外,我们使用 spring-ai-bom 进行版本管理:

$ xml
<dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>org.springframework.ai</groupId>
          <artifactId>spring-ai-bom</artifactId>
          <version>2.0.0-M6</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
      </dependencies>
    </dependencyManagement>

然后,配置服务器端口和服务器暴露的 MCP 传输协议。Spring AI 支持三种传输选项:

  • stdio:用于基于本地进程的通信
  • sse:基于服务器推送事件的传统 HTTP 传输
  • streamable:较新的 Streamable HTTP 传输,通过单个端点处理请求和流式响应

这里我们使用 streamable 协议。在 application.properties 中进行配置:

$ properties
server.port=3001
spring.ai.mcp.server.protocol=STREAMABLE

最后,添加一个工具,它从服务器向用户问好:

$ java
@SpringBootApplication
class McpUiApplication {
    public static void main(String[] args) {
        SpringApplication.run(McpUiApplication.class, args);
    }
    @McpTool(
        title = "Say Hello",
        name = "say-hello",
        description = "A simple tool that returns a greeting message."
    )
    String sayHello() {
        return "Hello from the MCP UI Application!";
    }
}

正如预期,该工具暴露给 AI 代理,当模型决定调用它时,问候消息将返回给用户。

3. 测试 MCP 服务器

有多种方法可以连接和测试 MCP 服务器。让我们尝试使用其中一些方法来触发 Say Hello 工具。

3.1. 使用 MCP Inspector 测试

一个方便的选择是 MCP Inspector,这是一个专为测试和调试 MCP 服务器而设计的交互式开发者工具

$ bash
npx @modelcontextprotocol/inspector

该命令会启动一个本地代理服务器以及一个基于 Web 的 UI,我们可以在浏览器中打开它来测试 MCP。使用这个界面,我们可以执行不同的操作:

  1. 连接到一个 MCP 服务器
  2. 查看它暴露的资源提示工具
  3. 触发工具

该界面非常直观: [LOADING...]

如图所示,我们已连接到使用 Spring AI 创建的 MCP 服务器,并成功运行了其 Say Hello 工具。

3.2. 使用 Claude Desktop 测试

或者,我们也可以使用 AI 工具来测试 MCP 服务器。毕竟,最终目标是使用像 Claude Desktop 这样的桌面应用程序来使用 MCP 服务器

首先,我们需要在 claude_desktop_config.json 文件中注册它,该文件的位置因操作系统而异:

  • 在 Windows 上:%APPDATA%\Claude\claude_desktop_config.json
  • 在 macOS 上:~/Library/Application Support/Claude/claude_desktop_config.json

Claude Desktop 原生仅支持用于本地 MCP 服务器的 stdio 传输,但我们的服务器使用 Streamable HTTP。为了弥合这一差距,我们使用 mcp-remote —— 一个小的 npm 实用程序,它作为一个本地 stdio 进程运行,并将每条 MCP 消息转发到远程 HTTP 端点。简单来说,Claude Desktop 通过标准输入输出与 mcp-remote 通信,mcp-remote 再将流量中继到位于 http://localhost:3001/mcp 的 Spring AI 服务器:

$ cat
"mcpServers": {
  "sport-spinner": {
    "command": "npx",
    "args": [
      "mcp-remote",
      "http://localhost:3001/mcp",
      "--transport",
      "http-only",
      "--allow-http"
    ]
  }
}

正如所见,还需要为 MCP 应用程序分配一个名称。我们称它为 sport-spinner,因为我们将扩展它,为用户推荐每天可以进行的运动。

最后,如果重新启动 Claude Desktop,我们应该能看到 MCP 服务器作为一个自定义连接器出现: [LOADING...]

因此,模型现在可以决定调用由 MCP 服务器暴露的工具: [LOADING...]

看起来我们成功连接到了 MCP 应用程序,并返回了一个 AI 工具可以使用或显示给用户的 String。现在,让我们升级应用程序,使其返回可以在 Claude Desktop 中渲染的 HTML。

4. 嵌入 HTML

到目前为止,MCP 服务器仅返回纯文本。然而,像 Claude Desktop 这样的现代 AI 工具也可以渲染服务器作为 HTML 资源暴露的丰富交互式 UI。我们可以通过结合一个触发 UI 的 @McpTool 和一个提供实际 HTML 的 @McpResource 来实现这一点。

让我们增强 sport-spinner,使其显示一个真实的、能够挑选今日运动的幸运大转盘。首先,在 src/main/resources/static/sport-spinner.html 下添加一个 HTML 文件,其中包含旋转转盘的 HTML、CSS 和 JavaScript。

4.1. 将 HTML 暴露为 MCP 资源

创建一个新的 Spring Bean,加载 HTML 文件并通过 @McpResource 注解暴露它:

$ java
@Component
class SportSpinnerUI {
    @Value("classpath:/static/sport-spinner.html")
    private Resource sportSpinnerResource;
    @McpResource(
        name = "Sport Spinner App Resource",
        uri = "ui://sport/sport-spinner.html",
        mimeType = "text/html;profile=mcp-app",
        metaProvider = CspMetaProvider.class)
    public String getSportSpinnerResource() throws IOException {
        return sportSpinnerResource.getContentAsString(Charset.defaultCharset());
    }
}

这里有几个值得强调的地方:

  • uri 在 MCP 服务器中唯一标识该资源
  • mimeType 使用 text/html;profile=mcp-app 配置文件——向客户端表明此 HTML 应作为交互式 MCP 应用渲染,而不是显示为原始文本
  • metaProvider 为资源附加额外的元数据——本例中是一个内容安全策略,该策略放行了 unpkg.com,以便页面可以从该 CDN 加载外部脚本

让我们看一下 CspMetaProvider

$ java
class CspMetaProvider implements MetaProvider {
    @Override
    public Map<String, Object> getMeta() {
        return Map.of("ui",
            Map.of("csp",
                Map.of("resourceDomains", List.of("https://unpkg.com"))));
    }
}

至此,我们应该准备好将 UI 连接到工具了。

4.2. 将工具链接到 UI 资源

最后,添加一个 MCP 工具,指示工具打开转盘:

$ java
@McpTool(
    title = "Spin Sport Wheel",
    name = "spin-sport-wheel",
    description = "Opens a fortune wheel that spins and randomly picks today's sport.",
    metaProvider = SportSpinnerToolMetaProvider.class)
public String spinSportWheel() {
    return "Opening the sport spinner wheel.";
}

关键元素是 metaProvider,它将此工具与我们之前定义的 HTML 资源关联起来

$ java
class SportSpinnerToolMetaProvider implements MetaProvider {
    @Override
    public Map<String, Object> getMeta() {
        return Map.of("ui",
            Map.of("resourceUri", "ui://sport/sport-spinner.html"));
    }
}

当模型调用 spin-sport-wheel 时,工具会读取此元数据,获取位于 ui://sport/sport-spinner.html 的资源,并将其内嵌渲染到聊天中,为用户提供一个完全交互式的转盘,而不是纯文本回复。

让我们重新启动 Claude Desktop,询问它今天应该做什么运动[LOADING...]

如预期所示,来自 Spring Boot 应用程序的 HTML 现在直接渲染在 Claude Desktop 的聊天界面中。此时,我们可以旋转转盘,让它挑选今天的运动,结果会反馈回对话中,以便模型做出反应。

5. 总结

在本教程中,我们学习了如何使用 Spring AI 构建一个 MCP 服务器,并将其连接到 Claude Desktop 这样的人工智能工具。

具体来说,我们从简单的 hello-world 工具开始,使用 MCP Inspector 和 Claude Desktop 进行了测试。然后,我们更进一步,通过 Spring AI 的 @McpTool@McpResource 注解暴露了一个丰富的交互式 HTML UI。最终,我们让工具将一个幸运转盘内嵌渲染在聊天中,并将结果反馈回对话。

和往常一样,完整源代码可在 GitHub 上 获得。