[控场AI]
· 6 分钟阅读· 3,131 字

用Python构建MCP Server:一个服务器同时接入Claude与OpenAI

用Python构建MCP Server:一个服务器同时接入Claude与OpenAI

MCP 统一 Agent 工具集成,一次编写服务器即可接入 Claude 与 OpenAI。

文章基于一位前微软、前 Apple Intelligence 工程师的教程,讲解如何用 Python 编写一个 MCP Server,同时接入 Claude Code 与 OpenAI Agent SDK。核心价值是一次编写工具、多处复用,避免为每个 Agent 重复写客户端。文中解释了 MCP 如何把 Agent 与工具的点对点集成降为统一协议连接,介绍了用装饰器定义工具、docstring 即描述、出错应抛 ToolError 而非普通异常等实践,并对比了 Claude 与 OpenAI 两侧接入代码的风格差异。远程服务器部分则强调安全:把远程服务器视为不可信、使用 allowed tools 白名单、写操作加审批、将工具返回当作非结构化输入以防 prompt injection。

MCP(Model Context Protocol)正在成为AI Agent工具集成的通用语言。本文基于一位前微软、前Apple Intelligence工程师的教程,讲解如何用Python编写一次MCP Server,同时接入Claude Code与OpenAI Agent SDK。核心价值很直接:一次编写工具,多处复用,无需为每个Agent编写客户端代码。

MCP解决了什么集成问题

在没有MCP的语境下,AI Agent与外部工具(GitHub、数据库、订单系统等)之间是点对点连接。据该教程作者分析,Agent与工具集成的数量会随两者规模乘积增长——当Agent数量增加时,集成的维护成本会迅速失控。

MCP连接示意

他给出的比喻是:原本需要为每一对“Agent-工具”编写独立集成,MCP作为中间层出现后,Agent侧只需维护一条协议连接,工具侧也同样如此。从工程角度看,这减少了重复适配代码,也让工具本身变成可被不同Agent框架共享的资产。

这解释了为什么Anthropic创建MCP后,OpenAI也选择支持它——它不是某一家厂商的私有协议,而是一个中立标准。

本地服务器:用装饰器定义工具

本地MCP Server使用stdio(标准输入输出)作为通信方式,这是最基础的形态。

在Python实现中,工具通过装饰器定义。函数的文档字符串(docstring)会直接变成工具描述,参数则从函数签名中提取。教程特别强调了一个容易出错的细节:抛出异常时应使用 ToolError,而非普通的 ValueError。

装饰器定义工具

原因在于错误处理的可读性。如果抛出普通异常,Agent看到的可能只是“执行工具失败”,没有返回原因,甚至可能触发无意义的自动重试。而 ToolError 会让模型看到明确的信息,例如“执行工具取消订单失败:订单已发货”,并附带返回值,方便Agent据此调整后续行为。

教程还提到,MCP支持resource(资源)机制,把policy、模板等以纯文本形式暴露给Agent,帮助模型在调用工具前做出判断。

stdio(标准输入输出) 是MCP定义的一种基础传输方式:客户端将服务器作为子进程启动,双方通过进程的 stdin 与 stdout 交换 JSON-RPC 消息,stderr 通常用于日志。它的优点是不需要监听网络端口、无需鉴权配置,天然适合本机运行的工具服务器;缺点是进程生命周期与客户端绑定,无法被多个客户端同时共享,也不适合跨机器调用。正因如此,MCP在stdio之外还定义了基于HTTP的传输方式,用于远程场景。

resource(资源) 是MCP中与tool并列的另一种原语。工具用于“执行动作”,资源则用于“读取内容”,通常以 URI 标识,返回文本或二进制数据,例如策略文档、提示模板、配置文件。客户端可以列出资源、按需读取,把它作为上下文提供给模型。Resource 一般是只读的,这也让它可以安全地暴露给 Agent 做调用前判断,而不触发副作用。

同一服务器接入Claude与OpenAI

这是整套方案中最具对比价值的部分。同一个MCP Server,接入两个不同的Agent框架时,客户端代码风格差异明显。

两种Agent行为差异

据教程作者演示,Claude侧的配置较为直观:在agent options中指定mcp_servers,给出name和command参数,server作为参数传入,再通过allowed_tools做过滤,权限模式与会话设置沿用之前的方式。

OpenAI侧则需要额外处理异步。作者提到需要创建 mcp_server_stdio 的异步进程,配合共享的server execution,再用 await 运行agent。作者个人更偏好OpenAI在allowed tools上的写法——直接写工具名和 require_approval 字段,简洁直观。

两者的行为也略有不同:同一个“取消订单”请求,Claude和OpenAI的执行路径不完全一致,这正是多框架适配时需要实测观察的地方。

远程服务器与安全策略

远程MCP Server通过streamable HTTP通信。据教程分析,Python对streamable HTTP的支持仍带有beta性质(代码中可见beta版本标记),而OpenAI侧已在使用生产级实现,作者对此评价“super简单”。

作者对远程服务器的安全建议相当明确:

  • 远程服务器是别人的代码,需要先弄清其实现;如果找不到实现,就去查可用工具列表,做核对
  • 只用allowed tools白名单,不要开放全部工具
  • 对任何写操作加审批,即使用户认为写入内容无害,也应有策略兜底
  • 把所有工具返回视为非结构化输入,警惕prompt injection

安全策略要点

这套思路的本质是把MCP Server当作不可信边界来对待,而不是默认可信的内部组件。

prompt injection(提示注入) 指攻击者把恶意指令藏进模型会读取的内容里,例如工具返回的网页、issue 正文、数据库字段,从而劫持 Agent 的后续行为。在 MCP 场景中,工具返回值和 resource 内容都可能是不可信来源。防御思路是把这些内容当作数据处理而非指令执行,配合最小权限白名单限制 Agent 能调用的工具范围,并对写操作强制人工审批,使被注入的指令即使被模型采纳,也无法造成不可逆的破坏。

allowed tools 白名单 是客户端侧的过滤器:即使服务器暴露了全部工具,客户端也只把其中一部分注册给模型。这样既能缩小工具描述占用上下文,也能降低误调用风险。Claude 通过 allowed_tools 参数声明,OpenAI 则用工具名加 require_approval 字段表达,并要求在异步进程中运行服务器。白名单与审批策略叠加,构成对不可信远程服务器的第一道防线。

常见错误与动手练习

作者指出的最常见错误,就是在MCP工具中抛出普通异常而非 ToolError。对比实验中,抛普通异常时Agent只会看到“error executing tool cancel_order”,没有返回值、没有原因,模型无从判断;换成 ToolError 后,模型能看到具体原因和返回内容,处理质量明显提升。

教程结尾留了一个练习:在allowed tools列表中移除 cancel_order,观察Agent行为变化。Claude侧只需删一行,OpenAI侧则创建一个静态工具过滤器,只保留一个工具名即可。

一句话总结:在MCP Server中写一次工具,Agent通过stdio或streamable HTTP接入;出错时优先使用 ToolError。

该教程的后续内容将涉及Claude Code与Codex等编码类AI Agent如何接入MCP Server,这可能是下一个值得关注的实践方向。

#MCP Server#Python MCP#Claude Code#OpenAI Agent SDK#Model Context Protocol#AI Agent工具集成#ToolError
分享:

相关推荐