MCP 面试高频考点:企业内网统一管理多个 MCP Server,Tools 权限与审计怎么落地?
MCP 面试高频考点:企业内网统一管理多个 MCP Server,Tools 权限与审计怎么落地?
面试场景
某企业内网有十几个业务系统,团队希望用 MCP 把这些系统统一暴露给内部 AI 应用:有的 Server 提供只读查询,有的提供工单创建、配置变更等写操作。现在要设计一个“内网 MCP 网关”,集中管理多个 MCP Server,做到统一接入、最小权限和审计。面试官围绕这个场景,逐层追问 Tools 设计、TypeScript MCP SDK 的工程实现、安全边界与可观测性。
第一轮:基础问题——能力怎么划分
面试官: 你要把这些系统接进 MCP,先说说每个 Server 暴露什么能力,Tools、Resources、Prompts 怎么分工?
候选人: 结论是:有副作用、需要参数并返回执行结果的操作做成 Tools;只读的上下文资料做成 Resources;固定工作流模板做成 Prompts。
原因是 MCP 的三类能力语义不同:Tools 是模型可发起调用的操作,应使用清晰的名称、描述和输入 schema;Resources 向应用提供可读取的上下文,通常由 URI 标识;Prompts 是用户可显式选择的模板化消息或工作流[资料1]。所以“查询某工单详情”如果只是给模型补充上下文,更适合 Resource;“创建工单”有副作用,必须是 Tool;而“故障复盘流程”这种多步模板适合 Prompt。
面试官: 那“查询工单”到底做 Resource 还是 Tool?
候选人: 看调用方是否需要模型自主决定时机。如果 Host 希望在调用模型前主动拼上下文,Resource 更合适;如果希望模型根据任务决定查不查、查哪个,则封装成 Tool 更灵活,但要控制调用次数和权限[资料1]。我的取舍是:高频、结构固定的上下文用 Resource;需要模型判断参数和时机的查询用 Tool,并在网关侧做限流与授权。
面试官点评: - 考察点:是否理解三类能力的语义差异,而不是把所有东西都塞进 Tool。 - 合格回答:能按“有无副作用、是否模型自主调用”划分。 - 加分项:指出同一业务查询在 Resource 与 Tool 之间的取舍依据。
第二轮追问:最小权限怎么落到 Tools 上
面试官: 你说网关做授权。Tool 的输入 schema 已经限制了参数类型,为什么还要服务端校验和授权?
候选人: 结论:schema 只是结构约束,不能代替服务端校验和授权。资料明确说,Tool 的参数 schema 不能代替服务端校验和授权,Server 必须把模型传入的文本视为不可信输入,对文件路径、URL、SQL、Shell 参数和资源标识符进行约束[资料1]。
具体到内网场景,我会做三层: 1. 身份层:网关识别调用方身份与所属租户/部门。 2. 能力层:按“用户 × Server × Tool”授权,写操作单独授权,不因为请求来自 AI 应用就默认可信[资料1]。 3. 参数层:对资源标识符做白名单或范围校验,比如只允许访问本部门工单 ID 段。
面试官: 如果某个 Tool 是“批量变更配置”,授权也通过了,还缺什么?
候选人: 缺执行前确认。高风险或不可逆操作应显示具体影响,并在执行前要求用户确认[资料1]。所以这类 Tool 我会在描述里写清影响范围,并在网关或 Host 侧插入确认环节,而不是让模型直接触发。
面试官: 为什么授权要放在网关,而不是每个 Server 各自实现?
候选人: 统一策略、统一审计、减少重复实现。不过要注意边界:网关做粗粒度和统一策略,Server 仍要对自身资源做细粒度校验,二者不是替代关系。资料也强调远程 MCP Server 应对每次请求执行授权检查,不能只判断用户是否已登录[资料1]。
面试官点评: - 考察点:是否把 schema 误当安全机制;是否理解“每次请求授权”。 - 合格回答:区分结构校验与授权,给出分层。 - 加分项:主动提出高风险操作的确认机制,并说明网关与 Server 的责任边界。
第三轮追问:用 TypeScript MCP SDK 落地时的工程细节
面试官: 你说用 TypeScript MCP SDK 写 Server。传输方式怎么选?内网多个 Server 由网关统一管理,这里有什么坑?
候选人: 结论:网关到各 Server 走远程传输,Server 侧不要假设“内网即可信”。
资料说明 stdio 适合由 Host 在本机启动子进程的场景,Server 的标准输出用于协议消息,调试日志应写到标准错误,否则可能破坏通信;Streamable HTTP 适合远程服务,远程部署还需考虑认证、授权、会话管理、限流和超时[资料1]。内网统一管理属于远程服务形态,所以我倾向 Streamable HTTP,并在网关层统一做认证、限流和超时。
这里有个容易踩的坑:即使是内网 Server,如果把调试日志打到标准输出,在 stdio 场景会直接破坏协议消息[资料1]。所以日志规范要作为接入基线强制检查。
面试官: 那 Tools 的注册和调用处理,代码结构怎么组织?请给出与版本无关的接口设计,不要猜具体 API。
候选人: 我不确定 TypeScript SDK 的具体方法名,所以给伪代码:
// 伪代码:与具体 SDK 版本无关
registerTool({
name: "ticket.create",
description: "创建工单;写操作,需用户确认",
inputSchema: { /* 结构约束 */ },
handler: async (args, ctx) => {
assertAuthorized(ctx.principal, "ticket.create"); // 每次请求授权
validateArgs(args); // 服务端校验
const result = await ticketService.create(args);
audit.log({ who: ctx.principal, tool: "ticket.create",
scope: args.projectId, status: "ok" }); // 脱敏后记录
return result;
}
});
原则是:注册时写清名称、描述和 schema;handler 内先授权、再校验、再执行、最后审计。
面试官: 如果 SDK 本身不带授权实现呢?
候选人: 那就把授权放在传输层或网关。资料提到 Java SDK 采用可插拔授权钩子、不自带授权系统,把授权集成到 Server 传输层[资料3]。思路可以借鉴:SDK 负责协议,授权交给企业已有的身份体系,避免锁定。
面试官点评: - 考察点:传输选型是否有依据;是否知道 stdio 的日志陷阱;代码是否有安全顺序。 - 合格回答:远程用 Streamable HTTP,handler 内授权与校验前置。 - 加分项:明确不猜 SDK API,用版本无关设计表达意图。
第四轮追问:异常与审计
面试官: 如果 Tool 执行到一半下游超时,审计日志怎么写?异常怎么返回给模型?
候选人: 结论:审计记录“结果状态”,异常返回结构化错误,不泄露凭据。
审计日志应记录谁在什么时间调用了哪个 Tool、关键资源范围与结果状态,并对敏感字段脱敏[资料1]。所以超时要记成失败状态并带上资源范围,而不是只记成功。返回给模型的错误信息要可读但不含内部凭据;凭据不应出现在日志、Tool 返回值或模型上下文中[资料1]。
面试官: 重试呢?固定重试几次可以吗?
候选人: 不能拍脑袋定固定次数或超时值。这些应由业务 SLA、操作风险和压测结果确定。写操作尤其要谨慎:不可逆操作重试可能造成重复副作用,需要幂等键或人工确认。
面试官: 还有什么取舍?
候选人: 统一网关提升了可控性和审计一致性,但增加了单点与延迟;把授权全放网关会弱化 Server 自身防护,所以两层都要有。审计越细,存储与脱敏成本越高,需要按风险和合规要求分级。
面试官点评: - 考察点:异常路径是否纳入审计;是否避免编造工程数字。 - 合格回答:状态化审计、脱敏、结构化错误。 - 加分项:指出写操作重试的幂等风险,并说明数值应依据 SLA 与压测确定。
总结
这场面试的核心不是背概念,而是把 Tools 语义、TypeScript MCP SDK 的传输与 handler 设计、最小权限和审计日志串成一条可落地的链路:能力按语义划分,schema 不等于安全,授权按每次请求执行,高风险操作要确认,日志要脱敏且记录结果状态。适用边界是内网统一接入与集中治理;取舍在于网关的统一性与单点成本、审计细度与存储成本之间的平衡。
参考资料
- MCP 基础知识
- MCP Python SDK:https://github.com/modelcontextprotocol/python-sdk
- MCP Java SDK:https://github.com/modelcontextprotocol/java-sdk
- Security Best Practices:https://modelcontextprotocol.io/docs/tutorials/security/security_best_practices
更多推荐

所有评论(0)