Dify MCP 集成实验(04):企业系统对接场景——企业系统对接选 MCP 还是插件?
1. 业务场景
先讲一个我们实际遇到的场景。
一家做客服工单 SaaS 的公司,坐席处理工单时要查客户背景:客户是什么等级、有没有历史订单。CRM 系统有 API,但 AI 助手不能直接调——要把能力封装起来。封装有两条路:写 Dify 插件(106-04 已实现),或者封装成 MCP server(本实验)。同一个需求,双实现,选哪条?交付时「什么时候配置接入、什么时候写插件」的决策,直接影响交付成本。
我们第一次接这类需求时,第一反应是「插件是 Dify 亲生的,肯定优先写插件」。真正动手才发现——选型不绑定实现:同一份契约,MCP 单文件 server.py 一条命令就起来,插件要打包签名安装;但插件全平台可用、MCP 跨平台通用。没有绝对答案,只有按客户场景算的账。我们把两条路都做出来逐维对比,结论才能站得住。
这不是个例。任何「企业系统对接 AI 应用」的项目都是这个模式:同一个 ERP/CRM 对接需求,MCP 和插件是两条路,选错成本不小——这是「企业级 AI 智能体系统集成」服务的关键技术判断。
2. 场景痛点
这个流程的痛点,在选型时体现得最直接:
- 选型没依据:什么时候配置接入、什么时候写插件——凭感觉选,交付时说不清为什么,客户追问就卡壳。
- 开发量差异大:插件要 manifest + provider yaml/py + tools yaml/py + 打包签名安装(多文件多步骤);MCP 单文件 server.py(~100 行)+ 一条命令起服务。
- 部署形态不同:插件上传安装进 Dify 平台(平台托管);MCP 是独立 HTTP 进程,Dify 配 URL——运维路径、网络路径都不一样。
- 复用范围不同:插件全平台任何应用可用(平台内);MCP 配置它的应用可用(跨平台通用,任何 MCP 宿主可连)——能力要给几个宿主用,直接决定选型。
本质上,选型不绑定实现——契约一致,双实现可互换,关键是按客户场景(复用范围/治理要求/网络环境)选。
3. 方案:为什么是 MCP vs 插件双实现对照
把 mock CRM 契约封装成 MCP server + Dify 工作流编排调用,与 106-04 同契约的插件实现对照——产出 MCP vs 插件选型实证。
选它的理由:
- 同契约对照:与 106-04 插件完全一致(字段名/类型/样本数据,CUS-XXX 格式、小写自动归一、param_invalid/not_found 错误码)——选型不绑定实现,双实现可互换;
- 六维对照表实测数据:开发量/部署形态/入 Dify/复用范围/认证/网络路径——每个维度都是 106-04 vs 107-04 的实测对比,不是空谈;
- 决策树可交付:客户语言版选型决策树(已有现成 MCP server?→ 配置接入;跨平台复用 → 自建 MCP;深度集成/签名治理 → 写插件),直接进服务包。
这篇文章我们就用它把 mock CRM 契约封装成 MCP server,与插件实现逐维对照,产出选型实证。
4. 整体架构
链路很清晰:本地 CRM server(两工具)→ Dify 工作流(双 MCP 工具节点)→ LLM 汇总客户画像 → end。关键设计是两条消费路径分开验证:结构化输出字段展开直连 LLM、list 输出经 code 节点解析——零新坑的编排模式。
5. 模块设计
5.1 契约对齐(与 106-04 插件一致,迁移纪律)
| 工具 | 参数 | 返回字段 | 错误 |
|---|---|---|---|
| get_customer_info | customer_id(CUS-XXX 3 位数字,小写自动归一) | customer_id/level/contact/tickets | param_invalid/not_found(SDK isError 透传) |
| get_customer_orders | customer_id(同上) | 订单列表 order_id/status/amount/tracking | 同上 |
5.2 MCP vs 插件六维选型对照表(实测数据,106-04 vs 107-04)
| 维度 | 106-04 插件(dify106_04_enterprise_tool) | 107-04 MCP(dify107_04_crm_server) |
|---|---|---|
| 开发量 | manifest + provider yaml/py + tools yaml/py + 打包签名安装(多文件多步骤) | 单文件 server.py(~100 行)+ 一条命令起服务 |
| 部署形态 | difypkg 上传安装进 Dify 平台(平台托管) | 独立 HTTP 进程(uvicorn :8904),Dify 配 URL |
| 入 Dify | 插件页上传 → 全平台工具列表可用 | 工具页 MCP tab 填 URL(API:POST tool-provider/mcp) |
| 复用范围 | 全平台任何应用可用(平台内) | 配置它的应用可用(跨平台通用,任何 MCP 宿主可连) |
| 认证 | 平台 credentials(UI 管理) | header/OAuth(107-05 验证) |
| 网络路径 | 插件直连出口,不经 squid(无 SSRF 限制) | 经 squid 代理(需白名单,107-03 实测) |
| 信任/治理 | 平台签名安装(信任高) | 外部 URL + 鉴权(信任低,需企业级认证) |
| 错误体系 | 四 code JSON(param_invalid/auth_failed/not_found/upstream_error) | SDK 异常 → isError + 错误信息透传(code 前缀保留) |
5.3 选型决策树(客户语言版,可进服务包)
6. 运行验证
| 输入 | 预期 | 结果 |
|---|---|---|
| CUS-001 | 客户等级 VIP、联系人张先生;最近订单含已送达 ¥1,299.00 与运输中 ¥599.00 | 通过 |
| cus-002(小写归一化) | 客户等级 normal;最近一笔订单 ORD-20260803003 pending ¥299.00 | 通过 |
| CUS-999(不存在) | not_found → workflow failed(显式非静默) | 通过(显式失败) |
| abc(格式错) | param_invalid → workflow failed | 通过(显式失败) |
| 双工具编排 | 一个 server 多工具在工作流多节点独立引用,零新坑 | 通过 |
7. 实战坑
| 坑 | 现象 | 修复 |
|---|---|---|
| list 结构化输出 | get_customer_orders 返回 list[Order],Dify 端 json=array[object](text 空同 107-03) | 下游用 code 节点解析 json 字段展平(cd_orders 模式),LLM 不直引 array[object](实测) |
| 错误 code 前缀 | server raise ValueError("not_found: ...") → Dify isError 信息透传含 code | 下游可用字符串匹配分支(107-06 优雅降级据此做)(实测) |
| 契约一致性 | 与 106-04 插件同契约(CUS-XXX/字段/错误 code) | 双实现可互换——选型不绑定实现,交付时按客户场景选(实测) |
| 网络差异 | 插件直连不经 squid(无 SSRF 限制,代码层自控)vs MCP 经代理(需白名单) | 重要运维差异,交付时在接入说明里写清(实测 107-04 + 107-03) |
8. 实验文档及源码获取
- 实验文档(完整操作步骤):DIFY-107-04:企业系统对接场景.md
- 源码(可直接导入):dify107_04_验证应用.yml
- Server 源码:dify107_04_crm_server 目录
- 交付验证记录(六维对照表 + 选型决策树):验证记录-04-企业系统对接场景.md
- 全部目录:dify-107/experiments | dify-107/dsl | dify-107/servers | dify-107/delivery
文章聚焦核心配置与采坑点;实验的完整分步操作(节点搭建/参数表/调试指引)见实验文档原文。