Skip to content

Spring AI MCP 实践 ​

本文用两个 Spring Boot 应用跑通一次工具调用。服务端发布加法工具 add,客户端通过 Streamable HTTP 发现并调用它,随后把同一个工具接入 ChatClient。手动调用只需要本机环境和 Maven 依赖。协议角色与调用时序见 MCP 协议与调用原理。

1. 准备环境 ​

准备 JDK 17 或以上版本和 Maven 3.6.3 或以上版本。示例使用 Spring Boot 3.5.15 和 Spring AI 1.1.8,通过 Streamable HTTP 连接同一台机器上的两个应用。Spring AI 1.1.8 发布记录

2. 服务端发布 add 工具 ​

新建 mcp-server 目录,写入 pom.xml。Spring AI BOM 统一管理相关 starter 的版本。

xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.15</version>
        <relativePath/>
    </parent>
    <groupId>example</groupId>
    <artifactId>mcp-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>1.1.8</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

在 src/main/resources/application.yml 中启用 Streamable HTTP。默认端点为 /mcp。Spring AI 服务端配置

yaml
server:
  address: 127.0.0.1
  port: 8080
spring:
  ai:
    mcp:
      server:
        protocol: STREAMABLE

创建 src/main/java/example/server/ServerApplication.java。Spring AI 扫描 Spring Bean 上的 @McpTool,生成工具定义并注册方法。Spring AI 服务端注解

java
package example.server;

import org.springaicommunity.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpToolParam;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
    }
}

@Component
class CalculatorTools {
    @McpTool(name = "add", description = "返回两个整数的和")
    public String add(@McpToolParam(description = "第一个整数") int a,
            @McpToolParam(description = "第二个整数") int b) {
        return Long.toString((long) a + b);
    }
}

3. 客户端发现并调用工具 ​

新建 mcp-client 目录并复制上面的 pom.xml。把项目 artifactId 改为 mcp-client,把依赖 spring-ai-starter-mcp-server-webmvc 改为 spring-ai-starter-mcp-client。写入客户端的 src/main/resources/application.yml。Spring AI 客户端配置

yaml
spring:
  main:
    web-application-type: none
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            calculator:
              url: http://127.0.0.1:8080
              endpoint: /mcp

创建 src/main/java/example/client/ClientApplication.java。客户端 starter 默认创建同步 Client 并完成初始化。

java
package example.client;

import java.util.List;
import java.util.Map;

import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.spec.McpSchema;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class ClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args).close();
    }

    @Bean
    CommandLineRunner invokeTool(List<McpSyncClient> clients) {
        return args -> {
            var client = clients.get(0);
            var tools = client.listTools().tools().stream().map(McpSchema.Tool::name).toList();
            System.out.println("tools = " + tools);

            var request = McpSchema.CallToolRequest.builder()
                    .name("add")
                    .arguments(Map.of("a", 19, "b", 23))
                    .build();
            var result = client.callTool(request);
            if (Boolean.TRUE.equals(result.isError())) {
                throw new IllegalStateException("工具执行失败 " + result.content());
            }
            System.out.println("result = " + ((McpSchema.TextContent) result.content().get(0)).text());
        };
    }
}

在两个终端中,先进入 mcp-server 执行 mvn spring-boot:run。等端口 8080 启动后,再进入 mcp-client 执行同一命令。客户端应打印以下内容,然后退出。

text
tools = [add]
result = 42

4. 让模型触发同一个工具 ​

在客户端加入模型 starter 并配置支持工具调用的模型。例如,使用 spring-ai-starter-model-openai 时,通过 SPRING_AI_OPENAI_API_KEY 提供凭证,并设置 spring.ai.openai.chat.options.model。将上面的 invokeTool 方法替换为下方片段,并导入 org.springframework.ai.chat.client.ChatClient 和 org.springframework.ai.mcp.SyncMcpToolCallbackProvider。Spring AI ChatClient、Spring AI MCP 客户端集成

java
@Bean
CommandLineRunner askModel(ChatClient.Builder builder, List<McpSyncClient> clients) {
    return args -> {
        var tools = SyncMcpToolCallbackProvider.builder().mcpClients(clients).build();
        var chat = builder.defaultToolCallbacks(tools).build();
        var answer = chat.prompt().user("请调用加法工具计算 19 加 23。").call().content();
        System.out.println(answer);
    };
}

SyncMcpToolCallbackProvider 把 Server 发布的工具转换成 Spring AI 的工具回调。模型选择工具后,回调发起 tools/call,Spring AI 将返回值交给模型继续生成回答。由于模型也可能直接给出 42,确认触发时应观察 Server 上的 add 方法是否被执行。

5. 排查常见问题 ​

  • 初始化失败或收到 404。 确认服务进程已启动,客户端使用的是服务端支持的传输,且 url 与 endpoint 拼接后指向真实端点。
  • 连接成功但列表没有工具。 先看服务端是否声明工具能力,再检查工具类是否为 Spring Bean,以及方法是否已被扫描并注册。
  • 手动调用成功,模型却没有触发。 检查模型是否支持工具调用、请求是否注册了工具回调,以及工具描述是否足够明确。
  • 需要接入其他机器。 示例绑定在本机回环地址。对外提供服务时,在 HTTP 入口鉴权,并在工具执行前校验调用者权限和参数。对写入或删除操作,由 Host 提供用户确认,再由 Server 执行权限检查。MCP 工具安全要求