为什么需要 MCP 服务器?
你是否遇到过这样的场景:向 AI 助手(比如 GitHub Copilot)询问 “北京今天的天气”,得到的回复却是 “我无法访问实时天气数据”?
这是因为大多数 AI 模型本身 “与世隔绝”—— 它们只能依赖训练时学到的知识,无法主动连接实时数据(如天气 API)、操作工具(如浏览器)或调用外部服务(如 GitHub)。而模型上下文协议(MCP)服务器就是解决这个问题的 “桥梁”:它让 AI 能像人一样 “使用工具”,比如调用天气 API 获取实时数据、控制浏览器访问网页,甚至操作 GitHub 创建代码提交。
举个例子:
- 有了 Playwright MCP 服务器,AI 能自动打开浏览器,帮你测试网站功能;
- 有了 GitHub MCP 服务器,AI 能直接帮你创建代码分支和拉取请求;
- 今天我们要做的 “天气 MCP 服务器”,能让 AI 随时获取全球任意城市的实时天气 —— 从此问 AI 天气,它能给你精准到温度、湿度的答案。
什么是 MCP 服务器?
简单说,MCP 服务器是 AI 与现实世界之间的 “翻译官” 和 “工具管理员”。它的核心作用是:
- 告诉 AI “你有哪些工具可用”(比如 “天气查询工具”);
- 接收 AI 的 “工具使用请求”(比如 “查上海的天气”);
- 调用实际的外部服务(比如天气 API)获取结果;
- 把结果整理后返回给 AI,让 AI 能基于此生成回答。
有了 MCP 服务器,AI 不再是 “纸上谈兵”,而是能真正 “动手” 解决需要实时数据或外部交互的问题。
本教程目标
我们将用 TypeScript 构建一个 “天气 MCP 服务器”,实现:
- 让 AI(如 GitHub Copilot)能通过这个服务器查询任意城市的实时天气;
- 掌握 MCP 服务器的核心开发流程,为后续开发其他工具(如股票查询、新闻获取)打基础。
准备工作
在开始前,请确保你的环境满足这些条件:
- 基本的 JavaScript/TypeScript 知识(能看懂简单的变量、函数和异步代码);
- 电脑上安装了 Node.js(推荐 v16 及以上,可通过
node -v
检查版本,没有的话去Node.js 官网下载); - 代码编辑器(推荐 VS Code,方便后续与 GitHub Copilot 集成测试);
- 网络连接正常(需要下载依赖和调用天气 API)。
步骤 1:项目初始化与环境配置
这一步我们要搭建基础的项目结构,安装必要的工具,让代码能正常运行。
1. 创建项目文件夹并进入
首先,打开终端(Windows 用 PowerShell 或命令提示符,Mac/Linux 用 Terminal),执行以下命令:
# 创建项目文件夹(名字可以自定义,这里用mcp-weather-server)
mkdir mcp-weather-server
# 进入文件夹
cd mcp-weather-server
这一步的作用是:为项目创建一个独立的文件夹,避免文件混乱。
2. 初始化 npm 项目
在终端中继续执行:
npm init -y
- 作用:通过 npm(Node.js 的包管理工具)初始化项目,生成
package.json
文件(这个文件会记录项目的基本信息和依赖)。 - 执行后,文件夹里会多出一个
package.json
,内容类似:
{
"name": "mcp-weather-server",
"version": "1.0.0",
"main": "index.js",
"scripts": { "test": "echo \"Error: no test specified\" && exit 1" },
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}
3. 安装必要的依赖
我们需要安装 3 类工具:
- MCP 服务器核心 SDK(
@mcp/server
):用于快速搭建 MCP 服务器; - TypeScript 相关工具(
typescript
、@types/node
、ts-node
):因为我们用 TypeScript 开发,需要编译和运行 TS 代码;
在终端执行:
npm install @mcp/server
npm install typescript @types/node ts-node --save-dev
--save-dev
表示这些工具是 “开发时依赖”(只在写代码时用,运行时不用);- 执行后,文件夹会多出
node_modules
(存放依赖代码)和package-lock.json
(记录依赖的精确版本)。
4. 配置 TypeScript 编译规则
TypeScript 需要通过tsconfig.json
文件指定编译规则(比如代码编译后生成的 JS 版本、是否严格检查类型等)。
在终端执行:
npx tsc --init
npx
是 npm 自带的工具,用于临时运行安装的包;- 执行后,文件夹会生成
tsconfig.json
,我们需要修改其中几个关键配置(用 VS Code 打开文件,找到并修改):
{
"compilerOptions": {
"target": "ES2020", // 编译后的JS兼容ES2020标准
"module": "ESNext", // 模块系统用最新的ES模块(与MCP SDK兼容)
"moduleResolution": "NodeNext", // 模块查找规则匹配Node.js
"outDir": "./dist", // 编译后的JS文件放在dist文件夹
"rootDir": "./", // 源代码(TS文件)的根目录
"strict": true, // 开启严格类型检查(减少错误)
"esModuleInterop": true, // 兼容CommonJS和ES模块
"skipLibCheck": true, // 跳过对库文件的类型检查(加速编译)
"forceConsistentCasingInFileNames": true // 文件名大小写严格匹配
}
}
这些配置的作用是:确保 TypeScript 代码能正确编译成 MCP SDK 支持的格式,避免运行时出错。
5. 修改 package.json,启用 ES 模块
MCP SDK 使用的是现代 ES 模块(即import/export
语法),而 Node.js 默认用的是 CommonJS 模块(require
语法)。为了兼容,需要修改package.json
:
用 VS Code 打开package.json
,添加"type": "module"
字段,修改后如下:
{
"name": "mcp-weather-server",
"version": "1.0.0",
"type": "module", // 新增:启用ES模块
"main": "main.ts", // 修改:入口文件为我们后续创建的main.ts
"scripts": {
"start": "ts-node main.ts", // 新增:用ts-node直接运行main.ts
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"@mcp/server": "^x.x.x" // 版本号可能不同,以实际安装为准
},
"devDependencies": {
"@types/node": "^x.x.x",
"ts-node": "^x.x.x",
"typescript": "^x.x.x"
}
}
- 新增的
"start": "ts-node main.ts"
让我们可以用npm start
直接运行 TypeScript 代码(不用先编译); "type": "module"
确保 Node.js 用 ES 模块语法解析代码,避免出现import
语法报错。
6. 创建主文件
在项目文件夹中创建main.ts
(这是我们的核心代码文件):
- 在 VS Code 中,右键项目文件夹 → “新建文件” → 命名为
main.ts
; - 暂时不用写内容,后续步骤会逐步填充。
步骤 2:安装项目所需的依赖库
在开始编写代码前,我们需要先安装两个核心工具库,它们是搭建 MCP 服务器的 “基础零件”。
1. 安装 MCP SDK(核心开发工具)
MCP SDK(@modelcontextprotocol/sdk
)是官方提供的开发包,里面包含了所有搭建 MCP 服务器的现成工具 —— 比如创建服务器实例、定义工具接口、处理 AI 与服务器的通信等。简单说,有了它,我们不用从零写代码,直接用现成的功能就能快速搭起服务器框架。
安装命令(在终端中执行):
npm install @modelcontextprotocol/sdk
执行后,npm 会自动从网络下载这个库,并把它安装到项目的node_modules
文件夹里,同时在package.json
的dependencies
中记录这个依赖(方便后续其他人运行项目时快速安装)。
2. 安装 Zod(数据验证工具)
Zod(zod
)是一个用于数据验证的库。它的作用是:确保 AI 发送给服务器的参数是 “合规” 的。比如我们的天气服务器需要 “城市名” 作为参数,Zod 可以检查 AI 是否真的传了一个字符串(而不是数字或空值),如果参数不对,会直接报错,避免服务器因为无效数据崩溃。
安装命令(继续在终端执行):
npm install zod
检查安装结果
安装完成后,打开项目中的package.json
文件,在"dependencies"
部分应该能看到这两个库的记录(版本号可能因安装时的最新版本略有不同):
"dependencies": {
"@modelcontextprotocol/sdk": "^1.13.1",
"zod": "^3.25.6"
}
这说明两个库已经成功安装,接下来可以开始编写服务器代码了。
步骤 3:构建基础的 MCP 服务器
这一步我们会从零开始,逐步写出能运行的基础服务器代码。打开之前创建的main.ts
文件,跟着以下步骤操作。
1. 导入需要的工具(代码开头)
首先,我们需要从刚才安装的库中 “导入” 要用的功能,就像做菜前把需要的食材拿出来一样。在main.ts
顶部添加以下代码:
// 从MCP SDK中导入服务器核心类和通信工具
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
// 从Zod中导入数据验证工具
import { z } from "zod";
McpServer
:用于创建 MCP 服务器实例的类(服务器的 “主体”);StdioServerTransport
:用于处理服务器与外部(比如 AI)通信的工具(通过终端的输入输出传递数据);z
:Zod 库的主入口,用于定义数据验证规则。
2. 创建服务器实例
接下来,我们需要创建一个服务器实例,相当于 “启动” 一个服务器程序。在导入代码下方添加:
// 创建MCP服务器实例,指定名称和版本
const server = new McpServer({
name: "Weather Server", // 服务器名称(会告诉AI这是什么服务器)
version: "1.0.0" // 版本号(用于区分服务器的不同版本)
});
这行代码会初始化一个服务器对象server
,后续所有功能(比如定义工具、启动通信)都要通过这个对象来操作。
3. 定义服务器的 “工具”—— 让 AI 能调用的功能
MCP 服务器的核心是 “工具”(Tool)—— 这些工具是 AI 可以调用的功能。比如我们要实现 “查询天气”,就需要定义一个get-weather
工具,告诉 AI:“你可以用这个工具查天气,需要传城市名作为参数”。
在服务器实例代码下方添加:
// 给服务器添加一个名为"get-weather"的工具
server.tool(
'get-weather', // 工具的唯一ID(AI调用时需要指定这个ID)
'Tool to get the weather of a city', // 工具描述(告诉AI这个工具能做什么)
{ // 参数规则(用Zod定义,确保AI传对参数)
city: z.string().describe("The name of the city to get the weather for")
},
// 工具的实际功能(当AI调用时,会执行这个函数)
async ({ city }) => {
// 暂时返回一个静态结果(后续会替换为调用真实天气API)
return {
content: [
{
type: "text", // 返回内容的类型是文本
text: `The weather in ${city} is sunny` // 具体文本内容
}
]
};
}
);
这段代码的每个部分都很关键,我们拆开来解释:
- 第一个参数
'get-weather'
:工具的唯一标识,AI 必须通过这个 ID 才能调用该工具(比如 AI 会说 “调用 get-weather 工具,参数是 city: 北京”)。 - 第二个参数
'Tool to get the weather of a city'
:给 AI 看的描述,让 AI 知道这个工具的用途(如果描述不清,AI 可能不会正确使用)。 - 第三个参数
{ city: z.string().describe(...) }
:定义工具需要的参数。这里用z.string()
指定 “city 必须是字符串”,describe
则告诉 AI 这个参数的含义(“需要查询天气的城市名称”)。如果 AI 传的参数不是字符串(比如传了数字),Zod 会自动报错,避免工具出错。 - 第四个参数(函数):工具的核心逻辑。当 AI 调用
get-weather
工具时,这个函数会被执行,参数city
就是 AI 传过来的城市名。目前我们先返回一个静态结果(比如 “北京的天气是晴天”),后续会改成调用真实的天气 API 获取实时数据。
4. 配置服务器的通信方式
服务器创建好了,工具也定义了,最后需要让服务器 “能听能说”—— 也就是配置通信方式,让它能接收 AI 的请求,并返回结果。
在工具定义代码下方添加:
// 创建基于终端输入输出的通信工具
const transport = new StdioServerTransport();
// 让服务器通过这个通信工具启动
server.connect(transport);
StdioServerTransport
:这是一种简单的通信方式,通过终端的stdin
(标准输入)接收 AI 的请求,通过stdout
(标准输出)返回结果。对于本地开发和测试来说,这种方式足够用了。server.connect(transport)
:让服务器通过这个通信工具 “上线”,开始等待 AI 的调用。
完整的基础服务器代码
到这里,main.ts
的完整代码如下:
// 导入所需的工具
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"
});
// 定义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`
}
]
};
}
);
// 配置通信并启动服务器
const transport = new StdioServerTransport();
server.connect(transport);
测试基础服务器(可选)
现在我们可以运行这个服务器,看看它是否能正常工作。在终端中执行:
npm start # 这个命令会通过package.json中配置的ts-node运行main.ts
如果一切正常,终端会显示服务器启动的信息(可能是空白或简单的日志),此时服务器处于 “等待状态”,随时可以接收 AI 的调用。
(注:目前这个服务器还只能返回静态结果,下一部分我们会连接真实的天气 API,让它能返回实时数据。)
步骤 4:使用 MCP Inspector 进行测试
在添加真实天气数据之前,让我们使用 MCP Inspector(一个基于 Web 的 MCP 服务器调试工具)测试我们的服务器。
启动检查器
运行此命令以打开服务器的 MCP 检查器:
npx -y @modelcontextprotocol/inspector npx -y tsx main.ts
运行该命令后,您将看到终端输出:
- 本地主机 URL(例如
http://127.0.0.1:6274
) - 唯一的会话令牌
- 预先填充了令牌的直接链接
💡提示:单击已包含令牌的链接以避免手动输入。
连接并测试
- 连接:单击检查器中的“连接”按钮
- 导航:点击顶部导航中的“工具”
- 选择:选择您的
get-weather
工具 - 测试:输入城市名称(例如“帕尔马”),然后单击“运行工具”
应该会看到响应:"The weather in Palma de Mallorca is sunny"
故障排除:
- 连接错误?请确保使用的链接已预填充令牌
太棒了!构建的 MCP 服务器已经正常运行了。现在,让我们让它真正发挥作用。
步骤5:添加真实天气数据
是时候让我们的服务器真正发挥作用了!我们将与Open-Meteo集成,这是一个免费的天气 API,无需 API 密钥。
天气 API 的工作原理
要获取天气数据,我们需要一个两步过程:
- 转换城市名称→坐标(使用地理编码 API)
- 使用坐标获取天气(使用天气 API)
更新工具功能
用此增强版本替换您现有的工具功能:
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 }) => {
try {
// Step 1: Get coordinates for the city
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();
// Handle city not found
if (!geoData.results || geoData.results.length === 0) {
return {
content: [
{
type: "text",
text: `Sorry, I couldn't find a city named "${city}". Please check the spelling and try again.`
}
]
};
}
// Step 2: Get weather data using coordinates
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 the complete weather data as JSON
return {
content: [
{
type: "text",
text: JSON.stringify(weatherData, null, 2)
}
]
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error fetching weather data: ${error.message}`
}
]
};
}
}
);
测试真实数据
- 重新启动MCP Inspector(Ctrl+C,然后重新运行命令)
- 在 Web 界面重新连接
- 使用“东京”或“纽约”等真实城市进行测试
现在应该能看到真实的天气数据,而不是“晴天”了!🌤️
第六步:将天气服务器与 VS Code 和 GitHub Copilot 集成
到这一步,我们已经搭建好了能返回实时天气数据的 MCP 服务器。接下来,我们要让它和 VS Code(代码编辑器)、GitHub Copilot(AI 助手)“连起来”,这样在写代码时,就能直接问 Copilot 天气了。
准备工作
在开始前,请确保:
- 你的 MCP 服务器代码(
main.ts
)已经保存,并且能正常运行(之前测试过返回天气数据); - VS Code 已安装,且安装了 “GitHub Copilot” 插件(如果没装,在 VS Code 的 “扩展” 面板搜索 “GitHub Copilot” 并安装,需要登录 GitHub 账号)。
第一步:在 VS Code 中注册你的天气服务器
注册的目的是告诉 VS Code:“我有一个本地的 MCP 服务器,地址是 xxx,你可以通过它和 Copilot 通信”。具体步骤如下:
打开 VS Code,确保已经打开我们的项目文件夹(
mcp-weather-server
)。打开 VS Code 的 “命令面板”:
- Windows/Linux 用户:按
Ctrl + Shift + P
- Mac 用户:按
Cmd + Shift + P
- Windows/Linux 用户:按
在命令面板中输入
MCP: Add Server
,然后按回车(这是 VS Code 中 MCP 相关的命令,用于添加新服务器)。选择服务器类型:在弹出的选项中,选择 “使用 stdio 的本地服务器”(因为我们的服务器是通过终端输入输出通信的,和本地程序一样)。
输入启动服务器的命令:
在 “输入命令” 的提示框中,输入npx -y tsx main.ts
。- 解释:
npx
是用来运行本地安装的工具的命令;tsx
是一个能直接运行 TypeScript 代码的工具(类似之前的ts-node
);main.ts
是我们的服务器入口文件。
这个命令的作用是:让 VS Code 知道 “如何启动你的服务器”。
- 解释:
给服务器起个名字:在 “姓名” 提示框中,输入
my-weather-server
(可以自定义,方便后续识别)。选择安装类型:在弹出的选项中,选择 “本地设置”(表示这个服务器配置只在当前项目中生效,不会影响其他项目)。
第二步:确认服务器配置文件
完成注册后,VS Code 会在你的项目文件夹中自动创建一个 .vscode
文件夹,里面有一个 mcp.json
文件。这个文件记录了服务器的配置信息,内容类似:
{
"inputs": [],
"servers": {
"my-weather-server": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"tsx",
"/Users/你的用户名/项目路径/main.ts" // 这里是你main.ts的实际路径
]
}
}
}
- 这个文件的作用是:告诉 VS Code “启动服务器需要执行什么命令”“服务器的类型是什么”。不用手动修改,保持默认即可。
第三步:启动服务器并测试与 Copilot 的连接
现在我们要启动服务器,然后让 Copilot 调用它来查询天气。
打开 VS Code 的 MCP 面板:
在 VS Code 左侧的活动栏中,找到并点击 “MCP” 图标(通常是一个类似 “工具” 的图标,如果没找到,可以在 “扩展” 中搜索 “MCP” 插件并确保已启用)。启动服务器:
在 MCP 面板中,找到你刚才注册的my-weather-server
,它的状态应该是 “未运行”。点击服务器名称旁边的 “启动” 按钮(通常是一个三角形的 “播放” 图标)。- 启动后,状态会变成 “正在运行”,表示服务器已经启动成功,随时可以接收 Copilot 的请求。
切换 Copilot 到 “代理模式”:
在 VS Code 左侧的活动栏中,点击 “GitHub Copilot” 图标,打开 Copilot 侧边栏。在侧边栏中,找到并点击 “代理模式”(Proxy Mode)—— 这个模式会让 Copilot 知道 “可以调用外部工具(比如我们的天气服务器)”。向 Copilot 询问天气:
在 Copilot 的输入框中,输入问题,比如 “东京的天气怎么样?”,然后按回车。允许 Copilot 调用工具:
第一次调用时,Copilot 会弹出一个提示:“是否允许使用 my-weather-server 中的 get-weather 工具?”,点击 “继续” 或 “允许”。
第四步:查看结果
稍等片刻,Copilot 会返回类似这样的结果:
东京今日天气
温度:28°C(体感 32°C)
湿度:75%
天气状况:多云,傍晚预计有小雨
这说明:Copilot 成功调用了我们的天气服务器,获取到实时数据后,还自动整理成了易读的格式(而不是原始的 JSON 数据)。
为什么这个功能很有用?
到这里,你可能会好奇:这个集成到底解决了什么问题?
AI 能直接用你的工具:以前 Copilot 因为没有实时数据接口,无法回答天气问题;现在通过你的 MCP 服务器,它能主动调用工具获取数据,相当于给 AI 装了 “实时数据接口”。
一次开发,多处可用:只要服务器符合 MCP 协议,不仅能和 GitHub Copilot 配合,还能和其他支持 MCP 的 AI 工具(比如 Claude、ChatGPT 的插件模式)兼容,不用重复开发。
数据实时更新:服务器每次调用都会请求天气 API 的最新数据,不会有缓存过期的问题,确保信息是最新的。
易于扩展:后续你可以给服务器添加更多工具,比如 “查询未来 3 天的天气”“获取空气质量指数”,只需要在
main.ts
中新增工具定义,Copilot 会自动识别并使用这些新功能。
完整代码参考
这是最终main.ts
文件:
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',
'Tool to get the weather of a city',
{
city: z.string().describe("The name of the city to get the weather for")
},
async({ city }) => {
try {
const response = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${city}&count=10&language=en&format=json`);
const data = await response.json();
if (data.results.length === 0) {
return {
content: [
{
type: "text",
text: `No results found for city: ${city}`
}
]
};
}
const { latitude, longitude } = data.results[0];
const weatherResponse = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&hourly=temperature_2m,precipitation,apparent_temperature,relative_humidity_2m&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 fetching weather data: ${error.message}`
}
]
};
}
}
);
const transport = new StdioServerTransport();
server.connect(transport);
下一步:增强服务器
准备好将构建好的天气服务器提升到一个新的水平了吗?以下是一些建议:
🚀 额外的天气工具
延伸预测
server.tool('get-forecast', 'Get 7-day weather forecast', ...)
天气警报
server.tool('get-alerts', 'Get severe weather warnings', ...)
空气质量
server.tool('get-air-quality', 'Get air pollution data', ...)
共享搭建的属于自己的服务器
- 发布到 NPM:让其他人可以使用
结论
🎉恭喜!已成功搭建属于自己的第一个 MCP 天气服务器!
您所取得的成就:
- ✅ 从零开始创建功能齐全的 MCP 服务器
- ✅ 集成来自外部 API 的实时天气数据
- ✅ 将其连接到 VS Code 和 GitHub Copilot
- ✅ 学习了模型上下文协议的基础知识
关键要点:
- 简单: MCP 服务器的构建比看起来要容易得多
- 力量:真实数据使人工智能交互更有价值
- 灵活性:同一服务器可跨多个 AI 平台工作
- 面向未来:您正在构建下一代人工智能的基础设施
下一步是什么?可能性无穷无尽!天气只是个开始,现在你可以将 AI 连接到数据库、API、文件系统以及你能想到的任何服务。
祝各位读者搭建愉快!🚀