ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Completions与通知机制:自动补全、进度上报与状态通知

Completions与通知机制:自动补全、进度上报与状态通知 摘要MCP Completions原语提供自动补全能力通知机制支持进度上报和状态推送。本文详解补全请求响应格式、进度通知协议和长任务实时状态更新实现。Completions与通知机制 自动补全、进度上报与状态通知我之前给团队写过一个批量数据导出工具跑一次要好几分钟。用户每次都来问我到底是卡死了还是在干活。后来我把 MCP 的进度通知接上界面能实时显示处理到第几条问题一下子就没了。这篇就来聊聊 MCP 里那些容易被忽略的交互细节包括自动补全、进度上报、日志推送和资源变更通知配套可运行的代码。MCP 通知机制全景MCP 底层是 JSON-RPC 2.0。请求有 id 要等响应通知没有 id 也不需要响应是单向的“即发即忘”消息。这套单向通道撑起了 MCP 里大部分实时交互。服务端能主动发给客户端的常用通知有这么几类。通知方法触发时机关键字段notifications/progress长任务执行中progressToken、progress、total、messagenotifications/message服务端打日志level、logger、datanotifications/resources/updated某个资源内容变了urinotifications/resources/list_changed资源清单变了无notifications/tools/list_changed工具清单变了无notifications/prompts/list_changed提示清单变了无notifications/cancelled取消进行中的请求requestId、reason记住一点通知本身不保证送达网络断了就丢了。所以协议规定进度通知的 progress 值必须单调递增断了重连也不会回退客户端按最新值渲染就行。进度通知实战进度通知的玩法是“客户端先给令牌服务端再拿着令牌回传进度”。客户端在请求的_meta.progressToken里塞一个字符串或整数服务端在处理过程中不断发notifications/progress把同一个 token 带回来。协议里 progress 必须递增total 可以省略不知道总量时就别填message 给人看的。我用 FastMCP 写一个长任务工具配合 Context 对象上报进度和日志。日志通知与等级控制日志通知用notifications/message发送字段是 level、logger、data。level 走的是 syslog 那套从 debug 到 emergency 共八级。客户端会先发logging/setLevel设一个最低等级服务端只回传达到等级的日志。在 FastMCP 里直接用 Context 的快捷方法就行ctx.info()、ctx.debug()、ctx.warning()、ctx.error()分别对应不同等级。这些日志会作为结构化通知发给客户端方便在界面上分级展示。Completions 自动补全Completions 原语让服务端给 prompt 参数和 resource URI 模板提供补全建议做出类似 IDE 输入提示的效果。客户端发completion/complete带一个引用类型和当前输入值服务端返回最多 100 条建议。引用类型只有两种ref/prompt按 prompt 名字引用ref/resource按 URI 引用。这里有个很多人搞错的地方Completions 只支持 prompt 参数和 resource URI 模板不支持 tool 参数补全。我最早以为 tool 参数也能补全调了半天没反应翻规范才发现压根没这个能力。下面用低级 SDK 写一个带补全的服务端给 code_review 这个 prompt 的 language 参数做补全。资源与列表变更通知当服务端的资源内容、资源清单、工具清单或提示清单发生变化要主动通知客户端刷新缓存。比如后台跑了个任务改了某个配置文件就发notifications/resources/updated带上 uri客户端收到后重新读取该资源。新增或删除了工具就发notifications/tools/list_changed客户端重新拉取工具列表。这类通知没有参数体resources/updated 除外它带 uri语义就是“你缓存的清单过期了重新拉一次”。客户端收到后调对应的 list 方法即可。完整代码先装依赖。pipinstallmcp[cli]fastmcp服务端progress_server.py用 in-SDK 的 FastMCP 实现长任务进度和日志上报。# progress_server.py# 进度上报与日志通知的服务端示例importasynciofrommcp.server.fastmcpimportFastMCP,Context# 创建一个命名服务端名字会显示在客户端里mcpFastMCP(ProgressDemo)mcp.tool()asyncdefbatch_export(total:int,ctx:Context)-str:模拟批量导出逐条处理并上报进度和日志。 Args: total: 要处理的记录总数 ctx: MCP 注入的上下文用来发进度和日志 # 打一条 info 日志会作为 notifications/message 发给客户端ctx.info(f开始批量导出共{total}条记录)# 逐条处理模拟耗时操作foriinrange(1,total1):# 上报进度参数依次是当前进度、总量、可读消息# report_progress 是协程需要 awaitawaitctx.report_progress(i,total,f正在处理第{i}/{total}条)# 每处理 10 条打一条 debug 日志便于排查ifi%100:ctx.debug(f已处理{i}条进度{i/total:.0%})# 模拟单条耗时真实场景换成实际处理逻辑awaitasyncio.sleep(0.2)# 收尾日志标记任务结束ctx.info(批量导出完成)returnf成功导出{total}条记录if__name____main__:# 默认走 stdio 传输适合被客户端以子进程方式拉起mcp.run()客户端progress_client.py用 standalone FastMCP 的 Client 接收进度回调。# progress_client.py# 进度通知的客户端示例连接上面的服务端并接收进度importasynciofromfastmcpimportClientasyncdefon_progress(progress:float,total:float|None,message:str|None):进度回调每收到一条 notifications/progress 就触发一次。 Args: progress: 当前进度值单调递增 total: 总量未知时为 None message: 服务端附带的可读消息 # total 存在时算百分比否则只显示当前值iftotal:percentprogress/total*100print(f[进度]{percent:5.1f}%{message})else:print(f[进度]{progress}{message})asyncdefmain():# 用脚本路径构造客户端会自动以 stdio 方式拉起服务端子进程clientClient(progress_server.py)asyncwithclient:# 调用长任务工具传入进度回调# progress_handler 会被绑定到客户端生成的 progressToken 上resultawaitclient.call_tool(batch_export,{total:30},progress_handleron_progress,)# 打印最终返回值print(最终结果:,result.data)if__name____main__:asyncio.run(main())补全服务端completion_server.py用低级 SDK 给 prompt 参数做补全。# completion_server.py# Completions 自动补全服务端示例基于低级 SDKimportmcp.server.stdioimportmcp.typesastypesfrommcp.server.lowlevelimportNotificationOptions,Serverfrommcp.server.modelsimportInitializationOptions# 创建低级服务端实例名字任意serverServer(CompletionDemo)# 预置的编程语言候选词真实项目可换成数据库查询结果LANGUAGES[python,pytorch,pyside,javascript,java,rust,ruby]server.list_prompts()asyncdefhandle_list_prompts()-list[types.Prompt]:声明服务端有哪些 prompt客户端据此展示可选模板。return[types.Prompt(namecode_review,description代码审查提示模板,arguments[types.PromptArgument(namelanguage,description要审查的编程语言,requiredTrue,)],)]server.complete()asyncdefhandle_complete(ref,argument,context):补全请求处理器根据引用类型和当前输入返回建议。 Args: ref: 引用对象PromptReference 或 ResourceReference argument: 当前正在输入的参数含 name 和 value context: 已解析的其他参数做多参数联动时有用 # 只处理对 code_review 这个 prompt 的补全ifisinstance(ref,types.PromptReference)andref.namecode_review:# 针对 language 参数做前缀匹配ifargument.namelanguage:# 用当前输入值做前缀过滤values[langforlanginLANGUAGESiflang.startswith(argument.value)]# 返回补全结果values 最多 100 条returntypes.CompleteResult(completiontypes.Completion(valuesvalues,totallen(values),hasMoreFalse,))# 其他情况返回空结果returntypes.CompleteResult(completiontypes.Completion(values[],total0,hasMoreFalse))asyncdefrun():启动 stdio 服务端等待客户端连接。# stdio_server 提供标准输入输出读写流asyncwithmcp.server.stdio.stdio_server()as(read_stream,write_stream):awaitserver.run(read_stream,write_stream,InitializationOptions(server_namecompletion-demo,server_version0.1.0,capabilitiesserver.get_capabilities(notification_optionsNotificationOptions(),experimental_capabilities{},),),)if__name____main__:importasyncio asyncio.run(run())效果验证服务端写好后先用 Inspector 快速验证进度通知。在项目目录执行下面命令会打开一个可视化调试界面。mcp dev progress_server.py在 Inspector 里调用batch_export工具传入total30右侧的通知面板会实时滚动显示notifications/progress和notifications/message进度条从 0 涨到 100%。跑客户端脚本验证端到端流程。python progress_client.py终端会按 0.2 秒一条的频率打印进度百分比最后输出“成功导出 30 条记录”。补全服务端同样用 Inspector 验证。执行mcp dev completion_server.py在 Prompts 面板选 code_review在 language 参数框里输入py会下拉出 python、pytorch、pyside 三个建议。常见问题与避坑1. 进度回调始终不触发。我最早用 ClientSession 直接调call_tool怎么都没收到进度。原因是客户端没把 progressToken 放进请求的_meta服务端的ctx.report_progress找不到对应 token 就静默丢弃了。用 FastMCP Client 的progress_handler参数会自动注入 token别自己手搓请求又忘了带。2. 并发任务进度串台。progressToken 必须在所有活跃请求里全局唯一。我有一次图省事给两个并发任务用了同一个固定 token结果两条进度线交叉显示。token 用自增计数器或 UUID 生成任务结束就释放。3. progress 值回退被客户端忽略。协议规定 progress 必须单调递增。我在重试逻辑里把计数器重置成 0 重新发客户端直接忽略后到的较小值。重试时要么继续递增要么发一条全新的任务。4. 日志发了客户端看不到。日志受logging/setLevel控制。客户端默认可能只收 warning 以上你发的 info 日志就被过滤了。调试时让客户端把等级设成 debug或者只用 warning 和 error 发关键信息。5. 以为 tool 参数也能补全。Completions 只覆盖 prompt 参数和 resource URI 模板tool 参数没有补全能力。想要 tool 参数提示得在 tool 的 description 或参数 description 里写清楚枚举值让模型自己选。小结MCP 的通知机制把“请求-响应”之外的实时交互补全了。进度通知靠 progressToken 关联请求日志通知靠等级过滤Completions 给 prompt 和 resource 做输入提示列表变更通知让客户端缓存不过期。用好 Context 对象的report_progress和info等方法长任务体验能上一个台阶。下一篇我们换到传输层看 stdio、SSE 和 Streamable HTTP 三种传输模式各自适合什么场景。相关推荐JSON-RPC 2.0MCP通信的底层语言通知机制实战长任务进度上报与实时状态推送MCP协议全景Host、Client、Server架构详解
返回列表