AI Agent 能聊天、能推理,但一旦要查天气、搜文档、调内部 API,它就卡住了——模型本身没有"动手"的能力。MCP(Model Context Protocol)就是解决这个问题的标准化协议:Anthropic 提出它,目标很明确——让任何 Agent 都能用统一的方式调用外部工具,就像 USB Type-C 让所有设备共用一根线。
Solon AI 框架已经把 MCP 的服务端开发封装成了注解驱动的方式,写一个工具服务几乎和写一个普通 REST 接口一样简单。下面拆开来看。
MCP 到底解决了什么
Agent 调工具,过去每个平台各搞一套:OpenAI 有 function calling,LangChain 有 Tool abstraction,各家 SDK 格式不统一。MCP 做的事很简单——定义一套标准协议,覆盖三个角色:
- 工具提供方:暴露能力(查天气、读数据库、发邮件……)
- Agent 客户端:发现并调用这些工具
- 协议层:传输格式、生命周期管理、错误处理
类比一下:没有 MCP 之前,每家厂商自己做充电线;有了 MCP,大家统一用 Type-C。Agent 不需要知道工具是谁实现的,只需要知道接口长什么样。
Solon AI 的 MCP 服务端:两个注解搞定
Solon AI 把 MCP 服务端开发压缩到了两个核心注解:
@McpServerEndpoint:声明这是一个 MCP 服务端入口,配置路径、名称等元信息@ToolMapping:把一个 Java 方法映射为 MCP 工具,自动生成工具描述、参数 schema
这意味着你不需要手写 JSON schema、不需要手动拼协议消息,框架帮你干了。你只写业务逻辑。
实战:从零写一个天气查询 MCP 工具
下面用一个最小可运行的项目演示。假设我们要给 Agent 提供一个"查城市天气"的工具。
1. 项目依赖(Solon 框架 + Solon AI MCP)
<!-- pom.xml -->
<project>
<groupId>demo</groupId>
<artifactId>mcp-weather-server</artifactId>
<version>1.0</version>
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>3.0.5</version> <!-- 请确认最新版本 -->
</parent>
<dependencies>
<!-- Solon AI MCP 服务端支持 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-ai-mcp-server</artifactId>
</dependency>
<!-- Solon Web(提供 HTTP 传输能力) -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-web</artifactId>
</dependency>
</dependencies>
</project>
版本号请到 Solon 官方仓库确认最新稳定版,上面是示意值。
2. 工具服务类
package demo;
import org.noear.solon.ai.mcp.server.McpServerEndpoint;
import org.noear.solon.ai.mcp.server.ToolMapping;
import org.noear.solon.annotation.Component;
@Component
@McpServerEndpoint(name = "weather-tools", description = "提供城市天气查询能力")
public class WeatherToolServer {
@ToolMapping(name = "get_weather", description = "查询指定城市的当前天气")
public String getWeather(String city) {
// 这里用模拟数据演示;实际项目可对接真实天气 API
if ("北京".equals(city)) {
return "北京:晴,气温 28°C,湿度 45%,风速 3m/s";
} else if ("上海".equals(city)) {
return "上海:多云,气温 31°C,湿度 70%,风速 5m/s";
} else {
return city + ":暂无天气数据,请尝试北京或上海";
}
}
@ToolMapping(name = "get_forecast", description = "查询指定城市未来3天天气预报")
public String getForecast(String city) {
// 同样用模拟数据
return city + " 未来3天:第1天晴 28°C,第2天多云 26°C,第3天小雨 22°C";
}
}
关键点:
@McpServerEndpoint的name是 Agent 发现工具时看到的名称,description告诉 Agent 这个服务能干什么@ToolMapping的name和description会自动生成 MCP 协议要求的工具描述和参数 schema——方法的参数名直接成为工具的输入字段- 返回值是
String,MCP 协议要求工具返回文本结果,框架自动包装成协议格式
3. 启动入口
package demo;
import org.noear.solon.Solon;
public class App {
public static void main(String[] args) {
Solon.start(App.class, args);
}
}
启动后,Solon 会自动注册 MCP 服务端端点。Agent 客户端通过标准 MCP 协议(SSE 或 stdio)连接,就能发现 get_weather 和 get_forecast 两个工具并调用。
4. 验证服务是否就绪
# 启动应用后,用 curl 检查 MCP 端点(具体路径取决于 Solon 配置)
curl http://localhost:8080/mcp/weather-tools
# 如果返回工具列表 JSON,说明服务已注册成功
参数校验与多类型返回
实际项目中,工具方法不会这么简单。Solon AI 的 @ToolMapping 支持更复杂的场景:
@ToolMapping(name = "search_docs", description = "在知识库中搜索相关文档")
public String searchDocs(String query, int limit) {
// limit 会被自动识别为整数类型参数
// 框架根据方法签名生成对应的 JSON schema
if (limit <= 0 || limit > 20) {
return "参数错误:limit 需在 1-20 之间";
}
// 实际对接向量数据库或全文检索
return "找到 " + limit + " 条与「" + query + "」相关的文档";
}
框架会从方法签名中推断参数类型(String → string schema,int → integer schema),不需要你手写 schema 定义。这是注解驱动方式最大的效率优势。
几个落地决策点
把 MCP 工具服务从 demo 推到生产,有几个选择需要提前想清楚:
传输方式:MCP 支持 SSE(HTTP 长连接)和 stdio(标准输入输出)两种传输。SSE 适合远程部署、多 Agent 共享;stdio 适合本地进程嵌入。Solon AI 对两种都有支持,根据部署拓扑选。
工具粒度:一个 @McpServerEndpoint 可以挂多个 @ToolMapping,但别把几十个工具塞进一个服务。按业务域拆分——天气一个、文档检索一个、内部 API 一个——Agent 发现和选择工具会更高效。
错误处理:工具返回的错误信息会直接传给 Agent 的推理链。返回结构化的错误描述(而不是抛异常),Agent 才能自主决定是重试、换参数还是换工具。
安全边界:MCP 工具暴露的是真实世界的能力。查天气风险低,但"删除数据库记录"这种工具必须加权限校验。在 @ToolMapping 方法内部做鉴权,不要依赖 Agent 自觉不调。
上手清单
- 确认 Solon 和 solon-ai-mcp-server 的最新版本
- 创建一个 Solon 项目,加上 MCP 依赖
- 写一个
@McpServerEndpoint类,挂 1-2 个@ToolMapping方法 - 启动,用 MCP 客户端(Claude Desktop、Cursor 或任意 MCP 兼容 Agent)连接验证
- 逐步替换模拟数据为真实 API 调用
- 按业务域拆分多个 Endpoint,控制每个服务的工具数量
MCP 正在快速成为 Agent 工具生态的连接标准。Solon AI 把服务端开发压到了注解级别,写法和普通业务代码几乎无差别——这降低了接入门槛,也意味着你现有的 Solon 项目可以零摩擦地变成 Agent 的"手脚"。