工具权限与评分实战:scope拦截+健康度指标(MCP实战手记·篇12 延伸)

MCP工具权限 / 工具评分 / 可观测性

本篇是《MCP实战手记》篇12(企业级Toolbox治理)的延伸篇,只拆「权限拦截 + 健康度评分」两个点:把篇12 §3 两层 scope 拦截和 §7 看板指标拆开——scope 聚合防爆炸(踩坑5)、成功率/P99/报错率告警阈值给落地值,并接篇9 身份、篇13 多租户。仓库(tagv12):Gitee

0. 为什么权限和评分要一起讲

篇12 开篇六类事故里,「权限泛滥」和「质量失控」是慢性毒:前者越权调工具,后者不知道哪个工具稳、哪个天天 500。

权限解决"谁能调",评分解决"调得稳不稳"——治理层两端:发现/调用之前先过权限,调用之后用指标反向淘汰劣质工具。

本文只做 caller+scope 两层拦截 + 健康度指标采集(代码量中,只给变化部分);真实 IdP、治理 UI 标待生产,见篇13。

1. 两层拦截:发现层 + 调用层

篇12 §3 已定:①发现层list()按 caller 过滤可见 Toolbox(看不到无权工具);②调用层实际调前校验requiredScope(调了不该调的被拦)。管理器只给元数据+查询 API,拦截发生在分发层/网关层。

// 发现层:caller 看不到它无 scope 的工具List<ToolboxDefinition>list(StringcallerId,List<String>scopes,Filtersf){returnregistry.list(f).stream().filter(def->scopes.containsAll(def.getRequiredScope()))// 可见需持有全部 requiredScope.toList();}// 调用层:resolve 时再拦一次ToolboxDefinitionresolve(StringcallerId,List<String>scopes,ToolboxIdid,Stringv){ToolboxDefinitiondef=registry.resolve(id,v);if(!scopes.containsAll(def.getRequiredScope()))// ② 调用层 scope 拦截thrownewAccessDeniedException("缺 scope: "+def.getRequiredScope());returndef;}

两层都要有:发现层防"看见不该看的",调用层防"绕过列表直接调"。

默认最小权限:工具若未配requiredScope视为公开(可见可调)。生产建议反设为"无 scope 不可见",公开工具显式打标,避免漏配变成越权。

2. scope 聚合:别让每工具一个 scope(踩坑5)

踩坑5原文:每工具一个 scope,配置膨胀难维护。例子:get_report配scope:report:gen、query_store配scope:store:query…… 工具 50 个就 50 个 scope,运维者记不住、配错就大面积 403。

修法——角色级 scope 聚合:把业务相近的工具归到一个角色 scope。

治理前(每工具一 scope,爆炸): get_report -> scope:report:gen query_store -> scope:store:query export_csv -> scope:report:export ...(50 个工具 = 50 个 scope) 治理后(角色级 scope,收敛): get_report / query_store / export_csv -> scope:toolbox:retail # 零售工具一组 audit_log -> scope:toolbox:admin # 管理面单独一组
// 注册时把工具归到角色 scope,而非逐个细粒度voidregister(ToolboxDefinitiondef,StringroleScope){def.setRequiredScope(List.of(roleScope));// 角色级,而非 scope:report:genregistry.register(def);}

caller 拿到scope:toolbox:retail就能调零售组全部工具,新增同组工具无需改 caller 授权——权限随工具规模线性收敛。

3. 健康度指标:成功率/P99/报错率

篇12 §7 看板给过阈值(参考值,按业务调):成功率<99%告警、P99>3s告警、报错率>1%告警。采集点在调用拦截处埋点:

// 埋点挂在【实际工具执行】处(MCP 分发层拦截器 / AOP 包裹 @Tool 方法),// 不要只挂在 resolve——resolve 只选定义不执行,否则成功率/P99 统计失真voidafterCall(ToolboxIdid,longcostMs,booleanok){metrics.timer("toolbox.call",id).record(costMs);if(!ok)metrics.counter("toolbox.error",id).increment();// 成功率 = 1 - 报错数 / 调用数,Prometheus 滑动窗口(如 5m)算}

告警阈值(与篇14 全链路监控打通):

指标 阈值 含义 成功率 < 99% 接口不稳定,需排查 P99 耗时 > 3s 慢调用拖累调用方 报错率 > 1% 异常偏多,可能要 deprecate > 阈值需配「持续 5min 超阈 + 告警静默」再触发,避免瞬时抖动误报;窗口按业务调。

低于阈值的工具在 §7 看板标红,配合 §6 弃用流程——质量差的先标期下线,形成"指标驱动治理"闭环。

4. 与篇9身份 / 篇13多租户衔接

5. 岗位对照

本篇能力 -> 对应岗位 / 方向 scope 两层拦截 -> IAM / 权限管理 / 零信任 角色级 scope 聚合 -> 平台权限治理 健康度评分 + 告警阈值 -> SRE / 可观测性 指标驱动弃用闭环 -> 平台稳定性

6. 边界声明


同专题推荐: