Model Context Protocol (MCP) 是一个标准化协议,使 AI 模型能够以结构化的方式与外部工具和资源交互。 可以将其视为 AI 模型与现实世界之间的桥梁——允许它们通过一致的接口访问数据库、API、文件系统和其他外部服务。 它支持多种传输机制,以在不同环境中提供灵活性。

MCP Java SDK 提供了 Model Context Protocol 的 Java 实现,通过同步和异步通信模式实现与 AI 模型和工具的标准化交互。

Spring AI 通过专用的 Boot Starters 和 MCP Java Annotations 全面支持 MCP,使构建能够无缝连接到外部系统的复杂 AI 驱动应用程序变得前所未有的简单。 这意味着 Spring 开发者可以参与 MCP 生态系统的两个方面——构建消费 MCP 服务器的 AI 应用程序,以及创建将基于 Spring 的服务暴露给更广泛 AI 社区的 MCP 服务器。 使用 Spring Initializer 引导支持 MCP 的 AI 应用程序。

 相关链接:

1、【Spring ai alibaba官方文档】Model Context Protocol(MCP)概览 | Spring AI Alibabahttps://java2ai.com/integration/mcps/examples/mcp

2、本文中的源码

本文中的工程源码已开源至Gitee代码仓库,地址为:

https://gitee.com/duyanjun/agent-harness-demo.git

3、AI智能体开发技术调研总结系列文章:

(一)、AI智能体开发技术调研总结

(二)、AI智能体开发技术调研总结 - 自定义 MCP 服务

一、自定义 MCP 服务

1、pom.xml

<dependencyManagement>
    <dependencies>
        <!-- Spring AI BOM 统一管理版本 -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>${spring-ai.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <!-- Spring AI MCP Server -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
    </dependency>
</dependencies>

2、application.yml

在配置文件中定义了 MCP 服务名、MCP 传输协议、MCP API地址,所以客户端调用该 MCP 服务地址是 http://localhost:8081/api/mcp/streamable

spring:
  application:
    name: mcpserver
  ai:
    mcp:
      server:
        # MCP 服务名
        name: tyzwkj-customMcp
        version: 1.0.0
        # 传输协议:STREAMABLE(推荐)| SSE(旧版)| STATELESS(无状态)
        protocol: STREAMABLE
        # 服务器类型:SYNC(同步,注册同步 @Tool 方法)| ASYNC(异步,注册异步 @Tool 方法)
        type: SYNC
        # 扫描 @McpTool 注解的 Spring Bean 并自动注册
        annotation-scanner:
          enabled: true
        request-timeout: 20s
        streamable-http:
          mcp-endpoint: /api/mcp/streamable
          keep-alive-interval: 30s
          disallow-delete: false
server:
  port: 8081

3、定义MCP工具类

通过@Component将该类注入Spring容器中,通过@McpTool声明一个可被模型调用的工具

package cn.tyzwkj.ai.mcpserver.tools;

import org.springaicommunity.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpToolParam;
import org.springframework.stereotype.Component;

@Component
public class CalculatorTools {

    @McpTool(name = "mcp_calculate_add",
            description = "将两个数字相加,返回它们的和。支持整数和小数。")
    public double calculateAdd(
            @McpToolParam(description = "第一个加数") double a,
            @McpToolParam(description = "第二个加数") double b) {
        return a + b;
    }

    @McpTool(name = "mcp_calculate_divide",
            description = "用第一个数字除以第二个数字,返回商。除数不能为 0,否则返回错误。支持整数和小数。")
    public double calculateDivide(
            @McpToolParam(description = "被除数") double a,
            @McpToolParam(description = "除数,不能为 0") double b) {
        if (b == 0) {
            throw new IllegalArgumentException("除数不能为 0,请传入非零的除数。");
        }
        return a / b;
    }

    @McpTool(name = "mcp_calculate_power",
            description = "计算 base 的 exponent 次幂,返回结果。支持小数次幂。")
    public double calculatePower(
            @McpToolParam(description = "底数") double base,
            @McpToolParam(description = "指数") double exponent) {
        return Math.pow(base, exponent);
    }

    @McpTool(name = "mcp_calculate_square_root",
            description = "计算一个非负数的平方根,返回结果。负数没有实数平方根,会返回错误。")
    public double calculateSquareRoot(
            @McpToolParam(description = "开方数,必须为非负数") double x) {
        if (x < 0) {
            throw new IllegalArgumentException("负数没有实数平方根,参数 x=" + x + " 必须 >= 0。");
        }
        return Math.sqrt(x);
    }

}

4、MCP 服务认证

通过引入认证过滤器,只对存在请求头 token-1,且只为 tyzwkjmcp-1 的连接放行

package cn.tyzwkj.ai.mcpserver.filter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.List;

/**
 * Mcp 服务认证过滤器,实现 WebFilter
 * 只对存在请求头 token-1,且只为 tyzwkjmcp-1 的连接放行。
 */
@Component
public class McpServerAuthFilter extends OncePerRequestFilter {

    private static final String TOKENHEADER = "token-1";
    private static final String TOKENVALUE = "tyzwkjmcp-1";

    /** 需要鉴权的路径(MCP Streamable HTTP 端点),可按需扩展 */
    private static final List<String> PROTECTED_PATTERNS = List.of("/api/mcp/**");
    private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    private static final Logger logger = LoggerFactory.getLogger(McpServerAuthFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        String path = request.getRequestURI();
        if (!isProtected(path)) {
            chain.doFilter(request, response);
            return;
        }
        String token = request.getHeader(TOKENHEADER);
        logger.info("鉴权请求: {} {}, TOKEN: {}", request.getMethod(), path, token);
        if (TOKENVALUE.equals(token)) {
            logger.info("preHandle: 验证通过");
            chain.doFilter(request, response);
        } else {
            logger.warn("Token验证失败: 请求的URL: {}, 提供的TOKEN: {}", path, token);
            logger.warn("要求的token为:{}", TOKENVALUE);
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
        }
    }

    private boolean isProtected(String path) {
        return PROTECTED_PATTERNS.stream().anyMatch(pattern -> PATH_MATCHER.match(pattern, path));
    }
}

二、在智能体中集成自定义的 MCP 服务

1、基于AgentScope-java框加构建智能体

        详情参见《AI智能体开发技术调研总结》

2、注册MCP服务

示例工程代码如果要展示MCP的效果,需要修改application.yml中的参数agent.mcp.enabled: true,启用MCP

package cn.tyzwkj.ai.agentharness.config;

import cn.tyzwkj.ai.agentharness.tool.BusinessTools;
import cn.tyzwkj.ai.agentharness.tool.KnowledgeTools;
import io.agentscope.core.tool.Toolkit;
import io.agentscope.core.tool.mcp.McpClientBuilder;
import io.agentscope.core.tool.mcp.McpClientWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;
import java.util.Map;

/**
 * 工具容器装配。
 *
 * <p>这里只注册自定义业务工具;Harness 会在此基础上补齐内置工具
 * (读写/编辑文件、目录检索、shell 执行、任务清单、记忆检索等),
 * 因此不需要手动把内置工具一个个加进来。
 */
@Configuration
public class AgentToolkitConfig {

    @Autowired
    private AgentProperties agentProperties;

    @Bean
    public Toolkit agentToolkit(BusinessTools businessTools, KnowledgeTools knowledgeTools) {
        Toolkit toolkit = new Toolkit();
        toolkit.registerTool(businessTools);
        if (agentProperties.getRag().isEnabled()) {
            toolkit.registerTool(knowledgeTools);
        }
        if (agentProperties.getMcp().isEnabled()) {
            // 自定义 MCP Server
            McpClientWrapper customMcpClient = McpClientBuilder.create("tyzwkj-customMcp")
                    .streamableHttpTransport("http://localhost:8081/api/mcp/streamable")
                    .headers(Map.of("token-1", "tyzwkjmcp-1"))
                    .buildSync();
            toolkit.registerMcpClient(customMcpClient).block();
        }
        return toolkit;
    }
}

三、验证

1、启动 MCP 服务

2、启动智能体

3、访问智能体

1、启动成功后在浏览器访问http://localhost:8080,如下图所示画面右侧【已注册工具】中展示出了自定义 MCP 服务的所有工具

2、输入问题 9999+1后,经过推理后智能体决定调用MCP 服务的工具mcp_calculate_add工具

执行结果:

以上就是本次对于智能体开发技术分享的全部内容。

Logo

更多推荐