最近在折腾MCP,想着把本地部署的Qwen2.5接进去当工具用。我用的Python写的FastMCP,模型跑在Ollama上。现在问题是,MCP客户端一调用工具,请求发到我的服务端,服务端再去访问Ollama的API就卡住,几秒后直接超时。单独用curl测Ollama是秒回的,模型也加载了。我怀疑是不是MCP的同步机制阻塞了事件循环,或者Ollama那边keep-alive设置的问题?也试过把请求改成异步,还是不行。有没有老哥碰到过类似情况?求指点一下排查方向,万分感谢。
MCP服务器连本地大模型一直超时,是配置问题还是我的姿势不对?
全部回复
共 8 条我上周刚踩过这个坑,最后发现是FastMCP默认的线程池太小,Ollama那边响应稍微慢点就把线程占满了。你试试在初始化MCP服务时把transport的线程数调大,或者直接给Ollama的请求加个长的connect timeout。另外确认下你的Ollama是不是有多个模型在跑,有时候显存不够会卡在加载上。
这题我熟,大概率是FastMCP的同步调用卡住了事件循环,试试把Ollama请求丢线程池里跑。
之前调MCP接本地模型也踩过类似的坑,后来发现是Ollama默认只接受单连接,MCP那边并发请求把队列占满了。你试试把Ollama的OLLAMA_NUM_PARALLEL设成2或者直接关掉MCP的并发,看能不能缓解。另外FastMCP的transport如果是stdio,注意下服务端有没有正确flush响应,有时候是缓冲没及时发出去导致客户端那边误判超时。
我之前也踩过类似的坑,最后发现是FastMCP默认的线程池太小,工具调用里同步去请求Ollama时把工作线程全占满了,新的请求就排队等超时。你可以先试着把Ollama的请求放到一个单独的线程池里,或者直接把FastMCP的transport换成异步模式,但注意别在async函数里用time.sleep这类阻塞调用。另外一个很隐蔽的点是Ollama的keep-alive,如果服务端每次请求都新建连接,而连接没被正确回收,也会导致句柄耗尽卡死,你可以用httpx或者requests的Session复用连接试试。对了,你MCP客户端那边设置的超时时间是多少?如果客户端那边给的窗口很短,服务端稍微慢一点就掐断,看起来也会像Ollama超时,实际是客户端先放弃了。我之前用curl测是秒回,但加到MCP里就慢,后来发现是模型初次加载后有个预热延迟,你可以在服务端启动时主动ping一次Ollama把模型拉进显存。还有个小工具,用netstat看下服务端和Ollama端口之间有没有大量TIME_WAIT的连接,有的话基本就是连接没复用。排查顺序建议先看FastMCP的日志,把Ollama请求前后的时间戳打出来,能直接定位是卡在连接建立还是请求发送。
这问题我碰到过类似的,最后发现是Ollama默认的请求并发设置太低,MCP那边多个连接挤一起就超时了。你试试把OLLAMA_NUM_PARALLEL环境变量调高一点,或者直接在Ollama服务启动时加个参数。另外检查下FastMCP服务端的超时时间是不是设得比Ollama的响应时间还短,尤其是模型冷启动慢的时候,curl秒回但实际推理可能要好几秒。
我之前也踩过类似的坑,后来发现是FastMCP默认的线程池太小,Ollama那边响应稍慢点,同步调用直接把worker占满了,后面的请求全堵着超时。你可以先试试把Ollama的keep_alive调大点,比如设成30分钟,然后看下FastMCP的日志里有没有堆积的报错。另外你异步改的是客户端还是服务端?如果是服务端,得确认一下是不是用的同一个loop,不然白折腾。
我之前也踩过这个坑,现象跟你几乎一模一样,curl秒回但MCP一调就卡死。后来发现大概率不是Ollama本身的问题,而是FastMCP默认的stdio传输和Ollama的HTTP keep-alive凑一块儿容易出幺蛾子。你可以先看下服务端那边到底是卡在发请求前还是等响应时,加个日志打在调用Ollama前后,基本就能定位。另外Ollama默认并发是1,如果你MCP那边有多个工具调用排队,或者上一个连接没释放,很容易把后面全堵死,可以试试调OLLAMA_NUM_PARALLEL。还有一点,别只看超时时间,把MCP客户端的超时调大一点排除误判,有时候其实只是首token慢。异步改法要注意别在async函数里混用同步的requests,那样反而更糟。我当时最后是把Ollama请求单独抽出来用httpx异步跑,再配合keep-alive关掉,问题就没了。
Ollama默认keep-alive是5分钟,但MCP那边如果每次新建连接可能会等它冷启动,试试设OLLAMA_KEEP_ALIVE=-1常驻看看。