大厂 MCP 面试实录:Tool 调用身份认证与最小权限设计

大厂 MCP 面试实录:Tool 调用身份认证与最小权限设计

本文为 MCP 后端开发岗位模拟面试复盘,围绕「为内部 RAG 知识库封装的远程 MCP Tool 增加身份认证、授权与最小权限控制」这一核心场景展开,覆盖基础概念、技术选型、方案设计与边界取舍。


面试官:同学你好,今天我们聊的场景是:公司要把内部研发/财务/人力三域的 RAG 知识库封装成 MCP Tool,部署为远程 Streamable HTTP 服务,供内部 AI 助手调用。第一个问题:为什么不能只靠 Tool 的参数 schema 做权限控制,防止用户越权访问其他域的知识库?

候选人 :首先给出结论:Tool 参数 schema 仅能做结构层面的约束,完全不能替代服务端的权限校验。原因有两个层面:第一,MCP 协议规定模型传入的参数都是不可信输入,恶意用户可以直接绕过客户端,构造任意参数的请求直接调用 Server 的接口;第二,我们的场景是远程部署的 HTTP 服务,请求可以不经过我们封装的客户端,直接发到 Server 端口,参数 schema 根本没有执行环境做拦截。比如财务域的 Tool 如果只在 schema 里限制 domain=finance,恶意用户可以直接把参数改成 domain=hr 直接调用,所以权限校验必须放在 Server 端全链路执行。资料1

面试官:你说得对,那如果我用 TypeScript MCP SDK 开发这个远程 Server,SDK 本身有没有内置的认证授权能力?我需要从零实现整套安全逻辑吗?

候选人:结论是:TypeScript MCP SDK 和其他语言的 SDK 设计思路一致,不会内置具体的认证授权实现,只提供可插拔的钩子,避免和特定安全生态绑定。参考 Java SDK 的设计,它会把授权能力集成到传输层,提供钩子函数让开发者接入自己公司的现有认证体系,比如我们已经落地的 OAuth2、JWT 或者内部 SSO 体系,不需要重复造轮子。资料2 具体到我们的场景,我会在 Streamable HTTP 的传输层前面加一个认证中间件,先校验请求携带的 JWT 令牌,解析出用户的角色、所属域等权限信息,再传递给后续的 Tool 调用流程。

面试官:我们的 RAG 知识库是分域隔离的,财务域文档只有财务岗员工能访问,研发域只有研发岗能访问,部分管理层有跨域权限。你设计的授权方案怎么和 RAG 的向量检索、重排能力结合,实现最小权限?不能出现用户检索到无权限文档的情况。

候选人:我会设计「身份层-资源层-操作层」三层授权模型,和 RAG 链路深度绑定: 1. 身份层:就是刚才说的传输层 JWT 校验,每次请求都校验令牌有效性,解析出用户的权限域列表,不缓存长期权限,最多缓存 5 分钟(具体时长根据业务对权限时效性的要求调整),避免转岗后权限未及时生效的问题。 2. 资源层:把 RAG 知识库的域和用户权限域做绑定,在向量检索的召回阶段就直接加权限过滤条件,把不属于用户权限域的文档直接从召回结果里过滤掉,不进入后续的重排和生成环节。参考 Azure AI Search 的 Filter-based security 设计,在查询向量数据库的时候就把权限标签作为过滤条件,从根源上避免无权限文档被召回。资料4 3. 操作层:限制 Tool 的调用范围,比如只有财务岗的用户才能调用财务域的检索 Tool,普通员工调用跨域 Tool 会直接返回权限不足。 整个 RAG 链路是:用户发起检索请求 → 身份层校验权限 → 向量检索带权限过滤召回 → 权限二次校验 → 重排 → 脱敏后返回结果,全程无权限文档不会流出。

面试官:如果出现两个异常情况:第一,用户刚转岗,权限还没同步到权限系统,调用 Tool 的时候被拦截了,怎么处理?第二,某个域的文档很少,权限过滤后召回的数量不足,达不到模型生成的要求,怎么处理?

候选人:第一个异常情况,首先我们的授权是每次请求都实时校验权限(或者最多缓存 5 分钟),如果权限系统同步延迟,会出现短暂的拦截,这是可以接受的,因为安全优先级高于可用性。如果业务要求转岗后立即生效,可以把权限系统的同步延迟控制在 1 分钟以内,或者提供权限预加载的接口,转岗成功后主动刷新用户的权限缓存。第二个异常情况,权限过滤后如果召回文档数量不足,绝对不能降级返回无权限的文档,而是直接返回提示「当前权限范围内未找到匹配的文档,请联系管理员申请权限」,同时把这次调用的指标(用户、Tool、召回数量、过滤数量)上报到监控系统,方便运维排查知识库的覆盖问题。

面试官:你提到用 TypeScript MCP SDK,具体怎么把授权逻辑插进去?还有 RAG 的检索结果返回给模型的时候,既要保证有用性,又不能泄露敏感内容,怎么处理?

候选人:首先是 SDK 的集成,TypeScript MCP SDK 支持自定义中间件,我们可以在 Server 启动的时候挂载认证中间件,以下是版本无关的通用设计,不依赖具体 SDK 版本:

typescript 复制代码
// 伪代码:TypeScript MCP Server 授权中间件挂载
const server = new McpServer({
  name: "internal-rag-tool",
  version: "1.0.0"
});

// 挂载认证中间件,在 Tool 调用前执行
server.use(async (ctx, next) => {
  const token = ctx.request.headers.get("Authorization")?.replace("Bearer ", "");
  if (!token) {
    throw new Error("未提供认证令牌");
  }
  // 校验 JWT,解析用户权限信息挂载到上下文
  ctx.user = await verifyJwt(token);
  await next();
});

// 注册 RAG 检索 Tool
server.tool("search_rag_docs", { /* 参数 schema */ }, async (params, ctx) => {
  // 从上下文中获取用户权限域
  const userDomains = ctx.user.permissionDomains;
  // 调用 RAG 服务,传入权限过滤条件
  const results = await ragService.search(params.query, {
    domainFilter: userDomains,
    topK: 5
  });
  // 二次校验返回结果的权限(避免向量数据库过滤逻辑漏洞)
  const filteredResults = results.filter(r => userDomains.includes(r.domain));
  // 敏感字段脱敏,比如文档里的身份证号、手机号
  const sanitizedResults = filteredResults.map(r => ({
    ...r,
    content: desensitize(r.content)
  }));
  // 记录审计日志
  auditLog.info({
    userId: ctx.user.id,
    tool: "search_rag_docs",
    domains: userDomains,
    resultCount: sanitizedResults.length,
    status: "success"
  });
  return { content: sanitizedResults };
});

然后是 RAG 结果的处理,我们会保留文档的来源元数据(比如所属域、文档ID、上传时间),方便模型引用和用户溯源,同时所有敏感字段在返回前统一脱敏,不会把原始敏感内容传给模型。

面试官:你这个方案有什么取舍?比如如果知识库有上百万份文档,每次检索都做权限过滤会不会影响性能?还有如果需要支持用户跨域检索,比如财务岗的员工需要同时查财务和人力域的文档,怎么处理?

候选人 :首先是性能取舍:在向量检索阶段加权限过滤,确实会比全量召回稍微增加查询耗时,具体延迟需要根据向量数据库的规模和索引情况压测确定,但这是安全必须付出的代价。我们可以通过两种方式优化:第一,在向量数据库的元数据里提前建权限域的索引,用预过滤的方式提升查询速度;第二,缓存用户的权限列表,避免每次请求都查权限系统。第二个跨域需求的问题,我们会在用户权限表里支持多域配置,比如财务岗的管理层可以配置 permissionDomains: ["finance", "hr"],检索的时候自动把多个域作为OR条件传给向量数据库,不需要用户额外操作。

面试官:这个方案最容易踩的坑是什么?比如我见过有团队把用户的 JWT 令牌写到 Tool 返回值里,或者调试日志里泄露了文档的敏感内容,你怎么避免?

候选人:最容易踩的坑就是敏感信息泄露,具体有三个层面要避免:第一,全链路日志脱敏,调试日志只打印用户ID、Tool名称、请求耗时、结果状态,绝对不打印 JWT 令牌、请求参数、返回的文档内容,生产环境的日志级别设置为 INFO 以上,关闭 DEBUG 日志;第二,Tool 返回值里绝对不能包含任何凭据信息,包括 JWT、API 密钥等;第三,RAG 的检索结果在返回前必须做敏感字段脱敏,比如身份证号、手机号、薪资等敏感内容,用掩码替换,避免模型把这些内容输出给用户。另外还要注意,不能因为请求来自内部 AI 应用就默认可信,所有的请求都要做权限校验,避免内部服务被冒用。资料1


面试官点评

  • 考察点:对 MCP 安全边界的理解、分层授权方案的设计能力、RAG 与 MCP 的融合能力、异常处理与可观测性设计。
  • 合格回答:能明确区分参数 schema 和 服务端校验的边界,知道远程 MCP Server 必须做全链路授权,能在 RAG 召回阶段加入权限过滤,避免无权限文档泄露。
  • 加分项:能结合 SDK 设计思路说明授权钩子的作用,能考虑到权限变更的时效性、召回不足的降级策略、跨域权限的支持、全链路脱敏和审计日志的设计,还能说出安全与性能的取舍。

方案适用边界与关键细节

  1. 适用边界:本方案适用于内部部署、有明确权限域划分的 MCP 远程服务场景,如果是公开的、无权限区分的 MCP Tool,不需要这么复杂的授权逻辑。
  2. 关键取舍:安全性与性能的平衡,召回阶段加权限过滤会略微增加查询延迟,但能从根本上避免无权限文档泄露,属于必须接受的取舍;缓存用户权限能提升性能,但会引入短暂的权限延迟,需要根据业务对安全时效性的要求调整缓存时长。
  3. 易踩坑细节:很多团队会在重排阶段才做权限校验,导致无权限文档已经被模型看到,正确的做法是在召回阶段就过滤掉无权限文档,从根源上避免泄露;另外不要把敏感信息写入日志或 Tool 返回值,这是最常见的泄露点。

参考资料

  1. MCP 基础知识 https://modelcontextprotocol.io/
  2. MCP Java SDK https://github.com/modelcontextprotocol/java-sdk
  3. MCP Python SDK https://github.com/modelcontextprotocol/python-sdk
  4. Retrieval-augmented generation (RAG) in Azure AI Search https://learn.microsoft.com/en-us/azure/search/retrieval-augmented-generation-overview
相关推荐
Akiyama_Mio-Kon2 小时前
CVE-2026-85654 深度解读:DynamoDB MCP Server 如何把数据模型风险带到 CDK 部署宿主
aws·dynamodb·cdk·mcp·cve-2026-85654·lac·agent 安全
gsls2008081 天前
告别 Vault 的复杂度:用 Go 标准库给 Windows 凭据管理器装上 MCP
windows·golang·mcp
极小狐1 天前
极狐GitLab Duo 功能更新:扩展 MCP 工具集、支持 MR 事件触发
运维·gitlab·agent·mr·极狐gitlab·mcp·极狐gitlab duo
xrlfreedom2 天前
大厂 MCP 面试实录:基于 OpenTelemetry 与 OAuth 2.1 的可重复集成测试方案设计
opentelemetry·mcp·oauth 2.1
吴佳浩3 天前
为什么每个人最终都会使用 Agent?从 LLM 到 Agent,看懂 AI 为什么一定会走向执行时代
llm·agent·mcp
仓三3 天前
Chrome DevTools MCP 上手:让 Coding Agent 自己调试前端页面
前端·chrome devtools·mcp
xrlfreedom3 天前
大厂 MCP 面试实录:设计需人工确认的高风险 Tool 的工程化方案
opentelemetry·mcp·rag 知识库·向量检索与重排
gsls2008083 天前
OpsKat封装MCP:用 Go 标准库把运维 CLI 变成 AI 的“手“
运维·人工智能·golang·mcp
zhuodedao3 天前
Spring AI + MCP 文件工具未调用问题复盘:为什么初始化成功却没有写入文件?
java·debug·agent·springai·mcp