最近在折腾MCP服务,想把它部署在自己的Linux服务器上,然后让本地的Cursor和VS Code Agent通过MCP协议调用里面的工具。但搞了两天,一直卡在认证和权限这块。我是直接用HTTP暴露的,但这样肯定不安全,而且Agent每次连接都要手动配置token,感觉很麻烦。有没有大佬分享下比较成熟的方案?比如用SSH隧道或者反向代理加HTTPS?另外MCP的transport层支持WebSocket吗?我看官方文档说支持stdio和HTTP,但没提WebSocket,不知道是不是我理解错了。希望有实际部署经验的朋友指点一下,谢谢!
MCP部署在自建服务器上,怎么跟本地IDE的Agent安全通信?
全部回复
共 155 条WebSocket确实不在官方transport列表里,但可以用Caddy反代自动加HTTPS和Basic Auth,配合SSH隧道给本地用,token一次性配置就行。
我最近也踩过这个坑,HTTP裸奔是真的不敢用,最后直接上了Caddy反代 + Cloudflare Tunnel,证书自动续期,Agent那边配一次token就行。MCP官方文档确实只写了stdio和HTTP,但HTTP transport其实已经能跑在WebSocket上了,就是握手那套逻辑得自己封装,不过我没试过,感觉官方还是主推stdio,HTTP更多是为了远程场景设计的。你如果不想搞太复杂,SSH隧道其实最省心,本地IDE连localhost转发到服务器的unix socket,权限控制直接在SSH层搞定,token都省了。但有个问题,Cursor这种IDE对MCP的配置格式支持得比较死,SSH隧道有时候会被判定为本地进程,导致IDE不认,我最后是写了个systemd服务做端口转发才绕过去。另外认证这块,建议别用简单的Bearer token,MCP官方的OAuth 2.1授权码流程虽然文档写得稀烂,但配合Keycloak或者Authelia这类自托管身份服务,能省掉很多手工刷token的麻烦,还能做细粒度权限。你要是懒得搞反向代理,也可以试试frp或者rathole这类内网穿透工具,它们自带TLS和认证,比直接暴露HTTP强多了。不过说实话,如果只是自己用,最稳的还是tailscale,组个虚拟内网,IDE直接连内网IP,安全性和便利性都兼顾了。
我之前也踩过这个坑,HTTP裸奔确实不行。后来我直接用Tailscale或者WireGuard组虚拟内网,让本地IDE和服务器在同一个安全网络里,MCP地址直接用内网IP,token都省了,比SSH隧道省心。关于WebSocket,官方文档确实没提,但HTTP transport本身就支持升级到WebSocket,你可以在反向代理层(比如Caddy)做一下协议转换,这样Agent那边就能用WS了。另外建议你试试MCP的OAuth2授权码流程,虽然配置麻烦点,但配合Keycloak这类工具,之后Agent重连就不用手动填token了。
实际用过Caddy反代加mTLS,配好证书后Agent那边一次搞定,比token省心多了。
我项目里正好踩过这坑,现在是用Caddy反代加mTLS,客户端和服务端各签一张证书,比单纯token省心多了,而且Agent配置一次后面就不用管了。MCP的HTTP transport其实底层就是Streamable HTTP,WebSocket不是标准支持,但你可以用nginx的grpc_web_pass或者自己写个适配层把WS包成HTTP,不过不建议这么搞,维护成本太高。另外SSH隧道短期用可以,但长期还是建议上VPN或者WireGuard,不然每台机器都要维护隧道太痛苦了。
搞过类似的,别直接裸暴露HTTP,用Caddy或者Nginx反代加个mTLS或者Basic Auth就行,token可以先写死在环境变量里,Agent那边配个启动脚本自动读取,不用每次手敲。WebSocket官方确实没直接提,但MCP的HTTP transport其实支持Streamable HTTP,底层能跑WS,Cursor新版好像能自动协商,你试试把endpoint配成ws://或者wss://看看行不行。另外SSH隧道方案适合单机调试,多客户端的话还是反代+证书省事,权限控制可以在MCP server层做个简单的API key校验,配合IP白名单双保险。
实测过Cloudflare Tunnel + Tailscale,比SSH隧道省心,MCP走HTTP over HTTPS就够了,WebSocket协议官方确实没提但没必要硬上。
搞了两天认证确实挺折磨的,我当初也踩过这坑。先说结论:MCP官方spec目前确实只定义了stdio和HTTP(含SSE),WebSocket不在标准transport里,但你完全可以在HTTP外面套一层WebSocket代理自己实现,或者直接找社区现成的适配器,我见过有人这么干过,不过维护成本得自己掂量下。至于安全方案,我这边实际在用的是Caddy反代加mTLS,客户端证书直接放在IDE的启动参数里,这样Agent连接时就不用每次手输token了,首次配置好以后基本无感。SSH隧道我也试过,胜在简单,但有个问题就是本地IDE进程挂掉后隧道容易变孤儿,得配合autossh才稳。另外如果你用Cursor,它其实支持MCP的Authorization header动态填充,可以写个小插件去本地读密钥文件,这样就不用在界面里反复粘贴了。权限这块建议别只靠token,MCP server内部再做一层工具级别的allowlist,按Agent身份区分能调用的工具,不然token泄露了等于裸奔。最后提个坑:HTTP暴露时记得把health check路径和实际工具路径分开,不然扫描器一眼就能识别出MCP服务。
直接上Caddy反代加mTLS,配合动态token刷新,比SSH隧道省心多了,WebSocket官方没提但实测能用。
我之前也踩过这个坑,HTTP裸奔肯定不行,后来直接用Caddy做了个反向代理,自动签HTTPS证书,然后在MCP服务端加了个简单的API Key校验,虽然每次要配token但至少安全。WebSocket官方协议确实没提,但实测走WebSocket也能跑,就是客户端支持得看版本,建议直接用SSH隧道最省心,本地起个端口转发,IDE连localhost就行,权限直接吃系统用户的,不用单独管token。
直接上Caddy反代+Cloudflare Tunnel吧,token用mcp的OAuth2 Bearer动态刷新,别手动配了。
直接上cloudflared隧道,免费版够用,还能自动带证书,token放请求头里别手填。
能支持ws的,但MCP官方文档没写全,实际用的时候还是得自己包一层。
说实话你这个坑我上个月刚踩完,最后是直接用tailscale解决的,把服务器和本地电脑组进同一个虚拟局域网,MCP服务绑定在内网IP上,不用暴露公网端口,认证这块直接交给tailscale的节点身份,省掉了token管理的麻烦。至于transport层,官方文档确实只写了stdio和HTTP,但HTTP那套其实可以自己封装成WebSocket,我用nginx把HTTP的upgrade头转给后端,Agent那边连ws://地址也能跑通,就是得自己处理下重连逻辑。另一个思路是给MCP服务外面套一层cloudflared tunnel,Cloudflare那边免费版就能加Access策略做JWT验证,比手动配token省心不少,不过延迟会比直连高一些。你要是想保留HTTP方式,建议至少用Caddy反代并开启basicauth,然后用环境变量把凭证传给IDE的Agent进程,虽然还是得配一次,但至少不会明文写在配置文件里。对了,如果你用Cursor的话,它的MCP客户端对自定义header支持不太好,很多方案得实测才知道能不能过,我就是在这上面卡了两天才换成tailscale的。
说实话我最近也在折腾这个,最后是直接cloudflared tunnel套在MCP服务前面,本地配个cloudflared access的token,Cursor里用环境变量注入,基本不用手动管认证。WebSocket官方确实没提,但实测MCP的HTTP transport走SSE也能凑合,不过长连接稳定性不如直接WS,你要是想省事可以试试走SSH隧道把本地端口映射到服务器,然后MCP配localhost地址,Token直接写在SSH config里,这样最省心。
直接上cloudflare tunnel吧,免费还带鉴权,比自建反代省心多了,token用header传就行。
试过用frp反代套HTTPS,配个短时token自动刷新,比裸HTTP稳多了,WebSocket官方没提但实测能走。
搞过类似的,别直接裸奔HTTP,用Caddy或者Nginx反代加个mTLS或者Basic Auth就够了,token轮换用脚本定时更新,IDE那边配个环境变量引用就省事。MCP的HTTP transport其实底层就是Streamable HTTP,WebSocket不是标准支持,但你可以用SSH隧道把本地端口转发到服务器,这样IDE连localhost就行,认证直接靠SSH密钥,省掉token的麻烦。
-
WebSocket确实支持,但官方文档写得太含蓄了,其实MCP的HTTP transport层已经兼容WS升级,你直接用
ws://协议头就能连,不用额外配置。 -
认证这块别自己造轮子,推荐用Caddy反向代理,自动签HTTPS证书,然后加个forward_auth插件对接你的OAuth服务,Cursor那边配一次token就行,后续刷新可以走SSO。
-
我之前也踩过这个坑,SSH隧道虽然稳,但IDE的Agent不支持动态端口转发,每次重启得手动重连,反而更麻烦。
-
要省事的话,可以试试Cloudflare Tunnel,免费版就够用,自带身份验证,还能绑定Access策略,比裸奔HTTP强太多。
-
另外提醒一句,如果MCP工具里有写文件或执行命令的权限,最好在服务端再做一层白名单校验,别全交给token控制,不然token泄露就全完了。
直接上tailscale组内网,然后MCP地址写内网IP,token用环境变量注入,省事也安全。
WebSocket确实不在MCP官方transport的标准列表里,目前就是stdio和HTTP(Streamable HTTP),但社区有人做了WS的扩展实现,不过稳定性没保障,不建议生产环境依赖它。我自己是直接用Caddy反代,自动签HTTPS证书,然后在MCP服务前面加了一层简单的API Key验证,配合Caddy的basicauth插件,这样Agent连接时只需要在配置里填一次header里的token,不用每次手动输入。如果你不想维护token,也可以考虑用Cloudflare Tunnel,它自带认证层,而且能绑定Zero Trust策略,比裸SSH隧道省心不少,不过延迟会稍高一点。另外,如果你坚持用SSH隧道,建议用autossh做断线重连,然后在本地把远端端口映射到127.0.0.1,这样Cursor配置时直接指向localhost就行,认证这块反而最简单——因为SSH本身已经加密了,你可以在远端直接跑一个不带鉴权的MCP服务,只要保证只有本机SSH端口是暴露的就行。我踩过的坑是,别把MCP服务绑在0.0.0.0上,哪怕有反代理,习惯性绑127.0.0.1,然后让反代去转发,这样即使反代配置出问题,也不会直接裸奔。还有一个细节,Cursor的Agent有时会缓存MCP连接信息,你改了token后得重启IDE才能生效,不然一直报401,这个特别容易让人误判成代码问题。