最近在折腾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服务器连本地大模型,工具调用总超时怎么排查?
全部回复
共 45 条大概率就是本地模型推理太慢卡了MCP的响应窗口,之前我接llama3也踩过这坑,把stdio传输改成sse或者调大client的timeout参数(比如到120秒)能缓解不少。另外你确认下server端有没有把工具执行和模型响应分开线程处理,我遇到过同步阻塞把事件循环卡死的情况,日志看着像超时实际是死锁。还有个思路是先在本地直接跑脚本测工具函数本身耗时多少,排除掉模型生成那段的干扰。要是换小模型比如Qwen2.5-3B还超时,那多半就是server实现问题了。
我最近也踩过类似的坑,MCP这层stdio的坑其实挺多的。你说模型端已经吐出了JSON参数但server没收到,这个描述很关键——大概率不是timeout太保守的问题,而是stdio的缓冲和换行处理上出了岔子。Python里如果用的是subprocess或者sys.stdin.read()阻塞读,很容易因为没读到明确的换行或EOF就卡死,Claude Desktop那边等不到完整响应自然就超时了。而且Qwen2.5-7B本地跑,首token延迟本身就比GPT-4o mini高不少,如果server在等模型完整输出后才一次性回传,那整体耗时很容易顶到MCP默认的60秒上限。你可以先试试在server端把每次读到的原始字节打出来,确认到底是没收到还是收到了没及时flush。另外stdio模式下stdout一定要严格只输出协议要求的JSON-RPC消息,任何print调试都会污染通道导致解析失败。我后来换成用asyncio配合明确的readline循环,再把工具执行放到线程池里避免阻塞事件循环,问题就没了。
你这情况大概率不是timeout设太保守,而是本地模型推理把整个调用链卡住了。Claude Desktop那边等MCP响应是有默认超时的,7B模型在本地跑,如果没做量化或者显存不够,生成那段JSON参数可能就要十几秒,再加上你server里如果用的是同步的sqlite3和阻塞式read循环,事件循环直接被堵死,回传自然更慢。GPT-4o mini没问题恰恰说明协议和工具定义是对的,差别就在推理延迟上。建议先单独压测一下模型从收到prompt到吐完JSON要多久,再在MCP server里把工具执行和模型调用拆到不同线程或async里去,别让stdio的读写和推理串在一条线上。另外可以看看是不是每次调用都重新加载模型或者重复初始化,那种开销比推理本身还致命。
同步阻塞事件循环的可能性更大,本地模型再慢也不至于每次都卡死,先查查server里是不是有同步IO没扔线程池。
本地模型首token延迟高,MCP的stdio读写又容易阻塞,建议先看下server是不是同步recv卡住了。