ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

Dify MCP 集成实验(02):工具进阶与协议原语——MCP 三原语如何落地?

Dify MCP 集成实验(02):工具进阶与协议原语——MCP 三原语如何落地? Dify MCP 集成实验02工具进阶与协议原语——MCP 三原语如何落地Dify 实验系列 · MCP 集成 02/6 | 实验编号DIFY-107-02基于 Dify 1.16.1 实测2026-081. 业务场景先讲一个我们实际遇到的场景。一家做客服工单 SaaS 的公司支持团队每天处理大量工单查询「退款相关的工单有哪些」「T1002 现在什么状态」这些查询如果能直接做成 MCP 工具客服门户的 AI 助手就能自己查。同时还有排障手册可读资源和工单分析模板提示词——在 MCP 协议里工具、资源、提示词是三种原语一个 server 都能表达。我们第一次接这类需求时第一反应是「把查询做成工具就完事了」。真正动手才发现——客户要的不只是工具排障手册、分析模板也是交付的一部分三原语都得能表达而且工具返回裸 dict 看着能用下游解析一碰就碎。协议能表达什么是上限平台消费什么是边界两头都要摸清。这不是个例。任何「外部系统数据进 Dify」的集成都是这个模式先搞清楚协议能表达什么tools / resources / prompts才知道哪些能力 Dify 用得上、哪些要换种方式包装——「Dify 只消费 tools」的源码结论要靠本实验的 server 107-03 接入实证。2. 场景痛点这个流程的痛点在协议落地时体现得最直接只会写工具不够客户要的不只是查询工具还有排障手册、分析模板——三原语都得能表达少一个交付就缺一块。结构化输出难工具返回裸 dict下游解析脆弱——字段错一个就崩structured_outputTrue时返回类型不对直接报InvalidSignature。参数校验缺失非法状态、不存在的工单号返回什么静默空结果最坑——下游把「没查到」误判成「查询失败」。协议能力边界不清不知道 Dify 只消费 tools——客户要「资源读取」时不知道怎么包装方案当场卡壳。本质上协议能表达什么是上限平台消费什么是边界——两头都清楚交付才不会返工。3. 方案为什么是 MCP 三原语完整实现在 107-01 地基上把 MCP 协议三原语tools / resources / prompts在 server 侧完整实现——多工具、结构化输出、参数校验、资源与提示词模板。选它的理由协议原生一套 server 全实现server.tool()重复装饰即可注册多工具1:N 关系实证server.resource()/server.prompt()补齐资源与提示词——三原语同 server 共存结构化输出强制structured_outputTrue Pydantic 模型——返回类型编译器级兜底裸 dict 直接报错不留给运行期契约一致性mock 工单字段ticket_id/status/updated_at与 105 工单系统一致迁移纪律——本实验产出的 server 是 107-03 的对照基准。这篇文章我们就用它扩展 107-01 的 server把三原语完整落地为客户「资源读取」类诉求的包装方式提供依据。4. 整体架构HTTP本地开发机dify107_02_support_server在 107-01 环境上扩展uvicorn :8902/mcptoolssearch_tickets / get_ticket_status多工具 参数校验 结构化输出resourcessupport://troubleshootinglist/read 处理器promptsticket_analysislist/get 处理器Dify 服务器107-03 接入预期只见 toolsresources/prompts 不可用链路很清晰本地 servertools resources prompts 三原语→ HTTP → Dify 服务器107-03 接入。关键设计是三原语同 server 共存为「Dify 只见 tools」的对照结论提供运行级实证基础。5. 模块设计5.1 结构化输出工具返回类型必须 Pydantic 模型frompydanticimportBaseModelclassTicketStatus(BaseModel):ticket_id:strstatus:strupdated_at:strtitle:strserver.tool(structured_outputTrue)defget_ticket_status(ticket_id:str)-TicketStatus:按工单号查状态格式错/不存在 → raise ValueError(not_found: ...)...坑点预埋structured_outputTrue时返回类型必须是 Pydantic BaseModel裸 dict 报InvalidSignature。5.2 资源与提示词三原语补齐# 资源静态 模板模板可读但不进 listSDK 2.0 观察点server.resource(support://troubleshooting)server.resource(support://troubleshooting/{topic})deftroubleshooting(topic:str|NoneNone)-str:...# 提示词SDK 2.0 PromptMessage 只认 user/assistant无 system 角色server.prompt()defticket_analysis(ticket_id:str)-list[dict]:return[{role:user,content:f请分析工单{ticket_id}的处理情况…}]5.3 多工具注册一个 server 暴露多个工具server.tool()重复装饰即可1:N 关系实证工具名冲突时 SDK 自动告警warn_on_duplicate_tools。6. 运行验证输入预期结果search_tickets退款pending返回 T1003通过search_tickets登录open空列表structured{result: []}空结果 ≠ 错误通过search_tickets非法状态 BADisErrorTrue 中文错误通过get_ticket_statusT1002structured_content完整返回通过get_ticket_statust1004 小写归一化 T1004 正常返回通过get_ticket_statusT9999 不存在status: not_found显式空结果非静默通过resources/list read列出并读取support://troubleshooting条目通过prompts/list get返回 ticket_analysis 模板user 消息通过7. 实战坑坑现象修复结构化输出要求 Pydantic 模型structured_outputTrue返回裸 dict 报InvalidSignature: return type dict is not serializable for structured output返回类型声明为 BaseModel 子类实测prompt 无 system 角色写role: system报 ValidationErrorSDK 2.0 PromptMessage 只接受 user/assistant实测模板资源不进 listresources/list只列静态 Resource{topic}模板可读但不在列表静态 模板双装饰read(login) 成功证明注册有效实测模板资源错误read 未知主题 → server 端 raise客户端收到 “Error creating resource from template”错误透传server 打堆栈日志实测空结果语义空列表返回structured{result: []}按「空结果 ≠ 错误」纪律处理下游不误判失败实测多工具命名冲突工具重名注册不报错SDK 自动告警warn_on_duplicate_tools命名规范避免实测8. 实验文档及源码获取实验文档完整操作步骤DIFY-107-02工具进阶与协议原语.mdServer 源码dify107_02_support_server 目录交付验证记录三原语对照清单 四类调用验证验证记录-02-工具进阶与协议原语.md全部目录dify-107/experiments | dify-107/dsl | dify-107/servers | dify-107/delivery文章聚焦核心配置与采坑点实验的完整分步操作节点搭建/参数表/调试指引见实验文档原文。下一篇Dify MCP 集成实验03MCP 接入 Dify 全链路——MCP Server 如何接入 Dify 应用 你在这个实验的场景里踩过什么坑欢迎评论区分享你的实战经验。
返回列表