">

给 MCP 参考服务器收紧权限:只读、主机白名单与超时的配置实操

MCP 官方参考服务器 v2.3.0 新增只读模式、Roots 收口、主机白名单与三层超时。这篇按官方 README 把它配成一套可验收的最小权限边界,含每步的成功判据与八个真实会卡住的地方。

这篇教程解决什么

2026 年 11 月 4 日,MCP 官方参考服务器发布 v2.3.0,一次性补上了几处此前要自己绕过去的边界开关:filesystem 服务器新增 --read-only 只读模式与 --confine-roots 目录收口,fetch 服务器新增 --allowed-hosts 主机白名单与可配超时,git 服务器新增只读的 git_remote 与默认快进合并的 git_merge。这些开关的意义不在「又多了几个参数」,而在于边界第一次可以由服务端强制执行,而不必依赖客户端自觉。

这篇教程的目标是把官方参考服务器从「默认能用」配成「能读不能写、只连白名单主机、超时有上限」的最小权限状态,并给出每一步的成功判据。读完你应该能自己写出两份配置(filesystem 与 fetch)、说清三道边界各防什么、以及用哪几个必然失败的请求去验收。

前提:本机有 Node.js 24 或更高版本(filesystem 走 npx 或源码运行时官方要求),fetch 服务器需要 MCP Python SDK 2.x;有一个支持 MCP 的客户端能改服务器启动参数;知道配置文件里 args 列表怎么写。命令与包版本以官方文档当前版本为准。

不覆盖的部分先说清:客户端侧的提示注入防护、OAuth 与远程服务器鉴权、审计日志留存、以及生产环境的网络隔离,都不在这篇里。这篇只处理「本地参考服务器进程」这一层的边界。

开始前的准备

第一件事是核对版本,别按仓库 tag 猜功能。 v2.3.0 是仓库的 tag,仓库里各包独立发版:这次 @modelcontextprotocol/server-filesystem 是 2.2.0,mcp-server-fetch 与 mcp-server-git 是 2026.11.4,其余包也各有自己的版本号。也就是说,看到发布说明里某个开关,要先确认自己装的那个包版本确实带了它,再往下配。这是官方发布说明里专门提醒的一点,跳过会在后面几步白折腾。

第二件事是分清客户端连的是哪一代协议。 官方 README 把连接方式分成两类:走 initialize 握手的 2025-era 客户端支持 Roots,可以在运行时动态改「允许目录」;2026-07-28 协议没有握手、也不会向客户端发起 roots/list 请求,命令行给的目录就是完整白名单。同一份配置在两代协议下的行为不一样,尤其是第 4 步,先看清楚再动手。

第三件事是准备验收材料。 一个只读目录、一个可写目录、一个白名单内的域名、一个白名单外的域名,外加一个响应慢的地址。后面每一步都靠这几个样例来确认「边界真的生效了」,而不是靠配置文件看起来对。

前置成本说明。 filesystem 走 npx 需要 Node.js 24 或更高版本;fetch 走 uvx 需要 Python 环境与 MCP Python SDK 2.x。两者都是本地进程,没有额外的服务费用;若用 Docker 方式运行 filesystem,需要能挂载目录并指定 ro 标志。涉及计费与额度的地方本文一律写「以官网为准」,不转述具体数字。

步骤详解

第 1 步:用命令行参数写死允许目录。 启动时把目录作为位置参数传给服务器,形如 mcp-server-filesystem /path/to/dir1 /path/to/dir2。官方明确说这是「在每一个协议版本下都可用」的方法,所以是默认选择;Roots 作为替代方式在 2026-07-28 协议里已被标记为弃用,且新协议连接根本用不上它。看到什么算成功:v2.3.0 新增了「启动时记录生效的允许目录及其来源」,日志里应当列出你传入的目录;没有命令行目录、且 2025-era 客户端又不支持 Roots 时,服务器会记录原因、关闭连接并以状态码 1 退出,看到这个退出就是在提醒你参数漏了。

第 2 步:加 --read-only,把写工具从列表里摘掉。 在参数里加 --read-only,形如 mcp-server-filesystem --read-only /path/to/dir1 /path/to/dir2。加上之后,服务器只注册被标注为 readOnlyHint: true 的工具——读文件、列目录、目录树、搜索文件、取文件信息、列出允许目录这些;write_file、edit_file 等所有带写能力的工具压根不出现在 tools/list 里,调用它们会按「未知工具」报错,而不是返回一个权限不足的提示。看到什么算成功:让客户端列一次工具清单,写类工具不在其中;再手动调一次写入,得到 Unknown tool 一类的错误。这一步的价值在于它由服务端强制执行,与客户端配置成什么样无关,npx 与 Docker 两种方式行为一致,两代协议也都一致。

第 3 步:加 --confine-roots,防止客户端把目录顶掉。 在参数里加 --confine-roots,形如 mcp-server-filesystem --confine-roots /path/to/dir1 /path/to/dir2。不加这个开关时,2025-era 客户端发来的 Roots 会完全替换命令行给的允许目录,不是取交集——这是官方 README 里特别标出的一处。加上之后,客户端的 Roots 只能收窄到命令行目录之内,不能替换或扩宽:落在命令行目录里的 root 按原样允许;包含命令行目录的 root(例如根目录)被收窄到该目录;落在所有命令行目录之外的 root 被忽略并记日志。看到什么算成功:让客户端声明一个比命令行更宽的 root,再试着读目录外的文件,应当被拒并在日志里看到那条被忽略的记录。注意没有命令行目录时这个开关不生效,服务器会在启动阶段给出警告。

第 4 步:只有部分目录要只读时,起两个实例并补一层系统只读。 --read-only 是服务器级的开关,覆盖该实例的全部允许目录,做不到「这个目录只读、那个目录可写」。官方给的做法是跑两个服务器实例:一个带 --read-only 只挂要保护的目录,一个不带、只挂需要写的目录。看到什么算成功:两个实例的工具清单不同,只读那个列不出写工具。但这里还有一层容易漏:这种隔离只在可写实例始终保留命令行目录时成立,2025-era 客户端的 Roots 可能把一个受保护目录暴露给可写实例。所以官方建议在确实要保护的地方,再用操作系统文件权限或 Docker 绑定挂载的 ro 标志补一道系统级只读。两道边界各防各的,别用其中一道替代另一道。

第 5 步:给 fetch 服务器加 --allowed-hosts。 在 args 里加 --allowed-hosts 后跟一个或多个主机名,参数也可以重复写,形如 uvx mcp-server-fetch --allowed-hosts docs.python.org 再加一个通配子域条目。每条只写主机名,不带协议、端口与路径;支持精确主机名、以星点开头的通配子域、以及 IP 字面量;匹配忽略大小写与结尾的点,国际化域名可写 Unicode 或 xn-- 形式。这个名单在服务器发出每一次请求之前按 URL 里的主机名检查,覆盖请求的页面、它的 robots.txt 检查、以及两者各自的每一跳重定向,工具调用与提示词发起的调用一视同仁。看到什么算成功:请求一个名单外的域名,应当在请求发出之前就被拒,错误信息里点名被拒的主机。

第 6 步:把通配子域和基域分别列上。 以星点开头的条目(形如星点加 github.com)匹配任意深度的子域,但不包含基域本身。想同时允许两者,必须把基域单独再列一条。IP 字面量条目只匹配网址里直接写该地址的情况,不匹配域名解析到该地址的情况。看到什么算成功:基域和任意子域各请求一次都通过;只写通配条目时,基域那次应当被拒。这一条看着琐碎,却是白名单上线后最常见的误判来源——现象是「明明配了白名单,官网却打不开」。

第 7 步:把超时按三层优先级配好。 fetch 的 HTTP 请求超时有三处可设,最具体的生效:单次调用的 timeout_ms 参数、服务器级的 --timeout-ms 参数、以及 FETCH_TIMEOUT_MS 环境变量。三处都接受 100 到 600000 毫秒之间的整数,默认 30000;超出范围时服务器拒绝启动,单次调用传超范围的值也会被工具拒绝。服务器级的值同时是工具对外声明的 timeout_ms 默认值。看到什么算成功:给一个明显超时的慢地址设一个较小的 timeout_ms,返回带 isError: true 的工具结果,文本里写明等了多久。这里要记住它界定的是「连接阶段,以及此后每一次读取」分别计时,不是整次下载的总时长——一个持续有数据到达的大页面不会因为总时长被切断。

第 8 步:确认私有地址守卫仍然开着,并做一次整体验收。 白名单与私有地址守卫是两道独立的检查,请求必须同时通过:服务器默认拒绝解析到回环、私网、链路本地、共享地址段、多播以及云元数据端点等非公网地址的请求,且每一跳重定向与 robots.txt 请求同样检查;把内部主机写进白名单并不会自动放行,那还需要 --allow-private-ips,而这个开关反过来也不会解除白名单。看到什么算成功:把 localhost 之类写进白名单再请求,仍然被拒。最后按第 2、5、7 步各准备一个必然失败的请求——一次写工具调用、一次白名单外域名、一次人为设小的超时——三者都应返回明确可读的错误,而不是静默成功或空结果。把这三条写进你的验收清单,以后每次升级包版本都重跑一遍。

常见坑与排错

目录名恰好叫 --read-only 或 --。 v2.3.0 的命令行解析会把这两个字符串当成选项,若真有这样的目录,要放在 -- 之后传入,用 -- 结束选项解析。官方发布说明把这条列为升级时需要注意的兼容性细节之一,属于不常见但一旦撞上很难自己猜到的情况。

以为 Roots 会和命令行目录取交集。 不会,是替换。2025-era 客户端发来的 Roots 会完全覆盖命令行允许目录,不加 --confine-roots 就可能把边界撑开。反过来,2026-07-28 协议下不会向客户端要 Roots,命令行目录就是全量白名单;服务器不带命令行参数启动时,这类连接上的每一次工具调用都会返回「没有允许目录」的错误。两代协议的行为要分开验,别用一次测试覆盖两种。

通配子域不含基域。 第 6 步已展开,这里再列一次是因为它的症状最容易被误读成「服务坏了」。另外白名单按 URL 里的主机名匹配,不按解析后的 IP 判断;私有地址守卫按解析结果判断,但官方明确提示它挡不住检查与连接之间发生的 DNS rebinding,也检查不了只有代理才能解析的主机名。这两点属于已知边界,不要当成已经解决。

robots.txt 返回 5xx 或 401、403 时抓取被拒。 官方说明:工具发起的抓取会遵守 robots.txt,且每一跳重定向也按目标主机的 robots.txt 检查;若 robots.txt 请求连不上,或返回 401、403、5xx,工具会拒绝抓取而不是把响应当规则读(RFC 9309 把 5xx 视为全部禁止);其他 4xx 视为无规则。提示词发起的抓取默认不受此约束。用 --ignore-robots-txt 可以关掉,但那是在改合规姿态,不是排错手段。

超时设了却没按预期触发。 先分清三件事:HTTP 请求超时只管连接与每次读取,不管整次下载;robots.txt 检查另有一套 5 秒超时;HTML 抽取在子进程里跑,也不受这个 HTTP 超时覆盖。所以「页面下载很久却没超时」不一定是配置没生效。另外单次调用的 timeout_ms 会盖过服务器级设置,排查时先把三处都打印出来看优先级。

版本号对不上,以为开关不存在。 前面提过一次:仓库 tag 与各包版本不同步。按仓库 tag 去判断「我该有这个功能」会得出错误结论,以你实际安装的包版本对应的 README 为准。

把只读当成安全边界的全部。 --read-only 让写工具不被注册,但它不覆盖同一台机器上其他进程、也不覆盖其他 MCP 服务器。官方把系统级文件权限与 Docker ro 挂载写成建议而不是可选项,原因就在这里。同理,git 服务器这次新增的 git_remote 是只读列举工具,会遮蔽远程地址里携带的凭据;但它只是「新增了一个只读工具」,不意味着整个 git 服务器变成只读——同一版还新增了 git_merge。别从一条发布说明推出全局结论。

进阶用法

把三道边界当成一条纵深链来设计,而不是三个独立开关。 命令行目录定义「共享范围」,--read-only 定义「能力面」,操作系统级只读或 Docker ro 挂载定义「兜底」;--confine-roots 则负责让客户端没法在运行时改写第一道。写配置时按这个顺序问一遍:范围给了吗、能力收了吗、客户端能改吗、系统层兜住了吗。四问都有答案,才算一条完整的边界。

用工具标注驱动客户端的自动放行策略。 官方 README 给 filesystem 的每个工具都设了 MCP 工具标注:readOnlyHint 区分读与写,idempotentHint 与 destructiveHint 只在 readOnlyHint 为 false 时有规范含义,每个文件系统工具还都设了 openWorldHint: false 表示不触达外部世界;fetch 工具则标成 readOnlyHint: true 且 openWorldHint: true。客户端可以据此决定哪些工具自动执行、哪些要人工确认,比在提示词里写「不要删文件」可靠得多。注意 readOnlyHint 为 true 的工具也照样带着另外两个标注,官方这么做的目的是让那些不先检查 readOnlyHint 的客户端也不会读错。

按任务类型拆服务器实例,而不是给一个实例开满权限。 只读查资料的会话挂一个 --read-only 实例,需要写入的会话另挂一个范围更窄的实例,两边各自记录生效的允许目录与来源。这样出问题时日志里能直接看出是哪个实例越了界,也避免为了偶尔一次写入就让常驻会话一直带着写能力。v2.3.0 新增的「启动即记录生效目录及其来源」正是为这种排错场景准备的。

把验收做成可重跑的清单。 第 8 步那三个必然失败的请求,配上「列出工具清单核对写工具是否消失」「声明一个更宽的 root 看是否被收窄」「基域与子域各请求一次」这三项,就是一份六条的回归清单。每次升级包版本先跑它,再谈新功能——包的独立版本号决定了升级后的行为不能只靠发布说明推断。

常见问题

加了 --read-only,是不是就不会误删文件了?

在这一台服务器、这一份配置下,写工具压根不会注册,客户端列不到也调不动,比「调用时拒绝」更彻底。但它不覆盖同一台机器上的其他进程、其他 MCP 服务器,也不覆盖已经存在的其他写入通道。涉及不可恢复的资料时,按官方建议再补一层操作系统文件权限或 Docker 绑定挂载的 ro 标志,把边界落在系统层而不是应用层。

--allowed-hosts 能不能代替私有地址守卫?

不能,两者是独立的检查,请求必须同时通过。白名单按 URL 里的主机名判断,私有地址守卫按解析出的地址判断;把内部主机写进白名单不会自动允许访问内网,那还需要 --allow-private-ips,而这个开关也不会解除白名单。更重要的是官方明确写了守卫的已知边界:它在请求前检查解析结果,挡不住检查与连接之间发生的 DNS rebinding,也检查不了只有代理才能解析的主机名。需要访问内网时,先把网络拓扑单独评估,别把开关当成结论。

两代协议的 Roots 差异会怎么影响我?

差别集中在「客户端能不能改允许目录」。走 initialize 握手的 2025-era 客户端支持 Roots,默认行为是完全替换命令行目录;2026-07-28 协议没有握手,也不向客户端发起 roots/list,命令行目录就是全量白名单。若你用的是老客户端,务必加 --confine-roots;若是新协议,重点反而是别漏传命令行目录。两种环境都有的话,两边各验一次,不要互相代推。

超时设大一点是不是就一劳永逸了?

不是。HTTP 请求超时只界定连接与每次读取,不界定整次下载;robots.txt 检查另有 5 秒超时,HTML 抽取在子进程里也不受它覆盖。把值调大只是让慢请求等更久,反而可能让一次异常调用长时间占着连接。更稳的做法是按任务类型分层设:常规抓取用服务器级的默认值,个别大页面在单次调用里用 timeout_ms 单独放宽,并把失败重试写在调用侧。具体取值范围以官方文档为准。

客户端已经在提示词里写了「不要写文件」,还需要这些开关吗?

需要。提示词是建议,服务端开关是强制执行。官方把这版只读模式设计成「由服务器而不是客户端决定哪些工具可用」,正是为了让边界不随客户端配置、模型判断或提示词改写而漂移。同理,主机白名单在请求发出之前就拦截,比让模型自己判断「这个域名能不能访问」可靠。提示词仍可保留,但它应当是最后一层说明,不是第一层约束。

相关工具与内容

能接 MCP 服务器的客户端,站内 Claude Code、Cursor、Cline 与 Cherry Studio 的详情页都有各自的接入说明;按类目看 AI编程工具 与 AI智能体 两个分类页,也能找到同一层的工具对照。

延伸阅读:给智能体配自主权契约 讲的是「允许做什么」在策略层怎么写,与本文在进程层怎么强制,正好是一体两面;Agentic Workflows 的四道护栏 处理的是工作流里的写权限与出网白名单,思路相近但落点不同;给智能体接上实时联网搜索 是联网侧的接线实操,与本文的 fetch 服务器边界可以连着读;AI 代码评审的三层闸门 同样在讲「边界装在哪一层」这件事。选型侧的判断在 给智能体接联网检索。

一手来源(官方页面,仅作溯源):MCP 参考服务器 v2.3.0 发布说明 https://github.com/modelcontextprotocol/servers/releases/tag/v2.3.0 ;官方 filesystem 服务器 README https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem ;官方 fetch 服务器 README https://github.com/modelcontextprotocol/servers/tree/main/src/fetch 。命令、参数与版本门槛以官方文档当前版本为准。

Related
教程 18 小时前

站点怎么接待 AI 智能体:从看见流量到分级放行

把「来访的 AI 智能体」当成需要分级接待的对象:先枚举流量,再按不标识、会话、账户、逐用户固定标识四档定要求,然后写成机器可读策略并配可复测的验收断言。

教程 11 阅读
快讯 1 天前

AWS 推出 Web Answer on Amazon Bedrock AgentCore:一次调用返回带引用的联网答案,经 MCP 接入

AWS 于 2026 年 11 月 5 日在 What's New 宣布 Web Answer on Amazon Bedrock AgentCore 正式可用。这是一个托管工具:智能体发出一个自然语言问题,一次调用就能拿到带引用、基于当前网页来源综合好的答案,无需自建检索、综合与引用链路。它建立在 6 月推出的 Web Search 之上,作为 AgentCore Gateway 的 target 经 MCP 调用、用 IAM 鉴权,当前仅在美国东部(弗吉尼亚北部)区域开放。

前沿快讯 24 阅读

继续阅读:AI 视频字幕怎么选:从剪辑内建到转码管线的五条路线 · 站点怎么接待 AI 智能体:从看见流量到分级放行

关于本文:本站文章由编辑部独立撰写,评测口径与免责说明见关于我们。想继续找工具,可从分类导航按场景浏览,或回首页搜索。

链接已复制