当前位置: 首页 > news >正文

一文读懂如何使用MCP创建服务器

如果你对MCP(模型上下文协议)一窍不通,在阅读本篇文章之前(在获得对MCP深度认识之前),你可以理解为学习MCP就是在学习一个python工具库mcp,类似于其它python工具库一样,如numpy、sys、opencv等,你需要先安装mcp,学习mcp的两个核心功能,一个是使用mcp来创建mcp 服务器,另一个是使用mcp来创建mcp 客户端。请注意,请注意,请注意,在开源社区中,已经有很多mcp服务器和mcp客户端可用了,可以按需选择;当然,如果你最后发现没有你所需要的mcp服务器或者mcp客户端,你再进行自己创建

在这里插入图片描述

在这里插入图片描述

所以参考资料来源于MCP官方介绍文档

文章目录

  • 一、为什么需要MCP?
  • 二、什么是MCP?
  • 三、开发者如何开发MCP服务器?
    • 现成的MCP servers
    • 开发自己的MCP servers
      • 我们将要构建的内容
      • 构建你的服务器
        • 配置环境
        • 导入包并设置实例
        • 辅助函数
        • 实施工具执行
        • 运行服务器
    • 使用 Claude 桌面软件客户端 测试服务器
      • 添加服务
      • 判断服务是否添加成功

一、为什么需要MCP?

设想一个场景,你现在有很多工具,需要调用这些工具,并且将工具响应结果拼接到提示词中,将提示词输入给大模型,大模型返回结果。很明显,普通的python API完全可以实现这个流程。但是,几乎每个工具,你都需要写一个特定调用大模型的上述流程(因为每个工具的返回结果不同)。这就很低效。

现在有一个文件系统服务,该服务提供以下工具:移动文件、复制文件、删除文件、新建文件、文件重命名。mcp的出现可以统一不同工具和大模型的交互方式。(如何统一交互方式请耐心往下阅读)

现在还出现了另一个服务叫浏览器服务,该服务提供以下工具:打开网页、下载文件。mcp的出现可以统一不同服务不同工具和大模型的交互方式。

现在还有一个服务叫PostgreSQL 服务,该服务提供以下工具:查询数据、删除数据、新增数据、更改数据。mvp的出现可以统一不同服务不同数据源和大模型的交互方式

说得概括性一些:

数据与工具本身是客观存在的,只不过我们希望将数据连接到模型的这个环节可以更智能更统一。Anthropic公司 基于这样的痛点设计了 MCP,充当 AI 模型的"万能转接头",让 LLM 能轻松的获取数据或者调用工具。

二、什么是MCP?

MCP的定义很简单:

MCP 是一个开放协议,它标准化了应用程序如何向 LLM 提供上下文。

如何理解这个概念呢?官方给出了USB-C的例子,下面以电脑连接硬盘为例子进行类比。

电脑可以通过电脑上面的USB-C接口、USB-C线去实现连接硬盘、读取数据的功能。这里的电脑就是MCP中的mcp 客户端的概念,硬盘就是mcp 服务器的概念。有些硬盘只能支持USB-B接口,那么你就需要一个接口转换器,将USB-B转换成USB-C接口才能让硬盘和电脑进行连接。最后的结果就是,如果你想要通过USB-C接口来实现硬盘、电脑的连接,那么硬盘和电脑都必须有USB-C接口。USB-C接口统一了USB-A、USB-B、HDML等所有电脑接口。

说得概括性一些:

把 MCP 想象成人工智能应用的 USB-C 端口。就像 USB-C 提供了将设备连接到各种外设和配件的标准化方式一样,MCP 也提供了将人工智能模型连接到不同数据源和工具的标准化方式。

MCP 可帮助您在 LLM 的基础上构建Agent和复杂的工作流程。LLM 经常需要与数据和工具集成,而 MCP 可提供以下功能:

  • 生态健全:预先建立的mcp服务器可以不断新增,大模型可以通过MCP简单、方便进行调用
  • 大模型统一性:就算mcp 服务器不断新增和扩展,大模型提供商和类型可以随意切换, LLM 提供商和供应商之间切换的灵活性非常好
  • 数据安全:mcp服务器的敏感数据保留在本地,是保护基础大模型应用架构内数据安全的最佳实践

三、开发者如何开发MCP服务器?

现成的MCP servers

并且官方也提供了非常多现成的 MCP Servers,你只需要选择你希望接入的工具,然后接入即可。现成可用的MCP servers如下:

1. awesome-mcp-servers

在这里插入图片描述

2. MCP Servers

在这里插入图片描述
3.MCP官方提供的servers

在这里插入图片描述

开发自己的MCP servers

开始构建您自己的服务器,以便在 Claude 桌面软件 和 其他客户端中使用。

在这里插入图片描述

在本教程中,我们将构建一个简单的 MCP 天气服务器,并将其连接到一个主机,主机就是Claude桌面软件。我们将从基本设置开始,然后逐步处理更复杂的应用场景。

我们将要构建的内容

许多 LLMs 目前没有获取天气预报和严重天气警报的能力。让我们使用 MCP 来解决这个问题!

我们将构建一个服务器,它暴露两个工具:get-alerts 和 get-forecast。然后我们将服务器连接到一个 MCP 主机(在这种示例中,MCP主机是Claude 桌面软件)

请注意!!!

服务器可以连接到任何客户端。我们在这里选择了 Claude桌面软件 以简化操作。如何构建MCP 客户端,请参考下节内容

在这里插入图片描述
最终的效果图如下,跟claude大模型咨询天气情况,大模型可以调用自定义的天气服务器的工具进行回答。
在这里插入图片描述

在这里插入图片描述
MCP 服务器可以提供三种主要功能:

  1. 资源 :可以被客户端读取的类似文件的数据(如 API 响应或文件内容)
  2. 工具 :可以被 LLM 调用的功能(需用户批准)
  3. 提示 : 预写好的模板,帮助用户完成特定任务

这篇教程主要将专注于工具。

构建你的服务器

需要提前安装好uv、python3.10、Python MCP SDK 1.2.0。这个服务器默认在Linux服务器上面搭建

让我们开始构建我们的天气服务器!完整代码如下,跟官网不一样,下面的代码我是在官方代码的基础上添加了中文注释

#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
@author: Junius 
@Email: see619055@gmail.com
@time: 2025/5/12 17:54 
@file: weather
@project: OpenAppAI
@describe: TODO
"""
from typing import Any  # 导入 Any 类型,用于灵活的类型注解
import httpx  # 导入 httpx 库,用于发起异步 HTTP 请求
from mcp.server.fastmcp import FastMCP  # 导入 FastMCP 框架,用于构建 MCP 服务器# 初始化一个名为 "weather" 的 FastMCP 服务器实例
mcp = FastMCP("weather")# 定义 NWS(美国国家气象局)API 的基础 URL
NWS_API_BASE = "https://api.weather.gov"
# 设置 User-Agent 请求头,标识客户端身份
USER_AGENT = "weather-app/1.0"async def make_nws_request(url: str) -> dict[str, Any] | None:"""向 NWS API 发起请求,并进行错误处理"""# 设置请求头,包含 User-Agent 和 Accept 内容类型headers = {"User-Agent": USER_AGENT,"Accept": "application/geo+json"}# 使用 httpx 异步客户端发起请求async with httpx.AsyncClient() as client:try:# 向指定 URL 发起 GET 请求,设置超时时间为 30 秒response = await client.get(url, headers=headers, timeout=30.0)# 如果响应状态码表示错误(如 4xx、5xx),抛出异常response.raise_for_status()# 返回解析后的 JSON 数据return response.json()except Exception:# 如果发生任何异常,返回 None 表示请求失败return Nonedef format_alert(feature: dict) -> str:"""将警报信息格式化为可读性强的字符串"""# 提取 feature 字典中的 'properties' 部分props = feature["properties"]# 将警报信息以结构化文本形式返回,各字段使用 get 方法避免 KeyErrorreturn f"""
Event: {props.get('event', 'Unknown')}                # 警报事件名称,若无则显示 Unknown
Area: {props.get('areaDesc', 'Unknown')}              # 警报影响区域描述,若无则显示 Unknown
Severity: {props.get('severity', 'Unknown')}          # 警报严重程度,若无则显示 Unknown
Description: {props.get('description', 'No description available')}  # 警报描述,若无则提示无描述
Instructions: {props.get('instruction', 'No specific instructions provided')}  # 警报应对建议,若无则提示无指令
"""# 使用 @mcp.tool() 装饰器注册 get_alerts 为 MCP 工具,用于获取天气警报
@mcp.tool()
async def get_alerts(state: str) -> str:"""获取某个美国州的天气警报。参数:state: 两位字母的美国州代码(例如 CA, NY)"""# 构造请求 URL,用于根据州代码获取警报信息url = f"{NWS_API_BASE}/alerts/active/area/{state}"# 调用 make_nws_request 异步发起 HTTP 请求获取数据data = await make_nws_request(url)# 如果返回的数据为空或不包含 features 字段,表示无法获取警报信息if not data or "features" not in data:return "Unable to fetch alerts or no alerts found."# 如果 features 是空列表,表示当前该州没有活动警报if not data["features"]:return "No active alerts for this state."# 遍历所有 feature 并使用 format_alert 格式化警报信息alerts = [format_alert(feature) for feature in data["features"]]# 将多个警报信息用 "---" 分隔后拼接成字符串返回return "\n---\n".join(alerts)# 使用 @mcp.tool() 装饰器注册 get_forecast 为 MCP 工具,用于获取天气预报
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:"""获取某个位置的天气预报。参数:latitude: 地理纬度longitude: 地理经度"""# 第一步:构造 URL 获取点位信息(包含预报网格链接)points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"# 发起异步请求获取点位数据points_data = await make_nws_request(points_url)# 如果点位数据为空,返回错误提示if not points_data:return "Unable to fetch forecast data for this location."# 从点位数据中提取详细的天气预报 URLforecast_url = points_data["properties"]["forecast"]# 发起异步请求获取具体的天气预报数据forecast_data = await make_nws_request(forecast_url)# 如果详细预报数据为空,返回错误提示if not forecast_data:return "Unable to fetch detailed forecast."# 提取各时间段的预报信息periods = forecast_data["properties"]["periods"]forecasts = []# 遍历前5个时间段,格式化输出天气信息for period in periods[:5]:  # 只显示最近5个时间段forecast = f"""
{period['name']}:                    # 时间段名称(如 Tonight, Thursday)
Temperature: {period['temperature']}°{period['temperatureUnit']}   # 温度及单位
Wind: {period['windSpeed']} {period['windDirection']}             # 风速和风向
Forecast: {period['detailedForecast']}                            # 详细预报描述
"""forecasts.append(forecast)  # 将每个时间段的预报添加到列表# 将多个时间段的预报信息用 "---" 分隔后拼接成字符串返回return "\n---\n".join(forecasts)# 如果该文件作为主程序运行,则执行以下代码
if __name__ == "__main__":# 初始化并运行 FastMCP 服务器,使用标准输入输出(stdio)作为通信协议mcp.run(transport='stdio')
配置环境

现在,让我们创建并设置我们的项目:

# 使用 uv 工具初始化一个名为 weather 的新项目目录。这会创建一个包含基础 pyproject.toml 文件的新文件夹,用于管理 Python 项目。
uv init weather
cd weather# 使用 uv 创建一个隔离的 Python 虚拟环境(virtual environment),以便该项目有独立的依赖包,不会与其他项目冲突。
uv venv
# 激活虚拟环境
source .venv/bin/activate# "mcp[cli]":表示安装 mcp 包,并额外安装其 CLI(命令行接口)相关依赖
# httpx:一个支持异步请求的 HTTP 客户端库,用于发起网络请求。
uv add "mcp[cli]" httpx# 创建服务器代码文件
touch weather.py
导入包并设置实例

将以下内容添加到 weather.py 的顶部: python weather.py:

from typing import Any  # 导入 Any 类型,用于灵活的类型注解
import httpx  # 导入 httpx 库,用于发起异步 HTTP 请求
from mcp.server.fastmcp import FastMCP  # 导入 FastMCP 框架,用于构建 MCP 服务器# 初始化一个名为 "weather" 的 FastMCP 服务器实例
mcp = FastMCP("weather")# 定义 NWS(美国国家气象局)API 的基础 URL
NWS_API_BASE = "https://api.weather.gov"
# 设置 User-Agent 请求头,标识客户端身份
USER_AGENT = "weather-app/1.0"

FastMCP 类使用 Python 类型提示和文档字符串自动生成工具定义,使其容易创建和维护 MCP 工具。

辅助函数

接下来,让我们添加用于查询和格式化来自国家气象服务 API 的数据的辅助函数:

async def make_nws_request(url: str) -> dict[str, Any] | None:"""向 NWS API 发起请求,并进行错误处理"""# 设置请求头,包含 User-Agent 和 Accept 内容类型headers = {"User-Agent": USER_AGENT,"Accept": "application/geo+json"}# 使用 httpx 异步客户端发起请求async with httpx.AsyncClient() as client:try:# 向指定 URL 发起 GET 请求,设置超时时间为 30 秒response = await client.get(url, headers=headers, timeout=30.0)# 如果响应状态码表示错误(如 4xx、5xx),抛出异常response.raise_for_status()# 返回解析后的 JSON 数据return response.json()except Exception:# 如果发生任何异常,返回 None 表示请求失败return Nonedef format_alert(feature: dict) -> str:"""将警报信息格式化为可读性强的字符串"""# 提取 feature 字典中的 'properties' 部分props = feature["properties"]# 将警报信息以结构化文本形式返回,各字段使用 get 方法避免 KeyErrorreturn f"""
Event: {props.get('event', 'Unknown')}                # 警报事件名称,若无则显示 Unknown
Area: {props.get('areaDesc', 'Unknown')}              # 警报影响区域描述,若无则显示 Unknown
Severity: {props.get('severity', 'Unknown')}          # 警报严重程度,若无则显示 Unknown
Description: {props.get('description', 'No description available')}  # 警报描述,若无则提示无描述
Instructions: {props.get('instruction', 'No specific instructions provided')}  # 警报应对建议,若无则提示无指令
"""
实施工具执行

添加工具执行处理器,工具执行处理器负责实际执行每个工具的逻辑。使用@mcp.tool()进行装饰的异步函数就是工具执行处理器。

@mcp.tool()
async def get_alerts(state: str) -> str:"""获取某个美国州的天气警报。参数:state: 两位字母的美国州代码(例如 CA, NY)"""# 构造请求 URL,用于根据州代码获取警报信息url = f"{NWS_API_BASE}/alerts/active/area/{state}"# 调用 make_nws_request 异步发起 HTTP 请求获取数据data = await make_nws_request(url)# 如果返回的数据为空或不包含 features 字段,表示无法获取警报信息if not data or "features" not in data:return "Unable to fetch alerts or no alerts found."# 如果 features 是空列表,表示当前该州没有活动警报if not data["features"]:return "No active alerts for this state."# 遍历所有 feature 并使用 format_alert 格式化警报信息alerts = [format_alert(feature) for feature in data["features"]]# 将多个警报信息用 "---" 分隔后拼接成字符串返回return "\n---\n".join(alerts)# 使用 @mcp.tool() 装饰器注册 get_forecast 为 MCP 工具,用于获取天气预报
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:"""获取某个位置的天气预报。参数:latitude: 地理纬度longitude: 地理经度"""# 第一步:构造 URL 获取点位信息(包含预报网格链接)points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"# 发起异步请求获取点位数据points_data = await make_nws_request(points_url)# 如果点位数据为空,返回错误提示if not points_data:return "Unable to fetch forecast data for this location."# 从点位数据中提取详细的天气预报 URLforecast_url = points_data["properties"]["forecast"]# 发起异步请求获取具体的天气预报数据forecast_data = await make_nws_request(forecast_url)# 如果详细预报数据为空,返回错误提示if not forecast_data:return "Unable to fetch detailed forecast."# 提取各时间段的预报信息periods = forecast_data["properties"]["periods"]forecasts = []# 遍历前5个时间段,格式化输出天气信息for period in periods[:5]:  # 只显示最近5个时间段forecast = f"""
{period['name']}:                    # 时间段名称(如 Tonight, Thursday)
Temperature: {period['temperature']}°{period['temperatureUnit']}   # 温度及单位
Wind: {period['windSpeed']} {period['windDirection']}             # 风速和风向
Forecast: {period['detailedForecast']}                            # 详细预报描述
"""forecasts.append(forecast)  # 将每个时间段的预报添加到列表# 将多个时间段的预报信息用 "---" 分隔后拼接成字符串返回return "\n---\n".join(forecasts)
运行服务器

最后,让我们初始化并运行服务器:

# 如果该文件作为主程序运行,则执行以下代码
if __name__ == "__main__":# 初始化并运行 FastMCP 服务器,使用标准输入输出(stdio)作为通信协议mcp.run(transport='stdio')

你的服务器已经完成!运行 uv run weather.py 确认一切正常。

现在从现有的 MCP 主机 Claude for Desktop 测试你的服务器。

使用 Claude 桌面软件客户端 测试服务器

Claude for Desktop 目前尚未在 Linux 上提供。Linux 用户可以继续阅读 构建客户端 教程,以构建一个连接到我们刚刚构建的服务器的 MCP 客户端。

你需要安装好 Claude 桌面软件,请从官网下载并安装最新版。

添加服务

我们需要为想要使用的任意 MCP 服务器配置 Claude for Desktop。为此,请在文本编辑器中打开您的 Claude for Desktop App 配置文件 ~/Library/Application Support/Claude/claude_desktop_config.json(软件安装在苹果系统中的路径) 。如果文件不存在,请确保创建该文件。

~/AppData\Claude\claude_desktop_config.json(window系统的配置文件路径)

然后您将在 mcpServers 键中添加您的服务器。只有在至少配置了一个服务器的情况下,MCP UI 元素才会在 Claude for Desktop 中显示。

在这种情况下,我们将像这样添加我们的单个天气服务器:

苹果系统下的配置

{"mcpServers": {"weather": {"command": "uv","args": ["--directory","/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather","run","weather.py"]}}
}

window系统下的配置

{"mcpServers": {"weather": {"command": "uv","args": ["--directory","C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\weather","run","weather.py"]}}
}

您可能需要在 command 字段中输入 uv 可执行文件的完整路径。您可以通过在 MacOS/Linux 上运行 which uv 或在 Windows 上运行 where uv 来获取它。确保你传递的是服务器的绝对路径。

这告诉 Claude桌面软件:

  • 有一个名为“weather”的 MCP 服务器
  • 通过运行 uv --directory /ABSOLUTE/PATH/TO/PARENT/FOLDER/weather run weather.py 来启动它。

保存文件,并重启 Claude 桌面软件。

判断服务是否添加成功

让我们确保 Desktop 版本的 Claude 能够识别我们在 weather 服务器中暴露的两个工具。你可以通过查找锤子 图标来确认这一点。

在这里插入图片描述

点击锤子图标后,你应该看到列出的两种工具:

在这里插入图片描述

如果锤子图标已出现,您现在可以通过在 Claude for Desktop 中运行以下命令来测试您的服务器:

  • What’s the weather in Sacramento?
  • What are the active weather alerts in Texas?

在这里插入图片描述

在这里插入图片描述

下一期讲解:如何构建MCP客户端,欢迎关注~

相关文章:

  • LWIP传输层协议笔记
  • C++ asio网络编程(5)简单异步echo服务器
  • 【】东方财务的Choice数据量化接口,在linux上安装python 版本,需要联系客户经理审核通过后就可以使用了。使用接口更加稳定和全面。
  • 智能指针入门:深入理解 C++ 的 shared_ptr
  • 【Mysql基础】一、基础入门和常见SQL语句
  • Matlab自学笔记五十四:符号数学工具箱和符号运算、符号求解、绘图
  • LLaMA Factory 深度调参
  • 右值和移动
  • 国产化Excel处理控件Spire.XLS系列教程:如何通过 C# 删除 Excel 工作表中的筛选器
  • 开疆智能Profinet转Canopen网关连接sick RFID读写器配置案例
  • 212. 单词搜索 II【 力扣(LeetCode) 】
  • RDB和AOF的区别
  • Kubernetes vs. OpenShift:深入比较与架构解析
  • Java学习手册:客户端负载均衡
  • Matlab 模糊pid的液压舵机伺服系统
  • 基于微信小程序的城市特色旅游推荐应用的设计与实现
  • Milvus 2.4 使用详解:从零构建向量数据库并实现搜索功能(Python 实战)
  • 记一次redis未授权被种挖矿
  • Java中进阶并发编程
  • langchain4j中使用milvus向量数据库做RAG增加索引
  • “应急侠”上线,应急管理部正式发布应急科普IP形象
  • 十大券商看后市|A股中枢有望逐步震荡抬升,把握结构性行情
  • 中国工程院院士、国医大师石学敏逝世
  • 一生要出片的年轻人,买爆相机
  • 公安部部署“昆仑2025”专项工作,严打环食药等领域突出犯罪
  • 上海优化营商环境再攻坚,企业和机构有哪些切实感受?