Dify MCP 接入踩坑实录:notifications/initialized 的终极解法

处理下面文章的MD错误格式,返回整个MD文章

关键词:Dify · MCP · JSON-RPC · notifications/initialized · invalid_param
结论先行:Dify 的 MCP 实现与 JSON-RPC / MCP 规范存在关键差异


一、问题背景

在将一个 MCP Server(HTTP 方式) 接入 Dify MCP Tool 时,服务端实现了:

  • initialize

  • notifications/initialized

  • tools/list

  • tools/call

但在 Dify 初始化阶段 cleanup 时,持续报错:

 
{
  "code": "invalid_param",
  "message": "Error during cleanup: ... validation errors for JSONRPCMessage",
  "status": 400
}

错误会随着返回内容变化而变化,极难定位。

二、问题现象汇总(所有失败尝试)

在 notifications/initialized 阶段,以下返回方式全部失败:

❌ 1. 不返回内容(204 No Content)

text
204 No Content
Content-Type: text/html

失败原因:

  • Flask 默认返回 text/html

  • Dify cleanup 阶段强制校验 Content-Type

❌ 2. 返回空 JSON

json
{}

失败原因:

  • 虽然是 object

  • 但不符合任何 JSON-RPC Message 类型

❌ 3. 返回 null 

null

失败原因:

  • null → NoneType

  • Pydantic 要求 object

❌ 4. 返回空字符串 

<empty body>

失败原因:

  • JSON 解析直接 EOF

  • 报 Invalid JSON: EOF while parsing

❌ 5. 返回 JSON-RPC Response(伪造)

json
{
  "jsonrpc": "2.0",
  "id": 0,
  "result": {}
}

失败原因:

  • Dify cleanup 阶段明确不允许 Response

  • 即使格式完全正确也会报错

三、关键发现:Dify 的真实校验逻辑

通过多轮错误信息反推,Dify 在 cleanup 阶段做了如下逻辑:

python
parsed = json.loads(response_body)
JSONRPCMessage.model_validate(parsed)

其中 JSONRPCMessage 是一个 Union:

  • JSONRPCRequest

  • JSONRPCNotification

  • JSONRPCResponse

  • JSONRPCError

结论:
Dify 要求:每一个 HTTP 响应体都必须是一个合法的 JSON-RPC Message

四、最终正确答案(唯一解)

✅ notifications/initialized 必须返回「Notification 本身」

即:返回一个 JSON-RPC Notification 对象,而不是 Response,也不是空

✅ 正确返回内容

json
{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}

满足:

  • ✔ 是合法 JSON

  • ✔ 是 object

  • ✔ 能匹配 JSONRPCNotification

  • ✔ 没有 id(符合 Notification 语义)

  • ✔ cleanup 阶段不会当成 Response

五、Flask 最终正确代码示例

python
from flask import Response as FlaskResponse
import json

if method == 'notifications/initialized':
    logger.info("MCP Notification initialized received")

    response_data = {
        "jsonrpc": "2.0",
        "method": "notifications/initialized"
    }

    return FlaskResponse(
        response=json.dumps(response_data),
        status=200,
        content_type="application/json"
    )

⚠️ 注意事项:

  • 必须有 jsonrpc

  • 必须有 method

  • 绝对不能有 id

  • Content-Type 必须是 application/json

六、最终可用的完整 MCP 交互时序

text
initialize
→ 200 application/json
→ JSONRPCResponse

notifications/initialized
→ 200 application/json
→ JSONRPCNotification

tools/list
→ 200 application/json
→ JSONRPCResponse

tools/call
→ 200 application/json
→ JSONRPCResponse

至此,Dify MCP Tool 可以稳定进入可用状态。

七、核心总结(一句话版)

Dify MCP ≠ MCP / JSON-RPC 规范

在 Dify 中:

  • Notification 不能"不回"

  • Notification 不能回 Response

  • 必须回一个 Notification 对象本身

八、经验教训

  1. 不要假设 Dify 严格遵循 MCP / JSON-RPC 规范

  2. cleanup 阶段的错误,往往来自"语义合法,但实现不接受"

  3. 这个问题只有通过穷举 + 反向工程错误信息才能定位

九、适用版本说明

  • Dify:1.7.x

  • MCP 协议:Dify MCP Tool(HTTP)

  • JSON 校验:Pydantic v2

十、后记

这是一个规范与实现严重偏差导致的经典坑。

如果你在 Dify MCP 接入时遇到:

  • invalid_param

  • cleanup validation error

  • JSONRPCMessage 校验失败

第一时间检查 notifications/initialized 的返回值。

写到这里,已经不是"会用 MCP",而是"理解 Dify MCP 实现细节"了。

posted @ 2025-12-31 21:04  编程笔记  阅读(0)  评论(0)    收藏  举报