Appearance
07. MCP (Model Context Protocol) 开放标准、资源互通与 Agent 安全控制
一句话定位:Model Context Protocol (MCP) 是由 Anthropic 等推动的 Agent 与本地/远程外部工具、数据源交互的通用标准协议;在实际工程中,必须建立 沙盒执行 (Sandbox)、最小化授权 与 人机协作控制钩子 (Human-in-the-loop Hook) 以拦截破坏性工具操作。
代码索引
| 主题 | Lab 说明 | 源码 |
|---|---|---|
| MCP 安全闸门(白名单 / 参数校验 / 路径边界) | mcp-tool-allowlist-server | server.js · client.js |
| MCP 握手 + Security Hook(黑名单 / 人工批准) | mcp-protocol-security-demo | server.js · client.js |
核心概念:MCP 架构与三大基本原语
图注补充:执行具身功能: 数据库 SQL / Shell / Git;读取上下文: 代码仓库 / 文档表 / Log 抓取。
1. 为什么需要统一 MCP 标准,而不是每个 Agent 自研 Function Calling API?
- 零散集成之痛:过去每个 AI IDE 或模型引擎各自封装一套专有工具规范(OpenAI Schema vs Google Function API vs 自研 Script),导致一个连接 Chrome DevTools 或 PostgreSQL 的插件必须为十几个应用重复编写 N 遍适配器。
- MCP 的统一抽象:MCP 通过标准的 JSON-RPC 2.0(基于
stdio管道或SSEHTTP 协议),明确规范了:- Tools(动作层) :带 JSON-Schema 输入约束的可执行操作(改变外部世界,如执行终端指令、修改文件)。
- Resources(只读层) :提供类似 URI 的统一访问语义(如
file:///repo/docs或db://users/schema),向大模型无损注入实时只读上下文。 - Prompts(模版层) :支持服务器端配置和共享可重用的提示词模板与对话流预设。
2. Agent 安全控制大拐点:安全沙盒与人机协同
由于 MCP 允许模型以操作系统终端或文件读写层面的最高权限工作,缺乏安全管控极易被恶意输入提示词注入 (Prompt Injection) 引发高危系统破坏(例如:针对一个不受信任的外部代码仓库读取了恶意注释,导致 Agent 被诱骗执行 rm -rf / 或将本地私钥发送到外部网络)。
协议帧长什么样:MCP 的 JSON-RPC 2.0 报文示例
MCP 的全部交互都建立在 JSON-RPC 2.0 帧上(走 stdio 时每帧一行,走 SSE 时包在 text/event-stream 里)。理解帧结构,才能看懂抓包、调试插件和排查"协议中断"类问题。
对应 Lab:mcp-tool-allowlist-server(
tools/list/tools/call帧与白名单闸门)· mcp-protocol-security-demo(补齐initialize握手与 Security Hook)——两 lab 均为纯 Node 零依赖,可直接复演下文帧。
1. 一次 tools/list(客户端询问服务端有哪些工具)
客户端发出请求:
json
{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}服务端返回响应(注意:必须用同一个 id 回,这是 JSON-RPC 关联请求与响应的唯一依据):
json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "read_file",
"description": "读取工作区内文件内容,只读操作",
"inputSchema": {
"type": "object",
"properties": { "path": { "type": "string" } },
"required": ["path"]
}
},
{
"name": "run_command",
"description": "在受限 shell 中执行命令,可能产生副作用",
"inputSchema": {
"type": "object",
"properties": { "cmd": { "type": "string" } },
"required": ["cmd"]
}
}
]
}
}- 可能执行顺序:Agent 引擎启动 → 先发
tools/list发现能力 → 再根据能力决定后续tools/call。 - 可能输出:上面这段
result.tools数组;LLM 据此知道"有哪些工具、每个要什么参数"。 - 观察重点:
inputSchema是 JSON Schema,LLM 用它来生成合法参数;工具描述写得越清楚,模型调用准确率越高。
2. 一次 tools/call(客户端真正调用工具)
json
{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "read_file", "arguments": {"path": "README.md"}}}服务端响应:
json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{ "type": "text", "text": "# Engineering Review Lab\n..." }
],
"isError": false
}
}- 可能执行顺序:LLM 生成
tools/call请求帧 → 服务端执行对应函数 → 返回result.content文本回给模型。 - 观察重点:
isError字段区分"正常返回"与"工具执行报错";工具内部异常应返回isError: true而不是直接丢弃响应,否则模型会把错误当作正常数据继续推理。
3. 一个破坏性工具在安全钩子下的完整链路
text
LLM 生成帧: {"method":"tools/call","params":{"name":"run_command","arguments":{"cmd":"sudo rm -rf /data"}}}
│
▼
Security Hook: 命中"命令执行 + 高危目录"规则
│
▼
等待人工确认: 弹窗 Allow / Reject ←── 用户决策点(Human-in-the-loop)
│
▼ 用户拒绝
返回 isError=true, 内容为 "用户拒绝执行"(不执行任何命令)为什么需要(框架)
- 为什么在构建高权限 AI 编程 Agent 时,必须对
Tools的读写与命令行操作实施物理划分与"人机确认(Human-in-the-loop)"?- 一句话答:由于大模型在处理非可信第三方输入(如开源 Issues / 外部爬虫页面)时存在被间接提示词注入(Indirect Prompt Injection)劫持控制权的天然隐患,对于产生侧作用(Side-effect)的高危系统指令(如文件写、进程起停、网络外部外送)必须强制要求人工拦截或限制在只读 Sandbox 环境中运行。
- 为什么推荐将只读类业务信息作为 MCP
Resources提供,而不是让 LLM 每次通过 Tool 调用去执行脚本获取?- 一句话答:
Resources遵循只读 URI 规范,可实现零执行副作用(No Side Effects)、按需上下文缓存与静态内容直接引用,避免由于大模型把读取要求误写为不可预测的变更类 Shell 脚本,既安全又大幅节约 Tokens 延迟。
- 一句话答:
Agent 安全边界开发最佳实践
对应 Lab:mcp-tool-allowlist-server 验证「白名单闸门 + 路径规范化/realpath 边界」;mcp-protocol-security-demo 用
MCP_APPROVE=1环境变量把 Human-in-the-loop 弹窗变成可测试输入,复演黑名单 deny / 未批准 reject 两层拒绝。
图注补充:Sec: 权限控制钩子 (Security Hook);Sec: 1. 请求调用执行
run_command(sudo rm ...);Sec: 2. 匹配规则项:命中终端执行或系统根路径;Usr: 3. 阻塞等待:弹窗拦截请求人工确认;Sec: 4. 用户明确点击授权 Allow / Reject;MCP: 5. 准许下发并注入 Namespace 限定工作目录。
- 绝对路径与工作目录边界隔离 (Chroot / Namespace Sandbox):
- MCP Tool 在注册文件操作工具时,必须强校验目的目标是否落在允许的 Workspace Root 根路径之下;严禁带入
../跳出到/etc、~/.ssh或其他私人敏感区域。
- MCP Tool 在注册文件操作工具时,必须强校验目的目标是否落在允许的 Workspace Root 根路径之下;严禁带入
- 读写权限按需细化 (Least Privilege Action Rules):
- 把所有接口清晰区分出
read_file(只读,可配置规则自动放行)与write_file/run_command(写或侧作用,必须根据影响范围开启用户许可询问)。
- 把所有接口清晰区分出
- 敏感信息过滤与脱敏 (Output Scrubbing):
- MCP Server 把外部 Shell 日志回传到 LLM 前,通过正则表达式对常见的系统环境变量如
AWS_ACCESS_KEY、OPENAI_API_KEY等秘钥串进行动态掩码屏蔽([REDACTED_KEY])。
- MCP Server 把外部 Shell 日志回传到 LLM 前,通过正则表达式对常见的系统环境变量如
常见误配、事故后果与排障
1. 事故:stdio 服务把调试日志打到 stdout,破坏 JSON-RPC 协议帧
- 误配原因:实现 MCP Server 时用
console.log()/print()输出调试信息,而stdio传输模式下 stdout 是唯一的 JSON-RPC 通道。 - 后果:客户端按"一行一个 JSON 帧"解析时读到夹杂的日志行,直接解析失败——轻则单次调用失败,重则整个会话协议中断、Agent 假死。
- 排障与修法:所有日志、警告、崩溃堆栈一律走
stderr;stdout 只允许出现合法 JSON-RPC 帧。排查时可先echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | your-server手动验证帧完整性。
2. 事故:文件类 Tool 未做路径校验,被 ../ 逃逸到工作区外
- 误配原因:
read_file/write_file直接拼接入参路径,未校验目标是否落在 Workspace Root 之下。 - 后果:模型(或被间接提示词注入劫持的模型)可通过
../读到~/.ssh/id_rsa、/etc/passwd等敏感文件,甚至覆盖系统配置,造成凭据泄露与数据破坏。 - 排障与修法:在 Server 侧对路径做规范化(
realpath)+ 前缀校验,拒绝任何跳出工作区根目录的目标;高危写操作再叠加人机确认钩子。
3. 事故:把真实凭据通过 Resources / Tool 参数注入模型上下文
- 误配原因:为了让 Agent 能直连数据库,直接把
DB_PASSWORD作为 Resource 内容或 Tool 参数下发。 - 后果:凭据进入 LLM 上下文后,一旦用户把对话或日志外发,密钥即泄露;且模型可能在输出中无意复述敏感串。
- 排障与修法:模型永远不该看到明文凭据——由 MCP Server 侧持有凭据并执行连接,只把结果(如查询结果)返回给模型;对返回内容做正则脱敏兜底。
对应实验
| Lab | 说明 | 源码 |
|---|---|---|
| mcp-tool-allowlist-server | 静态三闸门:工具白名单 / inputSchema 参数校验(-32602)/ 路径规范化+前缀+realpath 边界;stdout 只出 JSON-RPC 帧(与文首「代码索引」一致) | server.js · client.js |
| mcp-protocol-security-demo | 动态安全钩子:initialize 握手、高危命令黑名单 deny、副作用命令需 MCP_APPROVE=1 人工批准(fail-closed)、只读工具路径逃逸拦截,含自动化测试 | server.js · client.js |
本章复习题
- 在使用 MCP 架构进行扩展时,对于“查询线上服务当前内存使用情况”这类需求,应该注册为 MCP Tool 还是 MCP Resource?为什么?
- 答:应优先注册为 MCP Resource(或者只读型 Tool);因为该请求纯粹属于获取系统快照数据的非变更操作,使用通用规范的资源描述符(如
mcp://monitoring/memory)有利于统一授权审计和结果局部重换缓存。
- 答:应优先注册为 MCP Resource(或者只读型 Tool);因为该请求纯粹属于获取系统快照数据的非变更操作,使用通用规范的资源描述符(如
- 如何解决基于 standard input/output (
stdio) 传输的 MCP Server 在日志输出时意外损坏 JSON-RPC 通信协议帧的问题?- 答:MCP Protocol 的 JSON-RPC 主通信线独占系统标准输出流(
stdout),必须强制将所有服务器应用的自检警告与调试类 Debug 调试信息统一写入 标准错误流 (stderr) 或指定的外部文件流。
- 答:MCP Protocol 的 JSON-RPC 主通信线独占系统标准输出流(
对应实验室与拓展
- 实战指引:回顾 AI 编码中智能体执行命令与多层安全工具调用的基础知识,请复习 §08-ai-engineering/05-agent-tool-calling-architecture.md。
- 关联拓展:了解如何在代码审查和 CI 自动化验证流水线中安全调用与限制 AI Agent,可参考 §08-ai-engineering/06-ai-code-review-and-verification.md。