MCP这个缩写,今年以来在AI圈和B端软件圈里反复被提起,几乎每次聊到Agent落地都会碰到它。我一开始也以为这只是又一个接口协议,直到亲手把公司内部的流程管理平台接进MCP生态,才算真正理解它解决的是什么问题。简单说,MCP(Model Context Protocol,模型上下文协议)给大模型和外部的业务系统之间定了一套统一的“插座规格”,让AI不再只是停留在对话窗口里,而是能直接读取待办、给出审批建议、甚至把审批流程往前推一步。这篇文章想分享的,是我最近把一个轻量级流程管理平台接入MCP的完整落地记录,拆解“待办查看、审批建议、流程推进”这三个最常见的业务场景,也会讲清楚每个功能背后我为什么这样设计、踩了哪些坑。如果你正在做企业级Agent的落地,或者在评估AI与BPM、低代码平台怎么打通,这篇应该能给你一些可以直接参考的思路。
1. 为什么我不写一堆内部接口,而是选择MCP
1.1 传统点对点接入的痛点
在没有MCP之前,让大模型去操作一个业务系统,大部分团队的做法是给业务系统写REST接口,然后用Function Calling把接口一个个注册给模型。听起来也不复杂,但实际做起来非常痛苦。
首先是“点对点”的问题。流程管理系统有待办接口、审批接口、组织架构接口,如果还要对接HR系统、财务系统、项目管理系统,那就要为每个组合写一套适配逻辑。AI应用A对接了流程平台和财务平台,AI应用B对接了流程平台和项目平台,公共的流程能力被迫在每个应用里各实现一遍,维护成本成倍增长。其次是参数语义混乱。有的接口叫getPendingList,有的叫getTodoTasks,大模型靠函数名和描述去猜该用哪个,猜错一次就可能导致整个任务失败。
还有权限边界的问题。传统REST接口一旦被Agent调用,Agent拿到的往往是一个系统的完整访问能力,很难做到细粒度的“这个用户只能查询自己的待办、只能发起点级审批”。为了保证安全,很多团队干脆不让AI碰写操作,只做只读问答,落地价值大打折扣。
我在早期的某个内部原型里就踩过这个坑。当时给AI注册了十多个审批相关的function,结果它经常在“待办查询”和“任务列表”两个接口之间犹豫,甚至连续调用三次同一个只读接口把上下文塞满。问题不在模型本身,而在于接口的表达方式没有统一标准,模型承担了太多“理解接口语义”的责任。
1.2 MCP做对了什么
MCP的思路其实很朴素:与其让每个AI应用去适配每个业务系统,不如定义一套通用的协议,让业务系统按照统一的方式暴露能力。可以把它理解成充电口的标准化,以前每个设备都有自己的充电口,现在统一成Type-C,理论上一个充电头能带所有设备。
在这个架构里,AI应用作为MCP Client,业务系统通过MCP Server接入协议。MCP Server对外暴露三类能力:Tools(可执行的操作,比如推进审批)、Resources(只读的数据资源,比如审批详情)、Prompts(可复用的提示词模板,比如何时调用哪些工具的引导说明)。对于流程管理平台来说,工具和资源恰好覆盖了“操作”和“上下文”两个最关键的部分。
这套标准带来的直接好处是:一次封装,多处复用。同一个流程平台的MCP Server,可以同时被内部IM里的审批机器人、网页版的AI助手、甚至命令行工具使用。AI应用不需要关心流程平台底层是Java还是Python,内部API长什么样,只需要通过MCP协议跟Server对话。
1.3 审批流程场景为什么特别适合MCP
审批流属于“操作密集+数据密集”的场景,天然适合MCP的分层设计。用户在对话里问“我有哪些待办的采购申请要审”,这涉及数据读取,走Resources或Tools就能解决;“这个单子能不能同意”,这涉及业务规则判断,需要读取流程定义和单据明细;“帮我把这个单子批了”,这涉及写操作,需要权限控制、幂等控制和审计日志。
这些需求如果全部用Function Calling堆给模型,权限边界和操作安全很难控制。而MCP Server作为中间层,可以非常自然地把这些控制放在服务端:谁在这个身份下能查什么数据,谁有权限执行哪个操作,是否符合业务规则,全部在Server内部校验,模型只负责把用户意图翻译成一次标准调用。整体安全边界清晰很多。
2. 三个核心能力的拆解与设计
2.1 待办查看:让AI拿到的是“有用上下文”
很多人以为待办查看就是给AI返回一个任务列表,这其实低估了这个场景的复杂度。AI不是人,它不会像人一样扫一眼列表就知道哪些重要、哪些可以缓一缓,所以接口返回的数据结构必须足够“结构化”,并且要包含决策所需的上下文信息。
我在设计待办查询工具时,主要考虑了三层信息。第一层是任务基础字段:任务ID、标题、发起人、创建时间、截至时间、优先级。第二个是任务状态信息:当前所在的流程节点、前面的审批环节是否已经通过、后面还剩下哪些环节。第三层是关联信息:这个待办属于哪个流程模板,关联的单据在系统里的核心摘要是什么。
举个例子,用户问“我有哪些待办的差旅报销”,如果只返回“张X的报销单待审批”,那AI只能告诉用户有这么一件事,没办法继续追问“这个报销单是多少钱、什么类型的费用”。但如果在待办列表里就带上“金额、费用项目、超预算标识”这些摘要字段,AI就能基于用户的意图做更自然的交互。
接口设计上,我给list_pending_tasks定了这么几个参数:user_id、keyword、status、page、page_size。其中status支持pending、overdue、completed三种,keyword用于模糊搜索标题和发起人。返回格式是包含total、items、current_node_info的JSON结构。设计过程中最关键的一点是要控制单条数据的大小,一个待办返回的字段不能太多,否则十条待办就能把模型的上下文窗口塞掉一截,用户真正关心的细节反而沉在噪音里。
2.2 审批建议:规则引擎和LLM各干一半
审批建议是这三个能力里最容易“翻车”的一个,因为如果完全让大模型自由发挥,它很可能给出符合常识但不符合公司管理规定的建议。所以在实现时我坚持一个原则:规则判断交给代码,语言表达交给模型。
整个审批建议流程被拆成五步。第一步,根据待办ID读取审批单详情和当前流程节点;第二步,跑一遍预设的业务规则检查,比如“金额超过五万需要总经理审批”“预算不足时禁止通过”“发起人所属部门与审批人存在关联时需要回避”;第三步,查询相似的历史审批记录,给模型一个参照;第四步,把以上所有信息压缩成一段结构化的Context传给模型;第五步,限定模型的输出格式,强制它按照“审批结论—依据—风险点—建议动作”四段式生成。
这里有个比较重要的细节:规则检查结果在Server端必须是“硬结论”,模型不能反驳。比如系统判断“该单据当前处于强制复核节点,不允许直接通过”,那模型生成的建议里绝对不能出现“可以绕过复核”这种话。我会在传给模型的系统提示词里写明:规则检查结果为最高优先级,如果规则检查返回block,建议动作只能是退回或暂缓。这一步能挡住绝大多数因为模型“自作聪明”而产生的越权建议。
2.3 流程推进:写操作如何做到可控、可回退
流程推进是三个能力里风险最高的,本质上是让AI代替人去执行一个会产生业务影响的操作。我在实现时用了三把锁:操作白名单、执行前确认、操作审计。
操作白名单很好理解,MCP Server只暴露approve_approval、reject_approval、transfer_approval三个动作,除此之外的写操作一律不暴露给模型。这能防止模型在自由发挥时调用到意料之外的操作。执行前确认是我特别坚持的一点:当模型判断用户想要执行某个操作时,它必须先把“将要执行的操作、目标单据、操作理由”作为一个计划返回给用户,用户明确确认后,才允许调用写操作Tool。这个设计虽然多了一轮交互,但极大降低了误操作的概率。
幂等性也是写操作里容易忽略的问题。网络超时后AI重试一次,同一个审批单会不会被推进两次?我在工具入参里要求调用方传request_id,Server端用这个ID做去重,同一个请求ID只处理一次。每次操作调用成功或失败都会写入审计表,记录操作人身份、操作时间、来源请求ID、审批单当前状态变化。这样即使后续出了问题,也能快速定位是哪一次调用导致的异常。
3. 实操过程:把一个流程管理平台接入MCP
3.1 技术选型与Server骨架搭建
接入MCP之前,先要选一套趁手的Server框架。我团队技术栈以Python为主,所以我选了FastMCP这个Python SDK,它把MCP协议里底层的session管理、消息分发、JSON-RPC这些都封装好了,开发者只需要写最核心的工具和资源即可。
服务端骨架非常精简,核心代码如下:
from mcp.server.fastmcp import FastMCP mcp = FastMCP("lf-flow-mcp") @mcp.tool() def list_pending_tasks( user_id: str, keyword: str = "", status: str = "pending", page: int = 1, page_size: int = 20, ) -> dict: """查询指定用户在流程平台中的待办审批任务列表。""" # 这里调用内部流程平台API,做数据聚合 return service.query_todo_tasks( user_id=user_id, keyword=keyword, status=status, page=page, page_size=page_size, ) if __name__ == "__main__": mcp.run(transport="stdio")FastMCP底层支持HTTP和stdio两种传输方式。如果MCP Client运行在同一个本地进程或是同一台机器上,stdio最简单;如果Agent服务是独立部署的,需要通过网络访问,就改用HTTP传输,比如用sse或streamable-http模式。业务初期建议先用stdio把逻辑跑通,再切到HTTP,这样可以少踩一层网络配置的坑。
3.2 工具定义:命名、描述与参数设计的门道
工具定义的质量,直接决定大模型能不能准确找到该用的工具。我最开始写的描述很随意,比如“查询待办”,结果模型经常在有多张表可查时选错工具,或者在参数上自由发挥。后来我总结了一套工具描述写法:先说清楚这个工具解决什么问题,再给出核心参数说明,最后写清楚什么情况下用本工具、什么情况下不要用。
以下是两个对比示例。
不推荐的写法:
@mcp.tool() def get_todo(user_id: str) -> dict: """查询待办""" ...推荐的写法:
@mcp.tool() def list_pending_tasks( user_id: str, keyword: str = "", status: str = "pending", page: int = 1, page_size: int = 20, ) -> dict: """查询指定用户在流程平台中的待办审批任务。 - 当用户询问“我有哪些待办”“有什么需要审批的单据”时使用 - status 支持 pending(待处理)、overdue(已逾期)、completed(已处理) - keyword 用于按标题或发起人模糊搜索 - 如果用户需要查看某条待办的详细内容,不要用本工具,改用 get_approval_detail """ ...注意参数里连page/page_size这样的辅助字段都要写清楚说明,因为模型可能会尝试传一个非整数或巨大的page值。另外,描述里可以出现业务关键词,但不要堆太多无意义的关键词,这些描述本身都会消耗输入token,写得太冗余会影响模型对有效信息的感知。
3.3 用Resources暴露流程上下文
除了Tools之外,MCP的Resources机制非常值得用起来。Resources是只读数据源,通过URI来定位,比如lf-flow://approvals/{approval_id}。它适合放那些“模型可能需要主动去查、但不想通过固定Tool查询”的内容,比如审批单详情、流程定义、审批历史轨迹。
我实现了一个资源处理器,形如:
@mcp.resource("lf-flow://approvals/{approval_id}") def get_approval_detail(approval_id: str) -> str: """获取审批单完整上下文,包括单据字段、审批历史、当前节点、关联流程定义。""" data = service.query_approval_detail(approval_id) return format_approval_detail(data)这样设计的好处是,待办列表工具可以保持精简,只返回ID和摘要,当模型需要深入了解一张单据时,再通过URI去拉取。这其实就是一种按需加载的设计思路,跟人做事一样,不会一开始就把所有细节摆在桌面上,而是先看摘要,觉得有必要再打开详情。
3.4 身份、鉴权与数据隔离
MCP Server不能直接复用业务系统的超级账号。我在Server和业务系统之间加了一层代理身份层:AI应用请求到达Server时,必须先携带代表真实用户身份的Token,Server解析后,用该用户的身份去调用内部API。
整个链路是这样走的:用户给Agent发消息,Agent通过MCP Client调用Server,Server从请求上下文中拿到“当前是以哪个用户身份在操作”,再通过内部服务调用流程平台接口。这样流程平台看到的是“某某用户在通过某个应用操作”,而不是一个服务账号在操作。
数据隔离也很关键。查询待办时,Server必须强制使用当前身份对应的user_id,不能信任模型从对话里提取的user_id。比如用户说“查一下李四的待办”,如果模型把user_id参数填成了李四,Server也要靠身份层校验来拦截,不允许越权查询。这一步不是靠提示词约束的,而是靠服务端硬逻辑拦住的。
3.5 联调与真实对话测试
把Server跑起来之后,我用官方调试客户端做了一轮完整对话测试。比如用户输入:“帮我看看我这个月还有哪些报销单没审?”Agent会先命中list_pending_tasks,传入当前用户身份,并根据keyword自动补上“报销”作为搜索条件。返回列表后,模型发现有三条待办,其中一条金额比较大,于是主动调用get_approval_detail去查看那张单子的明细,然后生成了一段摘要给用户,最后问用户是否需要直接处理这笔报销。
这个过程看起来很自然,但每个环节都是靠工具描述和上下文设计一点点逼出来的。如果list_pending_tasks返回列表里没有金额字段,即使模型想判断数额大小也无从下手,只能继续追问用户,体验就打折扣。所以要提前站在模型的视角去看它需要什么信息来回答用户的问题 — 这一点对MCP工具设计非常有用。
4. 落地过程中踩过的坑与排查记录
4.1 模型找不到工具、调错工具
现象:用户明明问“我有哪些待办要审批”,模型却回答说“我现在没有权限查看待办”,或者调用了一个完全不相关的工具。排查下来多半是工具描述写得太模糊,模型无法把用户意图对应到工具上。
解决方式是把描述里的触发场景写清楚。我在list_pending_tasks的描述里明确写了“当用户询问待办、审批任务、任务清单时使用”,同时给了一个调用示例。改完之后,模型的命中率明显提升。另外一个容易被忽略的点是工具命名,尽量用动词开头的完整短语,比如list_pending_tasks比getTodo更容易让模型理解,命名风格尽量统一,不要一个下划线一个驼峰混着用。
4.2 上下文过长导致模型“失忆”
现象:一旦待办数量超过二十条,加上每条附带的流程节点信息,一轮请求下来直接逼近模型的上下文上限,模型在后续对话里开始忘掉前面提到的关键信息。原因是工具返回的数据量太“胖”,把所有信息原样丢给模型,没有做精简和筛选。
解决方式是分层返回:列表接口只返回核心字段,详情通过Resources按需获取;同时支持精简模式,系统可以在列表返回前把过长文本字段截断,比如审批意见只保留前50个字符。这个优化之后,上下文占用下降了接近一半,模型的回答质量也稳定了。
4.3 审批建议与业务规则冲突
现象:模型根据单据内容给出了“建议通过”的结论,但系统规则里明确写着该单据当前必须走“合规复核”节点,不允许直接通过。一旦用户听从模型建议去推进,就会产生一个不符合流程规范的操作。
这个坑靠提示词救不回来,必须在服务端做硬拦截。我把规则检查做成了工具链里绕不开的一步:模型在生成审批建议之前,必须先调用check_business_rules工具获取规则结论;如果规则返回block级别,Server直接拒绝执行任何“通过”类操作。建议模块内部也会根据规则结论强制改写输出模板中的“建议动作”字段,模型无法绕过。
4.4 重复推进与误操作
现象:用户在对话里让AI“推进这张单子”,AI先调用一次写接口,但因为网络超时,调用方重试了一次,结果同一个审批单被推进了两步。后续排查时发现审计表里多了一条连续操作记录,但当时并没有人意识到重复了。
原因就是缺少幂等控制。我在所有写操作入参里增加了request_id,模型的每次“计划执行”都会生成一个固定ID,Server端用数据库唯一索引存储这个ID,已经处理过的请求直接返回原结果,不重复执行。误操作问题则靠执行前确认机制兜底,模型在执行任何写操作之前必输出一份操作计划,用户确认后才会真的要调用写接口。
| 问题 | 典型原因 | 排查与解决 |
|---|---|---|
| 模型找不到工具 | 描述关键词不足、命名模糊 | 在描述中补充触发场景、调用示例,统一命名风格 |
| 上下文过载 | 返回字段过多、列表过长 | 精简列表字段、详情走Resources按需加载 |
| 建议与规则冲突 | 模型未感知规则或试图覆盖规则 | 规则检查作为硬门槛,block结果不可被模型改变 |
| 重复推进/误操作 | 缺乏幂等和确认机制 | 写操作强制带request_id,执行前输出操作计划待用户确认 |
5. 从Demo走向生产:我看到的扩展方向
5.1 多个业务系统共享同一个Agent
一旦流程管理平台的MCP Server稳定之后,我发现它带来最大的变化不是“AI会查待办了”,而是它变成一个标准接口层,可以同时被多个Agent复用。办公助手接它,客服机器人接它,项目助理也可以接它。
后面我又用同样的协议接了一个项目管理系统和一个数据报表平台。开发量主要集中在各自写一个MCP Server,而上层Agent完全不需要适配不同系统之间的差异。这种“协议化”的收益会在系统数量变多之后越来越明显,接口越多、越分散,MCP的标准化价值就越大。
5.2 给MCP Server加一层审计与监控
生产环境里,模型的行为不能被当作黑盒来看。我在MCP Server的请求链路上加了日志和审计表,每条工具调用都记录:用户身份、模型标识、调用时间、输入参数、返回摘要、耗时。有了这层日志,既可以回溯“AI为什么做了某个操作”,也可以用来做模型行为分析,比如观察它高频调用哪些工具、在哪些场景下会出现无效调用。
调试小技巧:我在测试时设置了一个固定身份叫“测试用户”,所有联调请求都走这个身份,同时打开MCP日志级别为DEBUG。这样能清晰地看到模型每一步的工具调用过程,排查问题时非常好用。等模型行为稳定后,再逐步放开到真实用户身份。
5.3 后续值得探索的智能场景
落地了查看待办、审批建议、流程推进这三件事之后,我还在思考一些更深的东西。比如待办预测:根据流程节点的历史处理时长,提前告诉用户“有一个采购审批预计明天到你这儿,可以先留意一下材料”。又比如自动催办:系统识别到某张单据在某个节点停留超过三天,Agent可以主动替用户生成一条催办消息推给责任人。再往后是流程挖掘,通过分析大量审批记录的节点路径,找出哪些流程经常卡在哪个环节、因为什么原因被退回。这些方向都不需要重新搭一套AI系统,只要在已有的MCP Server上新增工具和上下文资源,就能给Agent赋予新的能力。
关于MCP的落地,我个人比较大的体会是:技术选型并不难,难的是把AI该做的和系统该做的边界划清楚。规则判断、权限校验、幂等控制这些责任,尽量留在服务端,模型只负责理解和表达。只要这个边界不模糊,Agent在企业业务里能做的事情会比想象中多得多。