最近跟着教程折腾MCP,写了个最简单的weather server,用Python的FastMCP起的服务,本地跑着没问题。结果一接到Claude Desktop里就报“Failed to fetch MCP config”,我检查了路径和命令,甚至把config里的command换成了绝对路径还是不行。更诡异的是,用官方的filesystem server就能连上,说明不是客户端的问题。是不是我漏了什么环境变量?还是说stdio模式对子进程的工作目录有要求?看日志也看不懂,有没有老哥给个排查思路,最好能推荐个断点或者日志级别的工具,救救孩子。
MCP服务器连自家API都连不上,这玩意到底咋调试?
全部回复
共 24 条试试在config里加个env字段,把PATH和HOME显式传进去,stdio模式经常不继承shell环境。
这问题我上个月也踩过,最后发现是FastMCP默认的transport参数跟Claude Desktop的stdio握手逻辑对不上。你本地能跑是因为直接命令行启动时环境变量和cwd都正常,但Claude拉起子进程时工作目录会变成它自己的目录,所以绝对路径只是第一步,还得确认config里有没有显式传env,比如PYTHONPATH或者PATH里有没有带上你的虚拟环境。官方filesystem能连说明它内部处理了这些,但FastMCP的entrypoint可能没兼容Windows的python.exe路径。调试的话别死磕日志,直接用strace(Linux)或者Process Monitor(Windows)看子进程启动时的完整参数和cwd,再不行就在server代码第一行写个写文件的探针,把os.getcwd()和环境变量dump出来。另外检查下是不是用了if __name__ == "__main__"的写法,FastMCP有时候需要mcp.run()而不是serve(),这两个在stdio模式下的序列化格式有区别。最后建议装个mcp-cli的调试模式,它能打印完整的JSON-RPC握手包,比看Claude那边的黑盒日志直观多了。
我之前也栽在这上面过,大概率不是你代码的问题,而是Claude Desktop启动子进程时的环境没继承你终端里的PATH。你试试在config里把command写成python的完整路径,同时把env字段加上,比如指定PYTHONPATH和HOME,我这么搞就好了。
另外调试有个土办法,别直接连Claude,先用个脚本模拟stdio输入输出,往stdin里丢个initialize请求,看能不能正常返回,这样能快速定位是服务本身挂了还是通信问题。日志的话,可以试试在FastMCP初始化时加个debug参数,或者用--debug跑,输出会详细很多,至少能看见卡在哪一步。
我之前也踩过这个坑,八成不是环境变量的问题,而是FastMCP默认绑定了IPv6或者localhost解析到了::1,Claude Desktop的子进程环境里解析不通。你试试在启动命令前加个--host 127.0.0.1,或者干脆在config里把env字段显式设一下PYTHONUNBUFFERED=1,有时候stdio模式输出缓冲也会导致握手超时。调试的话别用print,直接上logging模块把级别调到DEBUG,然后看Claude Desktop的日志文件(macOS在~/Library/Logs/Claude/下),那里会打印出实际执行命令和stderr输出,比看客户端报错有用多了。另外确认下你的FastMCP版本,老版本和Claude Desktop的MCP协议版本可能不兼容,升级到最新试试。
我之前也遇到过一模一样的坑,后来发现是FastMCP的入口文件用了if __name__ == "__main__"导致子进程找不到模块,换成直接暴露函数名给mcp.run()就好了。你可以先在终端里手动用mcp dev跑一下,看能不能正常握手,能的话就是Claude Desktop的配置问题,重点检查command后面有没有带参数,比如python -m这种。日志的话别只看stderr,加个logging.basicConfig(level=logging.DEBUG)到你的server文件里,把子进程的cwd和环境变量都打印出来,基本就定位了。
我之前也踩过这个坑,大概率不是环境变量的问题,而是stdio模式下子进程的cwd不对。你试试在config里给command加个shell包装,比如用bash -c "cd /绝对路径 && python xxx.py",或者干脆在代码里把工作目录固定一下。调试的话别用print,直接上logging,把stderr重定向到文件里看,FastMCP的日志级别调到DEBUG能输出不少信息。再不行就装个mcp-inspector,那个能可视化看到请求到底卡在哪一步。
之前我也踩过这个坑,FastMCP本地跑没问题但一挂到Claude Desktop就挂,八成是stdio模式下子进程的工作目录和PATH环境变量跟你的终端不一样。Claude Desktop在macOS上是以GUI应用启动的,它继承的环境变量很干净,你终端里那些通过.zshrc或.bashrc设置的路径它根本拿不到,所以就算你写了绝对路径,Python解释器可能都找不到依赖包。建议你先在config里把command改成类似/usr/bin/python3 -m fastmcp run weather_server.py这种,再配合把working directory显式指定到项目目录试试。要是还不行,就在server代码最开头加个sys.stderr.write把os.getcwd()和sys.path打出来,然后去Claude的日志目录(比如~/Library/Logs/Claude/)看输出,比看网络错误直观多了。另外强烈推荐用MCP Inspector这个官方调试工具,它能直接以stdio模式起你的server然后发tool call,能看清楚握手阶段到底哪一步断了。我那次最后发现是系统自带的python3版本太老,FastMCP要求3.10+,但Claude Desktop默认调的是/usr/bin/python3,换成homebrew的python路径瞬间就好了,你可以先查下这个。
这问题我踩过一模一样的坑,大概率不是环境变量,而是stdio模式下子进程的cwd和PATH没继承全。Claude Desktop在macOS上启动服务时工作目录是固定的,你试试在config里给command加个env字段,把PYTHONPATH和PATH手动指一下。调试工具别用断点,直接给FastMCP传debug=True,它内部会打印完整握手日志,比看系统日志直观多了。另外确认下你本地python和Claude Desktop跑的python是不是同一个,虚拟环境路径不一致也会这样。
这问题我上周刚踩过,大概率不是路径而是stdio模式的工作目录问题,Claude Desktop默认继承的cwd可能不是你server所在的目录,试着在config里加个env指定PYTHONPATH或者直接写死绝对路径的启动脚本试试。调试的话别用print,用logging写到文件里,然后去~/Library/Logs/Claude里翻mcp的日志,比终端输出直观多了,能看到具体的stderr报错。我之前也是FastMCP,最后发现是venv的python没找对,换成系统python就好使了。
这问题我上周刚踩过,多半是stdio模式下子进程的工作目录不对,Claude Desktop启动MCP时不会继承你终端里的cwd。试试在config里给command包一层bash -c,先cd到项目目录再跑python,或者直接用绝对路径指向venv里的python解释器,别用系统全局的。另外调试的话别盯着日志,用MCP Inspector(官方那个)能直接看握手和请求的原始输出,比啥都管用。环境变量倒是次要的,先把启动方式对齐了再说。
我之前也踩过这个坑,大概率不是环境变量的问题,而是stdio模式下子进程的工作目录没继承对。FastMCP默认会去当前目录找配置文件,但Claude Desktop启动子进程时cwd可能指向了别的路径,你试试在服务代码里显式打印一下os.getcwd()看看。另外调试的话别用print,直接上logging,把日志重定向到文件里,用tail -f实时看输出,比在Claude的报错里瞎猜强多了。还有个笨办法,先写个最简单的hello server,一点一点加依赖,排除是某个库初始化挂的。
八成是stdio模式下子进程的工作目录不对,试试在config里加cwd字段指到server文件夹,或者用npx跑一下看报错。
这问题我上个月也踩过一模一样的坑,最后发现不是环境变量也不是路径,而是Claude Desktop启动子进程时压根没继承你shell里的PATH。你本地跑没事是因为终端里有python环境,但桌面应用走的是GUI的launchd环境,干净得跟白纸似的,所以建议在config里把command写成python3的绝对路径,同时把FastMCP依赖的虚拟环境路径也写死。另外stdio模式对工作目录确实有要求,官方filesystem server能连上大概率是因为它内部处理了cwd,你可以在server代码开头加个print(os.getcwd()),然后通过stderr输出看日志——对,MCP的stdout是留给协议通信的,你平时print的调试信息全被吞了,得写到stderr或者文件里。排查工具的话,别用断点,直接用mcp-cli这个命令行工具,它能手动加载你的server并逐条发送initialize请求,比接Claude快得多。最后检查一下config的json格式,特别是mcpServers这个key的拼写,我那次就是多了个空格,报错信息还贼误导人。
我之前也踩过这个坑,十有八九是stdio模式下子进程的工作目录跟Claude Desktop启动时的目录不一致导致的。你可以试试在config里给command加个shell包装,先cd到server脚本所在目录再执行,或者用env显式设置PYTHONPATH。另外别只看MCP的日志,直接跑一下server的stderr输出,把错误重定向到文件里看看,很多真实报错都被吞了。
我之前也踩过这个坑,大概率不是环境变量的问题,而是stdio模式下子进程的工作目录默认继承自Claude Desktop的启动位置,你试试在config里给command包一层shell脚本,先cd到server目录再启动。排查工具的话别用断点,直接给FastMCP加个logging配置输出到文件,把stdout和stderr分开看,有时候报错信息被吞了就是没分清这两个流。另外记得确认下Python解释器路径,用which python拿绝对路径填进去,别用虚拟环境的相对路径。
这问题我上周刚踩过一模一样的坑,折腾了两天最后发现是工作目录的锅。你本地跑没问题是因为FastMCP默认在当前目录找配置文件,但Claude Desktop拉起子进程时工作目录是它的安装路径,你那些相对路径的读取逻辑全废了。建议先在server代码里把路径都改成硬编码的绝对路径,或者启动时os.chdir到你的项目目录试试。另外强烈建议别直接看Claude的日志,那个太抽象了,你直接在server的入口加个logging.basicConfig(level=DEBUG)然后把输出重定向到文件,这样能看清子进程到底有没有被正确拉起。还有个骚操作,你可以在config里把command换成python -m uvicorn这种带模块名的形式,有时候直接指向脚本文件会有权限问题。要是还不行就试试用inspect工具单独调试stdio通道,往stdin里手动丢JSON-RPC请求,看返回啥,这比在Claude里黑盒调试快多了。
之前我也被这个坑过,当时折腾了半天最后发现是MCP的stdio模式对子进程的cwd要求特别严格,Claude Desktop启动server时用的工作目录不是你本地终端那个,而是它自己的资源目录。你可以试试在config里把command写成bash -c,然后后面用绝对路径加cd到你的项目目录再启动python,这样能强制指定工作目录。另外那个Failed to fetch MCP config,我印象里不光是路径问题,也可能是你的server启动后没有在预期时间内输出协议握手信息,FastMCP默认会先打一行日志到stdout,但stdio模式下这是不允许的,必须全部走stderr,不然客户端就认为配置拉取失败。你可以把日志重定向到文件里,或者设置环境变量LOG_LEVEL=DEBUG再跑一次,看它到底卡在哪一步。如果你用的是新版Claude Desktop,检查一下app的日志文件,通常在~/Library/Logs/Claude/,里面会有更详细的报错堆栈。调试工具的话,我推荐直接用mcp-debugger这个npm包,它能模拟客户端发请求,还能看到完整的消息流转,比瞎猜快多了。最后检查一下你的Python环境,是不是用了虚拟环境但config里没写对解释器路径,有时候系统默认python和venv里的版本不一致也会导致连不上。
我之前也卡在这过,多半不是环境变量的事,是stdio模式下子进程的工作目录默认不在你项目里,FastMCP读不到相对路径的配置。你试试在server代码里把所有文件路径都改成绝对路径,或者干脆在启动命令前加个cd到项目目录再启动。日志的话别用print,直接用logging模块输出到文件,debug级别能看到MCP握手细节,比看Claude那个黑盒子强多了。
我之前也踩过类似的坑,最后发现是工作目录的问题。Claude Desktop启动子进程时,默认的cwd很可能不是你项目所在的路径,尤其用相对路径引用venv里的python时特别容易炸。你可以试试在config里把command写成/绝对路径/venv/bin/python,但script参数也用绝对路径,这样能排除掉一半可能性。另一个坑是环境变量,特别是PATH,Desktop的GUI启动方式不会加载你的shell配置文件(比如.zshrc),所以如果依赖了某个通过rc文件添加的工具链,子进程根本找不到。调试的话,别光看客户端日志,直接在你server代码里加--log-level DEBUG,或者更粗暴点,把stderr重定向到文件:2> /tmp/mcp.log,然后手动在终端里用同一个命令启动,对比两边的输出差异。如果还不行,试试用npx @modelcontextprotocol/inspector这个官方调试器,它能可视化模拟stdio交互,比裸看日志直观多了。不过按我的经验,八成是你config里某个字段没写对,检查一下args是不是数组格式,别漏了引号。
试试在MCP配置里加个env字段手动指下PATH,再不行就用--debug跑FastMCP,日志能直接打到stderr。