本文首发【零一探秘】公众号
在这篇文章中,我将构建一个天气查询的MCP Server,让 AI 代理(如 Cursor)能够获取实时天气数据。通过这个简单的示例,让你掌握模型上下文协议(MCP)的基本用法和开发流程。
大致的流程如下:
- 用 TypeScript SDK 从零写一个 MCP Server
- 接入真实的天气 API
- 跟Cursor IDE 集成
- 学会使用 MCP Inspector 调试
在构建之前,需要安装node.js环境以及Cursor IDE(或者是Claude、VS Code都可),另外最好掌握基本的TypeScript/JavaScript 语法.
什么是 MCP 服务器?
模型上下文协议(MCP)服务器是连接 AI 代理与外部工具和数据源的桥梁。你可以把它们看作帮助 AI 理解和操作真实世界应用的“翻译器”。
举个例子,当你在 Cursor 里查询天气时,它会返回如下结果:
“我无法通过当前的工具访问实时天气数据或天气 API。”
解决方案: 这时,我们就可以通过构建一个MCP Server, 让 AI 代理能够访问实时数据并执行相关操作。
在这个场景中, 我们的天气服务器将作为一个工具,任何兼容 MCP 协议的 AI 代理 都可以调用它来获取全球任意城市的实时天气信息。
下面我们一步步来完成这个MCP 工具的构建:
第一步:项目初始化
- 初始化项目
mkdir mcp-weather-server
cd mcp-weather-server
npm init -y
2. 创建主文件 touch main.ts 3. 在编辑器中打开 package.json,添加 type 字段启用 ES 模块:
{
"name": "mcp-weather-server",
"version": "1.0.0",
"type": "module",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
}
}
第二步:安装依赖
- 安装 MCP SDK
npm install @modelcontextprotocol/sdk
2. 安装 Zod 用于数据校验
npm install zod
现在 package.json 依赖应如下所示:
"dependencies": {
"@modelcontextprotocol/sdk": "^1.13.1",
"zod": "^3.25.67"
}
第三步:构建基础服务器
打开 main.ts,按以下步骤操作。
- 引入所需模块
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from "zod";
2. 创建服务器实例
const server = new McpServer({
name: "Weather Server",
version: "1.0.0"
});
3. 定义你的第一个工具
工具是 AI 代理可以调用的函数。我们创建一个 get-weather 工具:
server.tool(
'get-weather',
'Tool to get the weather of a city',
{
city: z.string().describe("The name of the city to get the weather for")
},
async({ city }) => {
// 目前先返回静态内容
return {
content: [
{
type: "text",
text: `The weather in ${city} is sunny`
}
]
};
}
);
4. 设置通信方式
const transport = new StdioServerTransport();
server.connect(transport);
第四步:用 MCP Inspector 测试
在添加真实天气数据前,先用 MCP Inspector(MCP 服务器的网页调试工具)测试你的服务器。
启动 Inspector
npx -y @modelcontextprotocol/inspector npx -y tsx main.ts
终端会输出本地地址和 session token,点击带 token 的链接即可。
连接并测试
- 点击 Inspector 里的“Connect”
- 选择“Tools”导航栏
- 选择 get-weather 工具
- 输入城市名(如“Shanghai”),点击“Run Tool”
你会看到响应:“The weather in Shanghai is sunny”
第五步:接入真实天气数据
我们用 Open-Meteo 免费天气 API(无需 API key)。
原理很简单:
- 先用地理编码 API 把城市名转成坐标
- 再用天气 API 查这个坐标的天气
工具代码升级如下:
server.tool(
'get-weather',
'查询指定城市天气',
{
city: z.string().describe("要查询天气的城市名")
},
async({ city }) => {
try {
// 第一步:查城市坐标
const geoResponse = await fetch(
`https://geocoding-api.open-meteo.com/v1/search?name=${city}&count=1&language=en&format=json`
);
const geoData = await geoResponse.json();
if (!geoData.results || geoData.results.length === 0) {
return {
content: [
{
type: "text",
text: `没找到城市 "${city}",请检查拼写再试一次。`
}
]
};
}
// 第二步:查天气
const { latitude, longitude } = geoData.results[0];
const weatherResponse = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code&hourly=temperature_2m,precipitation&forecast_days=1`
);
const weatherData = await weatherResponse.json();
return {
content: [
{
type: "text",
text: JSON.stringify(weatherData, null, 2)
}
]
};
} catch (error) {
return {
content: [
{
type: "text",
text: `获取天气失败:${error.message}`
}
]
};
}
}
);
重启 MCP Inspector,重新连接,再输入“Tokyo”或“New York”试试,就能看到最新的天气数据了。
第六步:与 Cursor IDE 集成
我们打开cursor settings配置面板,找到tools一栏,点击添加(最后一行路径替换为你本地的代码路径):
然后我们可以看到天气MCP Server已经启动。
启动并测试
- 点击 MCP 面板中服务器名旁的“Start”
- 状态应为“Running”
- 切换到 Copilot 侧边栏 → “Agent Mode”
- 询问:“What’s the weather like in Tokyo?”
现在我们在Cursor的agent模式下询问:What's the weather like in Shanghai,可以看到正确调用了天气查询MCP Server:
通过上述流程,可以看到在cursor中调用MCP 工具已经将原始 JSON 转换为美观的天气报告。
完整代码参考:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from "zod";
const server = new McpServer({
name: "Weather Server",
version: "1.0.0"
});
server.tool(
'get-weather',
'查询指定城市天气',
{
city: z.string().describe("要查询天气的城市名")
},
async({ city }) => {
try {
// 第一步:查城市坐标
const geoResponse = await fetch(
`https://geocoding-api.open-meteo.com/v1/search?name=${city}&count=1&language=en&format=json`
);
const geoData = await geoResponse.json();
if (!geoData.results || geoData.results.length === 0) {
return {
content: [
{
type: "text",
text: `没找到城市 "${city}",请检查拼写再试一次。`
}
]
};
}
// 第二步:查天气
const { latitude, longitude } = geoData.results[0];
const weatherResponse = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code&hourly=temperature_2m,precipitation&forecast_days=1`
);
const weatherData = await weatherResponse.json();
return {
content: [
{
type: "text",
text: JSON.stringify(weatherData, null, 2)
}
]
};
} catch (error) {
return {
content: [
{
type: "text",
text: `获取天气失败:${error.message}`
}
]
};
}
}
);
const transport = new StdioServerTransport();
server.connect(transport);
写在最后
好了,现在我们已经完成了一个最基础的 MCP 天气服务器搭建:
- ✅ 从零实现了 MCP 服务器
- ✅ 能查到实时天气
- ✅ 与 Cursor IDE集成
- ✅ MCP 的基本用法也掌握了
其实 MCP 服务器没想象中复杂,查天气只是个入门示例,后续你完全可以扩展查数据库、抓网页、连各种服务都行。 今天的分享就到这里,如果有疑问,欢迎留言讨论。