news 2026/9/28 19:05:23

Java开发者必看:用MCP协议让Claude实时查询天气,TaoToken统一Key接入实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java开发者必看:用MCP协议让Claude实时查询天气,TaoToken统一Key接入实战

1. 为什么 Java 开发者需要给 Claude 接上 MCP 天气能力

如果你平时用 Claude Desktop 写代码、查资料,会发现它有个天然短板:知识截止到训练时间,问它“北京现在天气怎么样”,它只能告诉你“我无法获取实时数据”。MCP(Model Context Protocol)就是解决这个问题的标准协议,它让 AI 模型通过 JSON-RPC 调用你写的外部工具,把实时数据喂回对话里。

MCP 是什么?简单说,它是 Anthropic 开源的一套“AI 与外部工具通信规范”,支持 stdio 和 SSE 两种传输方式。你写一个符合协议的 Server,Claude 就能在对话中自动发现并调用你注册的工具函数。适合谁?适合手上有 Java 业务系统、想快速给 AI 助手扩展能力的后端开发者——你不需要重写技术栈,用现有的 Jackson、HttpClient 就能搭起来。

这篇要落地的场景很具体:用 Java 写一个基于 stdio 的 MCP Server,注册一个get_weather工具,让 Claude Desktop 能实时查询城市天气。整个过程涉及 MCP Server 骨架、工具函数注册、Claude 侧 config 配置,以及一次真实的验证请求。我试过把模拟数据和真实 API 两种方式都跑通,下面按可复制的步骤展开。

2. TaoToken 前置:统一 Key 接入 Claude 与模型调用

在动手写 MCP Server 之前,先解决一个现实问题:Claude Desktop 本身需要能正常调用模型,而很多开发者的 Key 管理是散的——Claude 一个、其他模型一个、coding 工具又一个。TaoToken 在这里的作用是提供统一的 API Key 接入层,你可以在一个控制台里管理 Key,然后分别用于模型对话、Coding Plan 和 MCP 工具链的调试。

具体操作路径:先到官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 注册账号,然后进入控制台的 API Keys 页面创建一个 Key。这个 Key 后面会用在两个地方:一是 Claude Desktop 的模型接入配置,二是你调试 MCP Server 时用模型对话验证工具是否被正确调用。

如果你只是想让 Claude 能查天气,MCP Server 本身不直接调模型,它只负责响应 Claude 发来的 JSON-RPC 请求。但你需要一个能正常工作的 Claude 环境来测试整个链路。TaoToken 的模型对话入口可以用来快速验证“模型是否能理解天气查询意图”,而 Coding Plan 更适合你后续把 MCP 工具扩展到代码场景时使用。

注意:MCP Server 的 stdio 通信是本地进程间通信,不涉及网络代理,你只需要保证 Java 进程能被 Claude Desktop 正常拉起即可。

3. 可复制配置:Java MCP Server 骨架与工具注册

3.1 项目结构与 Maven 依赖

先建一个最小 Maven 项目,只需要 Jackson 做 JSON 处理:

<dependencies> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency> </dependencies>

项目结构保持扁平,一个 Java 文件就够:

weather-mcp-server/ ├── pom.xml └── src/main/java/com/example/mcp/ └── WeatherMcpServer.java

3.2 主入口与 JSON-RPC 分发

MCP 基于 stdio,核心逻辑是从System.in逐行读 JSON-RPC 请求,处理后从System.out写响应。主循环如下:

public class WeatherMcpServer { private static final ObjectMapper MAPPER = new ObjectMapper(); public static void main(String[] args) throws Exception { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String line; while ((line = reader.readLine()) != null) { if (line.trim().isEmpty()) continue; try { JsonNode request = MAPPER.readTree(line); handleRequest(request); } catch (Exception e) { // 生产环境建议记录日志 } } } }

handleRequest根据method字段分发到initialize、tools/list、tools/call三个处理器。注意:通知类请求没有id,直接忽略,不要回响应。

private static void handleRequest(JsonNode request) { String method = request.get("method").asText(); JsonNode params = request.get("params"); JsonNode id = request.get("id"); if (id == null || id.isNull()) return; try { JsonNode result; switch (method) { case "initialize": result = handleInitialize(params); break; case "tools/list": result = handleToolsList(); break; case "tools/call": result = handleToolsCall(params); break; default: sendError(id, -32601, "Method not found: " + method); return; } sendResponse(id, result); } catch (Exception e) { sendError(id, -32603, "Internal error: " + e.getMessage()); } }

3.3 初始化握手与工具列表

initialize返回协议版本、能力声明和服务器信息。协议版本建议写0.1.0,与主流客户端期望一致:

private static JsonNode handleInitialize(JsonNode params) { ObjectNode result = MAPPER.createObjectNode(); result.put("protocolVersion", "0.1.0"); ObjectNode capabilities = MAPPER.createObjectNode(); capabilities.put("tools", true); result.set("capabilities", capabilities); ObjectNode serverInfo = MAPPER.createObjectNode(); serverInfo.put("name", "java-weather-mcp"); serverInfo.put("version", "1.0.0"); result.set("serverInfo", serverInfo); return result; }

tools/list注册get_weather工具,输入参数用 JSON Schema 描述:

private static JsonNode handleToolsList() { ObjectNode result = MAPPER.createObjectNode(); var toolsArray = MAPPER.createArrayNode(); ObjectNode tool = MAPPER.createObjectNode(); tool.put("name", "get_weather"); tool.put("description", "获取指定城市的实时天气信息"); ObjectNode inputSchema = MAPPER.createObjectNode(); inputSchema.put("type", "object"); ObjectNode properties = MAPPER.createObjectNode(); ObjectNode citySchema = MAPPER.createObjectNode(); citySchema.put("type", "string"); citySchema.put("description", "城市名称,例如:北京、上海"); properties.set("city", citySchema); inputSchema.set("properties", properties); inputSchema.put("required", MAPPER.createArrayNode().add("city")); tool.set("inputSchema", inputSchema); toolsArray.add(tool); result.set("tools", toolsArray); return result; }

3.4 工具调用与真实天气 API 接入

tools/call提取城市名,调用天气查询。先用模拟数据跑通链路,再替换为真实 API:

private static JsonNode handleToolsCall(JsonNode params) { String name = params.get("name").asText(); JsonNode arguments = params.get("arguments"); if ("get_weather".equals(name)) { String city = arguments.get("city").asText(); String weatherInfo = getWeatherByCity(city); ObjectNode result = MAPPER.createObjectNode(); ObjectNode content = MAPPER.createObjectNode(); content.put("type", "text"); content.put("text", weatherInfo); result.set("content", MAPPER.createArrayNode().add(content)); return result; } throw new IllegalArgumentException("未知工具: " + name); }

模拟数据版本:

private static String getWeatherByCity(String city) { String[] conditions = {"晴朗", "多云", "小雨", "阴天", "雷阵雨"}; Random random = new Random(); String condition = conditions[random.nextInt(conditions.length)]; int temperature = 5 + random.nextInt(30); int humidity = 40 + random.nextInt(50); return String.format("%s天气:%s,温度%d℃,湿度%d%%", city, condition, temperature, humidity); }

接真实 API 时,用 Java 11+ 的HttpClient替换即可。以和风天气为例,把 API Key 放到环境变量里,不要硬编码:

private static String getWeatherByCity(String city) throws Exception { String apiKey = System.getenv("WEATHER_API_KEY"); String url = String.format( "https://devapi.qweather.com/v7/weather/now?location=%s&key=%s", city, apiKey ); HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .GET() .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); JsonNode root = MAPPER.readTree(response.body()); JsonNode now = root.get("now"); return String.format("%s天气:%s,温度%s℃,湿度%s%%", city, now.get("text").asText(), now.get("temp").asText(), now.get("humidity").asText()); }

3.5 Claude Desktop 侧 config 配置

编译打包后,在 Claude Desktop 配置文件中注册 MCP Server。macOS 路径是~/Library/Application Support/Claude/claude_desktop_config.json,Windows 是%APPDATA%\Claude\claude_desktop_config.json。

如果打成包含依赖的 fat jar:

{ "mcpServers": { "java-weather": { "command": "java", "args": ["-jar", "/absolute/path/to/weather-mcp-server.jar"] } } }

如果直接跑 class 文件,需要把 Jackson 的 jar 也加进 classpath:

{ "mcpServers": { "java-weather": { "command": "java", "args": [ "-cp", "/absolute/path/to/classes:/absolute/path/to/jackson-databind-2.15.2.jar", "com.example.mcp.WeatherMcpServer" ] } } }

配置改完后,完全退出 Claude Desktop(包括托盘图标),再重新启动。界面上会出现一个工具图标,点开能看到get_weather的说明。

4. 验证请求:一次真实的天气查询动作

重启 Claude Desktop 后,在对话里输入“北京今天天气怎么样”。Claude 会识别意图,弹出工具调用确认,然后你的 Java 进程被拉起,收到类似这样的 JSON-RPC 请求:

{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "get_weather", "arguments": { "city": "北京" } } }

你的 Server 返回:

{ "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "北京天气:多云,温度21℃,湿度67%" } ] } }

Claude 拿到结果后会在对话里展示:“根据查询,北京天气:多云,温度21℃,湿度67%。” 如果接的是真实 API,这里就是实时数据。

验证成功的标志有三个:Claude 界面出现工具调用提示、Java 进程被正常拉起、对话返回了天气文本。如果只看到工具图标但调用没反应,往下看排查部分。

5. 本篇常见错排查

5.1 Claude 看不到工具图标

最常见的原因是配置文件路径写错或 JSON 格式不合法。先用python -m json.tool claude_desktop_config.json校验 JSON。另外确认command里的java在系统 PATH 中,Claude Desktop 启动时的环境变量可能和你终端里不一样,建议写 Java 的绝对路径。

5.2 工具图标出现但调用报错

如果 Claude 提示“工具执行失败”,先手动在终端跑一遍 Server,看是否有异常输出:

echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | java -jar weather-mcp-server.jar

正常应该返回工具列表 JSON。如果报ClassNotFoundException,说明 fat jar 没打全,检查maven-assembly-plugin或maven-shade-plugin配置。

5.3 中文乱码

stdio 通信默认编码可能不是 UTF-8。在main方法开头强制设置:

System.setOut(new PrintStream(System.out, true, "UTF-8")); System.setIn(new FileInputStream(FileDescriptor.in));

或者在启动参数里加-Dfile.encoding=UTF-8。

5.4 真实 API 返回空数据

和风天气、OpenWeatherMap 这类 API 对城市名格式有要求,有的需要城市 ID 而不是中文名。先用 curl 单独测 API:

curl "https://devapi.qweather.com/v7/weather/now?location=101010100&key=YOUR_KEY"

确认返回结构后再改 Java 解析逻辑。另外注意 API Key 不要提交到 Git,用环境变量注入。

5.5 进程被反复拉起

Claude Desktop 每次调用工具都会启动一个新进程,如果你的 Server 启动慢(比如加载了大量依赖),会导致超时。建议把 Server 打成 fat jar 减少类加载时间,或者改用 SSE 传输方式让进程常驻。

6. 把 MCP 工具链接到你的日常开发流

天气查询只是个引子。你完全可以在同一个 Java MCP Server 里注册更多工具:查数据库、调内部 API、读文件、发消息。Claude 会根据工具描述自动选择调用哪个,你只需要保证每个工具的inputSchema描述清楚。

如果你后续想把 MCP 工具用在编码场景,比如让 Claude 通过 MCP 查询你本地的代码索引或构建状态,可以到 TaoToken 的 Coding Plan 页面看看长期编码方案的配置方式:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。调试 MCP Server 时如果想让模型快速验证工具返回,模型对话入口更轻量:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。Key 的管理和轮换在控制台完成:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,接入文档里有完整的 API 说明:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。

最后留一个实用技巧:MCP Server 的日志不要往 stdout 写,stdout 是 JSON-RPC 通道,任何多余输出都会破坏协议。要打日志就写 stderr 或文件,这是我在调试时踩过的坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 19:05:14

Claude Code Hooks 实战:用 TaoToken 统一 Key 打通 2025 开发工作流自动化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 19:02:49

2026 最新 AI 论文写作工具排行榜:TaoToken 统一 Key 接入配置指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 19:00:26

Harness Engineering 实战:用 AGENTS.md 给 AI Agent 套上缰绳与护栏

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 19:00:26

多传感器复合装备测试效率提升:从时间同步到自动化平台

多传感器复合装备这几年几乎成了各行业测试场里的标配&#xff0c;光、雷、热、惯导一上架子&#xff0c;硬件堆得漂亮&#xff0c;可真正动手测的人都是一肚子苦水。尤其是“多传感器复合装备测试”这个热词背后&#xff0c;真正让人头疼的不是传感器本身&#xff0c;而是测试…

作者头像 李华