2.1 filesystem:带访问控制的文件读写

它是什么

官方描述:sandboxed file read/write with path allowlists——带路径白名单的沙箱化文件读写。npm 包 @modelcontextprotocol/server-filesystem,版本 2.0.0,可执行名 mcp-server-filesystem。

在 2026 年 3 月的全球搜索量榜单上它排第 29(约 4.9k/月)。排名不高,但它是最基础的骨干——很多更复杂的 MCP 服务器本质上也是在帮模型更安全地碰到文件。

为什么 dsh 已经有了还要装

dsh 自带文件系统能力(见 DeepSeek Harness 完全使用指南),那这个服务器是不是多余?分场景看:

场景 用 dsh 自带 用 filesystem MCP
当前工作区内的文件 ✅ 更顺 多余
需要限定只读某个目录 靠审批 ✅ 白名单硬约束
跨多个 agent 工具复用同一套约束 ❌ ✅
给不信任的任务划安全边界 靠配置 ✅ 服务端强制
让外部 agent 只碰指定资料夹 ❌ ✅

核心差异在最后两列:白名单是服务端强制的,不依赖使用者记得开审批,也不会因为某次会话忘了切目录就扩大范围。审批是“请你确认”,白名单是“它物理上就进不去别的目录”——后者更省心。

安装与配置

先装:

npm install --global @modelcontextprotocol/server-filesystem

接进 dsh 的标准写法:

- insert:
    - id: fs-docs
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: filesystem
        transport: stdio
        command: mcp-server-filesystem
        args:
          - /Users/you/allowed-docs
        cwd: !!js process.cwd()

args 里列出的就是允许访问的目录。几个必须注意的点:

想达到的效果 args 写法
只开放一个目录 ["/abs/path"]
开放多个目录 ["/abs/a", "/abs/b"]
可读仓库但只写临时目录 装两个实例:一个只读工程根、一个只写 /tmp
  • 路径必须是绝对路径,相对路径会被直接拒绝;
  • 每一项单独成行,别用空格把多个目录拼进同一个字符串;
  • 符号链接按解析后的真实路径判定,指不出去也白搭。

进阶:用多实例做读写隔离

白名单是按“实例”生效的。如果你既想让 agent 读工程代码、又想让它把产物写进别处,不要在一个白名单里把两个都放开——那样“读代码”和“写产物”就共享了同一个大范围。更干净的做法是挂两个 filesystem 实例:

- insert:
    - id: fs-readonly-code
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: fs_code
        transport: stdio
        command: mcp-server-filesystem
        args: ["/Users/you/project"]
        cwd: !!js process.cwd()
    - id: fs-write-tmp
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: fs_tmp
        transport: stdio
        command: mcp-server-filesystem
        args: ["/tmp/scratch"]
        cwd: !!js process.cwd()

这样模型手里有 mcp__fs_code__... 和 mcp__fs_tmp__... 两套工具,写操作天然被限制在 /tmp/scratch,读代码始终在 project。权限边界写在配置里,不靠临时叮嘱。

一条安全纪律

只开放真正需要的目录。给整个 home 目录等于没限制——那不如直接用 dsh 自带能力,至少还有审批兜底。

实务上的分层做法:

~/.dsh/skills/          技能目录(按需)
/Users/you/allowed-docs 资料目录(常用)
/tmp/scratch            临时目录(可放开)

典型场景:你要让 agent 处理一批下载文件,但绝不想让它碰到代码仓库。把下载目录加进白名单、把仓库排除在外,就是 filesystem MCP 比“全局审批”更省心的用法。

常见用法

批量整理:

用 filesystem 服务器列出 allowed-docs 下所有 .md,
按文件名前缀分到对应子目录,列出移动清单先别动。

内容检索:

用 filesystem 服务器在 allowed-docs 里搜索包含"迁移"的文件,
返回路径与匹配行号。

受控写入:

用 filesystem 服务器把会议纪要写入 /tmp/scratch/notes/,
文件名用今天日期,写前先确认目录存在。

排错

现象 原因
路径不存在报错 args 里的目录没建
明明在目录里却读不到 给了相对路径,需绝对路径
符号链接指不出去 白名单按解析后路径判定
写入被拒 目标不在白名单目录内
中文路径乱码 终端编码问题,避免路径含非常规字符

它和另外几个服务器的关系

  • 需要跨会话记住文件元数据或笔记 → 看 2.2 memory;
  • 需要操作 Git 仓库(提交、分支、对比)→ 看 2.3 git;
  • 需要读网页再落盘 → 看 2.4 fetch。

小结

  • filesystem 的价值在服务端强制的路径白名单,不是能力本身。
  • 只开放真正需要的目录,给整个 home 等于没限制。
  • 适合跨工具复用约束、给不信任任务划边界、让外部 agent 只碰指定资料夹。
  • 多目录与读写分离,靠多实例而非一个大白名单实现。

延伸阅读