跳转至

2025

别让你的SSE MCP服务卡住!一行 requests.post 引发的性能危机

问题出现

在使用 Python 开发基于 MCP 的 SSE 服务时,如果不小心写了同步阻塞的代码,就非常容易踩进 IO 阻塞的大坑。来看下面这段示例代码:

from mcp.server.fastmcp import FastMCP
from pydantic import Field
import time
import requests

# 初始化mcp服务
mcp = FastMCP("hello-mcp-server")

@mcp.tool(name="url_get", description="访问某个url")
def get_url(url: str = Field(..., description="将要访问的url")):
    r = requests.get(url)
    return r.text

@mcp.tool(name="计算加法", description="计算加法")
def add(a: int = Field(..., description="第一个数"), b: int = Field(..., description="第二个数")):
    return a + b

def run():
    mcp.run(transport="sse")

if __name__ == "__main__":
    run()

uv sync 下载包版本问题

今天我们来聊一个使用 uv 工具进行python 项目管理时会遇到的包版本的问题。

当我们从远程仓库下载以个新的项目时,有了uv 工具,可以使用 uv sync 来一键同步项目开发的python 环境和第三方库,但是我们想象一个问题,如果项目在最早开发或者首次开发时,如使用 uv add mcp 安装了当时的最新版,此时,在pyproject.toml 文件记录的包版本为 "mcp>=1.6.0" 之后过了好久,这个包在pypi 中也更新了,如更新到 "1.7.0",那么当再次使用 uv sync 时,是安装 1.6.0 版本还是 1.7.0 版本呢?

Python类属性中的"共享列表"陷阱:为什么你的朋友成了别人的朋友?

今天给大家分享一个Python中非常容易踩坑的特性——类属性中默认值为可变对象(比如列表)时的诡异行为。

一个看似简单的例子

我们先看一个简单的Person类定义:

1
2
3
4
5
6
7
class Person:
    def __init__(self, name:str, frients:list=[]):
        self.name = name
        self.frients = frients

    def show_frients(self):
        print(f"{self.name}, frients: {self.frients}")

看起来很正常对吧?我们创建一个Person实例时,如果没有提供frients参数,就会默认使用空列表。

使用python开发mcp server之sse

前面文章我们使用python 实现了简单的天气查询mcp server,并使用cherry studio 和 Cline 实现了mcp server 的调用,之前是使用stdio 类型的mcp,本章看一下如何开发sse类型的mcp 服务。

与stdio 的区别

sse,Server-Sent Events 是基于http 长连接的服务,以往我们在开发大模型应用的时候,由于大模型生成token 不是一次性生成的,是一个token 一个token 生成的,为了避免调用端长时间等待,会一点点的输出给调用端。

在mcp 的开发过程中,也会用到sse,但是这里的sse 和大模型输出稍微有一点不同,sse 类型的mcp 会建立一个http 监听端口,客户端在调用mcp server 时,先和mcp 建立一个长连接,之后工具的输出都是通过这个长连接发送给客户端,由于sse是单向传输,客户端只能被动的接受服务端的数据,而不能在建立连接以后再次接收客户端的数据,所以客户端在调用mcp 工具时,需要向另外一个接口发送数据。所以开发sse 的mcp 会稍微复杂一些,但是官方python sdk 中FastMCP已经做了高级封装,开发者只需要关注工具的具体实现即可。

本地stdio 类型的mcp server,通过标准的输入输出来进行数据的交互,调用端需要提前安装好环境,如python 或者 node,当然如果mcp 是一个可执行的二进制文件也可以不用安装配置环境,只是目前大部分的mcp 使用python 或者 node 进行开发的。

使用python开发mcp server

上一篇文章介绍了UV工具的使用,有了uv 的基础,本篇我们来看一下如何使用python开发mcp server,目前主流的 mcp 分为 stdio 和 sse,stdio 为标准输入输出,通过调用工具获取工具的输出来交互,比如你在终端输入 ping host 命令,返回ping host 的输出,SSE 稍微复杂一些,通过http 接口,返回一个sse长连接,之后工具调用输入输出遵循JSONRPC规范,通过http 调用,但是结果通过SSE长连接返回,实现起来稍微复杂一些,但是调用工具和工具配置sse会更简单一些,本篇先介绍开发简单的 stdio 类型的 mcp server。工具为调用高德地图的天气查询接口返回某地的天气情况。

python在uv的基础使用

最近在进行MCP server 的开发,目前主流的 mcp server 主要以node 和python 为主,其中python 主要以uv 来启动服务的,我也是由此才开始接触uv,uv 工具可以管理本地的python 版本,虚拟环境以及打包发布,还可以运行脚本,作为mcp 开发的前序基础,本文主要记录以下使用uv 开发管理python 应用的各个环节。之后在进行mcp 开发时会一直使用uv 来管理环境。