从Java/K8s后端转AI工程,最快的方式就是直接写个东西发布掉。
虽然业务逻辑极其简单(就是查天气),但这个过程中踩的坑反而很有参考价值,尤其是对于想尝试构建 AI Agent 外部工具的同学。
这次实战下来感觉 MCP 协议确实把 AI 与外部数据的连接标准化了,只要后端封装得足够干净,Agent 调用起来非常顺滑。对于想从零开始尝试 MCP 开发的人来说,建议先找这种简单的公开 API 练手,把链路跑通比追求复杂功能更重要。
下一篇
分享一个关于AI Agent权限控制的实操坑 →
核心实现方案
这次用了 Node.js + TypeScript,配合官方的 @modelcontextprotocol/sdk。传输层走的是最稳的 stdio,输入验证交给 Zod。
我定义了三个只读 Tool:
get_municipality_forecast:按地区代码查预报get_station_observation:查气象站实测数据get_weather_warnings:查区域天气预警
避坑指南:这个API的“两步走”诡计
最让我意外的是,这个API居然玩了一手“预签名链接”的套路。你请求数据,它不直接给你结果,而是给你一个 JSON,里面包含一个 datos 字段,这个字段是一个 URL。你得拿着这个 URL 再请求一次才能拿到真正的天气数据。
如果直接把这个逻辑交给 LLM,Agent 可能会在两次跳转中迷路,或者在解析 JSON 时卡住。我的实操方案是把这个“两次跳转”封装在底层 Client 函数里,让 Tool 层面感知不到这个过程:
async function fetchAemet(path: string): Promise<any> {
// 1. 携带 api_key 请求端点 -> 返回 { estado, datos, metadatos }
// 2. 校验 estado 状态
// 3. 请求 datos 里的 URL -> 解码 -> 解析 JSON
}另外两个隐藏的深坑
在实际部署和测试时,还有两个细节差点让我心态崩了:
- 状态码欺骗:HTTP 状态码可能是 200 OK,但 JSON 里的
estado字段可能是 401 或 404。如果只依赖 HTTP 状态码,你会发现 Agent 拿到了一个“成功”的错误消息。 - 字符集地狱:这个 API 很多内容用的是
ISO-8859-1而不是UTF-8。如果直接用response.json(),西班牙语的特殊字符全都会乱码。必须先读成 Buffer,然后手动解码。
这次实战下来感觉 MCP 协议确实把 AI 与外部数据的连接标准化了,只要后端封装得足够干净,Agent 调用起来非常顺滑。对于想从零开始尝试 MCP 开发的人来说,建议先找这种简单的公开 API 练手,把链路跑通比追求复杂功能更重要。