Java开发,实践MCP

MCP

之前对LLM相关知识了解的不多,最近看了一些MCP相关的文章,通过工具获取外部系统数据或实时数据读取(在此之前没了解Function Call),觉得很牛*。看了一些文章,发现MCP扩展LLM的能力,动手实践了一下。围绕着LLM还是需要提示词工程

背景

最近比较火的一个技术------MCP(Model Context Protocol,模型上下文协议)是一种由Anthropic公司推出的一个开放标准协议,目的就是为了解决 AI 模型与外部数据源、工具交互的难题。传统Function Call存在先天性的不足:线性指令执行机制带来的性能瓶颈与异构接口标准带来的兼容性瓶颈。而MCP的设计思路则不同,它遵循微内核架构的设计理念:定义架构和协议标准。号称工具调用的USB-C标准。

本篇文章注重实践,如果缺乏基础知识则移步至其他文章进行学习。

MCP基本架构

HOST

  1. 创建和管理多个客户端实例
  2. 控制客户端连接权限和生命周期
  3. 强制执行安全策略和同意要求
  4. 处理用户授权决策
  5. 协调 AI/LLM 集成和采样
  6. 管理跨客户端的上下文聚合

MCP Clients

  1. 建立每个服务器的一个有状态会话
  2. 处理协议协商和能力交换
  3. 路由协议消息双向传输
  4. 管理订阅和通知
  5. 维护服务器之间的安全边界

主机应用程序创建和管理多个客户端,每个客户端与特定服务器之间保持一对一的关系。

MCP Servers

  1. 通过 MCP 原语公开资源、工具和提示
  2. 独立运行,承担专注的责任
  3. 通过客户端接口请求采样
  4. 必须遵守安全约束
  5. 可以为本地进程或远程服务

实践

从两个方面去实践MCP:

  1. 可以使用CusorClaude去连接一些mcp server,直接使用。这些需要付费使用,VS code + Cline 免费使用,完成一个出行助手
  2. 通过官方提供的sdk,去编码实现一个MCP Server和MCP Client

Cline

VS code中下载Cline插件,并选择配置自己的LLM和密钥

获取MCP Server 的途径

出行助手
集成高德MCP Server,可以调用地图相关Tools

需要申请高德开发者API_KEY,个人使用很容易申请,地址:console.amap.com/dev/key/app

MacOS选手配置如下

json 复制代码
{
   "mcpServers": {
      "amap-maps": {
         "command": "npx",
         "args": [
           "-y",
           "@amap/amap-maps-mcp-server"
         ],
         "env": {
           "AMAP_MAPS_API_KEY": ""
         }
      }
   }
}

注意注意: windows选手的配置不一样,很容易踩坑,配置如下

json 复制代码
{
   "mcpServers": {
      "amap-maps": {
         "command": "cmd",
         "args": [
            "/c",
            "npx",
            "-y",
            "@amap/amap-maps-mcp-server"
         ],
         "env": {
           "AMAP_MAPS_API_KEY": ""
         }
      }
   }
}

配置好之后,可以查看这个server有哪些tools

设置提示词

现在可以正常进行提问

markdown 复制代码
五一计划去武汉游玩4天的旅行攻略:

1. 帮制作旅行攻略,考虑出行时间和路线,以及天气状况路线规划。

1.1 制作网页地图自定义绘制旅游路线和位置。

1.2 网页使用简约美观页面风格,景区图片以卡片展示。

2. 行程规划结果在高德地图app展示,并集成到h5页面中。

2.2 同一天行程景区之间我想打车前往。

3. 生成文件名 travel.html。

到这里为止,使用LLM结合MCP的应用已完毕

计算器 MCP

这里使用官方提供的sdk,编码完成一个 mcp server

应用环境

JDK 17+ springboot 3.3及以上

编码

核心依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp</artifactId>
</dependency>

编写一个计算器 tools

java 复制代码
public class ToolService {
    @Tool(name = "calculator", description = "简单的计算器工具")
    public String calculator(
            @ToolParam(description = "第一个数字 a") Double a,
            @ToolParam(description = "第二个数字 b") Double b,
            @ToolParam(description = "计算操作符(+ - * /)") String operation
    ) {
        double result = switch (operation) {
            case "+" -> a + b;
            case "-" -> a - b;
            case "*" -> a * b;
            case "/" -> a / b;
            default -> throw new IllegalArgumentException("未知操作");
        };
        return String.format("""
                这里是计算器工具
                %s %s %s = %s
                """, a, operation, b, result);
    }
}

启动程序时注册工具

java 复制代码
@Bean
public ToolCallbackProvider weatherTools(ToolService toolService) {
    return MethodToolCallbackProvider.builder().toolObjects(toolService).build();
}

应用打包

shell 复制代码
mvn clean package -DskipTests
Cline 测试

配置mcp

json 复制代码
{
  "mcpServers": {
    "demo": {
      "disabled": false,
      "timeout": 60,
      "command": "java",
      "args": [
        "-Dspring.ai.mcp.server.stdio=true",
        "-Dspring.main.banner-mode=off",
        "-Dspring.main.web-application-type=none",
        "-Dserver.port=8001",
        "-Dlogging.pattern.console=",
        "-jar",
        "/Users/wx/workspace/tvi/zz/spring-mcp/spring-mcp-server/target/spring-mcp-server.jar"
      ],
      "transportType": "stdio"
    }
  }
}

注意:这些命令相当启动jar,需要注意端口冲突,还需要禁止控制台输出

编码 MCP Client

应用环境

JDK 17+ springboot 3.3及以上

编码

核心依赖

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-client</artifactId>
    </dependency>
</dependencies>

配置文件,application.yaml

yaml 复制代码
spring:
  ai:
    openai:
      api-key: sk-***
      base-url: https://api.deepseek.com
      chat:
        options:
          model: deepseek-chat
    mcp:
      client:
        enabled: true
        name: demo
        version: 1.0.0
        type: sync
        request-timeout: 20s
        stdio:
          servers-configuration: classpath:/mcp-server-config.json


logging:
  level:
    io:
      modelcontextprotocol:
        client: debug
        spec: debug

mcp-server-config.json 配置文件

json 复制代码
{
  "mcpServers": {
    "amap-maps": {
      "command": "npx",
      "args": [
        "-y",
        "@amap/amap-maps-mcp-server"
      ],
      "env": {
        "AMAP_MAPS_API_KEY": "********"
      }
    },
    "demo": {
      "command": "java",
      "args": [
        "-Dspring.ai.mcp.server.stdio=true",
        "-Dserver.port=7002",
        "-Dspring.main.banner-mode=off",
        "-Dspring.main.web-application-type=none",
        "-Dlogging.pattern.console=",
        "-Dtransport.mode=stdio",
        "-jar",
        "/Users/wx/workspace/tvi/zz/spring-mcp/spring-mcp-server/target/spring-mcp-server.jar"
      ],
      "env": {
      }
    }
  }
}

启动类 Main.java

java 复制代码
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

    @Bean
    public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, List<McpSyncClient> mcpSyncClients) {
        return args -> {
            var chatClient = chatClientBuilder
                    .defaultSystem("""
                            你是个人小助手.
                            如果用户问出行相关请使用amap-maps相关工具回答;
                            如果用户问计算问题请使用demo mcp相关工具回答;
                            如果用户问题与上述无关,提醒用户"问题不在处理范围内",并告诉用户你有哪些能力
                            """)
                    .defaultTools(new SyncMcpToolCallbackProvider(mcpSyncClients))
                    // .defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory()))
                    .build();
            for (McpSyncClient client : mcpSyncClients) {
                System.out.println("mcp server => " + client.getServerInfo().name());
            }
            System.out.println("\n我是个人小助手\n");
            try (Scanner scanner = new Scanner(System.in)) {
                while (true) {
                    System.out.print("\n用户: ");
                    System.out.println("\nASSISTANT: " +
                            chatClient.prompt(scanner.nextLine())
                                    .call()
                                    .content());
                }
            }
        };
    }
}

至此,使用LLM增强应用的方法实践已结束,虽然我们的编码的案例比较简单,但是这里面的想象空间还是很大很大,打破了LLM的无法获取外界数据的局限性。之前有Function Call可以实现这种功能,但是是各个大模型厂商制定的,兼容性不高。MCP统一了使用规范,号称工具调用的USB-C标准。

相关推荐
拾贰_C4 小时前
【SpringBoot】MyBatisPlus(MP | 分页查询操作
java·spring boot·后端·spring·maven·apache·intellij-idea
就叫飞六吧9 小时前
Spring Security 集成指南:避免 CORS 跨域问题
java·后端·spring
冼紫菜10 小时前
[特殊字符]CentOS 7.6 安装 JDK 11(适配国内服务器环境)
java·linux·服务器·后端·centos
秋野酱12 小时前
Spring Boot 项目的计算机专业论文参考文献
java·spring boot·后端
香饽饽~、12 小时前
【第二篇】 初步解析Spring Boot
java·spring boot·后端
你是狒狒吗12 小时前
消息队列了解一哈
后端
Chandler2413 小时前
Go语言 GORM框架 使用指南
开发语言·后端·golang·orm
蚂蚁在飞-14 小时前
Golang基础知识—cond
开发语言·后端·golang
程序员爱钓鱼20 小时前
匿名函数与闭包(Anonymous Functions and Closures)-《Go语言实战指南》原创
后端·golang