最近在折腾MCP(Model Context Protocol)框架,想给LLM加个文件系统工具。我用Python写了个简单的MCP服务器,挂载到本地目录,结果客户端一直报“Transport not ready”或者“通道未就绪”。我确认了stdio传输和JSON-RPC格式都没问题,也试了用官方的mcp-cli工具启动,但一调用工具就卡住。是不是我异步处理写得不对?还是说MCP服务器必须用asyncio的run()来启动?网上资料好少,求各位大佬指点一下,感谢!
MCP服务器调用报错“通道未就绪”,有大佬遇到过吗?
全部回复
共 149 条这个报错一般是服务器主循环提前退出了,客户端还在等握手响应。你检查下是不是在stdio的read循环外面写了await asyncio.sleep或者直接return了?MCP的stdio传输确实得用asyncio.run()把整个server跑起来,不然事件循环一关通道就废了。我之前也踩过这坑,后来换成官方Python SDK的Server类加stdio_server上下文管理器就正常了。你可以先用mcp-cli的--debug看下有没有收到initialize请求,能快速定位是握手阶段还是调用阶段挂的。
我之前也踩过这个坑,报“Transport not ready”大概率不是JSON-RPC格式的问题,而是服务器初始化握手没走完就被调用了。MCP的stdio模式对启动顺序挺敏感的,建议用官方Python SDK里的Server加上stdio_server上下文管理器来跑,别自己手写asyncio循环。另外确认下是不是在initialize响应返回前客户端就发了tools/call,那样肯定卡住。你可以先跑个最简echo工具排除业务逻辑干扰。
我之前也卡在这个报错上,后来发现是MCP服务器的stdout被日志污染了,JSON-RPC对输出流纯净度要求特别高,任何print都会让客户端解析失败。你可以先检查下是不是有调试信息混进去了,用logging输出到stderr试试。另外asyncio.run()启动确实更稳妥,官方示例基本都是这么写的,手动管理事件循环容易出问题。
是不是没等server初始化完就发请求了?我之前也卡这,加个await sleep就好了。
我之前也踩过这个坑,大概率是服务器进程还没完成初始化握手,客户端就急着调工具了。你可以先试试在启动后加个延迟,或者在initialize响应里确认capabilities正确返回。另外MCP的stdio传输对stdout污染特别敏感,任何print都会破坏JSON-RPC流,检查下有没有调试输出混进去了。异步那块倒不一定要用asyncio.run(),但事件循环得保证常驻,别让主线程提前退出。
我之前也卡在这,换成asyncio.run()启动就通了,你可以试试。
这个思路不错,收藏了。
学到了,感谢分享!
我之前也踩过这个坑,报“Transport not ready”大概率不是JSON-RPC格式的问题,而是服务器进程启动后stdin/stdout的握手时序没对上。MCP的stdio传输要求服务器在初始化阶段严格按协议先回initialize响应,如果你在异步里把读循环和工具注册混在一起,客户端发请求时服务器可能还没进入可读状态,就卡住了。官方mcp-cli一调用就挂,更像是事件循环被阻塞了,比如你在工具函数里用了同步IO或者time.sleep,整个loop就停了。建议先确认用的是asyncio.run()包住server的run协程,别用loop.run_forever那种老写法。另外可以加日志把收到的每一条原始消息打出来,看客户端到底有没有把请求写进stdin,很多时候是缓冲区没flush导致的假死。我当初把print换成sys.stderr输出日志才定位到问题,stdout被协议占用了不能随便打东西。你现在的工具函数是纯async的吗,里面有没有混同步调用?