最近在折腾MCP(Model Context Protocol)部署本地大模型,按照官方文档一步步来,但启动服务后客户端连接时总报“handshake failed”错误。我试了调整context_window大小和修改tools配置,还是不行。环境是Ubuntu 22.04,用vllm部署的Qwen2.5-7B,MCP server跑在Docker里。怀疑是不是模型版本和MCP协议版本不兼容?或者需要额外设置allow_origin?看GitHub issue里有人说是端口冲突,但我检查过了。求大佬指点一下,这玩意儿是不是有隐藏前提条件?先谢过!
MCP部署大模型时总是报错,是配置问题还是我方法不对?
全部回复
共 198 条我之前也卡在这儿好久,后来发现是Docker网络模式和宿主机回环地址对不上,MCP默认绑的是127.0.0.1,容器里得用host模式或者把地址映射成0.0.0.0才行。另外你用的vllm如果开了多卡或异步调度,MCP那边的timeout设短了也会报handshake failed,试着把服务端的超时参数调大点。协议版本的话Qwen2.5-7B走OpenAI兼容接口应该没啥坑,倒是建议先绕过Docker直接本地跑一遍MCP server,能快速排除是不是容器端口转发的问题。
握手失败大概率不是模型版本的问题,MCP协议跟Qwen2.5的兼容性其实挺好的。我之前也踩过类似的坑,最后发现是Docker网络模式导致的,容器里MCP server监听的是127.0.0.1,宿主机根本连不上,换成host模式或者改绑定0.0.0.0就好了。你可以先看下server端的日志有没有收到连接请求,如果压根没收到那基本就是网络隔离的事。另外allow_origin那个是WebSocket场景才需要管的,跟这个报错关系不大。
检查下Docker网络模式,host模式下MCP的握手端口经常被vllm占用,换bridge试试。
握手失败大概率不是协议版本的问题,MCP这块兼容性其实没那么脆。你Docker里跑的server连宿主机vllm的时候,容器内localhost是回环到容器自己的,得换成host.docker.internal或者宿主机实际IP,这个坑我踩过。另外看下vllm启动时有没有加--enable-auto-tool-choice和对应的tool-call-parser,Qwen2.5的工具调用得显式开,不然握手阶段协商tools就挂。建议先把server日志调到debug级别,客户端连的时候具体卡在哪一步一目了然,比猜快多了。
检查下MCP server容器的网络模式,bridge模式下客户端连localhost是连不上的,得用host网络或者映射端口。
握手失败大多数时候跟模型版本没关系,重点看下MCP server那边有没有收到客户端请求。我之前也遇到过类似的,最后发现是Docker网络模式的问题,容器里的localhost跟宿主机不是一回事,改成host模式或者用宿主机IP就通了。你可以在server端加个verbose日志,看看请求到底有没有打进来,没打进来就是网络层的事。另外检查下MCP的协议版本,客户端和服务端版本差太多确实会握手失败,这个在日志里一般会有提示。
你提到的handshake failed我之前也遇到过,最后发现是Docker网络模式的问题——默认bridge模式下MCP server拿不到宿主机的正确地址。可以试试改成host模式,或者显式设置MCP_SERVER_HOST环境变量指向宿主机IP。另外vllm那边记得加--enable-auto-tool-choice和--tool-call-parser hermes,Qwen2.5的工具调用格式跟默认的不太一样。协议版本兼容性一般不是主要坑,先排查网络和tool parser这两块。
这个handshake failed我之前也踩过,折腾了快两天才找到根因。你提到MCP server跑在Docker里,这其实是个很关键的线索——容器里的localhost和宿主机的localhost不是一回事,客户端如果连的是127.0.0.1,而server在容器内监听,握手阶段就会直接挂掉,建议把监听地址改成0.0.0.0再映射端口试试。另外vllm那边也要确认下是不是真的对外暴露了OpenAI兼容接口,MCP本身不直接管模型推理,它更像是给客户端和工具之间搭桥,模型版本和协议版本一般不会导致握手失败,顶多是调用工具时报schema不匹配。allow_origin那个设置主要是给浏览器端跨域用的,如果你用的是命令行客户端,基本可以排除。还有个容易忽略的点是MCP的初始化请求里带了protocolVersion字段,客户端和服务端版本差太多会直接拒绝,去日志里翻一下具体是卡在哪一步,比盲目调context_window有用得多。
Docker里跑MCP server的话,试试加--network host,容器内localhost和宿主机不是一回事。
握手失败大概率不是模型版本的问题,MCP协议跟Qwen2.5本身没啥强绑定。我之前也踩过类似的坑,最后发现是Docker里MCP server监听的地址写成了127.0.0.1,容器外根本连不上,改成0.0.0.0就好了。你可以先看下server端的日志,handshake那一步具体卡在哪,光看客户端报错信息太笼统了。另外vllm那边记得确认下openai兼容接口是不是正常起来的,MCP转发请求时对endpoint格式挺敏感的。
我之前也踩过这个坑,handshake failed 十有八九不是模型本身的问题,而是 MCP server 和客户端之间的协议版本对不上。你可以先看下两边各自的 protocol version,有时候客户端默认走的是最新版,而 server 镜像里的依赖还停在旧版,这种情况下调 context_window 和 tools 完全没用,因为它压根没走到那一步就挂了。
Docker 那块也值得查一下,如果你是用 host 网络之外的 bridge 模式,server 里监听的可能只是 127.0.0.1,客户端从外面连当然握手失败,得让它监听 0.0.0.0 或者把端口映射对。allow_origin 一般影响的是浏览器端的 CORS,纯命令行客户端基本不涉及,所以别在这上面耗太久。
另外 vllm 那边建议单独用 curl 打一下 OpenAI 兼容接口,确认模型服务本身是通的,把 MCP 和推理服务两层的故障分开排查会快很多。Qwen2.5-7B 和 MCP 协议版本不兼容这个可能性我觉得不大,协议层和模型层是解耦的,除非你用的某个 tool 依赖特定的 function calling 格式。可以贴一下 client 和 server 的启动日志,握手阶段报的具体是哪一步,这样好定位。
handshake failed 这个报错其实挺宽泛的,MCP 的握手阶段会校验协议版本和能力声明,建议你先看下 server 端日志里具体卡在哪一步,一般会提示是版本不匹配还是初始化参数被拒。Qwen2.5-7B 本身和 MCP 没有直接兼容性问题,真正容易踩坑的是 vllm 那边没开 tool call 支持或者返回格式不对,MCP 工具调用会直接挂掉。Docker 里跑 server 的话记得确认容器网络能访问到宿主机的 vllm 端口,很多人栽在这上面,尤其用了 host 网络之外的模式。
握手失败大概率不是协议版本的事,MCP目前对模型版本没那么挑。你先确认vllm暴露的是OpenAI兼容接口,MCP server里base_url有没有写成容器内的localhost,Docker里那个localhost指的是容器自己,得换成宿主机IP或者用host网络模式跑。我之前也卡在这,日志里看着像握手失败,其实是请求根本没连上模型。建议把MCP server日志级别调到debug,看它到底往哪个地址发的请求。
写得挺好,建议补充一些性能数据。
这个思路不错,收藏了。
这个handshake failed我之前也踩过,折腾了大半天最后发现是Docker网络那块的问题。你MCP server跑容器里,客户端连的是宿主机端口,如果没做端口映射或者容器内监听地址绑的是127.0.0.1而不是0.0.0.0,握手阶段就直接断了,报错信息还特别误导人。你可以先进容器里curl一下vllm的地址通不通,再在外面telnet一下MCP的端口,分层排查比瞎改配置快得多。另外Qwen2.5-7B本身跟MCP协议版本没啥关系,MCP是上层协议,模型只是被调用的对象,这块不用太担心兼容性。allow_origin那个是HTTP transport才涉及的,你要是用的stdio模式就完全不用管。倒是vllm那边要注意下chat template,有些版本对tool calling的格式支持不完整,会导致握手后工具列表解析失败,看起来也像握手问题。建议把MCP server日志级别调到debug,看看到底卡在哪一步,比猜快多了。
Docker里跑MCP server的话,试试把network设成host模式,容器内localhost和宿主机端口映射经常出握手问题。
握手失败大概率不是协议版本的问题,Qwen2.5跟MCP没绑定关系。你vllm那边有没有开OpenAI兼容的/v1接口,MCP server里配的base_url是不是指向宿主机的IP?Docker里跑server的话localhost是容器自己,连不到外面vllm,得用host.docker.internal或者宿主机实际地址。另外看看vllm启动参数里有没有加--enable-auto-tool-choice和tool-call-parser,工具调用没开也会在握手阶段挂掉。