大厂 MCP 面试实录:基于 stdio 传输的只读业务上下文暴露方案设计
本文采用模拟面试形式,复盘 MCP 岗位面试中的场景设计题,聚焦 Resources 能力、stdio 传输与 Prompts 的落地实践,面向具备基础开发经验的读者。
面试官:今天我们聊一个实际业务需求——你所在的团队要给内部 AI 助手做业务上下文增强,需要把订单系统的只读规则、用户权限范围、商品类目说明三类静态业务资料,通过 MCP 暴露给模型,要求使用 stdio 传输,同时支持用户一键调用预设的上下文查询模板。你先说说整体的方案思路?
候选人:我的整体方案是基于 MCP Server 端实现,用 stdio 作为传输层,三类静态资料封装为 Resources,常见的查询逻辑封装为 Prompts,Host 侧只要启动本地子进程即可接入,不需要额外网络配置。 选型依据上,三类资料都是只读静态内容,没有副作用,符合 MCP 中 Resources 的语义定位——Resources 专门用于向模型提供可读取的上下文,由 URI 唯一标识,比强行设计成有操作语义的 Tool 更符合协议规范[资料1]。传输层选 stdio 是因为需求是内部工具,部署在员工本机,不需要远程访问,stdio 适合 Host 本机启动子进程的场景,比 Streamable HTTP 更轻量,不需要处理远程部署的认证、会话管理、限流等问题[资料1]。Prompts 的作用是把常见的查询模板提前封装好,比如“查询当前用户的订单规则”“查询商品类目说明”,用户不用自行编写提示词,直接选择对应的模板就能调用,减少模型对查询意图的理解偏差。
面试官:你把三类资料封装成 Resources,那 URI 设计有什么讲究?如果后续业务资料更新,怎么保证模型拿到的是最新内容,又不会频繁读磁盘影响性能?
候选人:URI 设计要遵循可读、可层级划分的原则,比如用order://rules/latest标识最新订单规则、user://permission/scope标识用户权限范围、product://category/list标识商品类目列表,符合 RFC 3986 的 URI 规范,也方便 Host 侧做预加载和缓存[资料2]。 内容更新机制上,MCP 的 Resources 是应用驱动的,Host 侧可以根据自身需求决定何时拉取资源[资料2]。我可以在 Resources 的响应元数据里加版本号字段,Host 侧缓存资源时同时记录版本号,每次调用前先对比版本号,只有版本变化时才重新拉取内容,既保证内容时效性,又避免频繁读磁盘。如果业务资料是存在本地文件里的,还可以监听文件的修改事件,文件更新时主动通知 Host 更新缓存,进一步降低延迟。
面试官:你提到用 stdio 传输,如果 Server 端不小心把调试日志输出到标准输出,会有什么后果?怎么规避?
候选人:stdio 传输下,MCP 的 JSON-RPC 协议消息是走 Server 的标准输出(stdout),如果调试日志也输出到 stdout,会直接破坏消息格式,导致 Host 侧解析失败,通信中断,轻则上下文获取失败,重则整个 AI 助手功能不可用[资料1]。 规避方式有两个:一是日志库配置把调试日志输出到标准错误(stderr),或者直接写入本地日志文件,只有协议消息走 stdout;二是在 Server 启动时做输出流校验,如果有非 JSON 内容输出到 stdout,直接终止进程并报错。另外 Host 侧也要做容错,如果子进程启动失败或者通信中断,要给用户明确的错误提示,比如“业务上下文服务异常,请检查安装是否完整”。
面试官:现在有个新需求:用户查询订单规则时,需要根据当前用户的角色返回不同的规则内容,这个需求用 Resources 还是 Prompts 实现更合适?如果后续要支持用户输入自定义查询条件,又该怎么调整?
候选人:这个需求要分场景选型:如果不同角色对应的规则是静态的、提前写好的,优先用 Prompts 实现更合适。我们可以把“查询角色对应订单规则”封装成一个 Prompt,预置user_role参数,用户选择模板时 Host 侧自动把当前用户的角色作为参数传入,Server 侧根据角色返回对应角色的 Resources 内容,逻辑清晰且可控。 如果后续要支持用户输入自定义查询条件,比如查询特定时间段的订单规则,就需要扩展只读 Tool 能力,把这个查询逻辑封装成只读 Tool,明确标注无副作用,参数里加时间范围的校验规则。这里要注意,Tool 的参数 schema 只是结构约束,Server 侧必须对用户输入的时间参数做合法性校验,防止 SQL 注入或者路径遍历等攻击[资料1]。另外所有用户传入的文本都要视为不可信输入,不能直接拼接文件路径或者查询语句。
面试官:这个 Server 要部署到团队所有员工的本机,怎么保证安全?有没有潜在的泄露风险?
候选人:首先是代码安全:Server 的代码是团队内部开源的,员工安装时可以做哈希校验,防止被恶意篡改。然后是内容安全:Resources 暴露的都是静态只读内容,Server 侧不会执行文件里的任何代码,只是返回纯文本,所以不会有代码执行风险。Prompts 里的参数都是预置的,用户不能输入任意内容,也不会存在注入风险。 如果后续扩展了动态查询 Tool,必须做参数校验,比如用户ID必须是数字格式,文件路径只能在规定的业务目录下,不能访问系统文件[资料1]。另外日志里不能打印敏感信息,比如用户权限内容、用户ID 等,要做脱敏处理,审计日志只记录调用时间、调用者、资源标识和结果状态,不记录敏感字段[资料1]。
面试官:那你写一个可落地的示例代码吧,用 Python 实现就行。
候选人:以下代码基于 MCP 公开规范与 Python SDK 公开文档设计,具体接口以官方文档为准[资料3]:
# 参考 MCP Python SDK 公开接口设计,仅作示例 from mcp.server import Server from mcp.types import Resource, Prompt, PromptArgument app = Server("business-context-server") # 定义只读业务资源 @app.list_resources() async def list_resources(): return [ Resource( uri="order://rules/latest", name="最新订单规则", description="订单系统核心规则说明,只读", mime_type="text/markdown" ), Resource( uri="product://category/list", name="商品类目列表", description="全量商品类目说明,只读", mime_type="text/markdown" ) ] @app.read_resource() async def read_resource(uri: str): if uri == "order://rules/latest": with open("./rules/order.md", "r") as f: return f.read() if uri == "product://category/list": with open("./rules/category.md", "r") as f: return f.read() raise ValueError(f"不支持的资源标识:{uri}") # 定义预设Prompt @app.list_prompts() async def list_prompts(): return [ Prompt( name="query-order-rule", description="查询当前登录用户的订单规则", arguments=[PromptArgument(name="user_role", description="用户角色", required=True)] ), Prompt( name="query-category", description="查询商品类目说明", arguments=[] ) ] @app.get_prompt() async def get_prompt(name: str, arguments: dict): if name == "query-order-rule": role = arguments.get("user_role", "guest") return { "messages": [{"role": "user", "content": f"请读取订单规则资源,针对{role}角色的用户,说明下单、退款、售后的相关规则"}] } if name == "query-category": return { "messages": [{"role": "user", "content": "请读取商品类目资源,说明全量类目的划分规则和适用范围"}] } raise ValueError(f"不存在的模板:{name}") if __name__ == "__main__": # stdio 传输:标准输出用于协议消息,标准错误用于日志 app.run(transport="stdio")这个示例的适用边界是静态只读业务资料的暴露,不支持动态参数化的资源查询,若要支持需扩展 Tool 能力。关键取舍是:stdio 传输仅支持本机部署,不支持多用户远程共享,适合小团队内部个人工具使用;如果是全公司大规模部署,建议换成 Streamable HTTP 传输,加上认证、授权和限流机制[资料1]。
面试官点评
考察点
本题核心考察四个方向:一是对 MCP 三类能力(Tools、Resources、Prompts)的语义区分,避免乱用能力;二是传输方式的选型权衡,是否了解 stdio 的适用场景和限制;三是安全边界意识,是否知道 MCP 场景下的常见安全风险;四是可落地能力,能不能把方案转化为可运行的代码。
合格回答
能明确区分 Resources 和 Tool 的适用场景,知道 stdio 传输下日志不能输出到 stdout 的要求,能设计合理的 URI 和 Prompts 模板,考虑到基本的参数校验和敏感信息保护,给出的示例代码能跑通核心流程。
加分项
能提到 Resources 的“应用驱动”特性,知道 Host 侧的缓存优化机制;能区分静态和动态场景的选型,考虑到后续扩展性;能指出 stdio 传输仅适合本机部署的边界,以及大规模部署的替代方案;能提到路径遍历、日志脱敏等容易被忽略的安全细节。
容易踩坑的细节
- 很多开发者会把需要动态参数的只读查询设计成 Resource,比如
user://permission/123,导致 Resource 列表爆炸,且 Host 侧无法预知所有可能的 URI,无法做预加载缓存。动态查询场景优先用 Prompts 或者只读 Tool 实现。 - stdio 传输下把调试日志输出到 stdout 是非常常见的错误,会导致通信直接中断,一定要把日志输出到 stderr 或者文件。
- 不要因为请求来自 AI 应用就默认可信,所有用户传入的参数都要做服务端校验,不能只依赖前端或者 Host 侧的限制。
总结
本场景下的技术选型逻辑非常清晰:只读静态业务上下文优先用 Resources 暴露,模板化查询逻辑用 Prompts 封装,本地小范围部署用 stdio 传输降低成本。整个方案的核心是遵循 MCP 的能力语义,不强行拼接技术,同时守住安全边界,保证服务稳定。如果是更复杂的动态查询场景,再扩展只读 Tool 能力,同时做好参数校验和权限控制。
参考资料
- MCP 基础知识
- Resources | https://modelcontextprotocol.io/specification/2026-07-28/server/resources
- MCP Python SDK | https://github.com/modelcontextprotocol/python-sdk
- Sampling | https://modelcontextprotocol.io/specification/2026-07-28/client/sampling