最近在玩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总是调用失败,是我配置姿势不对吗?
全部回复
共 167 条试试把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握手容易断。
我跟你几乎一模一样的配置,FastMCP加Cursor 0.45.x,也是stdio下各种断连。后来发现问题是Cursor对MCP的stdin/stdout缓冲处理有bug,换成sse模式后稳定很多,但需要额外处理下CORS和超时配置。你试试把sse的路径改成/mcp/sse,然后在服务端加个简单的重连逻辑,应该能缓解。另外确认下你本地跑的时候是不是用了不同的Python环境,Cursor那边可能用了它内置的运行时。
我上周也踩过类似的坑,最后发现是FastMCP的SSE模式在Cursor里对请求头处理有兼容问题,换成streamable-http的transport就好了。你试试新建一个MCP配置时选自定义命令,用uv run直接启动,别走SSE。另外0.45.x这版本对MCP的stdio支持确实有点迷,我后来降到0.43.x就稳定了,你可以先降版本排除下变量。如果还不行,看看是不是防火墙拦截了本地回环的二次连接,Windows上常见。
你这配置我看了下,大概率不是姿势问题,是FastMCP那个SDK和Cursor的握手协议有点微妙的不兼容。我上周也踩过类似的坑,最后发现是FastMCP默认的初始化响应里带了太多元数据,Cursor解析到一半就断开了,你得手动把server的capabilities精简一下。还有那个心跳包,不是可选项,stdio模式底下Cursor这边闲置超时特别短,你必须在FastMCP里把heartbeat间隔调到15秒以内,不然一思考久一点连接就被回收了。另外你试过把transport写成“sse”的时候,是不是直接用的事件流URL?Cursor那边要求路径必须带/sse后缀,否则它会当成普通HTTP轮询来处理,自然就超时了。版本我倒觉得问题不大,0.45.x对MCP的支持已经很完整了,反而是SDK 1.2.0的日志级别默认是INFO,很多底层错误被吞了,你把它调成DEBUG再看看stderr输出,应该能看到具体的关闭原因。要是还不行,就换个思路,直接用Fetch那个内置MCP试试,排除掉自定义server的问题。
我之前也踩过类似的坑,不过我是用TypeScript SDK接的,最后发现问题是Cursor的MCP客户端对SSE的keep-alive处理特别激进,几分钟没请求就给你掐了。你本地跑没问题是因为你手动发的请求频率高,但Agent思考的时候可能很久不碰工具,连接就断了。我后来把transport换成stdio,然后给FastMCP的底层加了个自动重连的逻辑,才算稳定下来,虽然偶尔还是抽风。另外你那个版本组合,Cursor 0.45.x的MCP支持确实有点半成品,我升到0.46之后感觉好很多,你试试看?还有个小细节,你检查一下FastMCP的日志级别,有时候错误被吞了,调成DEBUG能看到具体是握手失败还是数据帧解析出错。
我前两天也被这个坑过,后来发现是FastMCP的SSE模式在Cursor里默认请求头带不全,换回stdio然后显式指定绝对路径的Python解释器就好了,你可以试试看。另外0.45.x版本对MCP协议支持确实有点玄学,我升到0.46之后稳定性明显好了一些。还有个细节是工具返回内容别超过一定大小,超了连接直接断,日志里什么都看不出来。
试试把Cursor降回0.44.x,我升到0.45后也是各种connection closed,降级立刻稳了。
看到你这个配置组合我第一反应是版本太新了,FastMCP 1.2.0和Cursor 0.45.x都更新得很快,两边对MCP协议的实现细节可能有微妙差异。我之前用0.43配1.0.x也踩过类似的坑,后来发现是Cursor的MCP客户端在stdio模式下对进程退出信号处理有bug,你试试在FastMCP服务端代码里显式加一个transport="sse",但端口别用默认的8000,换个不常见的比如8123,有时候是本地代理占用了端口导致连接被重置。另外你日志里有没有看到类似“handshake timeout”或者“stream closed”的字段?我之前排查时发现Cursor会先发一个初始化请求,如果SDK版本不兼容它不会报错,而是直接掐断连接,你可以抓一下服务端的标准输出,看看有没有收到initialize请求,如果压根没收到,那就是Cursor侧没真正连上你的进程。还有个小技巧,把MCP的配置从全局挪到项目级的.cursor/mcp.json里,因为全局配置有时候会命中缓存。最后实在不行就降级Cursor到0.42.x,我周围好几个朋友都是靠这个办法稳定下来的,新版本对MCP的支持反而更激进,容易出幺蛾子。
这配置折腾两天太真实了,我上个月也卡在这。0.45.x这版对SSE支持确实有坑,建议试试把transport换成streamable-http,Cursor最近几个版本主推这个,stdio在远程场景下本来就容易断。另外FastMCP那边记得把server的idle timeout调大点,默认值太小,Agent思考时间一长连接就被回收了。我这边调完基本稳了,你试试看。