最近在折腾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时,模型一直返回空响应,是我姿势不对吗?
全部回复
共 195 条我之前也卡在这过,问题多半出在tool定义的strict模式上,DeepSeek对JSON Schema的校验比OpenAI严格,把additionalProperties显式设为false试试。另外MCP的tool调用确实会包装一层,你直接在messages里传tools参数,别完全照搬FastMCP的默认行为。空响应还有个常见坑是max_tokens设太小,函数调用结果一长就直接截断成空了,调大点能缓解。要是还不行,抓一下实际发给API的请求体,对比一下官方文档里的示例,格式错误基本就一目了然了。
我之前也卡在这块好久,后来发现是FastMCP默认把tool的parameters又包了一层,跟DeepSeek要的扁平结构对不上。你可以试试直接打印一下实际发给API的请求体,对比下官方文档里的示例。另外空响应多半是模型在等参数但没拿到,你把strict模式关掉或者手动把参数转成字符串再传试试。
我之前也卡这过,后来发现是MCP返回的tool结果格式跟DeepSeek预期的function calling不完全一样,得手动把MCP的content转成标准的JSON字符串再塞回去。还有那个参数格式错误,八成是JSON Schema里写了type: "object"但没给required字段,DeepSeek会严格校验这个。建议你先打印一下实际发给API的messages和tools,对比下官方示例,光看文档容易漏细节。
八成是MCP把tool参数又包了一层,DeepSeek只认原始JSON Schema,试试直接透传别让FastMCP加工。
我之前也卡在这过,大概率不是DeepSeek不支持MCP,而是FastMCP生成的tool schema和DeepSeek要求的格式有细微差别。你试试把parameters里的type字段显式写成"object",然后每个属性都加上"description",有时候缺了description它就会抽风。还有,空响应往往是因为模型觉得没有tool能处理这个请求,你可以在system prompt里加一句“必须调用工具来回答”,逼它走函数调用流程。如果还不行,抓一下实际发出去的请求体,对比下官方curl示例,多半能看出问题。
我之前也卡在这过,后来发现是MCP的tool返回格式跟DeepSeek预期的function calling不完全一样,尤其是parameters里的嵌套结构,它那边解析容易出问题。你可以试试把tool定义精简点,别用太复杂的JSON Schema,或者直接抓一下发出去的请求,看看实际payload长啥样。另外空响应有时候是超时导致的,把超时时间调大点试试。
大概率是tool返回的JSON Schema里少了strict或additionalProperties字段,DeepSeek对格式要求比文档写的更严。
我之前也卡这儿,后来直接把参数全改成字符串类型让它自动转才通。
我之前也卡在这块儿过,折腾了两天才发现不是MCP的问题,是DeepSeek的tool calling对strict模式支持得比较死。你检查下FastMCP传出去的parameters里有没有带"additionalProperties": false,DeepSeek那边如果不认这个字段,有时候会直接给你吞掉响应。另外,空响应还有个常见坑是temperature设太高了,模型有时候会“思考”到一半就中断,你试试调到0.1以下,或者加个max_tokens兜底,别让它觉得没话说了就给你个空壳子。函数调用参数格式错误那个报错,我怀疑是你tool定义里有个必填字段没给示例值,DeepSeek的模型在不确定怎么填的时候会瞎试,你把每个参数的description写清楚,再给个enum或者default,它就容易蒙对了。还有个笨办法,你先别走FastMCP,直接用requests调DeepSeek的原始API,把tool定义原样塞进去测一遍,如果通了,那就是FastMCP在中间层把schema给你改坏了,尤其是它可能自作主张给parameters外头包了一层。要是原始API也空,那你看看是不是工具名里有下划线或者连字符,换成纯字母数字立马好,别问我怎么知道的。
我之前也遇到过一模一样的情况,后来发现是我在MCP里定义tools时,把parameters的嵌套结构搞复杂了,DeepSeek对严格JSON Schema的兼容性没那么好,简化成扁平结构就好了。另外检查下FastMCP版本,旧版对tool调用响应的包装方式和官方文档有出入,升级到最新版试试。空响应很大概率是参数校验没过,但错误信息又没透传出来,建议你在调用前手动打印下发给模型的完整消息体,看下tool_calls是不是真的被正确解析了。
我之前也遇到过类似情况,后来发现多半不是MCP协议本身的问题,而是DeepSeek对tool calling的响应格式要求比OpenAI更严格。你检查下返回的报错信息里有没有“arguments”字段,它要求必须是合法的JSON字符串,不能直接传对象,我当初就是在这里栽的跟头。
另外FastMCP封装后可能会对工具描述做二次处理,建议你直接打印出实际发送给DeepSeek的请求体看看,尤其是tools数组里每个函数的parameters结构,有时候多一个“$schema”字段就会导致解析失败。
还有个坑是DeepSeek的chat模型如果遇到多个工具且没有明确用户意图时,容易返回空内容而不是正常的tool_call请求,你可以试试在system prompt里加一句“你必须通过调用工具来回答”,强行引导模型走function calling路径。
如果还不行,就先用OpenAI兼容模式跑一遍同样的代码,排除是DeepSeek的API版本差异还是MCP库的兼容性问题,这样定位起来更快。
我之前也遇到过类似情况,折腾了快两天。后来发现问题多半出在MCP把tools包装成结构化输出时,和DeepSeek原生的function calling格式有细微差异,特别是参数里嵌套object类型时容易触发它的解析bug。建议你先别用FastMCP,直接拿原始API调一次,把tool定义原样传过去,看能不能通——先排除框架层问题。我之前就是卡在这步,发现DeepSeek对严格JSON Schema里的enum和required顺序特别敏感,少个默认值它就返回空。另一个坑是MCP的tool name会加前缀,比如“query_weather”,但DeepSeek内部校验时可能不认带下划线的名称,你试试改成纯驼峰命名。还有个偏方,把parameters里所有字段都加上description,哪怕就写个“无”,模型有时就正常了,感觉是它解析时对空描述处理有bug。如果还不行,检查下你是不是把response_format设成了json_object,这个和tool调用会冲突,得去掉。最后实在不行就降级到DeepSeek的function calling接口,别走MCP那层,等官方更新吧,这坑我到现在也没完全摸清规律。
大概率是MCP把tool参数又包了一层,DeepSeek那边只认平铺的function calling格式,你检查下实际发出去的请求体。
我上次也卡这了,把tools定义直接改成DeepSeek原生格式,别用FastMCP的封装,立马就通了。
八成是DeepSeek的tool call对strict模式有要求,把parameters里加个"additionalProperties": false试试。
DeepSeek那边tool调用得用标准OpenAI格式,MCP的schema它经常解析不了,你先手动拼个function试试。
DeepSeek的function calling对参数schema挺挑的,你试试把parameters里的required字段和type都明确写全,别用嵌套太深的object。我之前也遇到过空响应,后来发现是tool返回的内容里混了非JSON格式,模型直接懵了。MCP那层其实只是帮你封装协议,底层还是走标准function calling,所以先拿掉MCP用原生API测一下,能通的话再套回去排查。另外注意DeepSeek的chat模型有时候对中文tool描述理解会偏,描述尽量写英文。