国产 MCP 的真实身份:不是模仿,是分叉
2024 年 11 月,Anthropic 发布 MCP(Model Context Protocol),外界很快把它比作"AI 世界的 USB-C"。到 2026 年,这套协议的生态已经不算小:Cursor、Windsurf 等编辑器接入了 MCP,OpenAI 的 Agent SDK 也正式支持 MCP,MCP Server 数量同步爆发(来源:天翼智库 2025 年 5 月分析)。从表面看,MCP 似乎已经稳坐事实标准。
但对一个在生产里跑过工具调用的团队来说,槽点也跟着规模一起长:默认鉴权只看 API Key、流式传输在跨地域网络下抖动、对国内网络环境和企业内网账号体系不友好。这给国产分支让出了一条缝。
所谓"国产 MCP 协议",不是某家大厂的官方项目,而是 2025 年下半年起,由国内开源社区主导的几个分支:以 ModelContextProtocol-NG、OpenMCP-China 为代表的分支保留了 Anthropic 协议的核心语义(tools/list、tools/call、resources/subscribe 一字未改),但把传输层从 stdio 默认换成 HTTP/2,过手鉴权改为 OAuth 2.1 + 国密 SM4 可选项,并补齐 NDJSON 事件流。
换句话说,它们不重新发明轮子,而是把轮胎换成更适配国内路况的型号。
为什么这次要动手迁
团队手上三个 Agent 已经稳定运行 8 个月:一个是合同条款检索(接 Elasticsearch + 自研文档解析),一个是工单摘要(接内部 CRM),另一个是面向运维的 CLI 助手(接 Prometheus + 公司内网知识库)。原本都跑在 LangChain 的 AgentExecutor 上,工具层用的是 LangChain 1.0 的 Tool 抽象。
听起来很顺,但接入新工具的路径很别扭:
- 每个新工具都要在 LangChain 里注册
BaseTool子类,写 args schema、pydantic 校验和错误回调,少则 60 行,多则 150 行; - 工具描述只在程序内有效,不能跨进程、跨 Agent 复用;
- 流式输出依赖 LangChain 的
CallbackHandler,对 SSE、WebSocket 边缘场景不友好; - 想做企业内网 SSO 鉴权,得在 LangChain 外套一层中间件,调试链路断。
如果 MCP 真像宣传的那样是"USB-C",这三个 Agent 的工具层应该可以一次性改完,工具描述可被外部发现,跨进程复用——这正是迁移的动机。但迁移前必须验证:分叉版本的鉴权与流式传输表现,是否覆盖了生产场景的所有硬约束。
实测差异:鉴权、流式与"国产分支"
测试环境:北京到上海双地域节点,模拟电信+联通双线,企业账号走 Okta SSO。
| 维度 | Anthropic MCP(2025-Q4) | 国产分支(本测试版 2026-Q1) |
|---|---|---|
| 默认传输 | stdio / SSE | HTTP/2(可回退) |
| 鉴权方式 | API Key | OAuth 2.1(PKCE)+ 国密 SM4 可选 |
| 流式格式 | SSE + JSON-RPC | NDJSON / SSE / WebSocket 三选 |
| 工具发现 | tools/list |
完全兼容,额外支持 prompts/list + resources/subscribe |
| 多租户 | 不内置 | 内置 tenant_id 字段 |
实测三个点:
- 鉴权链路:Anthropic 版在跨地域调用时,第一次握手延迟在 180–250 ms,国产分支降到 90–130 ms,主要省在 TLS 复用与国密握手;
- 流式稳定性:连续调用 1000 次工具,对比 P99 抖动,国产分支从 14.7% 降到 4.2%;
- 错误语义:两者都遵循 JSON-RPC 2.0 的错误码,国产分支补了
-32010(鉴权失败)、-32011(限流)业务级错误,便于上层做精细化重试。
代码层面,server.py 从原本 LangChain 里的 BaseTool 子类,改成 MCP 推荐的装饰器写法:
# 老版本(LangChain 1.0)
from langchain.tools import BaseTool
class GetContractTool(BaseTool):
name = "get_contract"
description = "根据合同 ID 获取条款"
args_schema = ContractInput
def _run(self, contract_id: str):
return es.search(contract_id)
# 新版本(国产 MCP 分支)
from mcp.server import Server
from mcp.types import Tool, TextContent
app = Server("contract-tools")
@app.list_tools()
async def list_tools() -> list[Tool]:
return [Tool(
name="get_contract",
description="根据合同 ID 获取条款",
inputSchema=ContractInput.schema(),
)]
@app.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "get_contract":
return [TextContent(type="text", text=es.search(arguments["contract_id"]))]
装饰器替代继承,最大的好处是工具描述 JSON 化,可以在不重启 Agent 的情况下被外部发现。
迁移耗时:不是"几小时"也不是"一个月"
三个 Agent 的迁移工作分散在 2 名工程师身上,记录如下:
| 模块 | 合同条款检索 | 工单摘要 | 运维 CLI 助手 |
|---|---|---|---|
| 工具层重写 | 0.5 人日 | 0.5 人日 | 1.0 人日 |
| 鉴权类目整合 | 0.3 人日 | 0.2 人日 | 0.5 人日 |
| 流式回调适配 | 0.5 人日 | 0.5 人日 | 1.0 人日 |
| 单元 + 集成测试 | 1.0 人日 | 0.8 人日 | 1.5 人日 |
| 合计 | 2.3 人日 | 2.0 人日 | 4.0 人日 |
总计约 8.3 人日(含联调、灰度切换、上线值班),比团队最初预估的两周提前了三天。最难的不是协议本身,而是把 LangChain 的 CallbackHandler 行为映射到 MCP 的 NDJSON 事件上:例如 LangChain 的 on_tool_start、on_tool_end 在 MCP 体系下要拆成 progress、result、error 三类事件,还得保证事件顺序与超时设置一致。
完整的迁移代码与测试报告已开源在团队仓库(migrate-agent-to-mcp-demo),包含:
- 三对一的迁移前后对比;
- 模拟客户端(基于 NDJSON 与 SSE),可独立跑通;
- 鉴权配置样例(OAuth 2.1 + 国密 SM4);
- 用
pytest-asyncio写的事件顺序回归套件。
哪些场景值得迁,哪些先按兵不动
迁移完成后,给出三条参考意见:
建议迁:
- 跨团队、跨 Agent 复用同一组工具(这是 MCP 的最大优势);
- 需要企业内网 SSO、细粒度权限或多租户鉴权;
- 已经在 LangChain 上做了大量自定义 BaseTool,想把工具层独立部署的团队。
暂缓迁:
- 单 Agent、单工具的玩具项目,MCP 的额外传输开销得不偿失;
- 已经把工具描述稳定在 LangChain
BaseTool体系内,且短期内不会跨进程复用; - 对网络隔离要求极严、需要把工具进程压在独立沙箱内的场景——MCP 的网络面比 stdio 更宽,要重新评估。
回到标题的问题:把工具调用层换掉要重写多少代码? 答案是一个具体的数字:8.3 人日,三 Agent,4 个核心模块。不是几小时,但也不是重写整个 Agent。在 2026 年的 Agent 生态里,这场迁移更像是一次中层装修:地板拆了重铺,但结构没动。
对正在评估 MCP 的团队,更值得提前回答的问题不是"要不要迁",而是"你的工具描述能不能脱离 Agent 进程独立发布"。如果可以,迁移会顺;如果还在每个 Agent 内部硬编码,那就再等等。
延伸阅读:可对照《Cursor 3 做代码预审,团队该把哪一步交给 AI》 一文,看 MCP 在客户端 IDE 中的另一类实践;以及《AI Agent 合规新解》 中关于企业级鉴权与数据合规的补充。