最近刚上手MCP,想用Cursor搭个本地服务器试水,结果折腾了两天。我参照官方文档装好Python SDK,写好了一个简单的文件搜索工具,启动后Cursor倒是能发现这个server,但每次调用工具跑几秒钟就提示连接中断,报错“transport closed”。我试过换端口、关防火墙,甚至还重启了电脑,问题依旧。是不是MCP的传输协议对本地socket有什么特殊要求?还是我代码里异步处理写错了?感觉网上资料太零散了,求大佬指点一个稳定的入门配置。
MCP服务器连Cursor老是断联,是我姿势不对吗?
全部回复
共 148 条八成是stdio的通信超时设置问题,试试在server里加个心跳保活或者调大超时时间。
这问题我上周刚踩过,八成不是传输协议的事,是MCP那个stdio transport跟你本地异步循环冲突了。你试试把server跑在单独进程,别跟Cursor共享事件循环,或者干脆换streamable-http模式看看。另外检查下Python SDK版本,3.x的transport实现改动挺大的,老版本日志里会有警告但不断连。我之前就是升级到最新mcp库后稳定了。
我之前也踩过这个坑,后来发现多半是Python SDK版本和Cursor内置的MCP客户端不兼容,换个0.9.x的稳定版就好了。另外你那个异步处理,工具函数里千万别用阻塞调用,否则容易把心跳包卡死。实在不行试试用stdio方式跑,别用HTTP,本地环境这个稳得多。还有个冷门点,就是环境变量里PATH没带上Python路径的话,也容易出现transport closed。
遇到transport closed大概率不是姿势问题,我前几天也踩过这个坑。你试试把stdio传输改成SSE模式,就是启动命令里加个--transport sse参数,再在Cursor里填对应的http地址,稳定性会好很多。另外检查一下你的异步工具函数是不是用了async def但没有正确await,MCP对事件循环很敏感,我之前就是漏了个await导致连接被掐断。端口防火墙那些反而影响不大,先排除代码层面的问题再说。
大概率是stdio传输模式下子进程生命周期没管理好,试试用supervisor保活或者换streamable-http模式。
我也遇到过一模一样的问题,当时差点把电脑砸了。后来发现大概率不是传输协议的问题,而是MCP的stdio模式在Cursor里生命周期管理比较脆弱,工具执行时间一长,或者中间有任何异步日志输出,就会触发超时断开。你可以试试把server的日志完全重定向到文件,别往stderr写任何东西,然后给工具调用加个超时重试逻辑,看看是不是就稳定了。另外,如果用的是本地socket,建议检查一下Cursor那边的进程回收机制,有时候它检测到server空闲几秒就会主动断开,不是你的代码错了。我之前换成sse模式,用uvicorn单独起一个服务,反而稳定很多,虽然配置繁琐点,但调试起来能直接看请求日志。还有个小坑,Python SDK版本和Cursor内置的MCP客户端版本可能不兼容,你试试把mcp库降到0.9.x或者升到最新,有时候就是版本匹配问题。最后实在不行,可以看看是不是系统代理或VPN在干扰本地回环连接,我关了某个网络代理软件后问题就消失了。
我也遇到过一模一样的“transport closed”,后来发现多半不是协议问题,而是MCP的stdio连接在Cursor里有个超时设置,默认时间很短。你可以试试在启动server时加个环境变量或者参数把超时调大,另外确认下工具函数里有没有长时间阻塞的同步操作,异步循环里记得加await。我当初是改成用sse模式才稳定下来的,虽然配置麻烦点,但比本地socket省心。
我也踩过这个坑,后来发现多半不是协议问题,而是MCP server那边超时设置太短,或者异步任务没保持事件循环活跃。你可以试试在工具函数里加个简单的日志输出,看断连前有没有异常堆栈。另外,如果用的是stdio传输,确认下Cursor启动子进程的环境变量有没有配全,Python路径不对也容易这样。我最后是换成了sse模式才稳定下来,你可以参考下。
我前两天也踩过这个坑,后来发现多半不是协议问题,是MCP的stdio模式在Cursor里对进程生命周期管理很敏感。你试试把server启动命令改成python -m mcp那种带入口点的写法,或者干脆用npx跑一个现成server验证下是不是代码问题。另外异步任务记得加超时和异常捕获,transport closed十有八九是子进程崩了,你可以在启动命令后面加个2>&1看看日志输出。
我之前也被这玩意折磨过,后来发现八成是异步循环里没处理好心跳或者超时,MCP对空闲连接挺敏感的。你可以试试在工具调用前后打点日志,看看是不是每次都在数据返回前就崩了,另外确认下SDK版本和Cursor内置的MCP客户端版本对不对得上,差太多也会这样。还有个土办法,把本地server改成用stdio模式而不是socket,稳定很多,我后来就是靠这个绕过去的。
我之前也卡在这过,后来发现多半是异步任务没保住事件循环,SDK默认走的stdio如果心跳超时就会断。你可以试试在工具函数里加个try-finally确保session不提前回收,或者干脆用streamable HTTP模式替代stdio,稳定性会好很多。另外别光看官方文档,去GitHub翻下mcp-python-sdk的issues,里面有不少人贴过类似报错,直接抄作业比瞎试快。
八成是stdio transport的buffer问题,试试把server端日志级别调低看下具体报错,或者换个sse模式稳一点。
我之前也踩过这个坑,后来发现多半是async方法里忘了用anyio的线程池或者把同步阻塞操作直接丢进了事件循环,导致心跳超时被掐断。你试试把工具函数改成async def,内部用await asyncio.to_thread包一下文件搜索逻辑,再加大--timeout参数,基本能稳住。另外别用默认的stdio传输,换SSE模式对本地调试更友好,至少断线时能看到具体日志,不至于一脸懵。
我之前也踩过这个坑,折腾了快一个礼拜才明白过来。你那个报错基本可以锁定在stdio传输的握手阶段,MCP对本地socket的要求其实没那么玄乎,但有个细节特别容易忽略:Cursor默认会用自己内置的Python环境去启动server,跟你终端里激活的虚拟环境完全是两码事。你可以先试试在MCP配置里把python路径写成绝对路径,比如/usr/bin/python3或者你conda环境的完整路径,别用裸的python命令。另外你那个文件搜索工具如果用了异步循环,记得检查一下是否在request到来时重新初始化了事件循环,很多现成例子里都有这个隐患,进程跑几秒就崩多半是event loop被回收了。还有个笨办法但特别有效,先别用Cursor,直接用MCP官方的调试客户端连你的server跑一遍,如果那边稳定,那就是Cursor侧的连接策略问题,可以试试把超时时间调长到30秒以上。最后建议你把日志级别调到DEBUG,MCP的Python SDK会打印详细的帧交换记录,看到底是哪一端先断开的,这个信息比瞎猜端口有用多了。
我之前也踩过这个坑,多半不是协议问题,而是Cursor那边的MCP客户端对超时特别敏感。你试试把工具里耗时的操作改成流式返回,或者干脆先返回一个“处理中”的状态,再异步把结果推过去。另外检查下Python SDK版本,我记得0.9.x之后传输层有改动,老代码容易断。如果还不行,可以看看服务端日志有没有报EOFError,那是典型的socket被提前关闭。
这问题我上个月也踩过,后来发现八成是stdio的通信超时设置太短,尤其文件搜索这种耗时操作,Cursor默认等不起就主动掐了连接。你可以试试在server启动参数里把超时时间调大,或者改用streamable HTTP模式,比本地socket稳很多。另外检查下异步循环是不是没用asyncio.run统一入口,混用线程池有时候也会莫名触发transport closed。
我也遇到过一模一样的“transport closed”,后来发现不是socket的问题,是Python SDK版本和Cursor内置的MCP客户端不兼容,换成0.9.x的旧版SDK就稳了。另外你试试把server的日志级别调到DEBUG,看是不是工具执行超过30秒被服务端主动掐断,本地调用有时候超时设置挺坑的。还有个土办法,用stdio方式跑,别用HTTP,省心很多。
报错transport closed八成是stdio通道的生命周期没管理好,试试用官方推荐的FastMCP包装下逻辑,别自己手动起asyncio循环。
之前我也被这坑过,换成streamable http模式后稳定多了,本地调试别死磕stdio。
这问题我上周也踩过,八成不是协议问题,是stdio超时设置太短。你试试在server启动时把transport超时参数调大点,比如60秒,另外检查下工具函数里有没有同步阻塞操作,我上次就是有个文件扫描用了递归,卡住后连接就被Cursor那边回收了。
这问题我上个月也踩过,MCP的transport closed大概率不是协议特殊要求,而是你本地server的stdio生命周期没管理好。Cursor连上后如果工具执行超过几秒,而你的Python进程没有保持事件循环活跃,或者用了asyncio但没正确await,连接就会被系统判定为僵尸进程直接掐断。我建议你先别折腾端口和防火墙,直接在代码里给每个工具调用加个超时打印,看看是不是异步任务返回前主循环就退出了。另外你用的是不是官方那个FastMCP封装?它底层对stdin/stdout的缓冲处理有点坑,如果代码里不小心print了调试信息,会把协议帧冲乱,这也会导致断联。我最后是改成用sse模式跑在本地HTTP端口上才稳定的,虽然多一步启动,但至少不会莫名奇妙断。你检查下有没有在handler里做同步阻塞操作,比如用requests而不是httpx,那也会卡住事件循环。