最近在折腾MCP(模型上下文协议)对接DeepSeek API,想搞个能自动查天气和数据库的Agent。环境是Python 3.10 + FastMCP库,DeepSeek用的是chat模型。结果设置完tools之后,发送查询请求,DeepSeek那边一直返回空response,偶尔报个“函数调用参数格式错误”。我查了官方文档,tool定义里parameters写的是JSON Schema格式,应该没毛病啊……是不是MCP的tool调用方式和普通function calling有区别?还是说DeepSeek本身对MCP支持不完善?有没有踩过坑的老哥指点一下,感激不尽。
MCP对接DeepSeek时,模型一直返回空响应,是我姿势不对吗?
全部回复
共 189 条我之前也卡在过这,大概率不是DeepSeek不支持,而是MCP的工具调用格式跟OpenAI那种原生function calling不完全一样。你检查下FastMCP生成的实际请求体,特别是tools数组里每个元素的type字段,DeepSeek可能不认带type的写法。另外空响应有时候是因为模型判断不需要调用工具,直接把参数吞了,你试试把系统提示词写明确点,强制它先输出工具调用。
大概率是MCP的tool返回格式和DeepSeek原生function calling不完全一致导致的,特别是参数里嵌套了复杂结构时容易触发“函数调用参数格式错误”。我之前也卡在这儿过,后来直接在FastMCP的tool装饰器里把parameters定义成最简平的JSON Schema,别用anyOf或$ref,就通了。另外空响应也有可能是DeepSeek在等模型生成tool_call但你没把历史消息带回去,第二轮会好很多。你可以先打印下原始返回看看是不是真空,还是被FastMCP吞了。
大概率是参数格式问题,DeepSeek对strict模式要求更严,试试把tool的parameters里type和required字段补全。
大概率是MCP的tool返回格式和DeepSeek预期的不完全一致,特别是参数里如果有嵌套对象或者数组,很容易触发它那个“格式错误”。我之前也卡在这,后来直接把FastMCP的tool定义打印出来跟OpenAI的function calling对比,发现它会把参数包一层,得手动展平。另一个坑是DeepSeek对空字符串响应特别敏感,建议在tool执行后强制返回一个明确的JSON结构,别让它有返回None的机会。你试试把parameters里每个字段都加上description,有时候缺了它反而会解析失败。
我之前也踩过类似的坑,而且大概率不是MCP和DeepSeek不兼容的问题。你那个“函数调用参数格式错误”提示其实挺关键的,我怀疑是FastMCP在把tools转成DeepSeek要求的function calling格式时,把JSON Schema里的某些字段给“包装”了一层。比如DeepSeek的chat模型对parameters里的$schema或additionalProperties这些键特别敏感,你直接照搬标准Schema可能就会触发它内部校验失败,然后返回空响应。我当时是把每个tool的参数手动拍平成纯type+properties+required的简单结构,去掉所有嵌套的$defs或ref引用才通的。另外你检查下请求日志里实际发给DeepSeek的payload,看看tools数组里有没有被FastMCP自动加上的annotations或者description字段,那玩意儿如果带了null值也可能导致解析中断。还有个笨办法,先用curl直连DeepSeek的API,把MCP那层去掉,只发一个最简单的tool定义和用户query,如果这样能正常返回,那问题就锁定在FastMCP的序列化逻辑上,直接改用原生requests库自己拼请求体反而更可控。总之别在MCP封装上死磕,先裸调API确认模型行为,再回头查中间层。
我之前也踩过类似的坑,最后发现问题出在MCP的tool返回格式跟DeepSeek预期的function calling结构不完全一致上。你直接在FastMCP里定义的parameters是JSON Schema没错,但DeepSeek对工具调用的响应要求可能更严格,比如它希望你在tool描述里明确标注哪些字段是必填,或者某个枚举值不能为空字符串,否则就静默返回空。建议你先抓一下DeepSeek那边的原始HTTP响应,看看是不是有个“invalid_request”之类的隐藏错误,别光看最终返回体。另外,FastMCP默认可能会把tool call包装成自己的格式,你试试直接用openai兼容模式调DeepSeek,手动构造tools数组,绕开FastMCP那层封装,很多莫名其妙的问题就消失了。还有个细节,DeepSeek对工具数量有限制,如果你一次塞太多工具,它可能直接罢工,先只挂一个天气工具测试。参数格式错误那个报错,我猜是你JSON Schema里写了“required”但实际传参时漏了字段,或者是类型定义成integer但传了string,它又不做隐式转换。最后建议你查下DeepSeek官方文档里对tool_choice参数的支持,有时候空响应是因为它压根没触发工具调用,而是直接返回了普通文本,你检查下是不是没设置tool_choice为“auto”。
八成是MCP把工具参数包装成嵌套结构了,DeepSeek不认,直接拉平再试试。
之前搞过类似的,大概率不是DeepSeek不支持MCP,而是FastMCP返回的tool schema和OpenAI格式有细微差异,DeepSeek解析严格,参数里多了或者少了必填字段就直接空响应。可以试试把tools定义里所有参数的description写全,再确认一下type是不是都明确标了string/integer,别用简写。另外报错说函数调用参数格式错误,八成是MCP把用户query包装成tool call时,arguments传成了字符串而不是对象,建议在发送前打日志看看实际payload长啥样。我之前就是这么排查出来的,改完就通了。
我之前也遇到过一模一样的情况,后来发现问题出在MCP的tool返回格式上。FastMCP默认会把工具结果包一层结构化数据,但DeepSeek的chat接口只认OpenAI那种纯文本的function calling返回,你得在工具定义里把strict模式关掉,或者手动把response_format设成text,不然它解析不了就会给你吐空响应。另外那个“函数调用参数格式错误”,大概率是JSON Schema里写了required字段但没给默认值,DeepSeek对缺失参数特别敏感,你试着把所有参数都加上optional或者给个空字符串兜底。还有个小坑,MCP的tool名称别用驼峰,DeepSeek那边对下划线命名更友好,我改成snake_case之后就没再报过格式错。你可以先用最简单的无参数工具测试一下链路通不通,再逐步加复杂度,这样能快速定位是哪一层出的问题。如果还不行,试试在请求里显式加上tool_choice:auto,有些版本不传这个默认就是不触发调用。
大概率是tool schema里少了strict: true,DeepSeek对宽松格式的兼容性很迷,加上试试。
我之前也遇到过类似情况,折腾半天发现是FastMCP默认把tool的parameters包了一层,跟DeepSeek要求的裸JSON Schema对不上,你把MCP那层转成标准function calling格式试试。另外空响应大概率是参数校验挂了但错误信息被吞了,建议在调用前先本地打印一下最终传给API的tool定义,看看是不是多了或者少了字段。DeepSeek对MCP的支持确实没OpenAI那么顺滑,但基本逻辑还是兼容的,别太怀疑姿势问题。
我之前也卡在这过,后来发现是FastMCP默认把tool的inputSchema给包装了一层,跟DeepSeek要的纯JSON Schema对不上,得手动把parameters字段解出来传。另外空响应大概率是模型觉得工具调用格式不对就直接摆了,建议把temperature调低点再试试,然后日志里看下实际请求体长啥样。
大概率是MCP的tool返回格式和DeepSeek的function calling不完全兼容,试试把response格式改成带content的规范结构。
我之前也栽在过这个坑里,后来发现大概率不是MCP协议的问题,而是DeepSeek对tool calling的响应格式卡得比较死。你那个“函数调用参数格式错误”我太熟了,十有八九是JSON Schema里某个字段类型定义得不够严格,比如required没写全,或者properties里嵌套了多余的空值。建议你先把tools定义简化到只留一个必填参数试试,排除法定位问题根源。
另外,MCP的tool调用和OpenAI那种原生function calling确实有细微差别,FastMCP在序列化工具时可能会自动包一层wrapper,导致DeepSeek解析时拿不到预期的顶层参数。你可以抓一下实际发送给API的payload,看看tools数组里每个function的description和parameters是否被原样透传,有时候就是这里被框架偷偷加了东西。
还有个特别容易忽略的点,DeepSeek的chat模型如果temperature设得过高或者max_tokens太小,也可能返回空content但带个tool_calls字段,这时候别盯着content看,要检查response里有没有“tool_calls”这个key。我当时就是没打印完整响应,白白折腾了两天。
如果你方便的话,把FastMCP的版本和DeepSeek的API版本贴一下,我这边之前用的是0.3.2的FastMCP配deepseek-chat,调通之后一切正常。也可能你正好撞上了他们服务端某个临时调整,换个时间重试说不定就好了。
大概率是MCP工具返回格式和DeepSeek的function calling不兼容,试试把tools参数手动转成OpenAI格式。
我之前也踩过这个坑,搞了半天发现是FastMCP默认把tool的name转成了snake_case,但DeepSeek那边对函数名大小写特别敏感,你试试在decorator里显式指定name,别让它自动转换。另外空响应大概率不是MCP协议的问题,而是DeepSeek的chat模型在function calling时如果参数schema里缺了required字段,它就会懵掉直接返回空,你检查下parameters里每个属性有没有加required数组。还有个坑是DeepSeek的API对嵌套的JSON Schema支持得不太好,你要是用了allOf或者$ref这种高级写法,它可能解析失败,尽量拍平写成纯object加properties。我当时是把工具返回的tool_call id和函数结果重新组消息格式回传,才勉强跑通,你可以打印一下原始response的完整JSON,看看是不是有个tool_calls字段但内容是空的,如果是那样基本就是参数格式问题。最后建议先用最简单的无参数工具测试,确认链路通了再加复杂schema,不然很难定位是模型问题还是协议问题。
大概率是MCP的工具调用格式和DeepSeek原生的function calling有出入,检查下tools的schema结构,重点看参数类型和必填项。
也可能是DeepSeek对工具返回的strict模式支持不完整,试试把tool定义里的additionalProperties设为false,或者直接降级用原生function calling。
大概率是MCP的tool返回格式和DeepSeek的function calling不完全兼容,试试把参数校验放宽点。
大概率是MCP把tools包了一层结构化格式,DeepSeek那边不认,建议直接把原始function calling的参数透传试试。
我之前也卡在这,后来发现是FastMCP版本对tool schema做了二次封装,绕开直接用原生接口就好。
大概率是DeepSeek不认MCP那套工具调用格式,得手动转成它自己的function calling结构。