mcp-file-server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-file-serverList files in the sandbox and read notes.txt for me"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
文件系统 MCP Server
一个基于 FastMCP 的本地文件系统 MCP Server。
让 AI 能够安全地读、写、检索你指定的目录 —— 所有操作都被限制在一个白名单根目录内,越界请求会被拒绝。
为什么做这个
大语言模型本身读不了你磁盘上的文件。要让 Agent 操作本地文件,必须给它工具。
但给 AI 一个能读写文件的工具,本身就是个危险动作:
read_file("../../Windows/System32/drivers/etc/hosts")—— 读系统文件write_file("../../important.txt", "")—— 覆盖任意文件search_content(".", "password")—— 扫出你的密钥
所以这个项目的重点不是"能读写文件",而是**"在能读写文件的同时,保证它跑不出去"**。
Related MCP server: MCP File Server
提供的能力
工具 | 参数 | 作用 |
|
| 读取文件内容 |
|
| 列出目录内容(区分目录/文件,目录在前) |
|
| 写入新文件(已存在则拒绝,不覆盖) |
|
| 递归搜索文件内容,返回 |
path 一律相对沙箱根目录,用 / 分隔。
一次完整调用长什么样
对 Host(Claude Desktop / 其他 MCP 客户端)说:
看看 sandbox 里有什么,把 notes.txt 的内容读出来,然后新建一个 backup.txt 把内容抄进去。
Agent 会依次调用:
list_dir(".") → 目录: sub
文件: notes.txt
文件: second.txt
read_file("notes.txt") → 这是一份测试文件。...
write_file("backup.txt", "这是一份测试文件。...") → 成功:已写入文件 backup.txt。🔒 安全设计(核心部分)
白名单根目录
BASE_DIR 是这个 Server 的权限边界。所有路径操作都必须落在这个目录内。
BASE_DIR = Path(__file__).resolve().parent / "sandbox"用 __file__ 锚定,而不是相对路径 —— 否则同一个脚本在 PyCharm 里跑和命令行跑,cwd 不同,BASE_DIR 就指向不同地方。
sandbox 放在脚本同级目录,这样整个项目可以整体搬走,不用改任何路径。
四步校验
def _safe(path: str) -> Path:
target = (BASE_DIR / path).resolve() # ① 拼接 + ② 展开
if not target.is_relative_to(BASE_DIR): # ③ 判断
raise ValueError(f"Path escapes sandbox: {path}")
return target # ④ 交付步骤 | 做什么 |
① | 把用户输入接到根目录下 |
② | 把 |
③ | 判断真实路径是否仍在根目录内 |
④ | 在里面就交付,不在就拒绝 |
⚠️ 顺序不能反 —— 有实测证据
is_relative_to() 只比较路径段,不帮你展开 ..。
攻击路径 : ...\sandbox\..\..\secret.txt
不 resolve 直接判断 : True ← 放行了,防护完全失效
resolve 后判断 : False ← 拦住了原因:sandbox\..\..\secret.txt 在字面上"以 sandbox 开头",所以 is_relative_to() 认为是子路径。
所以必须先算清真实落点,再判断范围。
⚠️ 也不能自己写字符串前缀判断
if ".." in path: ... # ❌ 符号链接 / Windows 短名可绕过
if str(target).startswith(str(BASE_DIR)): ... # ❌ 见下实测:
Path('C:/ab').is_relative_to(Path('C:/a')) → False ✅ 正确
'C:/ab'.startswith('C:/a') → True ❌ 误判C:/ab 是一个叫 ab 的目录,不是 a 下的 b。字符串前缀会把它们混淆。
为什么抽成独立函数
四个工具都需要同一套校验。抽出来之后,新增工具时忘了调用会非常显眼(因为每个函数开头都长一样)。抄在每个函数里,迟早漏一个。
错误处理设计
这个 Server 的"用户"是模型,所以错误信息不是给人看的日志,而是给模型的指令。
分界线
错误类型 | 处理方式 | 原因 |
安全类(越界) |
| 语义上是"程序拒绝执行",也便于留告警痕迹 |
业务类(不存在 / 是目录 / 编码错) |
| 属于"正常失败",模型应该读懂并换路径重试 |
异常消息用 ASCII(英文) —— 中文错误信息在 Windows 终端会乱码,模型可能也收到乱码,那就谈不上自愈了。
错误信息必须带"下一步动作"
错误:文件不存在(nope.txt)。可以先调用 list_dir 看看有什么。
错误:notes.txt 是文件不是目录,请用 read_file。
错误:路径为空。请传入相对于 sandbox 根目录的路径(例如 notes.txt)。每条都告诉模型接下来该怎么做,而不只是"失败了"。
对比反例:
错误:无法写入文件 deep/a.txt。 ← 模型不知道是权限、磁盘还是路径问题快速开始
环境
Python ≥ 3.10(开发环境为 3.13)
fastmcp >= 4.0
# 方式一:只装运行时依赖
pip install fastmcp
# 方式二:按 pyproject.toml 的声明安装(依赖 + 本项目)
pip install -e .方式二的好处:依赖清单写在 pyproject.toml 里,换台机器一条命令就能装齐,
而且以后加依赖只改那一处。
运行
# 直接运行(stdio,供 Host 调用)
python agent_mcp.py
# 用 CLI 查看它暴露了哪些工具
fastmcp list agent_mcp.py
# 命令行直接调一个工具
fastmcp call agent_mcp.py read_file path=notes.txt验证
# 正常读取
fastmcp call agent_mcp.py read_file path=notes.txt
# 越界 —— 应该被拒绝
fastmcp call agent_mcp.py read_file path=../secret.txt
fastmcp call agent_mcp.py read_file path=C:/Windows/win.ini
# 业务错误 —— 应该返回可读的提示
fastmcp call agent_mcp.py read_file path=nope.txt
fastmcp call agent_mcp.py read_file path=.
# 空路径
fastmcp call agent_mcp.py read_file path=
# 搜索(递归 + 行号)
fastmcp call agent_mcp.py search_content path=. keyword=hello判据:正常路径返回内容;两条越界返回 Path escapes sandbox;其余返回中文友好提示。
接进 Host
在 Host 的 MCP 配置里加上:
{
"mcpServers": {
"file-server": {
"command": "python",
"args": ["/绝对路径/agent_mcp.py"]
}
}
}⚠️
command必须是装了 fastmcp 的那个 Python 的绝对路径,不能只写python。多环境机器上写错会出现ModuleNotFoundError: No module named 'fastmcp'。
目录结构
mcp-file-server/
├── agent_mcp.py # Server 本体(四个工具 + _safe)
├── README.md
├── TEST-CASES.md # 测试样本清单 + 分场景测试命令 + 问题记录
├── pyproject.toml
├── .gitignore
├── LICENSE
└── sandbox/ # 沙箱根目录 = BASE_DIR,模型只能在这里操作
├── notes.txt / second.txt # 普通文本
├── empty.txt / blank.txt # 0 字节 / 纯空白
├── gbk.txt / bom.txt # GBK 编码 / UTF-8 BOM
├── crlf.txt # CRLF 换行
├── bin.dat # 假二进制 → 验证"读不了就跳过"
├── long.txt # needle 命中 60 行 → 验证结果上限
├── hello_big.txt # 190 KB → 验证大文件截断
├── huge_line.txt # 单行 50 KB → 验证单条截断
├── edge_20000.txt / edge_20001.txt # 长度上限的边界值
├── no_extension / my notes.txt / 中文文件.txt
├── empty_dir/ # 空目录 → 验证「(空目录)」
├── docs/ logs/ # 子目录,验证递归
├── data/2026/09/report/ # 5 层深
└── sub/deep/c.txt # 关键词在第 2、4 行 → 验证递归 + 行号⚠️
empty_dir/是空目录,而 Git 不跟踪空目录 —— clone 下来它不存在。 要跑list_dir path=empty_dir这条测试,先手动创建:mkdir sandbox\empty_dir。
每个样本具体测哪个分支,见 TEST-CASES.md 的「一、样本清单」。
sandbox 与脚本同级 —— BASE_DIR = Path(__file__).resolve().parent / "sandbox"。
整个目录可以随意搬动/改名,不需要改代码。
已知限制
限制 | 说明 |
不支持覆盖写入 | 文件已存在时 |
不自动创建父目录 | 写到不存在的目录会报错,不支持 |
只支持 UTF-8 文本 | 读写都按 UTF-8 处理,二进制文件读不了(搜索时会跳过) |
搜索有结果上限 | 默认 50 条( |
读取有长度上限 | 超过 20000 字符( |
列目录只做一层 | 不递归 —— 递归遇到软链接可能刷出几十万行 |
后续计划
write_file增加overwrite参数,支持显式覆盖搜索结果支持大小写不敏感选项
部署为远程 MCP Server(HTTP/SSE)
补充自动化测试
开发笔记
踩过的坑(部分)
坑 | 现象 |
| Windows 上解析成 |
| 抛 |
| 不存在的路径 |
| 空路径会定位到根目录本身,被误判为"是目录" |
| 空关键词会匹配所有行,必须挡空 |
| 必须 |
| 结果上限的内外两层都要管 |
测试方法
验证一个工具不是"跑一次看能不能用",而是"把每一种失败都跑一遍"。
以 read_file 为例,测试矩阵:
输入 | 期望 |
正常文件名 | 返回内容 |
| 越界拦截 |
| 越界拦截(绝对路径) |
不存在的文件 | 友好提示 |
| 友好提示 + 建议用 list_dir |
| 友好提示 |
| 友好提示 |
大文件(超过 20000 字符) | 截断到前 8000 字符 + 注明总长度 |
正好卡在上限的文件 | 不截断(边界值) |
其中空字符串、全空格、绝对路径这三条都是跑测试才发现的,写代码时想不到。
另外三条经验:
成功路径必须第一个测。 失败路径再多也证明不了核心功能是好的 —— 曾有一版四个失败路径全过,唯一失败的是"应该成功"那条,因为 bug 藏在唯一没被拦的路径上。
测试样本本身要先验证。 要测"二进制文件被跳过",得先确认那个文件真的会抛
UnicodeDecodeError;否则测试"通过"了,实际什么都没测到。边界值要成对测,造完立刻断言。
>和>=差一个字行为就不同,只测"远大于上限"的输入两种写法都通过 —— 必须拿正好卡在两侧的输入才验得出来。而造这类样本时(如"20001 字符"),先assert len(s) == 20001再拿去测:曾用'0' * (n // 10)造样本,整除丢余数导致两个文件一样大,边界根本没测到。
License
MIT
Related MCP Connectors
Securely search and manage workspace context files for AI agents and teams.
Sandbox workspace tools: search, file read, DB queries, integrations. Returns synthetic data.
Artifact store for AI agents — read, write, and search files by path; share by rendered URL.
The trust harness for AI agents. Set what an agent can do before it acts.
Related MCP Servers
- FlicenseAqualityDmaintenanceEnables secure filesystem operations with directory sandboxing and optional read-only mode. Supports file reading/writing, directory management, file searching, and text operations while restricting access to specified directories.12-
- AlicenseNot gradedqualityDmaintenanceProvides secure, sandboxed filesystem operations including reading, writing, listing, searching, and managing files and directories within a configurable working directory with strict security controls.3MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to safely explore directories, read files, search content by pattern or filename, and edit files with checksum verification and dry-run preview within sandboxed filesystem access.6 npm75ISC
- FlicenseNot gradedqualityDmaintenanceProvides secure file read and write operations within a sandboxed directory, allowing AI assistants to safely create, modify, and access files without risk of accessing the broader file system.-