最近跟着教程折腾MCP,用的官方Python SDK写了个简单的服务器,暴露了一个查询本地SQLite的函数。在Claude Desktop里配好mcpServers,启动后日志显示“Transport closed”,连initialize握手都没完成。我确认了URL是http://localhost:8000/mcp,也试过用--transport sse和streamable-http两种模式,都不行。
MCP服务器连自家API都连不上,是我配置姿势不对还是这玩意儿本来就难搞?
全部回复
共 47 条八成是Claude Desktop对本地回环地址的权限限制,试试把localhost换成127.0.0.1或者关掉代理再跑一遍。
这坑我踩过,多半是Python SDK版本和客户端不匹配,换个旧版或直接上stdio模式秒连。
碰到过类似的情况,当时也是卡在transport closed,后来发现是Claude Desktop对本地回环地址的权限卡得比较严,试试把localhost换成127.0.0.1,或者直接用--transport stdio走标准输入输出,比HTTP稳得多。另外检查下Python SDK版本,有些旧版本对streamable-http的支持有bug,升级到最新版再试试看。如果还不行,可以先用MCP Inspector单独调试服务器,能更快定位是握手协议问题还是配置问题。
八成是Claude Desktop对本地服务权限管太严,试试把地址换成127.0.0.1,或者检查下CORS头配了没。
这问题我遇到过,多半是CORS没配好,加个允许所有来源的中间件试试。
我之前也踩过这坑,后来发现多半是路径写错了,Claude Desktop对URL的解析挺死板的,试试不带/mcp后缀直接指向根路径,或者反过来确认一下是不是http和https混了。另外你检查过CORS没?本地调试时浏览器和桌面客户端策略不一样,有时候卡在握手就是跨域预检没通过。要是还不行,把SDK版本降到0.8左右试试,新版改动挺大,很多教程都是照旧版写的。
我上周刚踩过同一个坑,后来发现是Claude Desktop对本地host的校验卡得比较死,它默认可能把localhost解析到IPv6了,而服务只监听了IPv4。你试试直接改成127.0.0.1,或者把服务绑到0.0.0.0上,顺便在日志里加个请求打印,看看请求到底有没有打到你的进程上。另外streamable-http模式如果没实现好health check端点,握手也会直接断,你可以先抓包确认下是TCP层断了还是HTTP层返回了异常。
我前几天也踩过类似的坑,最后发现是Claude Desktop对本地回环地址的权限卡得比较死,试试把URL换成127.0.0.1而不是localhost,或者直接用--transport stdio走子进程通信,那个反而最稳。另外你检查下Python SDK版本和Claude Desktop内置的MCP客户端版本是否兼容,我升级SDK到最新版后握手就正常了,有时候“Transport closed”就是版本不匹配的烟雾弹。
我之前也被这玩意儿坑过,后来发现多半是SDK版本和transport模式有兼容性问题,官方文档更新太快,很多教程都是旧写法。你试试把SDK升到最新,然后只保留streamable-http,别开SSE。另外检查下CORS头,Claude Desktop的请求有时候会带Origin,服务端没处理就直接断连了。如果还不行,可以抓个包看看握手阶段到底卡在哪一步,比瞎猜快得多。
我之前也卡在过这个Transport closed上,后来发现是Claude Desktop对streamable-http的支持要求path必须精确匹配,不能带额外参数,而且它默认走的是stdio,你如果直接写http地址它反而会懵。建议你先用mcp dev那个调试工具单独测一下服务器,确认SDK自己发的initialize能通,再回过来看客户端配置,这样能快速定位是哪边的锅。
另外本地SQLite服务的话,先试试把host改成127.0.0.1而不是localhost,有些环境里IPv6解析会出幺蛾子,我之前就是这么坑的。如果还不行,检查下CORS头,浏览器和桌面客户端对跨域策略的处理不完全一样,SDK默认可能没开允许所有来源。
说实话这玩意儿现在生态还比较糙,官方文档和实际行为对不上是常态,多翻翻GitHub issue比看教程管用。你那个查询函数如果返回的是自定义对象,记得一定要定义serialize方法,不然就算握手成功,后面调用时传输层也会直接断掉。
我之前也卡在过这个握手阶段,后来发现十有八九是SDK版本和传输模式不匹配的问题。你试过直接用curl打一下那个URL看返回什么吗?如果是SSE模式,应该能看到text/event-stream的响应头,而streamable-http则需要POST一个空的JSON-RPC请求过去,光靠浏览器访问是看不出问题的。另外官方Python SDK最近改版挺频繁,有些版本对/mcp这个路径的默认处理有变化,建议你检查一下是不是同时装了mcp和fastmcp两个包,它们会抢同一个端口导致Transport closed。还有个坑是Claude Desktop的配置里如果填了--transport sse,但服务端实际启动的是streamable-http,握手就会直接断掉,两边参数得严格对齐才行。我之前是直接把SDK降级到0.9.x才跑通的,新版本反而各种幺蛾子。你要是实在排查不出来,可以开个--debug日志看看到底是哪一步报错,别光看“Transport closed”这个笼统信息。
我最近也踩过类似的坑,折腾了一整天才发现是路径问题。你那个URL看起来没问题,但Claude Desktop对localhost的解析有时候会抽风,我最后改成127.0.0.1才通的。另外你确认过SDK版本吗?官方Python SDK最近更新蛮频繁,streamable-http这个transport在0.5.0之前压根没实现完整,如果你是半年前装的依赖,那大概率就是版本不匹配导致的。还有个思路是先把防火墙和代理全关了试试,我之前就是被系统代理拦了,日志里也看不到具体报错,特别烦。不过说实话,MCP这个项目现在迭代速度太快,文档跟代码不同步的情况太多了,连不上真不一定是你的问题。你要是方便的话,可以开个--debug级别的日志,看看具体卡在哪个HTTP状态码上,这样定位起来会快很多。
大概率是CORS没配,本地调试时Origin不对直接被拒了,先抓包看下握手响应。
换个思路,试试直接用curl调一下你的端点,能通就是客户端配置问题,不通就是SDK版本坑。
我最近也踩过类似的坑,后来发现八成是SDK版本和transport模式没对齐。比如streamable-http在新版SDK里要单独装extra依赖,不然握手时直接断连。你试试把SDK升到最新,然后服务端启动日志里多打点debug信息,看是卡在CORS还是路径解析上,这俩最容易出这种莫名其妙的Transport closed。
我之前用fastapi挂MCP的时候,还得手动设置一下/mcp这个endpoint的响应头,不然Claude Desktop那边握手数据发过来就被拒了。你检查下是不是少了个Content-Type: application/json之类的头,有时候官方教程默认你环境里已经配好了,实际没提。
还有一种可能,你本地防火墙或者代理把localhost的流量拦了,尤其某些vpn工具会自动接管所有http请求。可以先试试用curl直接带JSON-RPC的payload打到那个URL,看返回是不是正常的MCP响应,这样能快速定位是客户端问题还是服务端问题。
说实话MCP这玩意儿现在文档和实现版本之间差异挺大的,官方SDK都还在快速迭代,连不上真不一定是你的锅。我上次折腾了整晚,最后发现是Claude Desktop缓存了旧的配置,重启应用才生效,你也可以试着重启下客户端清缓存。
我最近也卡在过这个坑,后来发现是Claude Desktop对自定义MCP server的路径解析有bug,尤其是用相对路径或带环境变量的command时特别容易直接Transport closed。你试试把server启动命令写成绝对路径,并且确保工作目录里没有中文或空格,我这样改完就好了。另外建议先用mcp dev单独跑一下,看服务端日志到底有没有收到HTTP请求,能少走很多弯路。
说实话,MCP这玩意儿目前生态还太早期,官方SDK自己都在频繁改接口。我之前用streamable-http模式也连不上,后来发现是版本不匹配,Claude Desktop只认特定的协议版本。你检查一下SDK和客户端版本,最好都升到最新,然后按官方示例原封不动跑一遍,别自己改配置。如果还不行,试试直接用Node.js版的SDK,Python那个对异步处理要求有点高,容易莫名其妙断连。
这问题我碰到过两次,一次是防火墙把localhost的8000端口拦了,另一次是Claude Desktop的沙箱环境默认不带localhost访问权限。你先用curl手动请求一下http://localhost:8000/mcp,看返回的是什么,如果是404说明路由没对,如果是连接拒绝那就是端口问题。另外注意MCP的握手是POST请求,不是GET,很多教程里没强调这点,你客户端配置里如果加了额外headers
大概率是SSE和streamable-http的endpoint路径不一样,直接翻一下SDK源码看路由注册,别光套教程。
八成是Claude Desktop对localhost的权限或CORS限制,试试用ngrok暴露公网地址再连一次。
八成是Claude Desktop对本地回环地址有限制,试试把localhost换成127.0.0.1,或者用ngrok暴露一下。
遇到过一模一样的坑,最后发现是Claude Desktop对本地回环地址的权限卡得比较死,试试把localhost换成127.0.0.1,或者直接在配置里写--transport sse的同时把URL末尾的/mcp去掉,有些版本对路径解析很敏感。另外确认下SDK版本,官方最近改过几次协议默认行为,老版本和新版客户端握手会失败。如果还不行,抓一下TCP包看是不是TLS或HTTP头的问题,比瞎猜快多了。
SSE和streamable-http混着试容易踩坑,检查下Claude Desktop的SDK版本和transport参数是不是严格匹配上了。
我最近也在折腾这个,症状跟你一模一样,后来发现问题基本都出在传输层配置上。Claude Desktop对streamable-http的兼容性其实挺挑的,特别是它默认走的是JSON-RPC over HTTP,但很多教程里给的示例代码还停留在旧版SDK的写法上,导致握手阶段就断了。你可以试试把URL改成不带/mcp后缀的根路径,有些实现会强制要求路径匹配。另外检查一下CORS头,Claude Desktop的请求来源跟浏览器不一样,服务器得显式允许才行,这个坑我踩了整整两天。还有个思路是直接用stdio模式先跑通本地验证,排除网络层干扰,然后再切回HTTP模式对比日志差异。要是还不行,可以考虑抓一下原始请求报文,看看是不是content-type没设置成application/json。反正这玩意儿目前生态确实乱,官方文档都经常前后矛盾,不是你姿势的问题。
我上周也卡在这,最后发现是Claude Desktop版本太旧不支持streamable-http,换个新版立马好了。