手把手教你用 Spring Boot 搭建一个 MCP Server

手把手教你用 Spring Boot 搭建一个 MCP Server

随着 AI Agent 技术的发展,MCP(Model Context Protocol) 正在成为连接大模型与外部工具的标准协议之一。使用 Spring Boot 搭建一个 MCP Server,可以帮助你将自己的业务能力(如数据库查询、文件处理、内部系统调用等)安全地暴露给 LLM Agents 使用。


🚀 使用 Spring Boot 搭建自己的 MCP Server

✅ 本文将带你从零开始构建一个符合 MCP 规范 的轻量级 MCP Server,支持:工具注册动态上下文交互JSON-RPC over HTTPOpenAPI 文档集成
🔧 技术栈:Spring Boot 3 + Java 17 + Maven + Spring Web + Jackson

一、什么是 MCP?

MCP(Model Context Protocol) 是由 Anthropic 提出的一种标准化协议,用于让语言模型(LLM)以结构化方式访问外部工具和数据源。

核心功能:

  • List Tools:列出可用的工具
  • Call Tool:调用指定工具并返回结果
  • Streaming Support(可选):支持流式响应
类似于 OpenAI 的 Function Calling 或 Google 的 Vertex AI Gateway,但更开放、轻量。

二、项目结构设计

src/ ├── main/ │ ├── java/ │ │ └── com.example.mcpserver/ │ │ ├── McpApplication.java # 主启动类 │ │ │ │ │ ├── controller/ │ │ │ └── McpController.java # 处理 /mcp 路由 │ │ │ │ │ ├── model/ │ │ │ ├── Tool.java # 工具元信息 │ │ │ ├── ToolCallRequest.java # 调用请求 │ │ │ └── ToolResult.java # 返回结果 │ │ │ │ │ └── service/ │ │ ├── ToolRegistry.java # 工具注册中心 │ │ └── impl/ │ │ ├── TimeTool.java # 示例工具:获取当前时间 │ │ └── WeatherTool.java # 示例工具:查天气 │ │ │ └── resources/ │ ├── application.yml │ └── openapi/mcp-api.yaml # OpenAPI 描述文件(可选)

三、添加依赖(pom.xml)

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Lombok 简化 POJO --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><!-- JSON 处理 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></endependency></dependencies>

四、定义核心数据模型

Tool.java —— 工具元信息

packagecom.example.mcpserver.model;importlombok.Data;importjava.util.Map;@DatapublicclassTool{privateString name;privateString description;privateMap<String,Object> inputSchema;// JSON Schema 格式}

ToolCallRequest.java

packagecom.example.mcpserver.model;importlombok.Data;importjava.util.List;importjava.util.Map;@DatapublicclassToolCallRequest{privateList<Map<String,Object>> toolCalls;}

ToolResult.java

packagecom.example.mcpserver.model;importlombok.Data;@DatapublicclassToolResult{privateString toolName;privateObject result;privateboolean isError;}

五、实现工具接口与注册中心

定义工具接口

// service/Tool.javapublicinterfaceTool{StringgetName();StringgetDescription();ObjectgetInputSchema();// 返回 JSON SchemaObjectinvoke(Map<String,Object> input);}

实现示例工具:获取当前时间

// service/impl/TimeTool.java@ComponentpublicclassTimeToolimplementsTool{@OverridepublicStringgetName(){return"get_current_time";}@OverridepublicStringgetDescription(){return"Returns the current time in ISO8601 format.";}@OverridepublicObjectgetInputSchema(){returnMap.of("type","object","properties",Map.of());}@OverridepublicObjectinvoke(Map<String,Object> input){returnMap.of("time",Instant.now().toString(),"timezone",ZoneId.systemDefault());}}

工具注册中心(自动收集所有工具)

// service/ToolRegistry.java@ServicepublicclassToolRegistry{privatefinalMap<String,Tool> tools =newConcurrentHashMap<>();publicToolRegistry(List<Tool> toolList){for(Tool tool : toolList){ tools.put(tool.getName(), tool);}System.out.println("✅ 注册了 "+ tools.size()+" 个 MCP 工具");}publicCollection<Tool>getTools(){return tools.values();}publicToolgetTool(String name){return tools.get(name);}}
Spring 会自动注入所有实现了 Tool 接口的 Bean。

六、编写 MCP Controller(核心端点)

// controller/McpController.java@RestController@RequestMapping("/mcp")@RequiredArgsConstructorpublicclassMcpController{privatefinalToolRegistry toolRegistry;/** * GET /mcp/tools - 列出所有可用工具 */@GetMapping("/tools")publicResponseEntity<List<Tool>>listTools(){returnResponseEntity.ok(toolRegistry.getTools().stream().toList());}/** * POST /mcp/call-tool - 调用工具 */@PostMapping("/call-tool")publicResponseEntity<List<ToolResult>>callTools(@RequestBodyToolCallRequest request){returnResponseEntity.ok(request.getToolCalls().stream().map(call ->{String toolName =(String) call.get("name");Map<String,Object> input =(Map<String,Object>) call.get("input");Tool tool = toolRegistry.getTool(toolName);if(tool ==null){returnnewToolResult(toolName,"Tool not found",true);}try{Object result = tool.invoke(input);returnnewToolResult(toolName, result,false);}catch(Exception e){returnnewToolResult(toolName, e.getMessage(),true);}}).collect(Collectors.toList()));}}

七、配置路由(application.yml)

server:port:8080logging:level:com.example: DEBUG 

八、测试你的 MCP Server

启动应用

mvn spring-boot:run 

1. 查看可用工具

curl http://localhost:8080/mcp/tools 

输出示例:

[{"name":"get_current_time","description":"Returns the current time in ISO8601 format.","inputSchema":{...}}]

2. 调用工具

curl -X POST http://localhost:8080/mcp/call-tool \ -H "Content-Type: application/json"\ -d '{ "toolCalls": [ { "name": "get_current_time", "input": {} } ] }'

返回:

[{"toolName":"get_current_time","result":{"time":"2025-11-04T15:40:00Z","timezone":"Asia/Shanghai"},"isError":false}]

九、进阶优化建议

功能实现思路
✅ 认证鉴权添加 JWT 或 API Key 验证(如 @RequestHeader("X-API-Key")
✅ 请求校验使用 @Valid 和 JSON Schema 校验输入参数
✅ 异步执行对耗时工具使用 @Async 支持非阻塞调用
✅ 日志追踪加入 MDC、Trace ID,便于调试
✅ OpenAPI 文档使用 SpringDoc(Swagger)生成 /docs 页面
✅ 流式响应改用 SseEmitter 或 WebSocket 支持 streaming
✅ 自动发现扫描注解(如 @McPTool)自动注册

十、部署与集成

部署方式

  • 构建成 JAR 包运行
  • 打包为 Docker 镜像
  • 部署到 Kubernetes 并通过 Ingress 暴露

与 AI Agent 集成

你可以将这个 MCP Server 地址注册到支持 MCP 的客户端中,例如:

{"mcpServers":{"my-company-tools":{"url":"https://mcp.yourcompany.com/mcp","apiKey":"xxx"}}}

目前主流平台如 Anthropic Claude,以及开源框架如 LangChainLlamaIndex 正在逐步支持 MCP。


✅ 总结:搭建 MCP Server 的关键步骤

  1. ✅ 定义工具接口 Tool
  2. ✅ 实现具体业务逻辑(如时间、天气、订单查询)
  3. ✅ 使用 ToolRegistry 自动注册
  4. ✅ 提供 /mcp/tools/mcp/call-tool 两个标准接口
  5. ✅ 安全加固 + 监控日志
  6. ✅ 部署上线并接入 AI Agent

🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Read more

OpenClaw.ai:Agentic AI 时代的“SpringFramework”时刻

—— 关于下一代智能体基础设施架构、生态演进与企业级可行性的系统性研究报告 第一章 历史的镜像:从软件危机到 Agentic AI 的基础设施真空 1.1 J2EE 的黄昏与 Spring 的黎明:关于复杂性的辩证法 要理解“Spring Framework 时刻”的深刻含义,我们必须将目光投向 21 世纪初的 Java 企业级开发领域。彼时,J2EE(Java 2 Platform, Enterprise Edition)虽然承诺了分布式计算的宏大愿景,但其实现方式——特别是 EJB(Enterprise JavaBeans)——却陷入了过度设计的泥潭。开发者被迫编写大量的 XML 配置文件,继承复杂的接口,不仅难以进行单元测试,且组件之间的耦合度极高。这种“重量级”框架导致的开发效率低下,被称为“J2EE

Flutter for OpenHarmony:Flutter 三方库 postgrest — 鸿蒙端直接访问 PostgreSQL 数据库的极速连接器

Flutter for OpenHarmony:Flutter 三方库 postgrest — 鸿蒙端直接访问 PostgreSQL 数据库的极速连接器

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在开发 Flutter for OpenHarmony 应用时,传统的“端-接口-数据库”模式往往显得过于沉重。 如果只是为了实现基础的增删改查,却需要编写大量的后端 API 逻辑、处理复杂的 SQL 拼写以及繁琐的 JSON 打包,这不仅增加了开发成本,也导致系统在面对业务变动时极其脆弱。 postgrest 正是解决这一痛点的利器。它是专门为 PostgREST(一个能将 PostgreSQL 数据库直接转换为 RESTful API 的高性能网关)打造的 Dart 客户端驱动。通过它,开发者可以在鸿蒙端以类似于编写 SQL 的语义,直接完成对云端数据库的高级检索与操作。 今天,我们将深入探讨如何利用该库在鸿蒙平台上实现“零接口开发”的数据交互体验。 一、原理解析 / 概念介绍

Node.js 后端开发全解析:从核心原理架构到实战应用

Node.js 后端开发全解析:从核心原理架构到实战应用

文章目录 * 前言 * 一、 核心原理与架构 * 1.1 Node.js 架构分层 * 1.2 事件循环机制 * 二、 后端架构设计 * 2.1 经典 MVC 分层架构 * 2.2 API 请求处理流程 * 三、 实战应用 * 3.1 技术栈选型 * 3.2 代码实现示例 * 四、 优势与劣势分析 * 4.1 优势 * 4.2 劣势 * 五、 总结与建议 前言 Node.js 的出现让 JavaScript 走出了浏览器,成为了全栈开发的核心技术。以下将从核心原理架构、后端架构设计、

给数据“立规矩” —— MySQL 新手必学的表约束全指南

给数据“立规矩” —— MySQL 新手必学的表约束全指南

🔥海棠蚀omo:个人主页                 ❄️个人专栏:《初识数据结构》,《C++:从入门到实践》,《Linux:从零基础到实践》,《Linux网络:从不懂到不会》,《MySQL:新手入门指南》                 ✨追光的人,终会光芒万丈 博主简介: 目录 一.为什么要有表的约束? 二.表的约束 2.1空属性 2.2默认值 2.3列描述 2.4zerofill 2.5主键 2.5.1复合主键 2.6自增长 2.7唯一键 5.8外键 前言: 在上一篇文章中我们讲解了MySQL中的各种数据类型,那么正是因为有了各种数据类型,才会有今天我们要讲的表的约束相关知识,那么这中间到底是怎么回事呢?下面我们就一起来看看吧。 一.为什么要有表的约束? 在上一篇文章中,我们认识了很多的数据类型,并在它们的下面我们也通过例子进行了演示,