Skip to content

07. MCP (Model Context Protocol) 开放标准、资源互通与 Agent 安全控制 ​

一句话定位:Model Context Protocol (MCP) 是由 Anthropic 等推动的 Agent 与本地/远程外部工具、数据源交互的通用标准协议;在实际工程中,必须建立 沙盒执行 (Sandbox)、最小化授权 与 人机协作控制钩子 (Human-in-the-loop Hook) 以拦截破坏性工具操作。


代码索引 ​

主题Lab 说明源码
MCP 安全闸门(白名单 / 参数校验 / 路径边界)mcp-tool-allowlist-serverserver.js · client.js
MCP 握手 + Security Hook(黑名单 / 人工批准)mcp-protocol-security-demoserver.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 管道或 SSE HTTP 协议),明确规范了:
    • 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 限定工作目录。

  1. 绝对路径与工作目录边界隔离 (Chroot / Namespace Sandbox):
    • MCP Tool 在注册文件操作工具时,必须强校验目的目标是否落在允许的 Workspace Root 根路径之下;严禁带入 ../ 跳出到 /etc、~/.ssh 或其他私人敏感区域。
  2. 读写权限按需细化 (Least Privilege Action Rules):
    • 把所有接口清晰区分出 read_file(只读,可配置规则自动放行)与 write_file / run_command(写或侧作用,必须根据影响范围开启用户许可询问)。
  3. 敏感信息过滤与脱敏 (Output Scrubbing):
    • MCP Server 把外部 Shell 日志回传到 LLM 前,通过正则表达式对常见的系统环境变量如 AWS_ACCESS_KEY、OPENAI_API_KEY 等秘钥串进行动态掩码屏蔽([REDACTED_KEY])。

常见误配、事故后果与排障 ​

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)有利于统一授权审计和结果局部重换缓存。
  • 如何解决基于 standard input/output (stdio) 传输的 MCP Server 在日志输出时意外损坏 JSON-RPC 通信协议帧的问题?
    • 答:MCP Protocol 的 JSON-RPC 主通信线独占系统标准输出流(stdout),必须强制将所有服务器应用的自检警告与调试类 Debug 调试信息统一写入 标准错误流 (stderr) 或指定的外部文件流。

对应实验室与拓展 ​

  • 实战指引:回顾 AI 编码中智能体执行命令与多层安全工具调用的基础知识,请复习 §08-ai-engineering/05-agent-tool-calling-architecture.md。
  • 关联拓展:了解如何在代码审查和 CI 自动化验证流水线中安全调用与限制 AI Agent,可参考 §08-ai-engineering/06-ai-code-review-and-verification.md。

站点构建时间:2026/8/24 23:43:17