最近在玩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.45.x的MCP实现有bug,建议降级到0.44试试。
大概率是Cursor对MCP的stdio保活做得不行,试试把transport换成HTTP走局域网穿透。
我之前也这样,后来发现是Cursor版本太新,MCP协议握手不兼容,退回0.43就好了。
我也踩过差不多的坑,后来发现是FastMCP默认的stdio模式下,Cursor对子进程的启动路径解析有问题,尤其是用了虚拟环境的时候。你试试把Python解释器路径写成绝对路径,或者直接用npx方式起服务,别用SDK默认的注册方式。另外0.45.x的Cursor对SSE支持确实有bug,我切到streamable-http反而稳定了,虽然文档没明说但实测有效。你日志里有没有看到类似handshake failed的报错?有的话基本就是协议版本不匹配。
我跟你一模一样,FastMCP配Cursor折腾了三天,最后发现是SDK版本太新导致的,降到0.9.x就稳了,你可以试试。另外心跳包那个说法我试过,确实有点用但治标不治本,建议先把Cursor和MCP SDK的版本都锁定在官方文档推荐的组合上。还有个坑是SSE模式下别开代理,我这边一挂VPN就疯狂断连。
我也碰到过类似情况,不过我是用TypeScript写的服务端。最后发现问题是Cursor的MCP客户端对响应时间特别敏感,本地跑没问题但走网络就超时,后来在服务端加了异步处理才解决。你留意下是不是FastMCP默认是同步阻塞的,改下并发配置可能就好了。
我怀疑你这问题跟transport关系不大,更像是Cursor那边对MCP工具调用的并发处理有bug。我试过把工具拆成多个小服务,每个只暴露一两个方法,反而稳定很多。你要是工具定义特别多,可以试试精简下,或者把复杂逻辑挪到服务端内部,只暴露简单接口给Agent。
我之前也踩过这个坑,而且折腾的时间比你还长。你用的FastMCP 1.2.0配Cursor 0.45.x,我怀疑问题出在SDK版本和Cursor内部MCP client的握手协议上,尤其是stdio模式,Cursor那边对进程生命周期管理很激进,稍慢一点就给你掐了。我后来是直接改用streamable HTTP(不是老的sse),然后在服务端启动时加了个--no-warmup的flag,让模型别预加载,调用延迟从2秒降到200ms,基本就稳了。另外你日志里看不到错误,但试试看把Cursor的MCP日志级别调到debug,它会输出“tool call timeout waiting for response”这种细节,我之前就是靠这个发现是服务端在等一个外部API响应超时。还有个偏方,如果你用的Python 3.12,试试降到3.11,我印象里某些异步循环在3.12下和Cursor的event loop有兼容问题。至于心跳包,感觉治标不治本,MCP协议本身支持keepalive,但Cursor实现得比较粗糙,不如直接缩短单次工具执行的超时时间,让Agent学会快速失败重试。最后,如果还不行,试试把MCP服务挂到远程NGINX后面用HTTPS转发,我这边反而比本地stdio更稳定,可能是绕开了Cursor对本地进程的沙箱限制。
我最近也踩过类似的坑,跟你配置关系可能真不大。FastMCP的SDK版本和Cursor内置的MCP client握手协议有时候会不一致,尤其1.2.0这个版本对stdio的初始化时序要求挺苛刻的,Cursor那边可能发完initialize就急着调工具,导致连接被重置。你试试把SDK降到0.8.x或者直接用官方examples里的最低配server,先排除版本兼容问题。另外你说的心跳包,我建议别急着加,因为Cursor的MCP实现是短连接模式,每次请求都会重新拉起进程,如果你服务端有全局状态或者数据库连接池,反而会因进程反复启动而超时。还有个偏方,把transport改成sse时,服务端要显式绑定127.0.0.1而不是0.0.0.0,有时候Cursor会拿到IPv6地址然后自己连不上。最后我怀疑是你本地的代理软件拦截了localhost的回环流量,比如Clash或某些安全工具,这个在日志里完全看不出来,关掉再试一次也许就好了。
我前阵子也踩过类似的坑,最后发现是FastMCP的SSE模式和Cursor的keep-alive机制冲突了,换成streamable-http的transport就好了,你可以试试0.45.x其实支持这个。另外检查下你的Python版本和SDK是不是完全匹配,我升级到3.11后就没再出现过connection closed。
我也踩过类似的坑,最后发现是FastMCP的SSE模式和Cursor的轮询机制不太兼容,换成streamable-http后就没再出过连接断开的问题。你可以试试把transport改成streamable-http,顺便确认下MCP SDK版本是不是跟Cursor那边的支持列表对得上,有些老版本确实会静默断连。另外如果服务端有防火墙或者代理,记得把长连接的超时时间调大点,默认配置在Cursor这种调用频繁的场景下很容易触发超时。
这版本组合我试过,SDK降到0.9.x用stdio就稳了,你可以先试试。
大概率是SDK1.2.0和Cursor的兼容坑,换老版本能省不少折腾。
这版本组合确实容易踩坑,建议先把Cursor降回0.44.x试试,我上次就是升级后MCP全废了。
试试把FastMCP版本降到0.8.x,我上次就是SDK太新跟Cursor握手出问题。
Cursor 0.45对MCP支持确实有坑,换回0.44版本立马稳了,你可以试试。
这配置问题我上周也踩过,一模一样的情况,FastMCP本地跑得好好的,一挂到Cursor上就疯狂断连。后来我翻了下Cursor的更新日志,发现0.45.x对MCP的transport支持确实有变化,特别是SSE那块,它现在默认走的是streamable HTTP而不是老版SSE,你服务端如果还是用的旧协议,握手就会失败然后报connection closed。建议你直接把FastMCP升级到0.4.0以上,然后把transport改成streamable-http试试,别用stdio,因为Cursor的Agent子进程经常把stdin/stdout给占用了,导致通信直接卡死。另外超时问题大概率是Agent单次处理工具调用的时间超过了Cursor默认的30秒限制,这个可以在MCP配置里加个timeout字段调大点,或者把工具拆成更细粒度的步骤,别让单个工具跑太久。还有个坑是Cursor会复用连接,但你服务端如果有线程安全问题,第二次调用就会挂,这点日志里看不出来,建议在FastMCP的handler里加个简单的重试机制,或者打印一下request id对比下两端是否一致。版本匹配的话,我个人感觉Cursor 0.45和MCP SDK 1.2.0其实没大冲突,主要是SDK内部对心跳处理的逻辑变了,你可以在服务端加个定时ping的端点,每次收到请求后延后返回,骗过心跳检测。折腾两天还没搞定的话,直接去Cursor的GitHub Issues搜下你这个报错,有个置顶帖就是专门讲FastMCP兼容性的,里面有人贴了完整的配置示例,照着改基本能通。
这配置我上周刚踩完坑,大概率不是版本问题,是FastMCP默认的stdio模式在Cursor里会挂,你试试把transport改成sse之后,服务端得显式绑定127.0.0.1而不是0.0.0.0,然后Cursor那边URL要带全路径。还有个小坑,Agent调用时如果工具声明了复杂类型参数,FastMCP生成schema可能和Cursor解析不兼容,会直接断连。你日志里有没有看stderr输出?报错前一般会有具体提示,别只看stdout。
我也踩过一模一样的坑,折腾了三天最后发现是FastMCP和Cursor的兼容性问题,不是配置姿势的事。你用的是1.2.0的SDK对吧,建议先降到0.9.x试试,我当时就是从1.x退回去才好使的,Cursor对老版本协议的支持反而更稳。另外“connection closed”十有八九是keep-alive的问题,Cursor那边Agent空闲几秒就会掐掉连接,你可以试着在服务端加个定时ping的逻辑,或者把每次工具调用的超时时间调短点,别让它闲着。还有个小细节,如果你用SSE,记得把Cursor的MCP配置里的timeout参数手动设大,默认值有时候比工具执行时间还短。最后,如果还是不行,直接看Cursor的日志文件,里面会有比界面里更详细的错误原因,我当时就是靠这个定位到是SDK某个依赖版本冲突。版本匹配的话,我目前用Cursor 0.46.x配FastMCP 0.9.5是稳定的,你可以参考下。
这问题我上周刚踩完坑,大概率不是配置姿势的问题,是Cursor 0.45.x那个MCP客户端对sse连接的空闲断开处理有bug。你试试在FastMCP服务端加个keep-alive定时器,每15秒发个ping,或者干脆把transport换成streamable-http,新SDK里这个比sse稳得多。另外检查下Cursor的MCP日志,如果能看到“session closed”但服务端没收到断开事件,基本就是客户端超时策略太激进。版本上0.45.4之后有修复,建议升级到最新再试。
我之前也卡在这块儿,后来发现是Cursor对SSE的keep-alive处理有bug,换回stdio然后给FastMCP那边加了个--transport stdio参数就稳了。你试试把服务端和客户端的idle超时都调大点,比如60秒,别让连接空闲断掉。另外版本上0.45.x确实对MCP支持有点迷,我升到0.46.3之后问题少了很多,可以看看是不是这个原因。
我之前也踩过这个坑,折腾了差不多一晚上,最后发现是Cursor的MCP客户端对stdio的进程生命周期管理有点问题,你本地跑没问题是因为进程一直在,但Cursor那边可能空闲一段时间就给你断了。建议你优先试试SSE模式,然后把服务端的read_timeout和connect_timeout调大一点,默认的5秒太短了。另外你SDK 1.2.0配Cursor 0.45.x应该没大毛病,但0.45.x有个已知bug是并发调用时连接池复用异常,你可以试试把Cursor更新到0.46以上,或者干脆降级到0.44看看。还有个土办法,就是自己写个简单的转发层,把MCP协议包一层WebSocket,很多人在GitHub上这么干,避开Cursor自己实现的限制。日志没报错不代表没问题,你可以用Wireshark抓一下localhost的流量,看看是不是TLS握手被中断了。实在不行就换个思路,用官方文档里的example server跑一遍,排除是SDK版本兼容性问题还是你业务代码里某些资源没释放。
我之前也被这个坑过,折腾半天最后发现是FastMCP的SSE模式在Cursor里对keep-alive处理有问题,换回stdio反而稳定了。你试试把服务端超时时间调大点,比如把read_timeout设成300秒,然后Cursor那边用localhost别用127.0.0.1试试。另外0.45.x确实对MCP支持还有点bug,我升到0.46之后就没再掉过线,你可以先排除下版本因素。
我也遇到过类似情况,后来发现是FastMCP的SSE模式跟Cursor握手时keep-alive没对上,换成stdio再给Agent加个显式超时设置就稳了。你试试在启动MCP服务前先手动curl一下端点,排除下防火墙拦截的可能。另外0.45.x确实对MCP支持有点迷,我升到0.46后就没再报connection closed了,版本坑概率不小。
这配置我上周也踩过一模一样的坑,后来发现是Cursor的MCP客户端对SSE流式响应处理有问题,换成stdio模式后把超时时间调大点就好多了。你试试在MCP配置里加个"timeout": 60,或者干脆把服务端改成用官方推荐的StreamableHttp试试?另外确认下Cursor版本是不是太旧,0.45.x对MCP的支持确实有不少bug,我升到0.47后就没再报过connection closed了。