Tool Calling安全防线:MCP应用中工具执行审批机制的设计与落地
当AI Agent从“回答问题”走向“执行操作”,工具调用的安全边界成为决定系统生死的分水岭。实证数据显示,仅37.2%的MCP应用在工具执行前设置了人工审批关卡。本文基于Microsoft AGT、MCP Guard、mcp-warden等生产级开源方案,系统拆解MCP工具执行审批机制的设计模式与落地实践。
引言:“调通功能,权限后面再加”的代价
“先把功能调通,权限后面再加。”这是我在安全审计中听到最多的一句话。开发者把所有工具一股脑塞给Agent——文件读写、数据库查询、Shell执行——权限不分级,操作不审批,日志只记了console.log。直到Agent被prompt injection打穿,拿到root shell,才意识到问题的严重性。
OWASP在2023版LLM Top 10中将“Excessive Agency”列为LLM08,2025版挪到了LLM06。核心意思一句话:Agent被授予了超出业务需要的权限和自主度。MCP(Model Context Protocol)固然提供了统一的工具调用接口,但协议本身不定义审批机制——标准化的只是执行表面,不是安全治理。
对200个MCP服务器的实证分析显示,每个服务器平均请求40.74个特权API,52%的权限验证依赖API Token和密码,未遵循最小权限原则。更关键的是,仅37.2%的MCP应用在工具执行前设置了人工审批关卡。这意味着超过六成的AI Agent在无人监督的情况下执行着可能改变系统状态的操作。
一、为什么MCP需要显式的审批机制?
1.1 协议成功 ≠ 业务完成
MCP调用成功,只代表一个格式正确的请求被送达了MCP Server。它不能证明:这次行动代表正确的人、高风险参数已经得到有效审批、网络重试不会造成重复扣款、超时后到底执行了还是没有执行。
1.2 四大攻击面
基于Microsoft对MCP生态的安全分析,工具调用面临四类主要风险:
| 工具投毒 | 恶意工具在描述中嵌入隐藏指令,模型误以为来自开发者 | MCP03:2025 |
| 提示注入 | 工具返回结果包含对抗性指令,污染后续推理 | LLM07 |
| 供应链攻击 | 拼写错误的工具名或恶意定义混入Agent工具集 | — |
| 级联故障 | Agent对出错服务器激进重试,拖垮下游服务 | — |
Microsoft内部红队评测显示:仅靠Prompt级别的安全指令,对抗性场景下的策略违反率高达26.67%。换句话说,超过四分之一的安全攻击得手了。依赖模型“遵守规则”来保障安全,是一条走不通的路。
二、审批机制的核心设计模式
2.1 三层工具分级
解决Excessive Agency的第一步,是对工具按风险等级进行分类。参考Linux capability模型的思路,可将MCP工具分为三档:
| L0 只读 | 无副作用,不修改任何状态 | 文件读取、数据库SELECT、HTTP GET | 直接放行 |
| L1 写操作 | 修改数据,但不涉及代码执行 | 文件写入、DB INSERT/UPDATE、HTTP POST | 需审批 |
| L2 危险操作 | 代码执行、权限变更 | Shell执行、eval、进程管理 | 需审批 + 沙箱 |
MCP Server端的权限分级配置实现:
# MCP server 权限分级配置
TOOL_PERMISSION_LEVELS = {
"read_file": 0, # L0 只读
"list_directory": 0,
"db_select": 0,
"write_file": 1, # L1 写操作
"db_insert": 1,
"db_update": 1,
"exec_shell": 2, # L2 危险操作
"eval_code": 2,
}
# 工具白名单,未列出的直接拒绝
ALLOWED_TOOLS = set(TOOL_PERMISSION_LEVELS.keys())
# 工具黑名单,优先级高于白名单
DENIED_TOOLS = {"drop_database", "shutdown_system"}
2.2 策略驱动的审批门
MCP Hangar的Approval Gate展示了审批门的标准工作模式:工具调用经过解析器检查,匹配三类策略——deny_list直接拒绝、approval_list进入人工审批、allow_list直接放行。
providers:
grafana:
tool_access_policy:
deny_list:
– "admin_*" # 完全阻断
approval_list:
– "delete_*" # 等待人工审批
– "create_alert_rule"
approval_timeout_seconds: 300
当工具命中approval_list时,执行立即暂停。Agent等待人工决策——批准则执行,拒绝则返回错误,超时则抛出approval_timeout。决策记录与调用链绑定,审计可追溯。
mcp-warden提供了更精细的policy控制:
const policy: GuardianPolicy = {
allowedTools: ["read_file", /^search_/],
restrictedPaths: [
{ path: "/etc", mode: "blocked" },
{ path: "/home", mode: "read-only" }
],
maxCallsPerMinute: 60,
approvalRequired: true
};
2.3 HITL审批流完整实现
Azure语音服务的MCP实现展示了HITL(Human-in-the-Loop)在真实产品中的集成方式:
async def _handle_mcp_approval_request(self, event, connection):
approval_id = event.item.id
server_label = event.item.server_label
function_name = event.item.name
# Auto-deny after too many calls to prevent infinite loops
if self._approval_call_count.get(server_label, 0) >= MAX_APPROVAL_CALLS_PER_TASK:
await connection.conversation.item.create(
item=MCPApprovalResponseRequestItem(
approval_request_id=approval_id,
approve=False
)
)
return
# Auto-approve if server already approved this turn
if server_label in self._approved_servers_this_turn:
await connection.conversation.item.create(
item=MCPApprovalResponseRequestItem(
approval_request_id=approval_id,
approve=True
)
)
return
# Store pending approval and ask user via voice
self._pending_approval = {
"approval_id": approval_id,
"server_label": server_label,
"function_name": function_name
}
核心设计要素:
- 防循环控制:单任务内对同一Server的审批请求超过阈值自动拒绝
- 就近批准:同一轮对话中已批准的Server,后续调用自动放行
- 语音交互:通过语音向用户请求授权,降低审批摩擦
三、生产级落地工具
3.1 MCP Guard:透明代理拦截
MCP Guard以透明代理方式运行,拦截JSON-RPC消息:
# 安装
npm install @permission-protocol/mcp-guard
# 配置策略
cat > pp.config.yaml << 'EOF'
default_action: allow
mode: enforce
rules:
– id: block-delete
tool: delete_user_data
action: block
– id: hold-deploy
tool: deploy_production
action: require_approval
EOF
# 运行MCP Server通过Guard
mcp-guard –config pp.config.yaml — node my-mcp-server.js
MCP Guard拦截tools/call请求后执行决策:allowed转发、blocked返回-32001错误、require_approval返回-32002错误。每个决策生成不可篡改的审计回执。
3.2 Microsoft Agent Governance Toolkit
Microsoft发布的Agent Governance Toolkit将策略检查直接注入MCP Server构建管道:
using AgentGovernance.Extensions.ModelContextProtocol;
builder.Services
.AddMcpServer()
.WithGovernance(options =>
{
options.PolicyPaths.Add("policies/mcp.yaml");
options.DefaultAgentId = "did:mcp:anonymous";
options.ServerName = "contoso-support";
});
启动时扫描工具定义,检测工具投毒、typosquatting、隐藏指令、schema滥用等威胁类别。运行时执行YAML定义的策略:
apiVersion: governance.toolkit/v1
version: "1.0"
name: mcp–governance–policy
default_action: deny
rules:
– name: allow–echo
condition: "tool_name == 'echo'"
action: allow
priority: 10
3.3 mcp-warden:全方位守卫
mcp-warden在NPM生态中提供了最全面的安全守卫:
import { McpGuardian } from "mcp-warden";
const guardian = new McpGuardian(policy, {
dryRun: false,
redactToolOutputs: true, // 自动删除返回内容中的PII
logger: (violation) => myLogger.warn(violation),
});
支持:精确匹配与正则工具授权、文件系统路径强制(blocked/read-only)、HITL审批门、提示注入扫描、敏感数据清洗(邮箱、API密钥、IP地址等)、每工具限流与熔断保护。
四、进阶:代理身份与委托链
当前Agent系统缺乏可验证的代理身份。MCP Host可以清晰地证明自己是OAuth客户端,但其上层运行的Agent身份在授权层几乎不可见。
Agent Identity and Delegation提案通过Ed25519签名链解决多层委托问题——每层委托只能收窄权限,无法扩大,验证时遍历完整链与撤销列表:
// 委托链示例:A -> B -> C
// A (root) -> B (resolve, merge, max $100) -> C (resolve only, max $25)
// 验证时取交集,C实际权限为:resolve, max $25
五、设计清单
| 工具分级 | L0/L1/L2三级分类,高风险工具强制审批 |
| 策略驱动 | deny/approval/allow三表分离,YAML外部化配置 |
| HITL审批 | 超时控制、防循环、就近批准 |
| 审计证据 | 不可篡改回执,决策原因可追溯 |
| 启动扫描 | 检测工具投毒、typosquatting、隐藏指令 |
| 敏感数据清洗 | 自动删除输出中的API Key、邮箱等PII |
| 身份委托 | 签名链验证,每层只能收窄权限 |
| 限流熔断 | 每Agent配额,失败超阈值后自动熔断 |
结语
MCP将工具调用标准化了,但标准化的只是执行表面。审批不是MCP内置的功能,而是生产部署必须补充的治理层。
留给读者一道思考题:当你的Agent可以执行deploy_production时,谁来批准这次部署?当它能delete_user_data时,谁来确认删除的是正确的那条记录?Agent的安全边界,取决于你在这个问题上愿意投入多少工程。
参考文献:


