MCP按需开启:给AI编程工具装上人工介入的调节阀

发布时间:2026/10/2 10:16:47
MCP按需开启:给AI编程工具装上人工介入的调节阀 先交代一下背景我主力用的编程智能体是 pi agent近半年我把各种 MCP server 往里面接从浏览器自动化、文件系统到数据库操作前前后后接了七八个。刚开始确实爽一句话就能让它查库、改文件、开浏览器验证页面。但越往后越不对劲最典型的一次我只是让它“打开项目里的日志文件看看报错”结果它连着调了三个不同的工具先列目录、再读文件、然后莫名其妙去访问了一个测试环境的 URL。不是说功能有问题而是工具一多模型自己都容易犯糊涂。我后来才想明白一个道理——MCP 的接入数量不是越多越好关键是“什么时候能用、什么时候不能用”这件事得由人来定。这篇就把我最近给 pi agent 做的“按需开启 MCP”改造完整分享一下包括设计思路、配置方法、踩过的坑以及最终沉淀下来的工作习惯。如果你也在用各种支持 MCP 的 AI 编程工具不管是 pi agent、Cursor 类工具还是别的 agent 框架这套思路应该都有参考价值。1. 一切的起因当 pi agent 接上第五个 MCP server 之后1.1 MCP 生态的火爆与“全接”冲动MCPModel Context Protocol这个概念简单说就是给 AI 模型开了一堆标准化的“插座”任何工具只要实现了这个协议模型就能直接调用。它的意义怎么强调都不过分——在 MCP 之前每个工具都要单独给 agent 写适配器现在一套协议全搞定。所以过去一年里几乎每天都有新的 MCP server 冒出来从 Playwright 类浏览器控制到数据库客户端从设计稿导出到游戏内存修改覆盖面大得吓人。这股浪潮起来之后大多数人包括最初的我的第一反应都是既然接口这么统一那就全接上呗。pi agent 支持在配置文件里声明一堆 mcpServers我当时的想法是“接上总比不接强要用的时候随时有”。结果就是这个“随时有”埋下了雷。1.2 我在真实项目中遇到的三个“工具失控”瞬间第一个案例是数据库误操作。我接了 MySQL 的 MCP server本来让 pi agent 查一下某个订单表的数量它倒是执行了但后面我瞅了一眼记录发现它顺带跑了一个 UPDATE 语句把某条测试数据的状态改了。虽然不是什么大事但如果你连的是生产库这就是事故级别的风险。第二个案例是上下文污染。我同时开着文件系统 MCP 和浏览器 MCP让它帮我“看一下线上页面的标题对不对”按理说应该它自己起一个浏览器去访问目标 URL结果它先列出了本地目录又把某个页面文件读了一遍来回折腾好几个回合才意识到需要用浏览器工具。工具的选择越多模型的决策路径就越长最后输出的质量反而不稳定。第三个案例最让我警惕重复初始化开销。每启动一个 pi agent 会话它会把所有已注册的 MCP server 都拉起握手。我有一次接了一个比较重的本地工具启动时要跑一堆初始化逻辑结果每次开新会话都要等十几秒体验非常糟糕。后来才知道这个 server 大多数时候根本用不上。1.3 “按需开启”不是反自动化而是给 AI 立规矩上面这些事让我意识到一个核心矛盾MCP 本质上是把“工具使用权”交给了模型但模型对“当前任务需要哪个工具”的判断力远没有我们想象的那么强。它更擅长的是沿着用户指令一路执行执行过程中哪个工具的名字看起来跟当前文本沾点边它就可能去调一下。这个时候“人工介入”就不是什么丢人的回退方案而是一种必要的工作流设计。按需开启的本质是把工具的使用权从“默认全给”改成“默认不给、显式放行”。这跟真实团队里的权限管理完全一致——你不会给一个实习生开全公司的服务器权限对吧那为什么给 AI 代理就可以什么都让它碰呢所以我的目标很简单pi agent 里注册的 MCP server 我可以保留一大堆但每个会话启动时它只会看到我这次明确授权的那一小撮工具。中间如果发现确实要用别的工具我再手动放行。人工介入不是放弃自动化而是在自动化和可控性之间装一个调节阀。2. 按需开启的设计默认关闭显式放行2.1 注册、启用、放行把 MCP 生命周期拆开我在改造之前先重新梳理了 MCP server 在 pi agent 里的生命周期拆成三个阶段注册Registered在配置里声明了这个 server 的存在包括启动命令、参数、环境变量等。注册不等于可用。启用Enabled当前会话启动时pi agent 会实际拉起这个 server并把它的工具列表注入给模型。启用是会话级的。放行Approved工具已经挂到了会话里模型可以调用但某些高风险工具在真正执行前还会向用户确认一次。一开始我想得很简单觉得只要加一个 enabled 开关就行。但实际用下来发现只做一层开关不够。因为有些工具比如文件系统的只读工具风险很低放开了也没什么而有些工具比如数据库写操作、shell 执行即使挂载了也应该在模型打算调用时拦一道等用户点头。所以最终的设计是三层的配置文件决定注册了哪些 server会话参数决定启用了哪些 server运行时确认规则决定哪些工具需要人工确认。这样既有粗粒度控制也有细粒度保险。2.2 配置层声明式注册与状态开关pi agent 的配置目录里我用的是一个 JSON 文件管理 MCP server。改造前它是这样的{ mcpServers: { filesystem: { command: npx, args: [-y, modelcontextprotocol/server-filesystem, /home/user/projects] }, playwright: { command: npx, args: [-y, playwright/mcplatest] }, mysql: { command: npx, args: [-y, mcp-server-mysql], env: { MYSQL_HOST: 127.0.0.1, MYSQL_USER: dev, MYSQL_PASS: devpass } } } }我的第一版改法很笨就是把暂时不用的 server 注释掉。但这样做有两个问题一是每次来回改配置都要重启 pi agent二是注释掉的 server 很容易忘记恢复等到真要用的时候还得现查文档。后来我换成了更明确的字段方式给每个 server 加一个 enabled 标志顺便加上 tags 描述它的用途场景{ mcpServers: { filesystem: { command: npx, args: [-y, modelcontextprotocol/server-filesystem, /home/user/projects], enabled: true, tags: [local, low-risk], approvalRequired: false }, playwright: { command: npx, args: [-y, playwright/mcplatest], enabled: false, tags: [browser, medium-risk], approvalRequired: true }, mysql: { command: npx, args: [-y, mcp-server-mysql], env: { MYSQL_HOST: 127.0.0.1, MYSQL_USER: dev, MYSQL_PASS: devpass }, enabled: false, tags: [database, high-risk], approvalRequired: true } } }enabled 字段只解决“会话默认是否拉起”的问题approvalRequired 解决“工具调用前是否人工确认”的问题。这两个字段分开之后我的控制粒度一下子就清晰了。2.3 会话层每次任务只带该带的工具配置改完之后还有一个关键问题pi agent 在启动一个会话时去读取配置里的 enabled 字段把对应的 server 都拉起来。但我的日常任务类型跨度很大写前端代码、查数据库、做端到端验证可能发生在同一天的不同会话里。如果我只在配置文件里设一个全局 enabled 状态那要么每开一次会话先去改文件要么永远面对“全都开着”的老问题。所以我又加了一层会话级别的工具白名单。pi agent 的启动命令支持附加参数我设计了一套自己的约定用一个--mcp-allow参数来限定当前会话启用的 MCP server 子集。比如pi --mcp-allow filesystem,playwright这个命令的意思是本次会话只拉起 filesystem 和 playwright 这两个 server其他注册过的哪怕配置里 enabled 是 true一律不启动。如果没传这个参数就回退到配置文件的 enabled 字段。实现上没那么玄乎pi agent 支持通过环境变量或者命令行参数注入配置覆盖我写了一个薄薄的 wrapper 脚本把--mcp-allow解析成内部配置的过滤逻辑。这样每次开新会话我就先想一下接下来这个任务AI 需要动浏览器吗需要摸数据库吗需要读哪个目录的文件想清楚了再启动。这一层设计最大的好处是工具列表短了模型的注意力自然就集中了。实测下来同一个任务在只挂两三个工具的会话里执行比在挂满工具的会话里执行成功率要高一截而且 token 消耗也降了不少。2.4 执行层举手报告与人工确认会话级的白名单只能解决“模型看到哪些工具”解决不了“模型会不会误用已经看到的工具”。所以第三层就是执行层的确认机制。前面配置里的 approvalRequired 字段就是干这个的。pi agent 在调用一个标记了 approvalRequired 的工具时会先把模型打算执行的参数打印出来等用户按 y 确认才真正跑。这个过程我称之为“举手报告”——模型把它的意图亮出来人点个头它才动手。你可能会觉得这样很烦每次还要盯一下。但实际用下来这个确认动作恰恰是“人工介入的艺术”里最核心的部分。因为模型在调工具的时候很多情况下你以为它知道自己在干什么其实它只是在文本模式上做概率生成。有一次它调用 MySQL 工具生成了一条 SQL我看到参数里 WHERE 条件是空的——如果那是一条 UPDATE整张表都被改了。那一刻我才真正理解人工确认不是在给 AI 拖后腿而是在给它踩刹车。3. 动手实现给 pi agent 配置按需 MCP 的完整过程3.1 第一步整理 MCP 清单划分“常用 / 偶尔 / 仅特定项目”在改任何配置之前我先做了个信息整理。我把所有已经注册的 MCP server 拉了一遍清单按使用频率分成三类分类判断标准我的例子常用至少一半会话都会用到filesystem、playwright偶尔特定阶段或特定任务才用mysql、redis-cli仅特定项目某个仓库或某类项目专属内部 API 调试工具、专用格式转换工具这个分类很重要因为它决定了 enabled 字段的默认值。常用类的我默认 enabled 置为 true偶尔类和特定项目类默认 false。之前我总是犹豫该不该把某个 server 永久开着一分类就不纠结了——不是“它有没有用”而是“这个会话大概率用不用得到它”。3.2 第二步改造配置文件挂上 enabled 与 approvalRequired整理完清单我按上一节给出的格式改了配置文件。这里有几个容易踩的细节先说在前面第一env 字段里的凭据不要硬编码。之前我图方便把 MySQL 密码直接写配置里。后来想这也是个风险点如果 pi agent 自身的运行日志记录了配置内容就相当于把密码泄露给了模型输出窗口。我改成了从环境变量读取的方式配置里只留变量名。第二tags 字段别看是个“软”字段它其实能帮助你在会话启动时快速判断。我甚至在启动脚本里加了按 tags 过滤的选项比如--mcp-allow-tags low-risk一次性放行所有低风险工具。第三不要在一个配置文件里维护所有项目的 server。我一开始把所有项目共用的 MCP 都塞进全局配置后来发现特定项目的工具会污染其他会话的决策。正确做法是全局配置文件只放通用工具项目目录下的.pi-mcp.json放该项目专属工具pi agent 支持配置文件合并全局 项目叠加生效。3.3 第三步实现会话级白名单参数pi agent 没有原生提供--mcp-allow这个参数所以需要一个 wrapper。我的实现思路很朴素启动前解析参数把要启用的 server 集合写到一个临时文件里然后 pi agent 读配置文件时合并这个覆盖。下面是 wrapper 脚本的简化版bash#!/usr/bin/env bash # 用法pi-run --mcp-allow filesystem,playwright [其他 pi 参数] MCP_ALLOW # 解析 --mcp-allow 参数 while [[ $# -gt 0 ]]; do case $1 in --mcp-allow) MCP_ALLOW$2 shift 2 ;; *) PI_ARGS($1) shift ;; esac done if [[ -n $MCP_ALLOW ]]; then # 生成一个临时配置覆盖文件 TMP_MCP_CONF/tmp/pi-mcp-allow-$$.json python3 - $MCP_ALLOW PY import json, sys, os allow set(sys.argv[1].split(,)) # 读取主配置 config_path os.path.expanduser(~/.pi/config.json) with open(config_path) as f: cfg json.load(f) # 把所有不在 allow 里的 server 强制 enabledfalse for name, server in cfg.get(mcpServers, {}).items(): if name not in allow: server[enabled] False else: server[enabled] True with open(os.environ.get(TMP_MCP_CONF), w) as f: json.dump(cfg, f, indent2) PY export PI_MCP_CONFIG$TMP_MCP_CONF fi exec pi ${PI_ARGS[]}这段脚本的职责就是把参数解析成白名单临时改一份配置文件出来启动 pi agent 时指向这份临时配置。注意我没去改用户的原始配置文件因为临时覆盖应该是一次性的不该污染持久配置。3.4 第四步运行时手动切换与会话中的动态放行有些需求是会话进行到一半才发现的比如我一开始只挂了 filesystem跑着跑着发现要查数据库。这种情况下重新开一个会话成本太高所以还需要一个运行时切换的手段。我在 pi agent 的会话里定义了一个特殊指令也可以说是约定好的 prompt比如输入/mcp-on mysqlagent 就会知道“用户要求启用 mysql 这个 MCP server”。底层实现上我的 wrapper 在启动时把过滤后的配置写到了一个特定位置/mcp-on这个指令本质上是让 agent 去修改这个运行时配置然后触发一次 server 的热加载。老实说热加载这个功能不是所有 agent 都支持得很完美。pi agent 在这方面还比较顺但如果你是其他框架可能要退而求其次要么接受会话中途无法动态加工具只能重启会话要么让 agent 通过命令行重新拉起一个子会话再把上下文带过去。我在实际工作中是两者混用的——重度任务中间发现缺工具我会选择把当前任务的关键上下文摘要一下开一个带新工具集的新会话继续而不是硬着头皮热加载。因为热加载有时候会带来上下文状态的割裂模型对“新出现的工具”反而不知道怎么用。3.5 远程 MCP 的按需连接wss 场景再提一个更进阶的场景远程 MCP server。有些 MCP 服务不是跑在本机的而是通过 WebSocket 对外提供服务地址类似wss://your-mcp-service.example.com/mcp?tokenyour_token_here远程 MCP 的按需开启比本地 server 多一层考量网络连接本身就有成本和风险。我自己的原则是远程 MCP 默认全部不启用只有明确需要在某次会话里访问远程数据时才手动连接。而且我在配置里不会把 token 直接写进 mcpServers 的 URL 里理由和之前不硬编码数据库密码一样。远程 MCP 的 token 我会通过环境变量注入配置里只写wss://your-mcp-service.example.com/mcp?token${MCP_TOKEN}让 pi agent 启动时去解析环境变量。这样即使配置文件被完整打印出来token 也不会跟着漏。按需连接还有一个好处是省流量和省握手时间。我知道有些人的远程 MCP server 一挂就是一天连接断断续续的token 过期了也不一定知道。我这个方案每次会话都是“用的时候现连”token 新鲜度反而更好管理。4. 实测踩坑记录这些坑不遇到一次很难长记性4.1 坑一工具描述自相矛盾AI 在多个工具之间反复横跳第一个坑跟配置无关是 MCP server 自身的工具描述问题。我接了某个文件管理工具和一个代码搜索工具这两个工具都能“读文件内容”但适用场景不一样。模型拿到的工具描述里一个说“read_file: 读取文件内容支持文本文件和源码”另一个说“search_code: 在代码库中执行语义搜索并返回匹配代码片段”。看起来还挺区分对吧但实际执行的时候pi agent 有时会拿着 read_file 的路径参数去调用 search_code导致对方报了参数错误然后它又回头调 read_file发现读出来的是二进制文件又去试别的工具。整个任务在工具间来回跳了三轮才完成token 烧得心疼。我的解决思路是给工具描述做脚注。具体做法是在 pi agent 的配置里给每个 MCP server 增加一段“使用说明”让模型在调用前先看{ mcpServers: { filesystem: { usageNote: 仅用于读取和编辑本地文件不要用于搜索代码语义。代码搜索请使用 search_code 工具且 search_code 属于 code-search server。 } } }pi agent 会在加载 server 时把这段 usageNote 注入到系统提示里。这个字段不是 MCP 协议标准的一部分而是我利用 agent 的提示词注入能力加的一层“说明书”。加了之后工具串调的频率明显下降。说白了MCP 告诉你“有这个工具”但不负责告诉模型“什么时候不用它”这个引导只能你来补。4.2 坑二MCP 初始化超时拖垮整个 agent 启动最早我把 enabled 设为 true 的 server 有点多其中有一个内部工具启动时要加载一个比较重的模型缓存每次启动大约要十几秒。而 pi agent 对 MCP server 的握手有超时时间这个 server 超时之后整个会话启动流程就会卡住有时候要等它把错误抛完才能继续。更麻烦的是这个超时错误会导致 pi agent 认为整个 MCP 子系统挂了连带着其他正常 server 的工具也没加载进来。我调试了半天才发现原来不是 all servers 全军覆没而是一颗老鼠屎坏了一锅汤。解决办法分两步第一步把这类启动慢的 server 从 enabled 里摘出去改成按需开启这是最直接的第二步如果确实有场景希望它常驻我给 wrapper 脚本加了一个并发初始化逻辑每个 server 独立握手超时的先跳过其他的照常加载后面想用再补连。这里说句实在话按需开启天然规避了这个坑。你想想一个重工具如果你只是偶尔用为什么每次会话都让它拖大家的后腿把它放到白名单外等真需要的时候再手动开启动慢也无所谓反正那时候你本来就要等它。4.3 坑三工具定义文本吃掉大量上下文窗口这个坑比较隐蔽。每个 MCP server 在连接时会把它的所有工具定义工具名、参数 schema、描述以 JSON 格式注入到上下文里。工具多的 server光是工具定义可能就几百行。如果同时挂五个以上 server工具定义加起来能占到上下文窗口的相当一部分。我当时用的一个浏览器控制 MCP工具数量特别多从打开页面、点击、填表到截图、读取控制台日志几十个工具定义确实丰富。但问题是我 90% 的场景其实只用其中五六个工具剩下的纯属浪费上下文。我一开始没意识到这个问题后来发现一个奇怪的现象同一个任务只挂文件系统 MCP 时模型回复质量明显更好上下文利用率也高。挂上浏览器 MCP 之后模型的回答开始变得“懒”——感觉它把一部分注意力花在了理解那一大堆工具定义上留给真正任务推理的空间就少了。我的应对策略是能用低上下文占用的 MCP server 就不用高占用的同一个 server 如果支持只加载部分工具部分 MCP server 有 tool 过滤配置就把常用工具设为首选加载冷门工具保持不加载。如果你用的 agent 框架做不到这种粒度那就回到老办法——按项目拆分配置文件让每个项目只面对它需要的工具集。4.4 坑四危险操作被 AI 自动重试这是我认为最值得警惕的一个坑。模型在调用工具失败后会自动尝试修复重试这是 agent 的基本能力。但伴随着这个能力它会陷入一种“不达目的不罢休”的状态。我有一次让它用数据库工具更新一批测试环境的数据它第一条 SQL 因为语法错误失败了。然后它没有停下来问人而是自己尝试修正语法第二条 SQL 逻辑上已经变成了完全不同的更新意图它在参数确认弹窗里展示了出来。我瞄了一眼发现在 WHERE 条件里少了一个关键的 is_deleted 过滤字段——如果不是有这个确认弹窗这条带 bug 的 SQL 就执行下去了。这个例子说明一个道理执行层的人工确认机制不是摆设它是最后一道肉身防火墙。尤其是在 agent 具备自动重试能力的今天模型对“失败”的应激反应是“换个姿势再来一次”而不是“停下来想想这个方向对不对”。所以我的建议是凡是带写操作的 MCP 工具无论你有多信任 pi agent 的代码能力approvalRequired 一定要设为 true。写操作之前让模型花五秒钟亮出它的意图比事后花五小时修数据要划算得多。4.5 坑五远程 MCP 的 token 管理与会话残留最后这个坑是关于远程 MCP 的。我前面提到用 wss 地址连远程 server实际用下来有个问题pi agent 在会话结束后不会主动断开 WebSocket 连接。如果你的远程 server 端没有设置空闲超时这个连接会一直挂着token 明明还能用新会话却可能遇到连接数上限。更麻烦的是token 一旦在会话期间过期比如远程 server 设置的是 15 分钟短 token模型在会话中间调用远程工具时会收到认证错误而它通常不会意识到是 token 问题只会反复尝试或者报一个很隐晦的错。我的处理经验是远程 MCP 坚决不设为常驻连接每次会话用之前现连用完立刻在会话里执行断开指令。同时 wrapper 脚本里我会检查当前环境变量的 token 是不是快过期了如果快过期就先刷新再启动会话。这些小细节看起来琐碎但等你被远程工具的认证错误折磨两次就知道有多值了。5. 我现在的使用习惯与人工介入的边界5.1 按场景决定工具集我给自己的三条默认规则折腾完这套按需开启机制之后我沉淀下来一套自己的使用习惯分三个典型场景纯前端/纯本地代码任务只开 filesystem code-search数据库和浏览器工具一律不启。因为这类任务的目标是改代码AI 只要会读文件、搜代码就够了给它数据库工具只会制造噪音。涉及接口联调/页面验证的任务开 filesystem playwright 一个 HTTP 调试 MCP。数据库工具依然不开除非任务明确说要查数据。数据相关任务开 filesystem mysql redis浏览器工具不开。而且 mysql 的 approvalRequired 必定为 true。这套规则我直接固化到了 wrapper 脚本里做成了三个快捷命令pi-dev、pi-web、pi-data。每次开工就选一个不用再手动敲一长串--mcp-allow参数。5.2 人工介入的“度”既要管得住也要放得开有人可能会担心这么层层确认会不会把 agent 的效率拖没了我个人的体会恰恰相反真正拖效率的是“模型在不该动的地方瞎动”。人工介入的关键不是“每个操作都拦下来”而是“风险越大的操作越要拦得坚决”。低风险的文件读取、代码搜索我几乎不做确认让它放手跑中风险的浏览器自动化我只在启动浏览器前确认一次高风险的数据库写操作、shell 执行、远程数据变更每一步都确认。这套分级策略跑了一个多月给我的感觉是该快的地方足够快该稳的地方也足够稳。5.3 按需开启不像是在限制 agent反而像是在给它减负最后说一点更主观的感受。在没有做人工介入设计之前我总觉得 agent 是一个“什么都会一点但经常自作主张”的助手。开了按需 MCP 之后它的行为收敛了很多工具误用的情况少了上下文窗口也腾出来了回复质量肉眼可见地变好。现在我每次启动会话都要先想一个问题这次任务AI 需要什么能力这个思考动作看上去是“增加人工负担”但实际上它让我更清楚自己要做的事也让 agent 更专注于它该做的事。人工介入不是对自动化的妥协更不是倒退它本身就是工作流的一部分。工具越多、能力越强这个“介入”的粒度就越要设计好——什么时候放手、什么时候把关、什么时候一键全禁这就是我理解的人工介入的艺术。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询