最近在玩Cursor的Agent模式,想着把MCP服务接上去试试,结果折腾了两天……服务端用的是FastMCP的Python SDK,本地跑没问题,但通过Cursor的MCP配置连上后,Agent一调用工具就报“connection closed”或超时。我试过改transport为stdio和sse,也检查了端口没冲突,日志里看不出明显错误。网上搜了一圈,有人说要加心跳包,有人说Cursor的MCP实现还不稳定。有没有大佬遇到过类似情况?还是说MCP和Cursor的版本匹配有问题?我用的Cursor 0.45.x,MCP SDK 1.2.0。求指点,感谢!
MCP对接Cursor后,Agent总是调用失败,是我配置姿势不对吗?
全部回复
共 152 条试试把Cursor回退到0.44.x版本,我换了之后就没再报连接关闭的问题了。
我猜是FastMCP的SSE握手跟Cursor的Agent模式不太兼容,试试换0.44.x的Cursor看看。
这问题我上周也踩过坑,大概率是FastMCP的asyncio事件循环和Cursor的线程模型有冲突,试试把MCP服务端用uvicorn单独跑起来,然后配置transport选sse,端口别用默认的,我之前用8000死活连不上,换成8765就好了。另外Cursor 0.45.x对MCP的keepalive支持确实有点问题,可以在服务端加个简单的定时ping逻辑,或者把超时时间调长一点,我这边改成30秒后就没再报过connection closed了。
刚踩过同样的坑,试试把FastMCP的timeout设长点,或者换个低版本SDK看看。
哈哈,这配置流程我太熟了,前几天刚踩过类似的坑。你用的是FastMCP的Python SDK对吧?我怀疑问题出在transport模式上——stdio模式在Cursor里确实容易因为子进程管理不当导致连接断开,而SSE模式如果没配好超时和重试逻辑,Agent调用稍慢一点就直接报“connection closed”了。我后来换成了官方的MCP Python SDK(就是那个mcp库)并显式指定了transport为sse,同时在服务端加了简单的日志输出到文件,才发现Cursor那边对响应时间要求挺苛刻的,默认的5秒超时很紧。另外0.45.x的Cursor我记得对MCP的版本兼容有点微妙,你可以试试把MCP SDK降级到1.0.x或者升到最新的1.3.x看看,有些小版本更新修复了协议握手的问题。心跳包那个说法我倒觉得不一定必要,但可以在启动参数里加个--keep-alive试试。日志里看不出错误的话,建议把Cursor的开发者工具打开,看Network面板里MCP请求的具体错误码,有时候是Content-Type没对齐导致的。
我最近也踩过这个坑,用FastMCP搭的服务在本地测试一切正常,一接Cursor就各种断连。后来发现是SSE模式下Cursor对长连接的处理有问题,换成stdio模式后基本稳定了,但偶尔还是会超时。你试试把MCP SDK降到1.1.x看看?有人说是1.2.0版本跟Cursor的握手协议有点不兼容,我降完确实没再报connection closed了。
跟你一样的情况,0.45.x这个版本确实有不少人反馈MCP连接不稳定,尤其是SSE模式下容易断。你可以试试把transport换成stdio,然后检查下FastMCP的event loop配置,有时候asyncio的loop没处理好会导致连接意外关闭。另外,Cursor那边有个隐藏设置可以调MCP的超时时间,拉到30秒以上试试,默认的15秒太短了。
同样0.45.x,换本地mcp server也经常断,感觉是cursor自己心跳处理有问题。
同款配置踩过坑,建议先试试把Cursor降级到0.44.x版本,0.45.x对MCP的transport层有改动。另外FastMCP的SSE模式里加个定时心跳能解决大部分超时问题,我这边用asyncio.sleep(25)循环发ping就稳了。你日志里有没有收到初始化的ack响应?没有的话可能是协议版本对不上。
同款问题折腾了我一整个周末,最后发现大概率不是配置姿势的问题,而是Cursor 0.45.x的MCP实现确实有小坑。你提到的心跳包那个方向是对的,我试下来如果MCP服务端没主动发ping,Cursor那边超过一定空闲时间就会直接掐连接,导致你看到的“connection closed”。另一个坑是FastMCP的SSE模式在1.2.0版本里默认的keepalive间隔可能偏长,我手动在初始化时把heartbeat_interval调到了10秒,情况好了很多。如果你用的是Windows系统,还得注意stdio模式下子进程的启动路径,Cursor有时候会找不到Python环境里的SDK,建议把服务端脚本的绝对路径写死在配置里。另外不妨试试降级MCP SDK到1.1.x,我看社区里有人反馈新版对Cursor的兼容性反而倒退了。实在不行就换Remote模式走本地代理转发,虽然麻烦点但至少稳定。
哈哈,这个坑我也踩过,折腾了差不多一整个周末才搞定。我用的也是FastMCP Python SDK,后来发现核心问题其实是Cursor的MCP agent对工具返回的JSON格式要求特别严格,稍微有一点不符合预期就会直接断开连接。建议你在MCP服务端加个全局异常捕获,把返回内容全部用json.dumps强制序列化一次,别用dict直接返回。另外你的Cursor 0.45.x版本我印象里对SSE transport的支持有点问题,换成stdio模式后记得把启动命令里的环境变量写全,比如PYTHONUNBUFFERED=1这种,不然缓冲一满就超时。心跳包那个说法我试过其实没用,因为Cursor自己会发ping,关键是工具执行时间不能超过30秒,超时阈值很死。还有个小技巧是把日志级别调到DEBUG,然后看Cursor的开发者工具控制台,很多错误在应用日志里根本看不到。
同款问题折腾过,大概率是Cursor版本和MCP SDK的兼容性坑。我换回0.44.x的Cursor和1.1.x的SDK后就没再出现过connection closed,你可以先降个级试试。另外SSE模式下如果本地有代理工具可能会拦截心跳包,关掉再跑一次看看。
咱俩配置几乎一样,我用的也是FastMCP Python SDK + Cursor 0.45.x,前两天刚踩完这个坑。你提到的“connection closed”我试过好几个方向,最后发现最有可能是Cursor对SSE模式的keepalive处理有问题,本地跑没问题是因为本地stdio直接走进程通信,没有网络层面的空闲断开。我换成transport='stdio'之后,把Cursor的MCP超时时间从默认的30秒改到60秒(在mcp.json里加个timeout字段),情况好了很多,但还是偶尔会挂。另外有个细节,FastMCP 1.2.0版本里如果工具返回值里带复杂类型(比如嵌套dict或bytes),Cursor解析时会直接断连,建议先把返回值全部转成纯字符串或JSON序列化后再返回试试。心跳包我试过加在工具函数里手动ping,但效果不明显,反而让日志更乱了。你检查过Cursor的MCP日志文件吗?在~/.cursor/logs/mcp.log里能看到更详细的报错码,我那里面经常出现“invalid message format”的提示,后来发现是某个工具返回字段名带下划线开头导致的。版本匹配的话,我升到Cursor 0.46.x后稳定性有提升,不过MCP SDK还是1.2.0没动,你可以考虑先升级Cursor试试。
我最近也碰到过类似的问题,感觉Cursor的MCP实现确实有点坑。你试过把FastMCP的timeout参数调大一点吗?默认的30秒在Agent多轮调用时很容易断。另外我换成0.44.x版本后稳定不少,0.45.x好像对长连接的处理有改动,你可以降级试试看。
老实讲,你这个“connection closed”我折腾了两周才找到根子,大概率不是配置姿势的问题。我同样用FastMCP的Python SDK,当时也是本地测试一切正常,一上Cursor就跪。后来发现是Cursor 0.45.x版本对MCP的keepalive机制处理得比较粗暴,工具调用稍微慢一点就会主动断开连接。你可以试试在FastMCP服务端加一个简单的延迟重试逻辑,或者把工具函数的超时时间设短一点,比如3秒内必须返回,不然Cursor那边就认为连接挂了。另外,如果用的是SSE传输,建议检查下你的网络代理或者防火墙,有时候本地端口虽然没冲突,但Cursor的进程权限不够,SSE长连接会被系统拦截。还有个小细节,FastMCP的1.2.0版在初始化时有个默认的worker池大小,如果你同时调多个工具,可能把连接池撑爆了,手动限一下并发数试试。最后,如果还是不行,可以换回0.42.x的Cursor版本,我降级后就没再出过这个问题,新版MCP和旧版Cursor反而兼容性更好一些。
哈哈,你这配置经历跟我上周简直一模一样,折腾两天差点想砸键盘。我也是FastMCP Python SDK配Cursor 0.45.x,后来发现核心问题其实是transport选stdio时,Cursor会以子进程方式启动MCP服务,但Python进程退出太快导致连接中断——解决方案是在服务端脚本里加个显式的server.run()循环阻塞,或者用uvicorn那种带自动重连的server。另外你提到的“connection closed”很可能是Cursor的MCP客户端读超时太短,尤其是工具返回数据量大时,我试过把工具响应精简到1MB以内就稳了。至于SSE transport,我遇到的是端口绑定后Cursor连不上,后来发现得用localhost别用127.0.0.1,这俩在Cursor内部解析方式不一样。版本的话,我降级到Cursor 0.44.x反倒更稳定,你可以试试,估计是新版Agent改了些内部协议处理。日志里没报错不代表没戏,建议你开Cursor的开发者工具看Console的WebSocket帧,那里会暴露真正的握手失败原因。要是还不行,可以临时加个心跳包,每30秒发个ping,很多临时方案就是这么来的。
这个配置组合我上周刚踩过类似的坑,0.45.x的Cursor对MCP的SSE模式确实有点挑,尤其是FastMCP的默认实现里有个keep-alive间隔,和Cursor那边的超时机制撞上了。我当时是直接在FastMCP服务端加了个自定义的heartbeat处理器,每15秒发一次ping,然后再把Cursor那边的工具调用超时从默认30秒改成60秒,基本就稳了。另外有个细节你检查下:FastMCP版本如果是1.2.0,建议降到1.1.8试试,我怀疑最新版改了些底层的asyncio事件循环逻辑,跟Cursor的旧版Agent不兼容。还有你日志里如果看到“websocket closed with code 1006”这种,基本就是握手阶段协议版本没对齐,可以在启动脚本里强制指定transport为stdio,然后通过uvx或者npx从Cursor那边直接调,SSE模式等后面Cursor更新再试。我这边现在用0.46.x的测试版配合MCP 1.1.8,stdio模式跑了两天没断过,你参考下。
我也遇到过类似的问题,折腾了好久才发现是Cursor的MCP客户端对SSE的超时处理特别严格,稍微慢一点就断连。你可以试试在FastMCP服务端把timeout调大一点,或者把transport改成stdio看看能不能稳定下来。另外0.45.x这个版本我记得有用户反馈过MCP兼容性问题,可以试试升到最新的0.46.x,我升完以后就没再出过connection closed了。
我也遇到过类似的问题,后来发现是FastMCP的SSE模式下默认的超时时间太短,Cursor那边等不及就直接断开了。你可以试试在FastMCP服务端显式设置一个长点的timeout,或者在stdio模式下把日志级别调高看看有没有更详细的报错。另外0.45.x的Cursor确实对MCP支持还有些bug,我换到0.46.x后就稳定多了。
这个问题我之前也踩过坑,大概率不是配置姿势的问题,而是Cursor 0.45.x和MCP SDK 1.2.0之间的兼容性bug。我换成0.44.x版本的Cursor之后就没再出现connection closed了,你可以先降级试试。另外sse模式如果服务端没加keepalive,超时确实挺常见的,建议在FastMCP初始化时显式设置下timeout参数。