MCP 是什么1.1 一句话理解MCP 是 AI 模型与外部世界交互的标准化协议。就像 USB 统一了设备接口MCP 统一了 AI 工具接口。1.2 三种原语原语作用类比Tools让 AI 调用函数执行操作远程过程调用Resources让 AI 读取结构化数据文件/数据读取Prompts提供可复用的提示模板模板引擎1.3 为什么选 MCP标准化同一套协议不同模型、不同工具都能互联互通自动发现客户端可以动态查询服务端提供了哪些工具跨模型复用工具服务只需开发一次所有模型都能用生态丰富Cursor、Claude Desktop、各大 IDE 都已支持二、快速入门5 分钟构建 MCP 服务2.1 添加依赖在pom.xml中引入 Solon AI MCPdependency groupIdorg.noear/groupId artifactIdsolon-ai-mcp/artifactId /dependency支持 Java 8、11、17、21、25、26。2.2 Hello World 服务端import org.noear.solon.Solon; import org.noear.solon.ai.annotation.ToolMapping; import org.noear.solon.ai.mcp.McpChannel; import org.noear.solon.ai.mcp.server.annotation.McpServerEndpoint; import org.noear.solon.annotation.Param; McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) public class HelloTool { ToolMapping(description 打招呼) public String hello(Param(description 名字) String name) { return 你好 name 欢迎使用 Solon AI MCP ; } } public class McpServerApp { public static void main(String[] args) { Solon.start(McpServerApp.class, args); } }2.3 Hello World 客户端import org.noear.solon.ai.mcp.McpChannel; import org.noear.solon.ai.mcp.client.McpClientProvider; import java.util.Map; public class McpClientTest { public static void main(String[] args) { McpClientProvider client McpClientProvider.builder() .channel(McpChannel.STREAMABLE) .url(http://localhost:8080/mcp) .build(); String result client.callTool(hello, Map.of(name, 阿飞)).getContent(); System.out.println(result); // 你好阿飞欢迎使用 Solon AI MCP } }就是这么简单一个注解McpServerEndpoint你的普通 Java 方法就变成了 MCP 工具服务。三、三种原语开发详解3.1 Tool工具调用Tool 是 MCP 最常用的原语让 AI 可以调用外部函数。McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) public class WeatherTool { ToolMapping(description 查询指定城市的天气预报) public String getWeather( Param(description 城市名称) String city, Param(description 日期格式 yyyy-MM-dd默认今天) String date ) { // 模拟天气数据 return String.format(%s %s晴14°C东风2级, city, date); } ToolMapping(description 查询空气质量指数) public String getAirQuality( Param(description 城市名称) String city ) { return String.format(%s AQI52良PM2.535, city); } }要点ToolMapping(description...)描述工具的用途AI 根据此描述决定是否调用Param(description...)描述参数含义帮助 AI 正确传参建议开启编译参数-parameters让参数名自动识别3.2 Resource资源读取Resource 让 AI 可以读取结构化数据源。import org.noear.solon.ai.annotation.ResourceMapping; McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) public class DocResource { ResourceMapping(uri docs://catalog) public String getCatalog() { return # 知识库目录 1. Solon 入门指南 2. Solon AI 开发教程 3. Solon Cloud 微服务实战 4. Solon Flow 流程编排指南 ; } ResourceMapping(uri docs://{category}/{id}) public String getDoc( Param(description 分类) String category, Param(description 文档ID) String id ) { return String.format(文档内容[%s] #%s, category, id); } }要点ResourceMapping(uri...)定义资源的 URI 模板支持 URI 模板参数如{category}/{id}客户端通过readResource(uri)读取3.3 Prompt提示模板Prompt 提供可复用的提示模板服务。import org.noear.solon.ai.annotation.PromptMapping; McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) public class QaPrompt { PromptMapping(name code_review) public String codeReviewPrompt( Param(description 编程语言) String language, Param(description 代码内容) String code ) { return String.format( 你是一位资深的 %s 代码审查专家。请对以下代码进行审查 %s %s 请从以下维度分析 1. 代码质量与可读性 2. 潜在 Bug 与安全问题 3. 性能优化建议 4. 最佳实践建议 , language, language, code); } }要点PromptMapping(name...)定义提示模板的名称客户端通过getPrompt(name)获取模板内容适合标准化常见 AI 交互模式四、四种传输通道Solon AI MCP 支持四种传输方式适配不同场景通道适用场景特点STREAMABLE生产环境首选HTTP 双向流式高性能STREAMABLE_STATELESS集群部署无状态支持负载均衡SSE兼容旧客户端服务端推送事件STDIO本地进程通信标准输入输出配置示例// 推荐Streamable HTTP生产环境 McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) // 集群友好无状态模式 McpServerEndpoint(channel McpChannel.STREAMABLE_STATELESS, mcpEndpoint /mcp) // 兼容模式SSE McpServerEndpoint(channel McpChannel.SSE, mcpEndpoint /mcp/sse) // 本地进程STDIO McpServerEndpoint(channel McpChannel.STDIO)客户端匹配// 必须与服务端通道匹配 McpClientProvider client McpClientProvider.builder() .channel(McpChannel.STREAMABLE) // 匹配服务端的 STREAMABLE .url(http://localhost:8080/mcp) .build();五、实战企业知识库 MCP 工具服务5.1 场景设计我们要构建一个企业知识库的 MCP 服务提供3 个 Tool搜索文档、获取详情、推荐相关文档1 个 Resource知识库目录索引1 个 Prompt专业问答模板5.2 完整服务端代码package com.example.knowledge; import org.noear.solon.Solon; import org.noear.solon.ai.annotation.ToolMapping; import org.noear.solon.ai.annotation.PromptMapping; import org.noear.solon.ai.annotation.ResourceMapping; import org.noear.solon.ai.mcp.McpChannel; import org.noear.solon.ai.mcp.server.annotation.McpServerEndpoint; import org.noear.solon.annotation.Param; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) public class KnowledgeMcpServer { // 模拟数据 private static final ListString CATALOG Arrays.asList( 1. Solon 快速入门, 2. Solon IoC 容器详解, 3. Solon AI 开发指南, 4. Solon Cloud 微服务实战, 5. Solon Flow 流程编排, 6. Solon Data 数据访问, 7. Solon Security 安全认证 ); private static final ListDocEntry DOCS Arrays.asList( new DocEntry(1, Solon 快速入门, 入门, Solon 是新一代 Java 应用开发框架...), new DocEntry(2, Solon IoC 容器详解, 核心, Solon IoC 容器支持依赖注入...), new DocEntry(3, Solon AI 开发指南, AI, Solon AI 提供完整的大模型集成能力...), new DocEntry(4, Solon Cloud 微服务实战, Cloud, Solon Cloud 提供分布式套件...), new DocEntry(5, Solon Flow 流程编排, Flow, Solon Flow 是轻量级流程引擎...), new DocEntry(6, Solon Data 数据访问, Data, Solon Data 统一数据访问抽象...), new DocEntry(7, Solon Security 安全认证, Security, Solon Security 提供认证授权...) ); // Tool: 搜索文档 ToolMapping(description 搜索知识库文档支持关键词匹配) public String searchDocs( Param(description 搜索关键词) String keyword, Param(description 最大返回条数默认3) int limit ) { ListDocEntry results DOCS.stream() .filter(d - d.title.contains(keyword) || d.content.contains(keyword)) .limit(limit 0 ? limit : 3) .collect(Collectors.toList()); if (results.isEmpty()) { return 未找到与「 keyword 」相关的文档; } StringBuilder sb new StringBuilder(搜索结果\n); for (DocEntry doc : results) { sb.append(String.format(- [%s] %s%s\n, doc.id, doc.title, doc.content)); } return sb.toString(); } // Tool: 获取文档详情 ToolMapping(description 根据文档ID获取完整文档内容) public String getDocDetail( Param(description 文档ID) String docId ) { return DOCS.stream() .filter(d - d.id.equals(docId)) .findFirst() .map(d - String.format(标题%s\n分类%s\n内容%s, d.title, d.category, d.content)) .orElse(文档不存在# docId); } // Tool: 推荐相关文档 ToolMapping(description 根据分类推荐相关文档) public String recommendDocs( Param(description 文档分类如入门、核心、AI、Cloud、Flow、Data、Security) String category ) { ListDocEntry results DOCS.stream() .filter(d - d.category.equals(category)) .collect(Collectors.toList()); if (results.isEmpty()) { return 分类「 category 」下暂无文档; } StringBuilder sb new StringBuilder(推荐文档\n); for (DocEntry doc : results) { sb.append(String.format(- [%s] %s\n, doc.id, doc.title)); } return sb.toString(); } // Resource: 知识库目录 ResourceMapping(uri knowledge://catalog) public String getCatalog() { StringBuilder sb new StringBuilder(# 企业知识库目录\n\n);
用 Solon AI 从零构建 MCP 工具服务:让 AI Agent 拥有真实世界的能力
MCP 是什么1.1 一句话理解MCP 是 AI 模型与外部世界交互的标准化协议。就像 USB 统一了设备接口MCP 统一了 AI 工具接口。1.2 三种原语原语作用类比Tools让 AI 调用函数执行操作远程过程调用Resources让 AI 读取结构化数据文件/数据读取Prompts提供可复用的提示模板模板引擎1.3 为什么选 MCP标准化同一套协议不同模型、不同工具都能互联互通自动发现客户端可以动态查询服务端提供了哪些工具跨模型复用工具服务只需开发一次所有模型都能用生态丰富Cursor、Claude Desktop、各大 IDE 都已支持二、快速入门5 分钟构建 MCP 服务2.1 添加依赖在pom.xml中引入 Solon AI MCPdependency groupIdorg.noear/groupId artifactIdsolon-ai-mcp/artifactId /dependency支持 Java 8、11、17、21、25、26。2.2 Hello World 服务端import org.noear.solon.Solon; import org.noear.solon.ai.annotation.ToolMapping; import org.noear.solon.ai.mcp.McpChannel; import org.noear.solon.ai.mcp.server.annotation.McpServerEndpoint; import org.noear.solon.annotation.Param; McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) public class HelloTool { ToolMapping(description 打招呼) public String hello(Param(description 名字) String name) { return 你好 name 欢迎使用 Solon AI MCP ; } } public class McpServerApp { public static void main(String[] args) { Solon.start(McpServerApp.class, args); } }2.3 Hello World 客户端import org.noear.solon.ai.mcp.McpChannel; import org.noear.solon.ai.mcp.client.McpClientProvider; import java.util.Map; public class McpClientTest { public static void main(String[] args) { McpClientProvider client McpClientProvider.builder() .channel(McpChannel.STREAMABLE) .url(http://localhost:8080/mcp) .build(); String result client.callTool(hello, Map.of(name, 阿飞)).getContent(); System.out.println(result); // 你好阿飞欢迎使用 Solon AI MCP } }就是这么简单一个注解McpServerEndpoint你的普通 Java 方法就变成了 MCP 工具服务。三、三种原语开发详解3.1 Tool工具调用Tool 是 MCP 最常用的原语让 AI 可以调用外部函数。McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) public class WeatherTool { ToolMapping(description 查询指定城市的天气预报) public String getWeather( Param(description 城市名称) String city, Param(description 日期格式 yyyy-MM-dd默认今天) String date ) { // 模拟天气数据 return String.format(%s %s晴14°C东风2级, city, date); } ToolMapping(description 查询空气质量指数) public String getAirQuality( Param(description 城市名称) String city ) { return String.format(%s AQI52良PM2.535, city); } }要点ToolMapping(description...)描述工具的用途AI 根据此描述决定是否调用Param(description...)描述参数含义帮助 AI 正确传参建议开启编译参数-parameters让参数名自动识别3.2 Resource资源读取Resource 让 AI 可以读取结构化数据源。import org.noear.solon.ai.annotation.ResourceMapping; McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) public class DocResource { ResourceMapping(uri docs://catalog) public String getCatalog() { return # 知识库目录 1. Solon 入门指南 2. Solon AI 开发教程 3. Solon Cloud 微服务实战 4. Solon Flow 流程编排指南 ; } ResourceMapping(uri docs://{category}/{id}) public String getDoc( Param(description 分类) String category, Param(description 文档ID) String id ) { return String.format(文档内容[%s] #%s, category, id); } }要点ResourceMapping(uri...)定义资源的 URI 模板支持 URI 模板参数如{category}/{id}客户端通过readResource(uri)读取3.3 Prompt提示模板Prompt 提供可复用的提示模板服务。import org.noear.solon.ai.annotation.PromptMapping; McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) public class QaPrompt { PromptMapping(name code_review) public String codeReviewPrompt( Param(description 编程语言) String language, Param(description 代码内容) String code ) { return String.format( 你是一位资深的 %s 代码审查专家。请对以下代码进行审查 %s %s 请从以下维度分析 1. 代码质量与可读性 2. 潜在 Bug 与安全问题 3. 性能优化建议 4. 最佳实践建议 , language, language, code); } }要点PromptMapping(name...)定义提示模板的名称客户端通过getPrompt(name)获取模板内容适合标准化常见 AI 交互模式四、四种传输通道Solon AI MCP 支持四种传输方式适配不同场景通道适用场景特点STREAMABLE生产环境首选HTTP 双向流式高性能STREAMABLE_STATELESS集群部署无状态支持负载均衡SSE兼容旧客户端服务端推送事件STDIO本地进程通信标准输入输出配置示例// 推荐Streamable HTTP生产环境 McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) // 集群友好无状态模式 McpServerEndpoint(channel McpChannel.STREAMABLE_STATELESS, mcpEndpoint /mcp) // 兼容模式SSE McpServerEndpoint(channel McpChannel.SSE, mcpEndpoint /mcp/sse) // 本地进程STDIO McpServerEndpoint(channel McpChannel.STDIO)客户端匹配// 必须与服务端通道匹配 McpClientProvider client McpClientProvider.builder() .channel(McpChannel.STREAMABLE) // 匹配服务端的 STREAMABLE .url(http://localhost:8080/mcp) .build();五、实战企业知识库 MCP 工具服务5.1 场景设计我们要构建一个企业知识库的 MCP 服务提供3 个 Tool搜索文档、获取详情、推荐相关文档1 个 Resource知识库目录索引1 个 Prompt专业问答模板5.2 完整服务端代码package com.example.knowledge; import org.noear.solon.Solon; import org.noear.solon.ai.annotation.ToolMapping; import org.noear.solon.ai.annotation.PromptMapping; import org.noear.solon.ai.annotation.ResourceMapping; import org.noear.solon.ai.mcp.McpChannel; import org.noear.solon.ai.mcp.server.annotation.McpServerEndpoint; import org.noear.solon.annotation.Param; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; McpServerEndpoint(channel McpChannel.STREAMABLE, mcpEndpoint /mcp) public class KnowledgeMcpServer { // 模拟数据 private static final ListString CATALOG Arrays.asList( 1. Solon 快速入门, 2. Solon IoC 容器详解, 3. Solon AI 开发指南, 4. Solon Cloud 微服务实战, 5. Solon Flow 流程编排, 6. Solon Data 数据访问, 7. Solon Security 安全认证 ); private static final ListDocEntry DOCS Arrays.asList( new DocEntry(1, Solon 快速入门, 入门, Solon 是新一代 Java 应用开发框架...), new DocEntry(2, Solon IoC 容器详解, 核心, Solon IoC 容器支持依赖注入...), new DocEntry(3, Solon AI 开发指南, AI, Solon AI 提供完整的大模型集成能力...), new DocEntry(4, Solon Cloud 微服务实战, Cloud, Solon Cloud 提供分布式套件...), new DocEntry(5, Solon Flow 流程编排, Flow, Solon Flow 是轻量级流程引擎...), new DocEntry(6, Solon Data 数据访问, Data, Solon Data 统一数据访问抽象...), new DocEntry(7, Solon Security 安全认证, Security, Solon Security 提供认证授权...) ); // Tool: 搜索文档 ToolMapping(description 搜索知识库文档支持关键词匹配) public String searchDocs( Param(description 搜索关键词) String keyword, Param(description 最大返回条数默认3) int limit ) { ListDocEntry results DOCS.stream() .filter(d - d.title.contains(keyword) || d.content.contains(keyword)) .limit(limit 0 ? limit : 3) .collect(Collectors.toList()); if (results.isEmpty()) { return 未找到与「 keyword 」相关的文档; } StringBuilder sb new StringBuilder(搜索结果\n); for (DocEntry doc : results) { sb.append(String.format(- [%s] %s%s\n, doc.id, doc.title, doc.content)); } return sb.toString(); } // Tool: 获取文档详情 ToolMapping(description 根据文档ID获取完整文档内容) public String getDocDetail( Param(description 文档ID) String docId ) { return DOCS.stream() .filter(d - d.id.equals(docId)) .findFirst() .map(d - String.format(标题%s\n分类%s\n内容%s, d.title, d.category, d.content)) .orElse(文档不存在# docId); } // Tool: 推荐相关文档 ToolMapping(description 根据分类推荐相关文档) public String recommendDocs( Param(description 文档分类如入门、核心、AI、Cloud、Flow、Data、Security) String category ) { ListDocEntry results DOCS.stream() .filter(d - d.category.equals(category)) .collect(Collectors.toList()); if (results.isEmpty()) { return 分类「 category 」下暂无文档; } StringBuilder sb new StringBuilder(推荐文档\n); for (DocEntry doc : results) { sb.append(String.format(- [%s] %s\n, doc.id, doc.title)); } return sb.toString(); } // Resource: 知识库目录 ResourceMapping(uri knowledge://catalog) public String getCatalog() { StringBuilder sb new StringBuilder(# 企业知识库目录\n\n);