MCP Server 能让 AI Agent 调用本地工具、内部服务、文件、数据库或 API,但“能调用”不等于“应该开放”。真正的风险往往不在 MCP 协议本身,而在你把什么能力包装成工具、给了多大权限、是否能审计和回滚。

如果你已经读过 MCP 协议详解MCP Server 开发实战,这篇文章不再重复协议入门,而是专门讲工具调用安全边界。你可以把它当成 MCP Server 上线前的检查清单。

为什么 MCP Server 的风险不在协议,而在工具边界

MCP 的价值是标准化工具连接方式。但一旦工具边界设计不好,模型就可能拿到过大的能力。

风险常见做法更稳做法
任意 shell暴露 run_command只暴露固定白名单命令
任意读文件让模型传完整路径限制根目录和扩展名
任意写文件允许覆盖任何文件只写临时目录或目标白名单
外部请求任意 URL fetch限制域名和方法
数据库操作让模型拼 SQL只提供参数化只读查询
发布动作工具直接 deploy / push必须人工确认或完全不开放

安全的 MCP Server 不是“功能越多越好”,而是“每个工具都能解释它能做什么、不能做什么、失败后怎么处理”。

第一步:把工具能力拆小

不要一开始就做一个万能工具。万能工具看起来灵活,但最难控制。

例如你想让 Agent 分析本地内容项目,不要开放:

不推荐工具问题
run_any_command(command)模型可能执行未知命令
read_any_file(path)容易读到密钥、配置、隐私数据
edit_any_file(path, content)覆盖风险高,难回滚

更好的拆法是:

工具输入输出边界
list_markdown_posts目录、数量限制文章路径和标题只读、只看文章目录
read_post_section文件、标题、长度指定小节限制文件类型和最大字符数
check_frontmatter文件路径缺失字段和异常项不修改文件
find_internal_links文件路径内链列表不访问外网
write_draft_note草稿名、内容写入草稿目录只写固定目录

工具越窄,模型越少猜,审计越简单。

第二步:限制输入、路径、命令和网络

MCP 工具描述要告诉模型怎么用工具,但真正的安全不能只靠描述。Server 端必须做硬限制。

输入限制

检查:

  • 必填字段是否明确;
  • 字符串长度是否有限制;
  • 枚举值是否固定;
  • 数字范围是否合理;
  • 不接受自由拼接的脚本、SQL 或 shell。

如果一个参数可以传入任意自然语言并决定底层动作,就要特别谨慎。

路径限制

文件工具至少要有:

  • 根目录白名单;
  • 禁止 .. 路径穿越;
  • 文件扩展名白名单;
  • 单次读取大小限制;
  • .env、密钥、数据库文件、私有配置做 denylist;
  • 写入目录和读取目录分开。

不要因为“只是本地工具”就放开整个磁盘。

命令限制

如果确实需要命令工具,优先做成固定动作,而不是传 shell 字符串。

目标更安全的工具形式
构建项目run_build(project_id)
跑测试run_tests(test_group)
格式检查run_lint(scope)
导出报告generate_report(report_type)

避免开放 bash -c、管道、重定向、删除、移动、权限修改、网络下载等自由组合能力。

网络限制

网络工具应明确:

  • 允许的域名;
  • 允许的 HTTP 方法;
  • 是否允许携带认证;
  • 响应大小上限;
  • 超时和重试策略;
  • 是否记录请求日志。

能用只读 GET,就不要开放 POST。能人工确认,就不要让模型直接提交外部平台。

第三步:区分只读、写入和外部副作用

所有 MCP 工具都可以先按风险分级。

等级示例默认策略
只读低风险列文件、读公开文档、检查 frontmatter可以自动调用
只读敏感读日志、读配置、查内部数据限制范围并脱敏
本地写入写草稿、生成报告、创建缓存只写固定目录
数据修改数据库更新、批量重命名、删除文件默认不开放或人工确认
外部副作用发邮件、提交 URL、发布、付款、deploy不自动执行

这个分级应该写进工具设计,而不是靠模型临场判断。

对于 AI Agent 工作流,可以把高风险工具放在人工确认之后。更完整的 Agent 架构边界,可以参考 AI Agent 开发指南AI Agent 专题

第四步:设计可审计输出和错误信息

安全不只是限制输入,还包括让输出可审计。

好的工具输出应该:

  • 结构稳定,最好是 JSON 或表格化字段;
  • 明确成功、失败、跳过和部分完成;
  • 不泄露密钥、token、完整内部路径或用户隐私;
  • 错误信息给出可行动原因,而不是底层堆栈;
  • 长日志只返回摘要和文件路径,不把全部日志塞回模型上下文。

例如,不要返回:

Error: permission denied at C:\Users...\secret.env with token xxx

更好的返回是:

读取被拒绝:目标路径不在允许目录或属于敏感文件类型。

这样模型知道下一步该换路径,但不会看到敏感细节。

第五步:上线前用最小客户端验证

MCP Server 能启动,不代表工具安全可用。上线前至少做这些验证:

验证项检查目标
工具列表只暴露需要的工具,没有 debug 工具
schema必填字段、枚举、长度、范围正确
正常路径合法输入能返回稳定结构
非法路径路径穿越、敏感文件、超大文件会被拒绝
错误参数缺字段、错类型、越界值有明确错误
权限边界写操作不能越过固定目录
日志不把密钥、token、用户数据写进日志
客户端接入stdio / HTTP 传输下行为一致

如果你做的是本地工具调用,可以继续对照 MCP Server 本地工具调用实战 的落地流程:先最小工具,再真实文件,再接入 Agent 工作流。

MCP Server 安全检查清单

发布或交给团队使用前,可以按这张表过一遍。

维度检查项
工具范围每个工具只做一类动作;没有万能 shell;没有未使用 debug 工具
输入 schema参数类型、长度、枚举、默认值和必填项明确
路径安全根目录白名单、扩展名白名单、禁止路径穿越、敏感文件 denylist
命令安全固定命令白名单;不接受自由 shell 字符串;不允许删除/移动/权限修改
网络安全域名、方法、认证、超时、响应大小都有边界
写操作只写固定目录;覆盖前可检测;删除和发布默认不开放
外部副作用发邮件、deploy、push、付款、URL 提交必须人工确认或不开放
输出审计返回结构稳定;错误可解释;不泄露敏感信息;长日志摘要化
测试验证覆盖合法输入、非法输入、越权路径、错误参数和客户端接入
运维记录有版本、owner、变更记录和回滚方案

这张清单不是形式。只要其中一项说不清楚,就说明工具边界还不够清晰。

常见错误

错误一:把 MCP 当成远程 shell

MCP 的价值是标准化工具调用,不是让模型自由执行系统命令。任意 shell 是最容易出事的工具形态。

错误二:只靠提示词限制权限

工具描述可以引导模型,但不能替代 Server 端校验。路径、命令、网络、写入都必须在代码里限制。

错误三:把读写混在一个工具里

读操作和写操作应该分开。只读工具可以更自由;写工具必须更窄、更慢、更可确认。

错误四:错误信息暴露太多

调试时完整堆栈很方便,但给模型返回时要脱敏。密钥、token、内部路径、用户数据不应该出现在工具输出里。

错误五:先接生产系统再补边界

顺序应该反过来:先 mock,后只读,后受控写入,最后才考虑生产系统。没有审计和回滚,不要开放高风险动作。

FAQ

MCP Server 一定要支持写操作吗?

不一定。很多有价值的 MCP Server 只做只读查询、索引、摘要和检查。只读工具更安全,也更适合早期落地。

可以开放一个通用命令执行工具吗?

不建议。除非在非常受控的沙箱里,并且命令、参数、目录、超时、输出和日志都有明确限制。大多数业务场景应该拆成固定工具。

MCP 工具要不要记录日志?

要,但日志应该脱敏,并记录工具名、参数摘要、结果状态、耗时和错误类型。不要记录完整密钥、用户隐私或大段原始输出。

AI Agent 调用 MCP 出错怎么办?

先看错误是否来自参数、权限、路径、网络还是工具内部异常。好的 MCP Server 应该返回可解释错误,让模型能换参数或停止,而不是继续重试扩大风险。

总结

MCP Server 安全的核心是最小权限和可审计边界。先把工具拆小,再限制输入、路径、命令和网络,区分只读、写入和外部副作用,最后用最小客户端验证合法和非法路径。

让 AI Agent 调用工具前,先问一句:如果模型误判,这个工具最多能造成多大影响?答案越清楚,MCP Server 越接近可用。