一个被低估的现实:MCP 跑通 Demo 容易,跑稳生产很难
2025 年下半年由 Anthropic 推出来的 MCP(Model Context Protocol),被社区捧成"Agent 时代的 USB-C 接口"。半年过去,GitHub 上 mcp-servers 组织已经攒到 1800 多个 Server,FastMCP、mcp-proxy、Inspector 这些工具链也基本齐了。问题在于:Demo 跑通和上生产完全是两件事。
我们跟十几位国内一线 Agent 开发者聊下来,发现大家踩的坑高度集中在三个地方——连接稳定性、权限边界、数据隔离。官方文档对这些场景的描述要么一笔带过,要么干脆没写。
连接失败:stdio 模式不是银弹,HTTP+SSE 才是真考验
新手最容易踩的第一个坑,是默认用 stdio 跑所有场景。stdio 模式本地调试确实方便,Claude Desktop、Cursor 这些客户端原生支持,但放到 Linux 服务器上跑长任务,问题马上浮现:
- 子进程崩溃后父进程收不到退出码,Agent 以为还在运行
- 日志混在 stdout 里,stderr 经常被吞
- 进程隔离差,一个 Server 起 200 个并发实例就开始 OOM
生产环境几乎都得切到 Streamable HTTP(MCP 在 2025 年 11 月的版本里从 HTTP+SSE 迁过来的新传输层)。这里有个反直觉的点:很多人以为 HTTP 模式更稳定,结果遇到第一个坑是反向代理的 SSE 缓冲。Nginx 默认 proxy_buffering 是开的,会把 SSE 流攒成批量再转发,客户端看到的就是"卡死"。
避坑配置片段(Nginx):
location /mcp/ {
proxy_pass http://mcp_backend;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_buffering off; # 关键
proxy_cache off;
proxy_read_timeout 86400; # 长连接保活
chunked_transfer_encoding on;
}
第二个连接层的坑是心跳。官方 spec 里 ping 间隔是可选的,但生产里强烈建议把超时设到 30 秒以内。某电商团队在 2026 年 618 备战期就因为 60 秒心跳超时,导致 Buying Agent(参考 《当 AI 替你下单》 一文中的 17.3% 订单场景)高峰期大批连接被服务端单方面断开。
权限失控:OAuth 不是配上了就安全了
MCP 在 2026 年初引入了完整的 OAuth 2.1 流程,听起来权限问题应该解决了。但实际落地时开发者发现,MCP 的权限模型和传统 SaaS 完全不是一回事。
最大的认知偏差在于:MCP Server 通常不直接持有数据,它只是 Agent 访问下游系统(数据库、CRM、内部 API)的代理。这意味着——
- 权限边界到底划在哪一层?Server 鉴权完,还要不要给 Agent 二次鉴权?
- Token 缓存到 Server 内存里还是每次重取?
- 用户撤销授权后,已经在执行的 Tool Call 怎么办?
某金融科技团队的实践值得借鉴(详见 《招行建行用 Multi-Agent 抓洗钱》):他们在 MCP Server 前再加一层 Agent-level 鉴权网关,每个 Tool Call 都强制带上 user_id 和 purpose,下游系统按最小权限原则二次校验。代价是多了一次网络跳转,换来的是——任何一条审计日志都能精确到人、到工具、到调用目的。
代码侧的小坑:很多官方示例把 client_secret 写死在配置文件里,这在欧盟 AI 法案 Q3 严格执法后(参考 《欧盟 AI 法案 Q3 执法首日》)直接会被认定为高风险违规。生产里务必走 Vault 动态注入,或者用 Workload Identity 这类云原生方案。
数据隔离:Agent 把你的数据库删了,不是因为它"想",是因为你没拦
2026 年最让人后背发凉的一类事故,是 Agent 在多租户场景下误删/误读数据。MCP 本身不解决多租户隔离,它假设你下游系统自己处理。但 Agent 调用链路一长,中间任何一环漏掉 tenant_id 过滤,就会出大事。
有团队的做法是在 MCP Server 的入口处强制注入上下文:
@app.tool()
async def query_orders(filter: OrderFilter, ctx: Context):
# 强制从 MCP 会话上下文取 tenant_id,不信任前端传入
tenant = ctx.session.metadata["tenant_id"]
return await db.query(
tenant_id=tenant,
status=filter.status,
limit=filter.limit
)
更稳的做法是把数据访问层整体下沉到一个独立 Service,MCP Server 只做协议适配,不碰原始字段。这样即便 Agent 被 prompt injection 攻击(参考 《Sora 3 视频生成陷阱》 中提到的合成内容治理难题),能泄露的也只是过滤后的视图。
那些官方文档没写的边角问题
除了上面三大块,还有几个高频小坑值得列出来:
1. Tool 描述就是 Prompt。MCP Server 的 description 字段会被原样塞进 LLM 的 system prompt。一个含糊的描述,模型就可能误调工具。某团队把"查询订单"改成"查询当前登录用户的、未支付的、最近 30 天的订单",误调用率直接降了一半。
2. 长任务必须支持取消。MCP 1.2 之后引入了 notifications/cancelled,但很多 Server 没实现。Agent 用户点了"停止",后台还在跑——这种"幽灵任务"在计费场景下会出大事。
3. 别忽略 progressToken。动辄几十分钟的 Tool(比如跑一个 70B 模型的 batch 推理,参考 《端侧大模型功耗墙》),客户端需要进度回调,否则用户以为卡死了。
写在最后:MCP 不是银弹,但确实是当前最优解
半年下来,社区对 MCP 的态度从"神化"走向"工具化"。它解决了 Agent 与外部系统对接的标准化问题,但没有解决 Agent 本身的安全性、可靠性、成本控制问题。这些仍然要靠上层框架(LangGraph、AutoGen)和下层基础设施(审计、限流、可观测)一起兜底。
如果你正在评估要不要上 MCP,建议先用 《AI Agent 自动化运维实战》 里提到的那套思路——先在一个非关键业务上跑闭环,验证完 Tool 描述、权限边界、错误恢复三件事,再考虑推广。MCP 的生态红利是真的,但坑也是真的。
避坑的本质,其实还是那句老话:把每一次 Tool Call 都当成一次生产环境 API 调用来设计。