最近在折腾MCP(Model Context Protocol),想把本地跑的Qwen2.5(7B)通过MCP服务器接到自己的知识库工具上。用的Python SDK写的Server,SSE传输,报错是“Connection timed out after 60s”。我本地模型是Ollama起的,端口11434,MCP服务器里回调地址填的是,但日志里模型推理明明已经出结果了,就是回调回不去。查了半天,怀疑是异步循环和Ollama的请求阻塞了,或者SSE的keep-alive设置有问题。有没有大佬遇到过类似情况?是MCP的timeout参数要调,还是Ollama服务端得开CORS?求个排查思路,谢谢!
MCP服务器连本地大模型总超时,是不是我配置姿势不对?
全部回复
共 29 条我之前也踩过类似的坑,排查到最后发现根本不是MCP的timeout问题,而是SSE连接本身就没保持住。你回调地址填没问题,但Ollama那边如果走的是默认的HTTP请求,它会在同一个线程里等模型出结果,这时候异步事件循环就被卡住了,回调自然发不出去。你可以试试把Ollama的调用改成异步的,比如用httpx的AsyncClient,或者干脆把模型推理放到子线程里跑,别占用主循环。
另外你说日志里推理有结果但回调回不去,我怀疑是SSE的响应头没设置对,特别是Content-Type得要text/event-stream,而且每个event后面得跟两个换行符,不然客户端那边根本不会触发回调。还有个容易忽略的点,Ollama默认只绑定了localhost,如果你MCP服务器是跑在Docker或者另一台机器上,那得确认11434端口是不是真的对外暴露了。
你可以先curl一下Ollama的接口看看通不通,再在MCP服务器里打个断点确认回调函数有没有被触发。timeout那个60s其实只是个兜底,如果事件循环被阻塞,调多大都没用。CORS倒不太可能,本地服务一般不校验那个。先试试把Ollama请求改成异步,大概率问题就没了。
这问题我也踩过,大概率不是CORS的事,Ollama那边压根不校验这个。你回调地址填localhost,但MCP服务器如果是跑在容器或者别的网络命名空间里,这个地址就指向它自己了,根本回不到你本地工具,先确认下两边网络能不能互通。另外SSE超时60秒很常见,你模型推理虽然出结果了,但流式响应如果没按MCP要求的格式逐块推送,客户端会一直等,试试把回调改成实际局域网IP,再把timeout调大到120秒看看。
我之前也踩过类似的坑,尤其是用Ollama当后端的时候。你这个“模型出结果但回调超时”的现象,大概率不是MCP的timeout问题,而是你那个SSE连接根本没维持住。Ollama的请求是同步阻塞的,如果你在MCP server的处理函数里直接调用Ollama的接口,整个异步事件循环就被卡住了,SSE的心跳包发不出去,客户端那边60秒没收到任何数据就自动断开了。你可以试试把Ollama的调用丢给线程池或者用asyncio.to_thread,别让它在协程里同步等着。另外,回调地址填localhost有时候在容器或本机代理环境下会解析到IPv6的::1,而Ollama只监听了IPv4,这种错位也会导致连不上,直接改成试试。CORS那个基本不用管,那是浏览器端的限制,你的Python客户端不校验这个。排查的话,先开MCP server的debug日志,看SSE连接是不是创建后立刻被客户端关闭了,再确认一下你的Ollama是不是设置了keep_alive参数导致模型加载时间过长,但这个一般不会影响回调。我最后是把SSE的ping间隔调到了15秒,并且把MCP的请求改成流式输出才彻底解决,你可以参考下。
看到这个报错我第一反应不是MCP的timeout,而是你Ollama那边是不是默认绑定了localhost。你回调地址填虽然看起来没问题,但Ollama在Windows或者某些Docker环境下可能只监听了IPv6的::1,导致从MCP服务器所在进程发过去的请求根本找不到目标。可以先试试netstat或者curl一下那个端口,确认到底是通还是不通。
另外你说模型推理已经出结果但回调回不去,这个现象挺典型的,大概率是SSE连接被Ollama的同步请求给堵死了。Python SDK里如果用的是同一个事件循环,模型推理阻塞了异步任务,keep-alive包就发不出去,客户端那边等够60秒就超时断开。你可以试试把Ollama的请求丢到线程池里执行,或者用httpx的AsyncClient配合asyncio.to_thread,别让推理占着主循环。
CORS那个基本不用管,本地服务之间没有浏览器参与,谈不上跨域。真正要查的是MCP服务器有没有在回调前正确发送heartbeat,有些SSE实现需要手动设置ping间隔,不然客户端会认为连接死了。你可以先在Ollama返回前手动往流里塞个注释行,看看能不能保持连接活跃。
如果上面都试了还不行,就把MCP的transport换成stdio试试,虽然不优雅,但能排除掉SSE本身的网络层问题。我上次搞类似的东西就是卡在keep-alive上,最后发现是SDK版本太老,升级到最新版就好了。你这报错是60秒整,八成是客户端默认超时,不是服务端问题,先查本地端口连通性,再查事件循环阻塞,一步步来。
这问题我踩过一模一样的坑,大概率不是CORS的事,Ollama那边压根不管这个。你试试把MCP服务器里回调地址的localhost换成,SSE对localhost解析有时候会卡在IPv6上。另外你怀疑的异步阻塞方向我觉得挺靠谱,Ollama的请求是同步阻塞的,如果把模型调用直接塞在SSE事件循环里,60秒超时基本必现,得用run_in_executor丢到线程池里跑。先改这两个地方看看,实在不行再把Ollama的keep_alive参数调成-1,让它别频繁释放模型。
我之前也卡过这问题,后来发现是Python SDK里SSE的timeout默认60秒,但Ollama那7B模型冷启动或者长上下文时推理经常超一分钟,回调还没发出去连接就被掐了。你可以先把MCP server里的timeout参数调到180秒试试,另外确认下Ollama那边是不是同步阻塞了event loop,用asyncio.to_thread包一下请求会好很多。CORS一般不影响SSE回调,除非你浏览器端直连,先别折腾那个。
我之前也踩过这个坑,日志出结果但回调超时,基本就是MCP Server的异步事件循环被Ollama的同步请求卡住了。Ollama默认单并发,你那7B模型推理时把线程占满,SSE的keep-alive就发不出去,客户端等不到心跳自然断。建议先把Ollama的OLLAMA_NUM_PARALLEL调大点,或者MCP这边用run_in_executor把推理请求丢到独立线程池。另外确认下回调地址别写localhost,换成127.0.0.1试试,有时候是IPv6解析的锅。
我之前也踩过这个坑,大概率是SSE长连接被中间层掐了,跟Ollama本身关系不大。你先看看MCP Server那边是不是同步调用Ollama把事件循环堵死了,换成httpx异步或者丢线程池里试试。另外60s这个数很像是默认超时,SDK里应该有timeout参数可以调大,顺手把keep-alive心跳也打开。CORS只在浏览器场景才有影响,你这种服务端回调基本不用管它。
我之前也踩过这坑,八成是Ollama那边没开并发,SSE回调卡住了,试试加个超时重试?