最近在折腾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服务器连本地大模型,工具调用总超时怎么排查?
全部回复
共 51 条大概率就是本地模型推理太慢卡了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卡住了。
我之前也踩过类似的坑,现象几乎一模一样,最后发现根本不是timeout数值的问题。你日志里模型端JSON已经出来了,说明卡点大概率在MCP server的stdio读写或者事件循环上,同步阻塞的可能性挺大的。Claude Desktop对stdio的响应是有隐含时序要求的,如果你在tool handler里同步跑SQLite查询还顺带打印了什么,很容易把stdout搞脏或者堵住,MCP那边就一直等不到完整响应。换成GPT-4o mini没事,我猜是因为它返回更快,恰好在你本地那套阻塞逻辑还没彻底卡死之前就糊弄过去了,属于掩盖问题而不是解决问题。建议你先在server里把handler改成async,SQLite用线程池或者aiosqlite跑,然后单独写个不经过Claude的测试脚本直接喂JSON-RPC请求,看回包延迟到底出在哪一段。另外Qwen2.5-7B本地推理如果和MCP server抢同一个进程或者GPU,也会让响应变慢,最好把模型服务和MCP server彻底分开部署。timeout可以适当调大当兜底,但别把它当主要修复手段,不然换个工具调用还是会炸。
你试试把MCP server改成async的,本地模型推理慢,同步阻塞事件循环基本必超时。
这个问题其实挺典型的,我也踩过类似的坑。你说GPT-4o mini正常,那基本能排除MCP server协议本身写错了,方向应该还是本地模型推理链路。Qwen2.5-7B在本地跑的时候,首token延迟可能就一两秒,加上生成完整JSON参数,如果工具schema稍微复杂点,三四秒很正常,而Claude Desktop那边默认的MCP超时可能就卡在某个阈值上。另外你提到用stdio,Python里如果是同步阻塞地等模型输出再写stdout,确实容易把事件循环堵死,尤其你还在同一个进程里做推理和MCP通信。建议先把MCP server的日志级别拉满,确认到底是没有收到请求,还是收到了但返回写不出去。可以试着把模型推理单独拆到一个子进程或异步任务里,MCP server只负责转发,别让它等模型。还有个偏方是用一个mock工具先测,如果mock秒回不超时,那就铁定是推理延迟的锅。
之前也踩过这个坑,大概率是同步阻塞搞的鬼。MCP server如果用同步sqlite3查询,Claude那边等不到响应就直接掐了,跟模型推理速度关系不大,毕竟GPT-4o mini换上去没问题说明协议链路本身是通的。建议换成aiosqlite或者把查询丢线程池里跑,另外把MCP的timeout参数调大试试,7B模型首token延迟确实容易顶到默认阈值。日志里能看到JSON生成但server没收到,也可能是stdio缓冲没flush,加个显式flush看看。
我之前也踩过类似的坑,大概率不是timeout设太短的问题。本地7B模型首token延迟本来就高,但你说模型端已经吐出JSON了,那更像是stdio pipe那边卡住了。检查下你的server是不是用了同步的sqlite3查询堵住了stdin读取循环,或者print之后没flush stdout。另外Claude Desktop对MCP的响应等待确实比想象的短,建议先把sqlite操作丢到线程池里试试看。
同步阻塞事件循环的可能性更大,先查查server里有没有time.sleep或者同步IO卡住了。