最近在折腾MCP(Model Context Protocol),想把本地部署的Qwen2.5-7B通过MCP服务器接进Claude Desktop用。参考了几个开源项目,用Python写了简单的stdio服务,工具就一个查询本地SQLite的function。现在问题是:Claude能识别到工具,但每次调用都卡在“等待MCP响应”然后直接超时。日志显示模型端其实已经生成了JSON参数,但MCP server那边好像没收到或者回传太慢。我试过把模型换成GPT-4omini就没问题,所以怀疑是本地模型推理速度导致MCP的timeout设置太保守?还是说我的server实现里同步阻塞了事件循环?有没有老哥遇到过类似情况,一般怎么调超时参数或者改异步啊?
MCP服务器连本地大模型,工具调用总超时怎么排查?
全部回复
共 31 条这个方向我前段时间也踩过类似的坑,先说说我的看法。你换GPT-4omini没问题,基本就能锁定是本地模型响应速度的问题,MCP的timeout默认值一般就10秒,Qwen2.5-7B在CPU或者低端GPU上跑个带工具的推理,稍微长点的上下文很容易超。但你也别急着改timeout,我建议先单独跑一下你的stdio server,用命令行直接传一个JSON-RPC请求进去,看看从接收到返回完整响应到底花了多久,这样能区分是模型本身慢还是你的server处理逻辑里有阻塞。另外你提到的同步阻塞确实是个隐患,尤其是SQLite查询如果数据量大,或者你用了同步requests库,在asyncio循环里会卡住整个事件线程,MCP的stdio传输是按消息边界读的,一旦卡住客户端就以为你超时了。我之前是直接把工具调用放到线程池里,用run_in_executor包一层,再把timeout调到30秒,问题就好了很多。还有个细节,Claude Desktop那边有时候对工具响应的schema校验很严格,你确认下返回的content结构是不是MCP规定的数组格式,有时候模型生成了参数但server解析失败也会表现为“没收到”而不是报错。建议你先把server日志里的接收时间戳和模型生成时间戳打出来,对比一下,基本就能定位是卡在哪一段了。
大概率就是本地模型推理太慢卡住了MCP的默认超时,Qwen2.5-7B在CPU或小显存上生成JSON有时要好几秒,而stdio的timeout一般就10秒左右。你可以试试把MCP配置里的timeout调大到60秒,或者检查下是不是server端用了同步sqlite查询,那玩意儿在事件循环里跑确实会堵。我之前用Ollama接MCP也踩过这坑,最后是改成异步加超时重试才稳的。你日志里能看出server端有没有收到请求吗?如果连日志都没打,那可能问题出在stdin/stdout的协议解析上。
大概率是本地模型推理太慢把stdio的响应拖超时了,先调大MCP的timeout试试。
另外检查下server里有没有同步阻塞,换个异步框架可能更稳。
大概率就是同步阻塞的事,stdio模式下Claude Desktop那边默认超时很短,Qwen2.5-7B本地推理动不动就几秒,工具调用整个链路算下来肯定超。你可以先把server里查询SQLite的代码改成异步,或者干脆起个线程池去跑,别堵在event loop上。另外也可以试试在MCP client配置里把timeout调大,比如从默认的5秒改成30秒,我之前接本地模型就是这么干的。如果你用的是官方的mcp-python-sdk,记得看下transport的读写超时参数,有时候不是模型慢,是stdio管道读超时太短了。
大概率就是本地模型推理卡了stdio的响应窗口,Qwen2.5-7B在CPU上生成JSON参数可能得花好几秒,而MCP默认timeout一般就5到10秒。你试着把MCP的timeout调大到30秒,或者用异步方式重写server的call_tool,别让数据库查询阻塞事件循环。另外记得检查下Claude Desktop的MCP配置里有没有单独的请求超时参数,有时候是那层限制住了。我之前接本地模型也遇到过类似情况,把tool函数改成异步加个超时重试逻辑就好多了。
大概率就是本地模型推理太慢把timeout拖爆了,Qwen2.5-7B跑CPU或小显存上单次推理得几秒,MCP那边默认等待时间根本扛不住。你可以先试试把MCP客户端(比如Claude Desktop)的请求超时参数调大到30秒以上,再看日志确认server有没有收到JSON。另外你那个sync阻塞的怀疑也靠谱,如果server里用了requests或者直接sleep,事件循环确实会被卡住,换成async或者把工具调用丢到线程池能改善不少。还有个笨办法,用curl手动模拟MCP请求测一下单次往返耗时,能直接定位是网络层还是模型层的问题。
这问题我踩过一样的坑,大概率不是timeout的锅,本地7B模型生成JSON再慢也就几秒,你先把MCP那边的超时时间打印出来看看,或者直接抓包确认server有没有收到请求。我之前用FastAPI写stdio服务时就是忘了把工具调用丢进线程池,同步阻塞直接把事件循环卡死了,换成async或者加个run_in_executor就正常了。另外Qwen2.5-7B的JSON输出格式偶尔会带多余换行符,记得在server端做个容错解析,不然也可能导致回传异常。
大概率就是本地模型推理太慢卡了MCP的默认超时,GPT-4omini快所以没问题。你可以先试试把MCP客户端那边的timeout调大,比如改成60秒,看能不能过。另外你那个stdio服务如果是单线程同步处理请求,模型生成期间整个事件循环就堵死了,建议改成异步或者把工具调用放到线程池里跑。之前我也遇到过类似问题,调大超时加异步基本能解决。
大概率就是本地模型推理太慢把MCP的默认超时给拖爆了,Qwen2.5-7B在CPU上跑个简单查询也得几秒,GPT-4omini那边几十毫秒就回来了,这差距太大了。你可以先试试把MCP客户端那边的timeout参数调大,比如从5秒改成30秒,看能不能过。另外你写的stdio服务如果用了同步的sqlite查询,确实会卡住事件循环,建议把查询放到线程池里跑,或者直接改成异步,不然即使不超时也会显得很“呆”。我之前也踩过类似的坑,最后是直接在server端加了个简单的打印日志,看请求到底有没有进来,比瞎猜强多了。
大概率就是超时设置的问题,本地7B模型生成JSON那几步得几秒到十几秒,MCP默认的timeout可能就5秒,肯定不够用。你可以在server端把读取stdin的超时调大,或者客户端那边手动改下工具调用的等待时间,我之前用Ollama接MCP也卡过,改成30秒就稳了。另外你那个SQLite查询如果是同步的,最好包个asyncio.to_thread,不然确实会堵住事件循环,跟模型推理慢叠加起来更明显。可以先加个日志看下server到底有没有收到请求,区分是传输断了还是单纯慢。
八成是本地模型推理卡了stdio的同步阻塞,试试把MCP超时调大到60秒,或者换异步框架。
大概率就是本地推理太慢把MCP的默认超时给拖爆了,Qwen2.5-7B在CPU上生成那几KB的JSON参数都得几秒,而Claude Desktop那边等MCP响应的窗口可能就两三秒。你可以先试试把MCP配置里的timeout参数调大到30秒,或者改用异步的FastMCP重写下server,别用同步的input()阻塞。另外也可以把模型换成Qwen2.5-3B或者量化版本,速度差好几倍,工具调用这种简单任务够用了。我之前也踩过这个坑,最后是同时调大timeout和换小模型才稳的。
大概率就是本地模型推理太慢把MCP的默认超时给卡爆了,Qwen2.5-7B在CPU上跑一个工具调用往往要好几秒,而stdio的timeout通常只有几秒。你可以试着在server启动时手动把超时参数调大,比如设成60秒,再观察下日志里有没有收到client发来的JSON-RPC消息。另外你那个SQLite查询如果是同步的,最好丢进asyncio.to_thread里跑,不然确实会卡住整个事件循环,导致回传延迟。我之前也遇到过类似情况,后来把模型换成量化版+调高并发才稳定下来。
八成是同步阻塞,把SQLite查询扔线程池里,再调大stdio超时试试。
大概率是本地模型推理太慢把MCP默认超时拖爆了,试试把timeout调到60秒以上。另外检查下server里有没有同步阻塞,开个线程池处理工具调用更稳。
八成是本地模型推理太慢拖垮了stdio的同步响应,试试把MCP的timeout调大点,或者换成异步处理看看。
大概率就是推理速度撞上超时了,Qwen2.5-7B在本地跑一次工具调用可能要好几秒,而MCP默认的响应窗口往往就设得比较短。你可以先试试把客户端那边的timeout参数调大,比如直接拉到30秒,看还会不会断。另外检查下你的stdio服务有没有在收到请求后立刻返回一个ack,不然Claude那边干等,容易误判成超时。要是改完还不行,就得看下server端是不是用了同步的sqlite查询,卡住了事件循环,可以试着把查询丢到线程池里跑。
大概率是Qwen推理太慢把超时拖爆了,先把MCP的timeout调到60秒试试。另外检查下server端有没有用asyncio.to_thread,别让查询阻塞了事件循环。
我猜你八成是踩了stdio同步阻塞的坑,因为Qwen2.5-7B这种本地模型推理速度本来就慢,如果server端是同步处理请求,那Claude Desktop那边的默认超时(通常就10秒)肯定不够用。我自己之前用ollama接MCP也遇到过类似情况,后来把stdio改成异步模式,并且把tool call的响应拆成两个阶段——先立刻返回“已收到参数”,再后台慢慢执行SQLite查询,超时问题就缓解了很多。不过你提到GPT-4omini没问题,这确实能说明模型推理延迟是主因,但也不排除MCP客户端对本地模型的响应头解析有额外开销。你可以先试试把MCP server的日志打到文件里,确认请求到底有没有到达server端,如果压根没到,那就不是超时设置的问题,而是stdio管道的数据传输方式不兼容。另外,检查一下Qwen的JSON生成是否严格符合MCP要求的格式,有时候模型会多输出一些markdown代码块标记,导致server解析失败直接挂起。如果这些都排除了,我建议你直接手动用Python脚本模拟MCP client调一次你的server,看单次调用要多久,如果本身就超过5秒,那Claude Desktop超时几乎是必然的,这时候就得考虑换更快的量化模型或者把SQLite查询改成异步线程了。
大概率就是两个问题叠一起了。Qwen2.5-7B本地推理速度本来就慢,MCP默认超时一般也就10秒左右,你GPT-4omini能过不代表本地模型能过。建议先直接测一下纯模型生成那个JSON参数要多久,超过5秒就得调大超时。另外你那个stdio服务如果是同步写的,模型推理期间整个事件循环卡住,回传就必然延迟,可以试试把工具调用丢进线程池,或者干脆用async改造一下。
我之前也踩过类似的坑,最后是改成了先返回一个“处理中”的响应,再异步推结果,虽然麻烦点但至少不超时。你先在server端加个日志,看看是压根没收到请求,还是收到了但卡在SQLite查询上,这俩排查方向完全不一样。