最近在尝试把公司内部的一个文档助手用 MCP 协议包装成服务,部署到 K8s 集群上。本地用 Python 的 mcp 客户端测试没问题,但一上生产,客户端(用的官方 SDK)就频繁报连接超时,偶尔能连上也很快断掉。我检查了服务端日志,发现它明明在监听端口,也没有明显报错。怀疑是不是 MCP 的 heartbeat 机制在生产环境网络波动下不够稳定,或者我的 ServerCapabilities 配置有问题?有没有大佬遇到过类似情况,求指点一下排查思路或者调优经验。
MCP 服务部署到生产环境后,客户端连接老是超时怎么办?
全部回复
共 150 条K8s 里 Service 的 sessionAffinity 没开吧?MCP 长连接容易被随机转发到不同 Pod 上。
先看看 K8s 的 service 是不是走了 conntrack 超时,长连接容易被悄悄掐掉,加个 keepalive 试试。
K8s 里 MCP 超时坑挺多的,我之前也踩过。先查下 Service 的 sessionAffinity 是不是没开,默认轮询会把同一个客户端的请求打到不同 Pod,连接自然就断了。另外看下 Ingress 或 LB 的 idle timeout,很多默认 60 秒,比 MCP 的 heartbeat 间隔还短,心跳还没发出去连接就被掐了。ServerCapabilities 一般不至于导致超时,重点还是放在网络层和长连接保活上。
先抓包看下超时是卡在TCP握手还是MCP初始化阶段,K8s的Service和Ingress超时配置也顺手查查。
这个思路不错,收藏了。
学到了,感谢分享!
K8s 上跑 MCP 服务确实容易踩这个坑,本地好好的上生产就断,太常见了。你服务端日志没报错但客户端超时,我第一反应是看 Service 和 Ingress 那层有没有 idle timeout,很多云厂商的 LB 默认 60 秒就掐连接,MCP 的 SSE 长连接正好撞枪口上。heartbeat 这块官方 SDK 的间隔是可以调的,生产环境网络抖动大的话适当缩短心跳、加上重连退避会稳不少。另外 ServerCapabilities 里如果把不需要的能力都开着,握手阶段返回的 payload 会变大,弱网下也容易拖慢首连。还有个容易忽略的点是 K8s 的 readinessProbe 如果配得太激进,Pod 还没完全就绪就被打进流量,也会表现为偶发连不上。建议先抓一下客户端侧的完整报错和时间戳,跟服务端 accept 日志对一下,看是卡在 TCP 握手还是 MCP 初始化阶段,定位能快很多。
K8s 里超时先别急着怀疑 heartbeat,大概率是 Service 或 Ingress 的空闲连接超时把长连接掐了,MCP 这种流式连接特别容易中招。可以看下 nginx 的 proxy_read_timeout 和云 LB 的 idle timeout 是不是比客户端心跳间隔还短。我这边之前也是本地好好的,上集群就断,最后发现是 LB 默认 60 秒回收连接。另外确认下客户端是不是走的 ClusterIP 直连,如果经过 NodePort 或外部网关,MTU 和 TCP keepalive 也值得查一查。
K8s 上 MCP 超时确实挺常见的,我们之前也踩过。先确认下 Service 的 sessionAffinity 是不是没开,MCP 长连接如果被 kube-proxy 轮询到不同 pod 上,表现就是连上就断。另外看下 ingress 或 LB 的空闲超时时间,默认 60s 经常比 heartbeat 间隔短,调大试试。ServerCapabilities 一般不至于导致超时,除非你开了 SSE 但没处理好 flush。
我之前也踩过类似的坑,本地好好的,一上 K8s 就各种超时,最后发现是 Service 的 sessionAffinity 没开,MCP 这种长连接被负载均衡打到不同 pod 上,握手和心跳对不上就直接断了。你可以先确认下客户端连的是 ClusterIP 还是经过 Ingress,中间有没有 nginx 之类的反代,proxy_read_timeout 默认 60s 很容易把空闲连接掐掉。heartbeat 那块我倒觉得不是根因,官方 SDK 的间隔一般够用,除非你们网络真的有明显抖动。另外 ServerCapabilities 配错通常表现为能力协商失败而不是超时,日志里应该能看到,所以优先级可以往后放放。建议先抓个 tcpdump 或者看 conntrack,确认连接是被 RST 还是自然超时,这个能直接区分是网络层还是应用层的问题。还有 K8s 的 readinessProbe 如果配得太激进,pod 频繁重启也会让长连接莫名其妙断掉,顺手查一下 restart 次数。