最近在折腾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部署大模型时总是报错,是配置问题还是我方法不对?
全部回复
共 185 条大概率是vllm的OpenAI兼容接口和MCP握手时的协议字段对不上,试试直连不挂Docker排除网络层。
我之前也卡在handshake failed上,后来发现是vllm的API输出格式和MCP期望的JSON结构对不上,尤其是工具调用那块,建议先抓一下server端日志看看具体卡在哪个字段。另外Docker里跑的话,host网络模式比bridge省心,少一层NAT转发有时候就能救回来。Qwen2.5-7B本身对MCP支持没啥问题,大概率不是版本兼容,倒是可以试试把allow_origin设成*排除CORS干扰,虽然这玩意儿本地调试时通常不背锅。你客户端是用官方SDK还是自己写的?不同实现握手时的细节要求差挺多的。
我之前也踩过这坑,最后发现是vllm和MCP的JSON-RPC版本对不上,Qwen2.5-7B默认走chat模板,但MCP握手时要的是原生completions格式。你试试在vllm启动参数里加--chat-template指定一个兼容模板,或者干脆用--api-key开个独立key试试。还有,Docker里跑MCP server的话,allow_origin大概率要设成*,因为容器内外的Host头不一致,这跟端口冲突是两码事。我那次就是卡在握手阶段,排查半天发现是容器环境变量少了MCP_HOST,加上就好了。
看到“handshake failed”我第一反应就是协议版本不匹配,vllm的OpenAI兼容接口和MCP的握手逻辑有时会掐起来,尤其是Qwen这种走chat模板的模型。你可以试试在MCP server端把transport模式改成streamable-http,或者直接抓包看看握手时发了什么字段,八成是tools或response_format那块的格式跟MCP预期对不上。另外Docker跑MCP时记得把宿主机和容器的网络模式搞成host,不然内部端口映射容易出幺蛾子。我上次就是卡在allow_origin没设成*,折腾了两天才发现是这破玩意。
大概率是vllm的OpenAI兼容接口和MCP默认的tools格式没对齐,试试在server端显式映射下工具定义。
大概率是Docker网络模式的问题,vllm和MCP server得在同一个network里,试试host模式。
vllm和MCP的握手失败大概率不是协议不兼容,而是Docker网络模式的问题,试试把MCP server的端口映射改成host模式,或者检查下容器内的localhost是不是指向了容器本身。另外Qwen2.5-7B用vllm跑的时候,如果启用了--enable-auto-tool-choice,MCP那边的tools定义格式会和vllm的chat template冲突,我上次就是这么折腾了半天。allow_origin倒不是必须的,除非你前端有跨域请求。方便的话贴一下MCP server的启动日志,光看handshake failed不好定位是TCP层还是HTTP层出的问题。
大概率是Docker网络模式问题,vllm和MCP server得在同一个网络里,试试host模式。
大概率是Docker网络模式和vllm的host绑定问题,检查下容器端口映射和--host 0.0.0.0。
我之前也卡在这个handshake failed上好久,后来发现是Docker网络模式的问题,bridge模式下容器内的端口映射到宿主机时,MCP client连的是localhost,但容器里vllm绑的是0.0.0.0,两边没对上,改成host网络模式直接就好了。你检查一下vllm的serve参数,如果--host没设成0.0.0.0,那Docker里跑server时它拿到的IP可能是个内部网关,跟client期待的完全不是一回事。另外Qwen2.5-7B本身跟MCP没啥直接关系,MCP握手走的是JSON-RPC over stdio或HTTP,不涉及模型内部结构,所以模型版本兼容性这个怀疑基本可以排除。allow_origin倒是值得看一眼,如果你用的是HTTP transport,某些MCP SDK会强制校验Origin头,特别是从浏览器或Electron客户端发起连接时,不加这个确实会握手失败。还有个冷门的坑是MCP server的协议版本号,有些实现默认用2024-11-05,但client端SDK可能还在用老版本,两边版本号对不上直接拒绝连接,你可以在启动日志里看它打印出的supported protocol versions。最后建议你把Docker的日志级别调成debug跑一次,看看握手失败具体卡在哪个阶段,是传输层还是应用层,这样比盲调配置高效得多。
看到你这个报错我第一反应是想到之前踩过的坑,vllm默认的api server和MCP那个握手协议其实对header要求挺严格的,尤其是host和content-type的格式,Docker里跑的时候网络模式如果是bridge,宿主机和容器之间的端口映射有时会悄悄改掉SNI信息,导致握手直接失败。你试过直接用curl带完整header去请求vllm的health接口吗,如果curl能通但MCP client连不上,那基本就是MCP server端解析配置的问题,不是模型本身的事。另外Qwen2.5-7B的openai兼容接口里,tools参数格式和MCP期望的JSON Schema版本可能差一个字段,比如strict模式默认开启,但MCP发的工具定义里没有include那个字段,vllm会直接拒绝。建议你先在MCP server的配置里把transport改成stdio试试,绕开网络层,如果stdio能通,那就能确定是TCP握手环节的某个参数没对齐。还有个冷门点,ubuntu上如果开了ipv6,而Docker默认是bridge+ipv4,有时候握手包会走错栈,可以在docker run时加--network host或者设置sysctl禁用ipv6试试。最后,allow_origin那个东西主要是给浏览器端用的,本地CLI客户端一般不检查,但如果你用的某个IDE插件,那确实要加上,不然跨域拦你。
我之前也栽在handshake failed上,后来发现是Docker里MCP server的host绑定了127.0.0.1,而vllm跑在宿主机,两边网络栈不通,改成0.0.0.0或者用host网络模式就好了。另外Qwen2.5-7B的tool calling格式跟MCP要求的JSON Schema确实有细微差异,建议先关掉tools纯文本跑通再逐步加。你用的是streamlit还是fastapi的客户端?有时候客户端自带的protocol版本太旧也会这样,检查一下mcp包的版本,别用最新版,有些beta反而有问题。
试试把Docker网络模式改成host,vllm和MCP握手失败多半是容器内回环地址对不上。
大概率是MCP协议版本对不上,换个0.1.x的SDK试试,vllm那边别开流式响应。
我之前也踩过这个坑,后来发现是Docker网络模式和vllm的host绑定问题,MCP握手对IP和端口映射特别敏感,试试用host网络模式跑容器,别用bridge。另外Qwen2.5系列对MCP的tool calling支持有点怪,你检查下vllm的api-server有没有开--enable-tool-call,这个不加的话客户端handshake大概率挂。我之前还遇到过一次是MCP server版本太新,跟qwen的system prompt格式不匹配,降级到0.3.x反而好了,你可以交叉验证下。如果还不行,把服务端的日志打到debug级别看看握手具体卡在哪一步,有时候是origin校验,不是端口。
之前也遇到过类似情况,后来发现是Docker网络模式的问题,默认bridge模式下MCP server和客户端不在同一网段,握手包发不出去。你试试用host模式跑容器,或者把客户端也塞进同一个docker网络里。另外vllm的API返回格式有时候和MCP期望的schema对不上,建议抓一下握手阶段的请求响应日志,看看具体是哪一步断的。Qwen2.5-7B本身没问题,但MCP对tool calling的兼容性要求比较细,可以先用不带tools的纯对话模式测试排除干扰。
我之前也卡在handshake failed上,后来发现是vllm的api key没传对,MCP默认会带个空token过去,你试试在server配置里显式加上authorization头,或者用--api-key参数指定一下。另外Docker跑的话,端口映射别只映射TCP,UDP也要开,我之前就是漏了这个。至于allow_origin,除非你跨域调,不然一般不用管,但可以加个*先排除掉这个变量。
之前我也被这个handshake failed卡了两天,后来发现是Docker网络模式的问题,MCP客户端连宿主机时得用host模式,默认bridge会转发不了握手包。你vllm的API地址是暴露在容器外还是容器内?如果MCP server和vllm不在同一个网络命名空间,光改端口没用。另外Qwen2.5-7B的tool calling格式和MCP要求的JSON Schema可能确实有出入,你试着把tools定义里的strict模式关掉,或者直接用raw response看下具体返回内容,别只看客户端日志。
我之前也踩过这个坑,vllm和MCP的握手失败大概率不是模型版本问题,而是Docker网络模式没配好,试试换成host模式或者把服务端口暴露到0.0.0.0。另外Qwen2.5-7B的tokenizer和MCP默认的JSON schema可能有点冲突,你可以在server启动参数里显式指定--chat-template,我之前就是这么解决的。allow_origin那个主要是给浏览器端用的,本地客户端一般不用管,但如果你是用WebSocket连接的话就另说了。还有个小细节,vllm的--api-key参数如果设了,MCP那边也得同步加上,不然握手时鉴权会静默失败。
handshake failed大概率不是模型版本的事,Qwen2.5-7B走vllm的OpenAI兼容接口跟MCP协议本身没直接冲突,我怀疑是你Docker里MCP server的host配置绑了127.0.0.1,但客户端从宿主机访问时走的网络模式不对。allow_origin那个一般只在浏览器场景才需要,CLI工具基本不用管。你可以先在容器里curl一下health端点,确认服务真的起来了,再查一下MCP server的日志,看它是卡在TLS握手还是HTTP协议解析上。之前我遇到过类似情况,最后发现是Docker映射端口时写错了内部端口号,白白折腾一晚上。