最近在折腾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部署大模型时总是报错,是配置问题还是我方法不对?
全部回复
共 186 条遇到过类似的,当时卡了我一整天,最后发现是vllm的API格式和MCP默认的tool calling不匹配,得在MCP server里手动指定openai兼容接口。你可以先curl一下vllm的/v1/models看看返回结构,再对照MCP的handshake逻辑排查。另外Docker跑MCP时,容器内的localhost和宿主机不通也可能导致这个报错,试试network_mode: host。
我之前也卡在这玩意儿上挺久,handshake failed大概率不是模型或MCP版本的问题,而是Docker网络模式和vllm监听地址的锅。你试试把MCP server的host设成0.0.0.0,然后客户端连接时用宿主机IP而不是localhost,因为容器里访问宿主机的vllm服务得用host.docker.internal或者直接桥接模式。另外allow_origin这个确实得配,但主要是浏览器场景,纯客户端连接一般不用,不过你既然提了GitHub issue,建议翻一下vllm的--api-key参数,有时候MCP握手会带鉴权头,而vllm默认不开认证就直接拒绝。还有个小坑,Qwen2.5-7B的tokenizer会带特殊token,MCP的initialize请求里如果带了过长system prompt,可能触发vllm的max_model_len限制,虽然你调了context_window但未必同步到了vllm的启动参数上,最好把--max-model-len也显式设一下。我上次是换用sse传输模式绕过去的,streamable http在docker里握手老超时,你可以临时切到sse试试稳定性。要是还不行,抓包看看握手响应体的具体错误字段,vllm一般会返回详细reason,别光看客户端日志。
遇到handshake failed大概率不是模型本身的问题,vllm的OpenAI兼容接口跟MCP协议栈之间经常卡在HTTP头或子协议协商上。你试试在MCP server的启动参数里显式声明--transport streamable-http,同时检查Docker映射端口时有没有把TCP和UDP搞混,我之前就被这坑过一次。另外Qwen2.5-7B用vllm跑的话,建议把--enable-auto-tool-choice关掉,MCP自己的tool schema跟vllm的tool calling有时候会打架。allow_origin一般不用设,除非你前端跨域了,但报错信息里没提CORS的话就先别管。要是还不行,直接抓包看握手请求返回的response body,比猜配置快得多。
这报错我熟,当时用vllm起Qwen也踩过这坑。你检查下MCP server容器里有没有把host设成0.0.0.0,Docker默认网络模式下外部访问经常卡在这。另外vllm的API返回格式和MCP期望的OpenAI兼容接口可能有细微差别,建议先裸curl一下MCP的endpoint看响应结构对不对,不行就换TGI试试。
我之前也踩过这个坑,折腾了两天才发现是vllm的API和MCP握手时默认用的endpoint不匹配,Qwen2.5-7B得在server启动参数里显式指定chat template,不然容易在协议协商阶段直接挂掉。你试试把Docker的network模式改成host,绕开端口映射那层,有时候vllm监听的是内网IP就会出这种诡异问题。另外allow_origin一般不影响本地连接,倒是检查下MCP server的日志里有没有cors或者websocket相关的报错,那个比handshake错误更有指向性。
vllm serve加个--enable-auto-tool-choice试试,之前我卡这好久,Qwen的tool calling格式和MCP默认的不太一样。
我之前也遇到过一模一样的handshake failed,折腾了两天才发现是vllm和MCP的HTTP/2协商问题,跟context_window真没啥关系。你试试在MCP server的启动参数里显式加上--protocol-version,或者干脆把Docker的网络模式改成host模式,有时候端口映射会莫名丢header。另外你检查下Qwen2.5-7B的模板格式,MCP对system prompt的编码方式挺敏感,尤其带tools定义的时候。我之前升级到最新的vllm版本顺手解决了,建议你也先排除这个变量。
遇到这种handshake failed,十有八九不是协议版本问题,vllm和MCP都更新挺勤的,反而容易出兼容性坑。我之前用Docker跑MCP的时候,发现容器内的localhost跟宿主机不通,你得检查一下server绑定的地址是不是0.0.0.0,还有客户端连的是不是容器映射出来的端口。另外Qwen2.5-7B的openai兼容接口有时候会吞掉MCP需要的特定header,你可以试试在vllm启动参数里加--api-key随便设一个,绕过某些校验逻辑。如果还不行,抓个包看看握手时返回的具体错误信息,比瞎调参数靠谱多了。
看到这个报错我第一反应是Docker网络模式的问题,vllm和MCP server如果不在同一个network里,握手阶段经常会出现这种诡异失败,你试试用host模式或者docker compose把两个服务放一起。另外Qwen2.5-7B的chat模板和MCP的tool calling格式确实有已知兼容性问题,特别是当模型返回的function call参数不是严格JSON时,协议解析会直接崩,你可以在server端加个日志看看实际收到的模型输出是什么。allow_origin这个一般只在浏览器端用到,本地客户端应该不影响,但如果你用的是SSE传输,有些实现会检查Origin头,建议在配置里直接设成*先排除掉这个变量。还有个小坑,vllm的api server默认不暴露tool_choice参数,MCP的官方python sdk在初始化时会去探测这个能力,探测失败就报handshake,你需要手动在启动命令里加--enable-auto-tool-choice。最后忍不住问一句,你Docker镜像里的MCP SDK版本是不是和客户端那边的完全一致?版本错位也会导致握手时能力协商失败,我上周刚被这个坑过。
我之前也踩过这个坑,折腾了两天才发现根本不是协议版本的问题。你vllm暴露的端口是8000吧,但MCP server默认连的是8080,这俩对不上就会报handshake failed,你在docker映射端口的时候检查一下环境变量里有没有显式指定MCP_ENDPOINT。另外allow_origin这个确实要设,尤其是从浏览器或者前端工具连的时候,不设的话CORS直接挡掉,但如果你是用Python SDK连的话倒不是必须的。还有个小细节,Qwen2.5-7B的chat template和MCP要求的tool calling格式不完全匹配,你需要在vllm启动参数里加--enable-auto-tool-choice,不然模型根本不认你发的工具调用,但报错可能不是handshake而是后续的tool call error。建议你先用mcp的官方调试客户端连一下,把日志级别调到debug,看具体卡在哪个阶段,是TLS握手还是JSON-RPC初始化。我那次最后发现是docker网络模式用了bridge,容器里访问宿主机vllm要用host.docker.internal而不是localhost,这种隐藏前提真的让人头大。
我之前也踩过这个坑,后来发现是vllm的API返回格式和MCP默认的JSON-RPC解析对不上,尤其是Qwen2.5这种带tool_calls字段的模型,得在server端手动映射一下。你试试把Docker里的MCP server日志打出来看下具体是握手哪一步断的,是HTTP头不对还是协议版本协商失败。另外allow_origin我这边没设也能跑通,但如果是跨域请求还得检查下Docker的网络模式,host和bridge模式对端口绑定行为有影响。我最后是换了MCP的Python SDK版本才解决,建议你也试试最新版。
大概率是Docker网络模式问题,试试host模式或者检查下vllm的API地址是不是容器内访问不到宿主机。
我之前也卡在这,查了下发现是Docker网络模式问题,改成host模式再配下allow_origin就好了。
这个报错我上周刚踩过,vllm默认的api server和MCP的握手格式其实不兼容,得用mcp适配层转一下。另外Docker跑的时候记得把host.docker.internal映射好,不然客户端从宿主机连进去容易握手失败。你可以先试试不用Docker直接裸跑MCP server,排除网络问题再折腾配置。如果还不行,看看vllm日志里有没有CORS相关的警告,那个allow_origin确实要显式配一下。
我之前也卡在这,Docker里跑MCP记得把host网络模式打开,不然握手必失败。
我之前也卡在handshake failed这个错误上好几天,最后发现问题根本不在MCP配置上,而是vllm的API输出格式和MCP期望的JSON-RPC结构对不上。你检查过vllm的response里有没有带额外的meta字段吗?Qwen2.5-7B的chat template有时候会往返回里塞usage信息,MCP的握手阶段对消息边界特别敏感,多一个字段都可能直接判定失败。另外Docker网络模式也得注意,如果MCP server是bridge模式而客户端从宿主机连,那别用localhost,得用容器IP或者配host.docker.internal,这个坑很多人踩。allow_origin那个我倒觉得不是关键,除非你开了浏览器端调试。还有个偏门思路,试试把MCP协议版本锁定在2024-11-05,新版本对tool schema校验严格很多,vllm动态生成的tools定义经常有类型不匹配。最后建议你开debug日志对比一下客户端发出的initialize请求和server端收到的原始字节流,我之前就是这么发现vllm莫名给字符串加了BOM头的。
我之前也卡在这过,后来发现是Docker网络模式的问题,默认bridge模式下vllm和MCP server的通信会走NAT,有时候握手包就被丢了。你试试改成host模式,或者让MCP server直接连宿主机IP而不是localhost。另外Qwen2.5-7B的chat模板和MCP的tool calling格式可能不匹配,vllm那边要确认下--enable-auto-tool-choice有没有开,不然协议版本对不上也会报这个错。allow_origin倒不是必须的,除非你前端有跨域请求。
还有个小坑,你检查下Docker里MCP server的版本,0.9和0.10对初始化握手要求不一样,旧版可能不兼容新vllm的OAuth流程。我上次就是升了下vllm到0.8.x之后,MCP server必须跟着更新才行。你先跑个最简单的echo server试试,排除掉模型本身的问题,再一步步加tools和context_window,这样能缩小排查范围。
我之前也踩过这个坑,折腾了两天才发现是vllm的api_key校验和MCP的握手逻辑对不上,你试试在Docker里把环境变量VLLM_API_KEY设为任意非空值,然后MCP server的配置里也加上对应的Authorization头,很多报错都是这类隐性的鉴权问题。另外Qwen2.5-7B的chat模板和MCP的工具调用格式确实有兼容性问题,建议先用MCP官方测试模型跑通再换,不然排查起来很乱。你检查过Docker和宿主机的网络模式吗?bridge和host模式下端口映射行为不一样,也可能导致握手包被丢弃。
vllm和MCP握手失败大概率是协议版本不匹配,试试把vllm的api-server升级到最新版。
这报错八成是Docker网络模式搞的鬼,试试host模式或者检查下容器内的监听地址。
我之前也踩过这个坑,折腾两天最后发现是Docker网络模式的问题。你试试把MCP server跑在host网络下,别用bridge,vllm和Docker容器之间的localhost互通经常出这种幺蛾子。另外Qwen2.5-7B的chat模板和MCP默认的tool calling格式确实有兼容性问题,建议先换个支持function calling的模型验证下,比如Qwen2.5-72B或者Llama3.1,排除模型本身的原因。allow_origin一般不用动,除非你前端跨域,不然报错不会指向handshake。还有个思路是抓包看下握手阶段具体哪个字段没对上,错误信息里往往藏着真实原因。