【技术文档摘要】: 提供台湾当前天气和天气预报以及台湾和东亚卫星天气图像的MCP工具。
该服务器从CWA获取并转换原始天气数据到调用工具的代理。
Config = {
"cwa": {
"command": "python",
"args": ["path_to_your/server.py","--ui_mode","terminal"],
"transport": "stdio",
"env": {
"CWA_API_KEY": "your_cwa_api_key"
}
}
}
演示CLI基础的MCP客户端如何连接到服务器的示例:
import asyncio
from langchain_community.chat_models import ChatOllama
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import AgentType, initialize_agent
llm = ChatOllama(model="qwen3:14b") # 或其他LLMs
# 加载MCP工具
client = MultiServerMCPClient(Config) # Config在上面定义
tools = asyncio.run(client.get_tools())
# 创建一个可以访问MCP工具的react代理
agent = initialize_agent(
tools, llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)
# 用户查询
query = "台北现在的天气怎么样?"
response = asyncio.run(agent.ainvoke(query))
LLM选择的工具返回:
位置:臺北市
天气概况:阴时多云短暂阵雨
降水概率:40 百分比
户外热舒适指数:舒适至闷热
最高温度:31°C
最低温度:27°C
query="给我台中的3天天气预报"
代理选择的工具返回:
臺中市
温度 相对湿度 风速 降水概率
---------- ------------- ------------------- ------------ ------------------------------
2025-08-03 [28, 26]°C [92, 83]% [7, 4] [60, 30]%
2025-08-04 [29, 26]°C [94, 80]% [5, 3] [40, 20]%
2025-08-05 [32, 26]°C [91, 78]% [5, 2] [50, 20]%
2025-08-06 [32, 25]°C [88, 76]% [4, 2] [20, 10]%
2025-08-07 [29, 26]°C [90, 86]% [3, 2] [20, 10]%
query="给我台南的1周天气预报"
选定的工具输出:
臺南市
平均温度 最高温度 最低温度 相对湿度 风速 降水概率 UV指数
---------- ------- ------- ------- -------------- ------------ ----------- ----------
2025-08-03 28 28.5 27.5 91.5 5 70 5
2025-08-04 27.5 28.5 27 90.5 4.5 25 4
2025-08-05 28.5 30 27 88.5 4.5 20 7
2025-08-06 29 30 27 87.5 4.5 nan 6
2025-08-07 29 30 27 87 4 nan 8
2025-08-08 29 30.5 27 86.5 3.5 nan 8
2025-08-09 29 30 27 86 3 nan 8
query="给我台湾的红外线天气图像"
我们在终端上得到台湾红外线卫星图像的彩色ASCII渲染:
<img width="1000" height="360" alt="infrared_taiwan" src="https://gips1.baidu.com/it/u=473984346,3016332157&fm=3081&app=3081&f=PNG?w=1046&h=720" />如果LLM是基于浏览器的,并且通过Config中的--ui_mode browser部署了MCP服务器,则工具输出的是base64编码的图像字符串:
请注意ASCII渲染中的阿拉伯数字代表图像的“白色”程度——数字越大,区域越云。
query="给我台湾的可见光天气图像"
所选工具返回与运行环境兼容的图像渲染:
<img width="1000" height="360" alt="visible_taiwan" src="https://gips3.baidu.com/it/u=1172949385,2970458721&fm=3081&app=3081&f=PNG?w=1046&h=720" />或
query="给我台湾的雷达反射率天气图像"
终端基础的LLM选择的工具返回
<img width="1000" height="360" alt="radar_taiwan" src="https://gips3.baidu.com/it/u=1066626516,614385715&fm=3081&app=3081&f=PNG?w=1046&h=720" />或者,如果LLM在Web界面运行,
<img width="720" height="600" alt="O-A0058-003 (1)" src="https://gips0.baidu.com/it/u=502152060,1464379193&fm=3081&app=3081&f=PNG?w=3600&h=3600" />对于雷达反射率图像,ASCII渲染中的阿拉伯数字表示原始雷达反射率RGB图像的“亮度”。 <br><br> CWA还提供了涵盖北京、重庆、河内、胡志明市、新加坡、文莱、深圳、香港、马尼拉、上海、台北、首尔、大阪、东京和札幌等东亚地区的天气图像。因此,
query="给我香港的红外线天气图像"
query="给我东京的可见光天气图像"
query="给我上海的雷达反射率天气图像"
LLM将用户自然语言查询转化为工具调用,获取
<img width="1000" height="360" alt="infrared_ea" src="https://gips3.baidu.com/it/u=2607644575,2532772283&fm=3081&app=3081&f=PNG?w=1046&h=720" /> <img width="1000" height="360" alt="visible_ea" src="https://gips2.baidu.com/it/u=942333600,1781545240&fm=3081&app=3081&f=PNG?w=1046&h=720" /> <img width="1000" height="360" alt="radar_ea" src="https://gips1.baidu.com/it/u=3243946282,933915998&fm=3081&app=3081&f=PNG?w=1046&h=720" />请注意,在几乎所有的代理AI框架中,包括react代理,工具输出会被传递给LLM以生成最终响应。这种设计对于可读文本输出是合适的,因为LLM可以进一步总结或翻译工具输出。然而,我们的工具输出是ANSI转义码或base64编码字符串,大多数LLM并未训练过这些内容。将这样的字符串传递给LLM作为最终响应并不高效。解决方法是在代理工作流程中跳过最后一步,直接将工具输出返回给用户。下面展示了这种工作流程的实现:
import asyncio
from langchain_ollama import ChatOllama
from langchain_mcp_adapters.client import MultiServerMCPClient
myConfig = {
"cwa": {
"command": "python",
"args": ["d://Python//MCP//CWA//server.py","--ui_mode","terminal"],
"transport": "stdio",
"env": {
"CWA_API_KEY": "CWA-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
}
}
client = MultiServerMCPClient(myConfig)
tools = asyncio.run(client.get_tools())
llm = ChatOllama(model='gpt-oss:20b') # 或其他LLMs
llm_with_tools = llm.bind_tools(tools) # 工具调用代理
# 一个实用程序,用于根据用户查询确定LLM选择的工具
get_tool = lambda msg, tools: next((tool for tool in tools if tool.name == msg.tool_calls[0]['name']), None)
# 用户查询
query="给我台湾的红外线天气图像"
ai_msg = llm_with_tools.invoke(query) # LLM决定调用哪个工具
selected_tool = get_tool(ai_msg, tools) # 在工具中识别出选定的工具
# 调用工具
result = asyncio.run(selected_tool.ainvoke(ai_msg.tool_calls[0])).content
# 打印结果
print(result)
# 不再将结果反馈给LLM
# response = llm_with_tools.invoke(result)
参考langchain如何进行基本代理工作流程 https://python.langchain.com/docs/how_to/tool_results_pass_to_model/。
台湾天气MCP服务器有3个工具:
get_current_weather_conditions(location_name): 获取台湾指定城市/县的当前天气。可用的22个地点名称包括:
宜兰, 花莲, 台东, 澎湖, 金门, 连江,
台北, 新北, 桃园, 台中, 台南, 高雄,
基隆, 新竹县, 新竹市, 苗栗, 彰化, 南投,
云林, 嘉义县, 嘉义市, 屏东。<br><br>返回
指定城市的当前天气状况概要,包括降水概率、户外热舒适指数以及最高和最低温度。
get_weather_forecast(location_name, num_days): 获取台湾指定城市/县的3天或1周天气预报。有效的地点名称包括:
宜兰, 花莲, 台东, 澎湖, 金门, 连江,
台北, 新北, 桃园, 台中, 台南, 高雄,
基隆, 新竹县, 新竹市, 苗栗, 彰化, 南投,
云林, 嘉义县, 嘉义市, 屏东。<br><br>返回以下表格之一:
> 3天天气预报表,列出指定城市在未来3天内的预测温度范围、相对湿度、风速(蒲福风级)和降水概率。
> 7天天气预报表,列出指定城市在未来7天内的预测平均温度、最高温度、最低温度、相对湿度、风速(蒲福风级)、降水概率和UV指数。
get_current_weather_image(region, wavelength): 获取台湾或东亚的卫星天气图像。图像每10分钟更新一次。<br><br>返回
根据运行环境预格式化的天气图像。
> 如果工具在'terminal'模式下运行,图像将转换为彩色ASCII字符,并用三重反引号包裹在Markdown代码块中,以保持对齐和等宽格式。
> 如果在'browser'模式下运行,输出将被包裹在HTML安全的base64编码的<img>标签中,以便在基于Web的界面中直接渲染。
> LLM不需要推断运行环境。相反,它应该按照提供的格式显示输出。工具确保输出已针对预期环境进行了预格式化。
CWA API密钥,可以从免费的CWA账户(https://opendata.cwa.gov.tw/userLogin)获得
python=3.13.2
mcp=1.10.1
requests=2.32.3
pandas=2.2.3
tabulate=0.9.0
pillow=11.0.0
matplotlib=3.10.3