最近在玩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 条试试把FastMCP降到0.11.x,之前我也遇到connection closed,升到1.x后和Cursor兼容性反而差了。
我之前也踩过这个坑,最后发现是FastMCP的stdio模式在Cursor子进程里环境变量没继承全,尤其是PATH和PYTHONPATH,导致SDK初始化时悄悄挂了。你可以试试把服务端改成绝对路径调用python,或者直接在配置里写死环境变量看看。另外0.45.x这版对SSE的支持确实有bug,我换回0.43.x就稳定了,你可以降级对比下。
这配置我上周也踩过差不多的坑,后来发现是FastMCP版本和Cursor的MCP客户端握手协议对不上,SDK 1.2.0建议换到1.1.x试试。另外stdio模式下Cursor对进程退出信号处理挺粗暴的,你试试在服务端加个优雅关闭的逻辑,或者干脆用sse配合nginx做下长连接保活。我当时是换了transport之后又发现超时时间太短,在Cursor设置里把MCP请求超时调到60秒就稳了,你可以先排查下是不是这个。
还有个小细节,本地跑没问题不代表Cursor环境没问题,它那个沙箱对子进程的资源限制挺狠的,可以试试把服务端日志写到文件里,看是不是启动后就被杀了。我之前就是被这个坑了半天,日志全在stdout里直接丢了。
我最近也踩过类似的坑,后来发现是FastMCP的SSE模式默认带了session管理,Cursor那边握手逻辑对不上,换成streamable-http或者干脆用stdio反而稳了。你试试把SDK降到1.0.x看看,我这边0.46的Cursor配1.0.4就没再掉过连接。另外超时的话,检查下是不是工具里有大文件传输,MCP默认的response大小限制很容易触发。
我之前也卡在过这上面,后来发现是FastMCP版本和Cursor的兼容性问题,你试试把SDK降到1.0.x或者干脆用官方的mcp库重写下客户端。另外,stdio模式在Cursor里有时候会因为进程退出时机不对导致connection closed,建议换个思路,用sse模式并且手动在服务端加个keep-alive定时器,每15秒发个空事件。还有,0.45.x的Cursor确实有已知的MCP bug,去更新到最新预览版可能直接就好了,你日志里看不到错误是因为它经常不打印底层socket异常。
我升到0.46.x后问题消失了,你这版本确实有点旧,先试试升级吧。
试试把FastMCP降到0.9.x,我换了之后就没再断过,Cursor这版本对1.x兼容性确实有点迷。
遇到过类似的,不过我是用TypeScript SDK接的,最后发现是Cursor那边对stdio的进程生命周期管理有问题,agent闲置一会儿连接就被回收了。你试试把MCP server包一层,用supervisord之类的东西保活,或者干脆用streamable-http试试新版协议。另外0.45.x确实对MCP支持还比较早期,我升到0.47之后稳定性好了不少。
还有个思路,你本地跑通的话可以先抓一下Cursor发出的初始化请求和工具调用请求,看看是不是参数格式对不上,FastMCP默认的协议版本可能跟Cursor期望的不一致。我上次就是卡在tools/list的response schema上,手动改了下server的capabilities才解决。
我遇到过类似的,当时是FastMCP版本和Cursor的MCP client握手协议不兼容,把SDK降到1.0.x就稳了。另外你试试把transport改成sse后,在Cursor里别用默认的localhost,换成127.0.0.1,有时候IPv6解析会搞鬼。心跳包那个说法我也见过,但感觉治标不治本,先排查下是不是服务端启动日志里有异常退出,比如stdout被污染了。
之前我也踩过类似的坑,而且折腾的时间比你还长。我当时是0.44.x版本配MCP 1.1.0,跟你一样本地FastMCP跑得飞起,一进Cursor就疯狂断连。后来发现不完全是版本匹配问题,更可能是Cursor对MCP的stdio传输有超时限制,它默认的进程存活检测很激进,你服务端稍微慢一点(比如首次加载模型或初始化工具列表)它就判定连接死了。你可以试试在FastMCP启动时加个--debug参数,然后把所有日志输出到文件,看是不是在调用前就已经被Cursor的进程管理器杀了。另外SSE模式你确认下是不是用的streamable HTTP而不是老的SSE端点,Cursor这个版本支持的其实是新协议,很多教程还在用旧写法。还有个偏方,把工具函数里所有同步阻塞操作改成async,哪怕只是sleep也换掉,能明显减少连接被掐的概率。最后建议你直接降到Cursor 0.42.x试试,那个版本我印象里对MCP的容错处理反而更宽松,虽然功能少点但稳定很多。要是还不行,可以考虑用本地代理把MCP转成HTTP服务再挂上去,绕过它的进程管理逻辑。
我之前也踩过这个坑,折腾了快一晚上,最后发现是FastMCP的SSE模式和Cursor的兼容性问题。你用的SDK 1.2.0,Cursor 0.45.x这个组合我印象里确实有bug,尤其是SSE那边,Cursor自己实现的客户端对事件流的解析有点严格,稍微慢一点就报connection closed。建议你试试两个方向:一是把FastMCP的日志级别调到DEBUG,看看服务端是不是在等什么请求头,Cursor默认会发一个Origin过去,有些本地服务会拒绝;二是别用FastMCP的包装,直接裸写一个MCP协议端点,用官方Python SDK的底层方法,我这么改完就稳了。另外心跳包其实不是关键,MCP的协议本身有超时机制,但Cursor那个实现好像没按规范来,它那个超时时间设得特别短,我后来在服务端手动把每个请求的处理时间控制在2秒内,基本就不掉了。你试试看是不是工具本身执行太慢,比如你那个工具里有没有同步的数据库查询或者网络请求,加个异步或者缓存能好很多。版本匹配的话,我建议你降级到MCP SDK 1.0.3试试,那个版本跟Cursor的磨合度反而更高。
我也踩过这坑,换成streamable-http传输,然后给客户端加个重连机制就好了。
试试把FastMCP升到2.x,老版SDK跟Cursor握手容易断。