背景

最近AI比较火爆,那就不得不提及AI的左膀右臂,MCP。简单介绍一下MCP是什么。

MCP是什么

       不知大家在用deepseek、Kimi、gpt的时候,有没有这种感觉,你问一些问题,AI只能提供解决办法,不能直接把结果告诉你。
      比如,你问,帮我创建一个excel,在excel中写上xxx数据。它会告诉你操作流程:打开WPS,点击“新建”,…,却不能真正的创建文件,它没有执行能力。
       你问,今天北京的天气怎么样,它可能会告诉你:【打开浏览器,输入北京天气】,而它却不能搜索浏览器将结果告知你。即:它只能回答你问题,不能帮你干活,它只能给你提供方案,不能真正的帮你执行。
       因为,AI大部分都是基于知识库进行回答,AI并没有联网搜索功能,没有读写磁盘的能力等等,在这种情况下,AI只是一个工具,与计算器、字典没有什么区别。
       那怎么才能让AI为我们干活呢,答案就是MCP!mcp可以让AI长出手和脚,可以让AI真正的帮你做事,mcp可以让AI连接数据库,执行sql;可以在电脑上创建文件,读取文件,执行linux命令;可以搜索浏览器,获取结果。
       一个大家最熟悉的例子就是,千问帮我们点奶茶!千问直接对接了淘宝闪购的商品选购接口、高德的定位服务、支付的支付接口。实现了无需通过传统页面点击模拟用户操作。千问是真真正正的帮我实现了选品、下单、支付流程。使用千问下单奶茶,AI正在创造一个新时代!

MCP定义:Model Context Protocol,模型上下文协议,是由 ‌Anthropic 公司于 2024 年 11 月开源‌的一种标准化通信协议,旨在统一大语言模型(LLM)与外部工具、数据源和服务之间的交互方式,被广泛称为 ‌“AI 的 USB-C 接口”‌ ‌。
简而言之,MCP是一种标准协议,标准化了AI工具与外部工具/服务的交互方式,像一个插座一样连接了AI与外部服务。

MCP本质:说到底,mcp还是一个服务,AI工具引入mcp包,AI就是mcp的客户端,提供外部服务/工具/数据源的、引入了mcp的服务就是mcp服务端,客户端与服务端之间通过mcp协议交互,本质还是服务的调用。是mcp让AI 从工具变成了小助手

工具说明

本次要手动实现一个天气查询的mcp工具。

基础准备

1、python3.9+、mac环境
我是mac电脑,python需要是3.9版本以上的,太低的会不支持。
我的情况是:电脑上有3.8和3.10两个版本的python,而环境变量中配置的是3.8版本的,但mcp又不支持3.9以下的,我又不想修改环境变量,因为,我的其他项目在用3.8。 这时,python提供了一个方式,python支持创建虚拟环境,在虚拟环境中可以使用指定的Python版本。

命令实操

1、创建虚拟环境

cd /User/xxx  # 进入一个目录
mkdir MyMcp  # 创建一个文件夹
cd MyMcp # 进入到该文件夹
ls /usr/local/bin/python*  # 先查看本地安装的所有Python版本,如果这个命令不好使,可以在搜索下其他的命令
# 我本地是有3.10版本的Python,但不是环境变量中配置的Python,所以在创建虚拟环境时我需要手动指定Python,但我需要先查看3.10版本的路径
which python3.10 # 打印出的路径是:/Library/Frameworks/Python.framework/Versions/3.10/bin/python3.10

python3 -m venv -p /Library/Frameworks/Python.framework/Versions/3.10/bin/python3.10 venv # 使用指定版本Python创建虚拟环境venv -p代表指定Python版本
source venv/bin/activate # 激活虚拟环境  在MyMcp目录下执行即可。当前目录结构应该是MyMcp/venv/...
# 激活成功之后,命令行最前面应该会出现(venv)

deactivate # 退出虚拟环境,如果要删除的话,直接删除当前文件夹即可

2、安装核心库

虚拟环境创建好后,开始安装核心包

pip install mcp aiohttp anyio fastmcp # 这个命令就是默认安装mcp、aiohttp、anyio、fastmcp 最新版本

这些库中,mcp是核心库,aiohttp用于处理HTTP请求,anyio用于管理异步并发。

安装好之后,可以查看所有安装的包的版本

pip list  # 查看所有
pip show mcp # 查看mcp包的详细信息

mcp版本是:1.26.0
fastmcp版本是:3.0.2
aiohttp版本是:3.13.3
anyio版本是:4.12.1
brew版本是:3.6.2

3、创建mcp服务器

1、创建脚本
touch server.py # 创建一个名为server.py的脚本
2、写代码(stadio方式交互)
import asyncio
import sys
import aiohttp
from mcp.server.fastmcp import FastMCP
from mcp.server.stdio import stdio_server

# 创建一个FastMCP服务,参数是服务名,可自定义
mcp = FastMCP("weather-server")

# 建议从环境变量读取 API Key
API_KEY = "" # 从官网上免费获取一个自己的key

# 定义为mcp的tool
@mcp.tool()
async def get_weather(city: str) -> str:
    """根据城市名称查询当前天气情况"""
    url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={API_KEY}&units=metric"
    timeout = aiohttp.ClientTimeout(total=10)
    
    try:
        async with aiohttp.ClientSession(timeout=timeout) as session:
            async with session.get(url) as response:
                response.raise_for_status()
                data = await response.json()
                temperature = data['main']['temp']
                description = data['weather'][0]['description']
                return f"{city}的当前天气:温度{temperature}℃,{description}"
    except Exception as e:
        return f"获取天气信息失败: {str(e)}"

if __name__ == "__main__":
   mcp.run() # 这种方式默认是以stadio方式交互的
3、写代码(http方式交互)
import asyncio
import contextlib
import aiohttp
from mcp.server.fastmcp import FastMCP
from mcp.server.stdio import stdio_server
from starlette.applications import Starlette
from starlette.routing import Mount
from starlette.middleware.cors import CORSMiddleware

# 创建Server实例,名字叫"weather-server"
mcp = FastMCP("weater-server", stateless_http=True,json_response=True)

print(type(mcp)) # 打印mcp类型
# 你的OpenWeatherMap API Key,建议从环境变量读取
API_KEY = ""

@mcp.tool()
async def get_weather(city: str) -> str:
    """根据城市名称查询当前天气情况
    
    Args:
        city: 城市名称,例如"Beijing""上海"
    
    Returns:
        返回该城市的当前天气信息,包括温度和天气状况。
    """
    # 构建请求URL
    url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={API_KEY}&units=metric"
    timeout = aiohttp.ClientTimeout(total=10)  # 设置10秒超时
    # 错误处理与超时控制
    try:
        async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.get(url) as response:
                    # 检查HTTP状态码是否成功
                    response.raise_for_status()
                    data = await response.json()
                    
                    # 解析返回的JSON数据
                    temperature = data['main']['temp']
                    description = data['weather'][0]['description']
                    result_text = f"{city}的当前天气:温度{temperature}℃,{description}"
                    
                    return result_text
                    
    except asyncio.TimeoutError:
        return "天气请求超时,请稍后重试"
    except aiohttp.ClientResponseError as e:
        return f"HTTP错误: {e.status} - {e.message}"
    except Exception as e:
        return f"获取天气信息时发生错误: {str(e)}"

# Create a combined lifespan to manage both session managers
@contextlib.asynccontextmanager
async def lifespan(app: Starlette):
    async with contextlib.AsyncExitStack() as stack:
        await stack.enter_async_context(mcp.session_manager.run())
        yield

# Create your Starlette app first
starlette_app = Starlette(routes=[Mount("/", mcp.streamable_http_app())],lifespan=lifespan,)

# Then wrap it with CORS middleware
starlette_app = CORSMiddleware(
    starlette_app,
    allow_origins=["*"],  # Configure appropriately for production
    allow_methods=["GET", "POST", "DELETE"],  # MCP streamable HTTP methods
    expose_headers=["Mcp-Session-Id"],
)

if __name__ == "__main__":
    mcp.run(transport="streamable-http")

4、说明
  • 工具声明:@mcp.tool()装饰器将函数注册为MCP工具。函数的参数和文档字符串会自动成为工具Schema的一部分,帮助AI模型理解如何调用它。
  • mcp.run() 这种方式默认是以stadio方式交互的,与Claude等客户端通信的标准方式。claude也可以设置使用http方式交互
  • mcp.run(transport=“streamable-http”) 这种方式使用http访问,可以使用postman访问。

4、启动服务(服务端)

  • 执行python命令,启动服务
python server.py
  • 以stadio方式交互,执行启动命令后,控制台应该是没有任何输出的,能看到光标在闪
  • 以http方式交互,控制台输出如下:
    在这里插入图片描述

5、配置mcp工具(客户端配置)

1、claude配置

我本地安装了claude客户端(命令行方式,非app),找到.claude.json文件,我的是在~目录下,编辑.claude.json文件,配置mcp

"mcpServers": {
    "weather-server": { # server.py脚本中的名字
      "command": "/Users/xxxx/MyMCP/venv/bin/python3.10", # 这个是虚拟环境中使用的python路径
      "args": [
        "/Users/xxxx/MyMCP/server.py" # 自定义的python脚本
      ]
    }
  }

在这里插入图片描述
在虚拟环境中使用which python3.10 (如果是其他版本,把命令中的3.10替换为自己实际使用的版本)命令查看虚拟环境中使用的python路径,填写到.claude.json配置文件的。

这里有一个小坑:我刚开始把mcp配置写在了projects的项目目录下,当我在非项目目录下启动claude时,会发现claude找不到我配置的mcp工具,这是因为mcp的配置有针对全局的,也有针对项目,我如果配置在项目目录下,那就只在该目录下使用;所以,最好是配置在全局,这样无论在哪儿启动claude,都可以使用mcp

6、使用mcp

1、在claude中使用
  • stadio方式与claude交互时,不需要手动启动mcp服务端,claude会自动启动mcp服务。配置完claude配置文件后,启动claude,如果启动claude之后,右下角没有提示“1
    mcp failed”,那就成功了一半(如果有,检查配置文件)。

  • 启动claude成功之后,输入/mcp,可以看到刚才自己写的mcp
    在这里插入图片描述

  • 向claude提问:查询北京今天的天气(claude会自动推断是否要使用mcp工具),也可以明确告诉AI,使用xxx工具

在这里插入图片描述

2、在postman中使用
  • 在postman中使用mcp时,需要手动将mcp服务启动,mcp启动成功后会有如下输出:

在这里插入图片描述
ip:127.0.0.1
port:8000
访问路径:http://127.0.0.1:8000/mcp(默认会带着mcp路径)

  • postman请求配置:
    1、请求头中添加:Accept = application/json
    2、body中配置
{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
        "name": "get_weather", // server.py中定义的方法名
        "arguments": {
            "city": "Beijing"  // 参数 要查询的城市
        }
    }
}

在这里插入图片描述

  • 获取响应结果
    在这里插入图片描述

总结

我在自己写脚本的过程中遇到很多坑,我本身是学java的,python接触不多,遇到了很多问题,但是今天写的时候,有些bug已经想不起来了。遇到的最难解决的两个问题就是:
1、跟着其他博主博客写代码,博主博客不写清楚包的版本号;
2、我本地可能是工具版本的问题,在下载工具包时,总是会报包不存在的问题,根本原因是我本地的brew有问题、pip命令也有问题(使用了/Users/xxx/MyMCP/venv/bin/python -m pip install --upgrade pip)命令升级pip就好了

有问题欢迎留言讨论~

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐