【Bug已解决】`unsupported call: mcp__<server>__<tool>` for MCP tools when used with custom Responses A...

【Bug已解决】`unsupported call: mcp__<server>__<tool>` for MCP tools when used with custom Responses A...
【Bug已解决】unsupported call: mcp__server__toolfor MCP tools when used with custom Responses API provider (Apps SDK custom model) 解决方案原始报错线索unsupported call: mcp__server__toolfor MCP tools when used with custom Responses API provider (Apps SDK custom model)当使用自定义的 Responses API provider 时调用 MCP 工具会报unsupported call因为该 provider 没有声明支持这种命名空间工具。一、现象长什么样用户配了一个「自定义 Responses API provider」比如自己搭的模型网关。然后想用一个 MCP 工具名字形如mcp__filesystem__read调用被 provider 拒绝unsupported call: mcp__filesystem__read换成官方内置 provider同样的工具却能调说明自定义 provider 的「支持工具清单」里没有mcp__前缀这套命名于是拒掉。 根因是工具名带提供方特定的命名空间前缀切换 provider 时前缀/能力没被适配和声明目标 provider 不认识就拒绝。二、背景工具命名空间与能力声明模型通过「工具名」调用外部能力。不同 provider 对工具名的约定不同内置 provider 认识mcp__server__tool这种 MCP 命名空间自定义 provider 可能只认识裸名read或自己另一套前缀还有的 provider 要求工具先在tools/list或等价声明里登记未登记即unsupported。 问题出在调用方用了 A 的命名发给了按 B 约定校验的 provider中间缺一道「命名空间翻译 能力校验」。三、为什么报 unsupported call根因3.1 命名空间前缀未翻译mcp__filesystem__read是给内置 provider 看的自定义 provider 要的是read或fs_read。没翻译直接发 → 不认识。3.2 provider 能力未声明自定义 provider 的「支持工具集」是空的或不含该工具调用前没校验就发出去 → 被拒。3.3 工具名含保留字符mcp__双下划线可能是某些系统的保留/分隔符自定义 provider 解析器把它当非法名。3.4 缺少适配层调用方直接拼 MCP 名发给 provider没有「provider 适配器」做转换与兜底。四、最小可运行复现命名不匹配被拒下面演示「按 A 命名发给 B provider」如何被拒class Provider: def __init__(self, name, supported_prefixes): self.name name self.supported_prefixes supported_prefixes # 该 provider 认哪些前缀 def call(self, tool_name): prefix tool_name.split(__)[0] if __ in tool_name else if prefix and prefix not in self.supported_prefixes: raise ValueError(funsupported call: {tool_name}) return f执行 {tool_name} builtin Provider(builtin, {mcp, native}) custom Provider(custom, {native}) # 自定义 provider 不认 mcp if __name__ __main__: print(builtin.call(mcp__filesystem__read)) # 成功 try: custom.call(mcp__filesystem__read) # 自定义 provider 拒 except ValueError as e: print(被拒:, e) # unsupported call: mcp__filesystem__read自定义 provider 不在supported_prefixes里直接拒——正是 Bug 表现。五、解决方案一provider 能力声明声明它支持什么每个 provider 明确声明「我支持哪些工具命名空间 / 哪些工具」调用前对照def provider_capabilities(provider_id): 返回该 provider 支持的工具前缀/集合。真实环境来自配置或握手。 caps { builtin: {prefixes: {mcp, native}, tools: set()}, custom_a: {prefixes: {native}, tools: {read, write}}, } return caps.get(provider_id, {prefixes: set(), tools: set()}) def is_supported(provider_id, tool_name): caps provider_capabilities(provider_id) if tool_name in caps[tools]: return True prefix tool_name.split(__)[0] if __ in tool_name else return prefix in caps[prefixes] if __name__ __main__: print(is_supported(custom_a, mcp__filesystem__read)) # False print(is_supported(custom_a, read)) # True声明 校验调用前就知道会不会被拒解决 3.2。六、解决方案二命名空间适配层翻译工具名切换 provider 时把 MCP 命名翻译成目标 provider 认的名字def translate_tool_name(tool_name, target_provider): 把 MCP 命名空间工具名翻译为目标 provider 认识的格式。 if __ not in tool_name: return tool_name parts tool_name.split(__) # mcp__server__tool - 不同 provider 不同映射 if target_provider custom_a: # 剥掉 mcp__server__ 前缀留裸名假设自定义 provider 按裸名路由 if parts[0] mcp: return parts[-1] # filesystem__read - read取末段 return tool_name if __name__ __main__: print(translate_tool_name(mcp__filesystem__read, custom_a)) # read print(translate_tool_name(mcp__filesystem__read, builtin)) # 原样适配层把mcp__filesystem__read翻成read再发给自定义 provider它就能认识了解决 3.1/3.3。七、解决方案三调用前校验 友好降级组合「能力校验 翻译」调用前若仍不支持给出明确原因而非神秘unsupporteddef safe_call(provider_id, tool_name): translated translate_tool_name(tool_name, provider_id) if not is_supported(provider_id, translated): return {ok: False, reason: fprovider {provider_id} 不支持工具 {tool_name}已尝试翻译为 {translated}, suggestion: 请在自定义 provider 中登记该工具或改用内置 provider} return {ok: True, tool: translated} if __name__ __main__: print(safe_call(custom_a, mcp__filesystem__read)) # {ok: False, reason: ...不支持..., suggestion: ...}翻译后仍不支持返回结构化原因 建议用户不再对着unsupported call发懵。八、跨 provider 一致性单一工具注册表所有 provider 共享一份「逻辑工具 → 各 provider 物理名」映射握手声明能力provider 接入时上报支持的工具/前缀调用方缓存保留字符约定工具名避免mcp__这类被多系统当保留的分隔符或明确其语义失败可重试到其他 provider某 provider 不支持能否路由到支持的。九、排查清单「自定义 provider 下工具报 unsupported call」按下面排查工具名是否带 provider 专属前缀如mcp__目标 provider 认吗第四节provider 是否声明了支持的工具/前缀第五节是否有命名空间适配层切换 provider 时翻译工具名第六节调用前是否校验不支持是否给原因而非神秘报错第七节保留字符冲突吗__是否被目标 provider 当非法能否路由到其他支持的 providerprovider 握手是否上报能力日志是否打印翻译前后工具名。十、小结「自定义 provider 下工具调用报 unsupported call」的根因是工具命名空间前缀在 provider 切换时未翻译、且目标 provider 能力未声明/未校验导致不认识的名字被拒。通用修复能力声明每个 provider 声明支持的工具前缀/集合调用前对照命名空间适配切换 provider 时把mcp__server__tool翻译成目标认的名字第六节校验 友好降级翻译后仍不支持返回结构化原因与建议共享映射 握手逻辑工具到各 provider 物理名的统一映射。 一句话工具名从来不是「全局唯一」的它绑定在某个 provider 的命名约定上跨 provider 调用必须有一层『命名空间适配 能力校验』把 A 的语言翻译成 B 的语言并在翻译后仍不通时给出明确原因。把适配层做成调用链的标配自定义 provider 就能和内置 provider 一样顺畅使用 MCP 工具——这与第 122 篇工具路由、第 134 篇能力协商、第 131 篇 MCP 暴露共同体现「跨提供方的能力必须有统一寻址与适配」。

最新新闻

日新闻

周新闻

月新闻