尧图精选

在 Java 中创建你的第一个 Model Context Protocol (MCP) 服务器:Spring Boot + TaoToken 配置骨架

🕒 发布时间:2026/11/2 20:11:53 📁 来源:尧图网络
1. 为什么 Java 开发者需要关注 MCP 服务器如果你是一名写惯了 Controller、Service、Repository 的 Java 开发者第一次听到 Model Context ProtocolMCP可能会觉得这又是哪个新瓶装旧酒的协议。但实际接触下来你会发现MCP 解决的是一个非常具体的问题让 AI 模型能够以标准化的方式调用你已有的业务能力而不是把数据复制粘贴到对话框里。MCP 本质上是一套通信规范它定义了 AI 客户端比如 Claude Desktop、各类 IDE 插件、Agent 框架如何发现并调用外部工具。你写好的 Java 方法加上一个注解就能变成 AI 可以理解并调用的工具。这对 Java 后端来说意义很大——你不需要重写业务逻辑只需要把现有的 Service 暴露成 MCP 工具AI 就能帮你查询数据、触发计算、串联流程。Spring AI 在这个基础上做了进一步封装。它把 MCP 规范里那些繁琐的握手、序列化、传输层细节都藏了起来留给你的就是Tool注解和几个配置项。你可以用写 Spring Bean 的方式写 MCP 工具用application.yml管理服务器行为用依赖注入组织服务层。对于熟悉 Spring 生态的人来说上手成本几乎为零。这篇文章会带你从零搭一个可运行的 MCP 服务器包含完整的pom.xml依赖、application.yml配置、工具类实现以及如何通过 TaoToken 统一管理模型调用的 Key 和 API 通道。最后会给出验证 MCP 端点连通性的具体命令和预期返回确保你搭完就能确认它真的在工作。适合谁看有 Spring Boot 基础、想把自己的 Java 服务接入 AI 工作流的后端开发者正在做 Agent 工具链、需要标准化工具暴露方式的架构同学以及想理解 MCP 服务端到底怎么落地的人。2. 前置准备TaoToken 统一 Key 与 API 通道在开始写代码之前先把模型调用的通道准备好。MCP 服务器本身负责暴露工具但工具背后如果需要调用大模型比如做意图理解、参数补全、结果总结就需要一个稳定的 API 入口。TaoToken 在这里的角色是统一管理 Key 和请求通道避免你在多个模型供应商之间来回切换配置。你可以先到官网了解整体能力https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。注册后在控制台创建一个 API Key这个 Key 会用于后续application.yml里的模型调用配置。控制台地址https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite创建 Key 的页面https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewriteAPI 基础地址不带 UTM直接用于代码配置https://taotoken.net/api如果你后续要做长期编码或 Agent 类项目可以关注 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite需要说明的是MCP 服务器本身不强制依赖某个模型通道。但实际项目里工具调用往往伴随模型推理提前把 Key 和 Base URL 配好后面切换模型或调整参数时不用改代码结构。我建议把 Key 放在环境变量里application.yml通过占位符引用这样本地和线上环境可以共用同一份配置。3. 可复制配置pom 依赖与 application.yml3.1 Maven 依赖Spring AI 的 MCP Server 支持多种传输方式本地开发最常用的是 STDIO标准输入输出适合被 Claude Desktop 这类客户端直接拉起。如果你要做远程服务可以选 HTTP/SSE。下面这份pom.xml片段覆盖了 MCP Server 和模型调用两部分依赖。properties java.version17/java.version spring-ai.version1.0.0-M6/spring-ai.version /properties dependencies !-- Spring Boot 基础 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter/artifactId /dependency !-- Spring AI MCP Server -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-mcp-server-spring-boot-starter/artifactId version${spring-ai.version}/version /dependency !-- 模型调用通道OpenAI 兼容协议 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId version${spring-ai.version}/version /dependency /dependencies repositories repository idspring-milestones/id nameSpring Milestones/name urlhttps://repo.spring.io/milestone/url /repository /repositories注意 Spring AI 的版本迭代较快1.0.0-M6是里程碑版本正式版发布后可以替换为稳定版本号。如果你的项目用的是 Gradle把对应依赖换成implementation写法即可坐标不变。3.2 application.yml 配置骨架配置文件分三块MCP 服务器标识、STDIO 传输要求、模型通道。STDIO 模式下必须关闭 Web 容器和 banner否则标准输出会被日志污染客户端解析会失败。spring: main: web-application-type: none banner-mode: off ai: mcp: server: name: java-mcp-demo version: 0.0.1 type: SYNC openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: gpt-4o-mini temperature: 0.7 logging: pattern: console: level: root: WARN org.springframework.ai: INFO这里有几个容易踩的点。web-application-type: none是必须的因为 STDIO 传输不需要 HTTP 端口。logging.pattern.console置空是为了避免日志混入标准输出但如果你需要调试可以临时改成%d{HH:mm:ss} %-5level %msg%n并输出到文件。api-key用环境变量注入启动前执行export TAOTOKEN_API_KEY你的Key即可。4. 服务端骨架工具类与注册4.1 数据模型用一个 record 表示课程数据简洁且不可变。Java 17 的 record 在这里很合适序列化时字段名直接对应 JSON key。public record Course(String title, String url) { }4.2 工具服务类核心是Tool注解。Spring AI 会扫描被注解的方法把方法名、描述、参数签名注册成 MCP 工具。AI 客户端拿到工具列表后会根据描述决定调用哪个方法、传什么参数。Service public class CourseService { private static final Logger log LoggerFactory.getLogger(CourseService.class); private final ListCourse courses new ArrayList(); Tool(name get_courses, description 获取所有可用课程列表) public ListCourse getCourses() { log.info(MCP tool invoked: get_courses); return courses; } Tool(name get_course_by_title, description 根据课程标题精确查找单门课程) public Course getCourseByTitle(String title) { log.info(MCP tool invoked: get_course_by_title, title{}, title); return courses.stream() .filter(c - c.title().equalsIgnoreCase(title)) .findFirst() .orElse(null); } PostConstruct public void init() { courses.addAll(List.of( new Course(Spring Boot 实战入门, https://example.com/spring-boot), new Course(Spring AI 与 MCP 开发, https://example.com/spring-ai-mcp) )); } }Tool的name建议用英文小写下划线避免客户端解析异常。description要写清楚用途这是模型判断是否调用该工具的主要依据。参数名会直接暴露给模型所以title这种语义明确的命名比t更好。4.3 主类注册工具在主应用类里把服务类的方法注册成ToolCallbackSpring 的组件扫描会自动注入CourseService。SpringBootApplication public class McpServerApplication { public static void main(String[] args) { SpringApplication.run(McpServerApplication.class, args); } Bean public ListToolCallback courseTools(CourseService courseService) { return List.of(ToolCallbacks.from(courseService)); } }ToolCallbacks.from()会反射扫描传入对象上的Tool方法生成对应的回调。如果你有多个服务类可以多次调用from()然后合并到一个 List 里。5. 验证请求与预期结果5.1 启动服务器打包后直接运行mvn clean package -DskipTests java -jar target/mcp-server-0.0.1-SNAPSHOT.jarSTDIO 模式下进程启动后不会输出任何内容这是正常的。它在等待标准输入传入 JSON-RPC 消息。5.2 用 JSON-RPC 手动验证打开另一个终端用echo管道发送初始化请求。MCP 协议基于 JSON-RPC 2.0先发initialize再发tools/list。echo {jsonrpc:2.0,id:1,method:initialize,params:{protocolVersion:2024-11-05,capabilities:{},clientInfo:{name:test-client,version:1.0}}} | java -jar target/mcp-server-0.0.1-SNAPSHOT.jar预期返回类似{jsonrpc:2.0,id:1,result:{protocolVersion:2024-11-05,capabilities:{tools:{}},serverInfo:{name:java-mcp-demo,version:0.0.1}}}接着验证工具列表echo {jsonrpc:2.0,id:2,method:tools/list,params:{}} | java -jar target/mcp-server-0.0.1-SNAPSHOT.jar预期能看到get_courses和get_course_by_title两个工具包含各自的inputSchema。如果返回里tools数组为空说明ToolCallbacks.from()没有扫描到注解检查服务类是否被Service标注、主类是否注册了 Bean。5.3 调用工具echo {jsonrpc:2.0,id:3,method:tools/call,params:{name:get_courses,arguments:{}}} | java -jar target/mcp-server-0.0.1-SNAPSHOT.jar预期返回课程列表的 JSON 数组。到这里一个最小可用的 MCP 服务器就跑通了。如果你更想先在对话界面里验证模型通道是否正常可以打开模型对话页面https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 确认 Key 和 Base URL 配置无误后再回到代码调试。6. 常见报错排查启动后无任何输出客户端连接超时。检查web-application-type是否为none以及banner-mode是否关闭。如果控制台有 Spring Boot 的启动日志说明配置没生效日志会污染 STDIO 流。tools/list 返回空数组。最常见的原因是Tool方法所在的类没有被 Spring 管理或者主类里没有注册ToolCallbackBean。另外确认spring-ai-mcp-server-spring-boot-starter依赖已正确引入版本与 Spring AI 其他模块一致。调用工具时报参数反序列化失败。MCP 客户端传参是 JSONJava 方法参数如果是复杂对象需要保证字段名和 JSON key 一致。record 类型默认支持普通 POJO 需要 getter/setter 或JsonProperty标注。模型调用返回 401 或 403。检查TAOTOKEN_API_KEY环境变量是否在当前 shell 生效base-url是否写成https://taotoken.net/api注意不要多加路径。如果用的是 IDE 启动需要在 Run Configuration 里单独配置环境变量。STDIO 模式下日志干扰。把logging.pattern.console设为空字符串或者把日志输出重定向到文件。调试阶段可以临时开启但接入客户端前必须关掉。接入相关的文档和 Key 管理入口在这里接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite API Keys https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。如果你用的是 Claude Code 这类编码工具可以参考 ClaudeCodeAnthropic 配置说明https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite 。7. 下一步从骨架到可用服务跑通上面的骨架后你可以按这几个方向扩展。把CourseService里的内存列表换成真实的 Repository接数据库或远程 API给工具方法加上参数校验和异常处理避免模型传入非法参数导致 500如果要做远程 MCP 服务把传输方式从 STDIO 换成 HTTP/SSE配置spring.ai.mcp.server.type和对应端口。长期做 Agent 或编码辅助的话建议把模型调用统一走 TaoToken 的 Coding PlanKey 和额度集中管理切换模型时只改application.yml里的model字段。工具注册这块随着服务类增多可以按业务域拆成多个Bean方法每个方法负责一组工具的注册保持主类清爽。最后提醒一点MCP 工具的描述文本会直接影响模型调用准确率。description写得太模糊模型可能该调不调写得太长又会占用上下文。建议用「动词 对象 返回内容」的结构比如「根据课程标题查询单门课程的详细信息」比单纯写「查询课程」效果好很多。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →