在我的上一篇博客中,我解释了Model Context Protocol是如何工作的。今天,我们自己动手,从头开始搭建一个MCP服务器。在这次教程里,我打算用两个工具来做个简单的MCP服务器,并在Claude Desktop里试试这两个工具。不过官方教程读起来有点绕,所以我把代码调整了一下,让它更简单易懂。
1. 搭建开发环境这是本教程的文件结构示例。
以下是一个简单的Python项目的文件结构:
.
├── 📁 venv (虚拟环境)
├── 📄 helpers.py (辅助工具)
├── 📄 server.py (服务器)
└── 📄 tools.py (工具)
首先,让我们为MCP服务器创建一个虚拟环境。为了简单,我使用默认的`venv`工具。但如果你想的话,也可以使用像Poetry或uv这样的Python包管理器。
# 在 Windows 下
python -m venv venv
venv\Scripts\activate
# 在 Linux 下:
python3 -m venv venv
source venv/bin/activate
创建虚拟环境并激活它。
在激活虚拟环境之后,安装所需的依赖。
pip install mcp[cli] httpx
这是一条Python包安装命令
## 2. 创建辅助函数:
我们正在开发一个工具来获取特定位置的天气预报,以及另一个用于获取指定美国州天气警报的工具。为此,我们将会创建两个辅助函数。第一个函数将负责处理API请求,以获取天气数据。第二个函数将负责格式化从API请求中获取的数据。我使用了`httpx`模块来执行API调用,但如果你更喜欢,也可以使用`requests`模块来发起API调用。第二个函数将格式化从API调用中获取的数据。让我们创建一个`helpers.py`文件。
```python
# 工具函数
from textwrap import dedent
import httpx
from typing import Any
import logging
USER_AGENT = "weather-app/1.0"
async def make_nws_request(url: str) -> dict[str, Any] | None:
"""向NWS API发出请求,并进行适当的错误处理。"""
headers = {
"User-Agent": USER_AGENT,
"Accept": "application/geo+json"
}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
response.raise_for_status()
return response.json()
except Exception as e:
logging.error(e)
return None
def format_alert(feature: dict) -> str:
"""将告警信息格式化为可读的字符串。"""
props = feature["properties"]
return dedent(
f"""
事件: {props.get('event', '未知')}
区域: {props.get('areaDesc', '未知')}
严重程度: {props.get('severity', '未知')}
描述: {props.get('description', '无可用描述')}
说明: {props.get('instruction', '无具体说明')}
"""
)
3. 制作工具
现在我们有了帮助函数,让我们创建一个 tools.py
文件来实现 MCP 工具,把它们整合进工具中。确保每个工具函数都有详细的文档字符串,清楚地说明工具的作用。这些注释对于确定哪个工具适合特定任务非常重要。此外,函数名就是工具的名字。在这种情况下,get_alerts
和 get_forecast
将是我们的工具名称。如果你想的话,你也可以在添加工具到服务器时自定义一个名字和描述。
这些工具基本上在做的是通过一个帮助函数从天气API获取数据,然后用另一个帮助函数来格式化数据,最后返回结果。
# tools.py
from textwrap import dedent
from helpers import make_nws_request, format_alert
NWS_API_BASE = "https://api.weather.gov"
async def get_alerts(state: str) -> str:
"""获取美国某州的天气警报。
参数:
state: 两位字母的美国州代码(例如 CA, NY)
"""
url = f"{NWS_API_BASE}/alerts/active/area/{state}"
# 调用辅助函数
data = await make_nws_request(url)
if not data or "features" not in data:
return "无法获取警报或没有找到警报。"
if not data["features"]:
return "该州目前没有活跃的警报。"
# 调用辅助函数
alerts = [format_alert(feature) for feature in data["features"]]
return "\n---\n".join(alerts)
async def get_forecast(latitude: float, longitude: float) -> str:
"""获取某个位置的天气预报。
参数:
latitude: 位置的纬度
longitude: 位置的经度
"""
# 首先获取预报网格端点
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
# 调用辅助函数
points_data = await make_nws_request(points_url)
if not points_data:
return "无法获取该位置的天气预报数据。"
# 从 points 响应中获取预报 URL
forecast_url = points_data["properties"]["forecast"]
# 调用辅助函数
forecast_data = await make_nws_request(forecast_url)
if not forecast_data:
return "无法获取详细的天气预报。"
# 将周期格式化为可读的预报
periods = forecast_data["properties"]["periods"]
forecasts = []
for period in periods[:5]: # 仅显示接下来的 5 个周期
forecast = dedent(
f"""
{period['name']}:
气温: {period['temperature']}°{period['temperatureUnit']}
风向和风速: {period['windSpeed']} {period['windDirection']}
天气预报: {period['detailedForecast']}
"""
)
forecasts.append(forecast)
return "\n---\n".join(forecasts)
4. 创建服务器端
好的。我们已经完成了MCP工具的制作。现在我们来搭建MCP服务器,并把这些工具添加进去。我将为此创建一个server.py
文件。在这里,我使用stdio方法来进行通信,因为这是一个本地的服务器。
# server.py
from mcp.server.fastmcp import FastMCP
from tools import get_alerts, get_forecast
# 启动FastMCP服务器
mcp = FastMCP("weather")
# 添加工具
# mcp.add_tool(get_alerts, name="Get-Weather-Alerts", description="TOOL DESC")
mcp.add_tool(get_alerts)
# mcp.add_tool(get_forecast, name="Get-Forecast", description="TOOL DESC")
mcp.add_tool(get_forecast)
if __name__ == "__main__":
# 启动服务器
mcp.run(transport='stdio')
我们给我们的MCP服务器起名为“weather”。接下来,我们将给服务器添加一些工具功能。你可以为工具自定义名称和描述。不过,工具名称需要遵守一些规则。
- 它只能包含字母和数字。
- 允许的特殊字符仅限于下划线 (_) 和破折号 (-)。
- 它必须至少包含一个字符。
- 长度不能超过 64 个字符。
最后,我们用stdio方式运行服务器。
5. 连接到 Claude 端我们已经搭建好了MCP服务器。现在我们可以将这个服务器与Claude Desktop连接起来。为此,我们需要创建一个JSON配置文件。请在以下位置创建该文件:C:\Users\USER\AppData\Roaming\Claude\claude_desktop_config.json
。
{
"mcpServers": {
"weather": {
// 在虚拟环境中运行 Python 脚本
// 虚拟环境中Python可执行文件的绝对路径
"command": "<PATH_TO_ENVIRONMENT>\\venv\\Scripts\\python",
"args": [
// 服务器脚本的绝对路径
"<PATH_TO_SERVER>\\server.py"
]
}
}
}
上述配置仅适用于这种特定情况。如果你使用的是 poetry 或类似 uv 的工具来管理虚拟环境,这种配置就不合适了。为了简化上述配置,假设你在一个包含 server.py
文件的文件夹中。你可以使用 venv\Scripts\activate
命令来激活虚拟环境,然后使用 python server.py
命令来运行 server.py
文件。配置所做的事情和上述步骤是一样的。保存文件后,重启 Claude 桌面程序。你无需手动启动服务器。
如果你正确完成了上述所有步骤,你会在Claude Desktop输入部分右下角看到一个锤子形状的图标。点击它就能看到可用工具的详细信息。
这里你就能看到我们工具的列表。正如之前提到的,工具名称对应于函数名称,工具的描述则来自于函数内部的文档字符串。此外,通过服务器的名称,你还能知道这个工具属于哪个服务器。在这个教程里,我只使用了一个服务器,不过Claude Desktop其实支持连接多个服务器。
如果你查询某个州的天气预报,Claude Desktop 会请求运行 MCP 工具的许可。一旦获得许可,它将运行工具并提供结果。
如果你没有正确地按照上述步骤来做,你可能会看到类似这样的错误。
点击“打开MCP设置按钮”就会弹出一个新的弹出窗口。
在这里,你可以看到你在JSON配置文件中指定的命令及其参数。试着在终端里用这些参数运行该命令。如果出现错误,可能出现问题的原因有以下两种:
- JSON 配置错误
如果遇到错误信息显示“系统无法找到指定的路径”或“没有这样的文件或目录”,这通常意味着文件路径可能不对。请检查 server.py
文件或虚拟环境中 python.exe
的路径,然后重启一下 Claude Desktop 应该就可以了。
- MCP服务端代码中的错误
如果你看到错误信息以“Traceback”开头,这意味着 MCP 服务器的 Python 代码可能出错了。先检查一下 Python 文件中的错误,然后修复它们并重启 Claude Desktop。
第八. 总结一下我们首先创建了一个辅助函数,它接受一个URL作为参数并返回JSON响应。我们还创建了另一个辅助函数,用于获取JSON字典并返回格式良好的字符串。之后,我们创建了两个工具。第一个工具获取美国州的天气警报信息,此工具接受一个美国州代码作为参数,调用辅助函数以获取天气预报数据,对其进行格式化,并返回结果。第二个工具以经度和纬度作为参数,调用辅助函数以获取天气预报数据,对其进行格式化,并返回结果。接下来,我们创建了MCP服务器,并将这些工具附加到MCP服务器上。然后,我们创建了一个JSON配置来连接我们的MCP服务器和Claude Desktop。当你要求特定地点的天气预报或美国州的天气警报时,Claude将读取工具描述,从你的提示中提取需要的信息,将其转换成工具所需的格式,并传递给MCP工具,获取输出后提供可读的结果。
感谢你加入我们的社区在你离开之前:
- 确保点赞并关注作者 👏
- 关注我们:X | LinkedIn | YouTube | Newsletter | 播客节目 | Differ | Twitch
- 了解最新的科技资讯 🧪
- 在 Differ 上创建您自己的免费 AI 博客 🚀
- 加入我们的内容创作者社群 Discord 🧑💻
- 获取更多内容,访问 plainenglish.io + stackademic.com
共同學習,寫下你的評論
評論加載中...
作者其他優質文章