MCP 实战系列(Day 2)- 动手搓个文件系统 MCP 服务器
上期回顾:MCP 实战系列(Day 1)- 什么是 MCP?
在上期文章中,我们详细介绍了 Model Context Protocol(MCP)的基本概念和应用场景。本节将带领大家开发一个简易的 Filesystem MCP Server,通过代码示例逐步讲解实现细节。
本期目标:掌握 MCP Server 开发的基础框架,实现一个支持基本文件系统操作的服务器。
开源地址:https://github.com/jinzcdev/mcp-demos

开发环境准备
官方提供了 Python、Node、Java、Kotlin、C# 五种语言的 MCP 服务器 SDK。本文以 Python 为例进行开发,其他语言的实现方式类似。读者可根据实际项目需求选择熟悉的开发语言。
MacOS/Linux 系统
- 安装 uv 工具
curl -LsSf https://astral.sh/uv/install.sh | sh
- 创建项目目录并安装依赖
# 创建项目目录并进入
uv init simple-filesystem-server-python
cd simple-filesystem-server-python# 创建虚拟环境并激活
uv venv
source .venv/bin/activate# 安装 MCP 相关依赖
uv add "mcp[cli]"# 创建 MCP Server 文件
touch simple_filesystem.py
说明:uv 是一个高效的 Python 包管理工具,功能类似 pip。如果更熟悉 pip,也可以使用 pip install "mcp[cli]" 安装依赖或创建虚拟环境。mcp[cli] 中的 cli 表示额外安装 typer 和 python-dotenv 两个库,前者用于创建命令行界面,后者用于加载环境变量(可通过查看 mcp 依赖库源代码中的 project.optional-dependencies 配置项找到这两个额外依赖)。最后创建的 simple_filesystem.py 文件是定义 MCP 服务的核心源文件,我们将在其中创建相关工具。
编写 MCP Server 代码
我们将实现一个简易的 Filesystem MCP Server,支持在指定目录中进行文件查找、读写等操作。
值得一提的是,Claude 官方已经提供了一个功能完备的 Node.js 版本 Filesystem MCP Server,包含了丰富的文件系统操作工具。本文选择使用 Python 重新实现,目的是帮助读者更清晰地理解 MCP Server 的 开发流程 和 工具设计思路,而非重复造轮子。
接下来,让我们逐步实现这个服务器。
1. 导入必要模块并初始化服务器
完成前面的准备步骤后,我们首先在 simple_filesystem.py 中导入所需模块,并通过命令行参数指定允许访问的目录:
from mcp.server.fastmcp import FastMCP
import os
import os.path as osp
import argparseparser = argparse.ArgumentParser(description="Simple Filesystem MCP Server")
parser.add_argument("allowed_dirs", nargs="+", help="List of allowed directories for file operations")
args = parser.parse_args()allowed_directories = [osp.abspath(dir_path) for dir_path in args.allowed_dirs]mcp = FastMCP("SimpleFileSystemMCPServer", log_level="ERROR")
说明:使用 argparse 解析命令行参数,在 MCP 服务启动时指定可访问的目录(防止 LLM 访问系统中的任意目录)。这里 FastMCP 初始化了一个名为 Simple Filesystem MCP Server 的服务器实例,日志级别设为 ERROR(测试时发现 Cline 客户端因为服务运行时输出的 INFO 日志导致无法列举服务工具,但不影响工具调用)。
2. 实现工具逻辑
使用 @mcp.tool 装饰器定义以下功能工具,这里的 @mcp.tool 可以理解为在 MCP Server 中注册一个工具,不定义 name 的情况下,工具名默认为函数名称:
(1) list_directory - 查找文件和目录
@mcp.tool(description="获取指定路径下的所有文件和目录的详细列表。返回结果会通过 [FILE] 和 [DIR] 前缀明确区分文件类型。该工具对于了解目录结构及查找特定文件非常实用。仅限在允许访问的目录中操作。"
)
async def list_directory(dir_path) -> str:if not osp.exists(dir_path) or not osp.isdir(dir_path):raise ValueError(f"{dir_path} is not a valid directory")entries = os.listdir(dir_path)formatted = []for entry in entries:entry_path = osp.join(dir_path, entry)if osp.isdir(entry_path):formatted.append(f"[DIR] {entry}")else:formatted.append(f"[FILE] {entry}")return "\n".join(formatted)
该工具返回指定目录下的文件和子目录列表,使用 [DIR] 和 [FILE] 前缀区分。当目录不存在时抛出异常,帮助模型理解当前文件系统状态。
最初定义工具时,我采用了 os.walk 递归调用的方式来实现目录遍历,但目录中可能包含大量依赖文件(如 node_modules),浪费 Token 数,所以我们只需要返回第一层的文件和目录列表即可,必要时让模型继续向下搜索即可。
(2) read_file - 读取文件内容
@mcp.tool(description="读取文件系统中的完整文件内容。支持处理多种文本编码格式,若读取失败将返回详细错误信息。适用于需要检查单个文件内容的场景。仅可在允许访问的目录中操作。"
)
async def read_file(file_path) -> str:if not osp.exists(file_path) or not osp.isfile(file_path):raise ValueError(f"{file_path} is not a valid file")with open(file_path, "r") as file:content = file.read()return content
该工具读取单个文件内容,当文件不存在或无效时抛出异常。
注意:如果文件内容过大也可能导致 Token 数溢出,实际开发中可设置字符数限制,超过则截断或做其他处理。
(3) write_file - 写入文件
@mcp.tool(description="创建新文件或完全覆盖现有文件内容。使用时需谨慎,此操作将直接覆盖目标文件且无警告提示。支持正确处理文本编码,仅限在允许的目录内执行。"
)
async def write_file(file_path, content) -> str:if not osp.exists(osp.dirname(file_path)):raise ValueError(f"Directory for {file_path} does not exist")with open(file_path, "w") as file:file.write(content)return f"Successfully wrote to {file_path}"
该工具实现文件写入功能,在目标目录不存在时抛出异常,成功则返回确认信息。
注意:写文件是危险操作,建议在 MCP 工具调用时确认是否执行该操作,避免误操作导致数据丢失。
(4) read_multiple_files - 批量读取文件
@mcp.tool(description="同时读取多个文件的内容。当需要分析或比较多个文件时,这种方式比逐个读取更高效。每个文件的内容将与其路径一并返回,便于追溯。即使个别文件读取失败,也不会中断整体操作。仅限在允许的目录内执行。"
)
async def read_multiple_files(file_paths) -> str:results = []for file_path in file_paths:try:if not osp.exists(file_path) or not osp.isfile(file_path):results.append(f"{file_path}: Error - Not a valid file")continuewith open(file_path, "r") as file:content = file.read()results.append(f"{file_path}:\n{content}")except Exception as e:results.append(f"{file_path}: Error - {str(e)}")return "\n---\n".join(results)
该工具支持批量文件读取操作,使用分隔符区分不同文件内容(保持数据结构化便于模型理解)。为保证健壮性,单文件读取失败不会中断整个操作,并将错误信息返回给模型处理。
说明:为了便于读者理解,我在上述 4 个工具的 description 部分使用了中文描述,在实际测试中,发现中英文描述均不影响模型理解工具含义。
3. 启动服务器
在文件末尾添加启动代码:
if __name__ == "__main__":mcp.run(transport="stdio")
最后,在项目根目录下,运行命令启动 MCP 服务器:
uv run simple_filesystem.py /path/to/dir1 /path/to/dir2
服务启动后不会有输出,这属于正常现象。下面我们将使用 MCP 客户端测试服务器。
测试 Filesystem MCP Server
常用的 MCP 客户端包括 Claude for Desktop、Cursor、Cline、GitHub Copilot(现已支持 MCP)、Cheery Studio 等。由于 Claude 客户端可能存在国内网络访问问题,而 Cline 与 GitHub Copilot 都内置了文件读取工具,不便测试,因此我们选择 Cherry Studio 进行测试。
安装并配置客户端
从官网 https://cherry-ai.com/ 下载最新版 Cherry Studio。
配置服务器
1、打开 Cherry Studio 的 设置,点击 MCP 服务器
2、手动 添加服务器 或点击 编辑 MCP 配置,将以下配置添加到配置文件中:


{"mcpServers": {"simplefilesystem": {"isActive": true,"name": "Filesystem MCP Server","type": "stdio","description": "用于获取本地目录列表、读写本地文件的 MCP Server","registryUrl": "https://pypi.tuna.tsinghua.edu.cn/simple","command": "uv","args": ["--directory","/ABSOLUTE/PATH/TO/simple-filesystem-server-python","run","simple_filesystem.py","/path/to/dir1","/path/to/dir2"]}}
}
注意:上述配置中的命令行参数 args,需修改为真实的项目地址与允许服务访问的目录。
3、在 设置-模型服务 中选择模型并输入 API Key(需开启函数调用功能),这里选择了 DeepSeek V3:

4、返回聊天页面,在输入框下启用 MCP 服务
功能验证

通过多次工具调用,模型成功读取了本地文件并执行了内容总结。
完整代码已经上传到我的 GitHub 仓库,并封装了更多文件操作的工具,可通过以下命令获取源代码:
git clone https://github.com/jinzcdev/mcp-demos.git
总结
本文详细介绍了如何使用 Python 开发一个简易的 Filesystem MCP Server,实现了四个核心功能工具:
list_directory- 目录内容列表read_file- 单文件读取write_file- 文件写入read_multiple_files- 批量文件读取
通过 Cherry Studio 客户端的测试验证了 Filesystem MCP Server 的功能。开发过程中我总结了以下创建 MCP Server Tools 的核心经验:
- 详尽的工具描述:清晰说明工具功能和使用场景,提升模型调用准确率
- 明确的错误反馈:工具调用失败时返回具体错误信息,辅助模型调整策略
- 保证工具健壮性:局部错误不要中断整体操作,返回部分成功结果
本文是 《从原理到实战:掌握 MCP》 系列的第二篇文章,间隔时间较长了。如果文章对你有帮助欢迎收藏、转发,您的关注是我更新的最大动力。如有疑问欢迎在评论区留言。
往期推荐:
- MCP 实战系列(Day 1):什么是 MCP?
- VS Code 预览版 Copilot 终于支持 MCP 了:试试使用 MCP 快速查询 GitHub Issues 吧
相关文章:
MCP 实战系列(Day 2)- 动手搓个文件系统 MCP 服务器
上期回顾:MCP 实战系列(Day 1)- 什么是 MCP? 在上期文章中,我们详细介绍了 Model Context Protocol(MCP)的基本概念和应用场景。本节将带领大家开发一个简易的 Filesystem MCP Serverÿ…...
LabVIEW运动控制(三):EtherCAT运动控制器的高效加工指令自定义封装
ZMC408CE 高性能总线型运动控制器 ZMC408CE是正运动推出的一款多轴高性能EtherCAT总线运动控制器,具有EtherCAT、EtherNET、RS232、CAN和U盘等通讯接口,ZMC系列运动控制器可应用于各种需要脱机或联机运行的场合。 ZMC408CE支持PLC、Basic、HMI组态三种编…...
Java接口性能优化面试问题集锦:高频考点与深度解析
1. 如何定位接口性能瓶颈?常用哪些工具? 考察点:性能分析工具的使用与问题定位能力。 核心答案: 工具:Arthas(在线诊断)、JProfiler(内存与CPU分析)、VisualVM、Prometh…...
Xilinx虚拟输入/输出(VIO)IP核详细介绍及使用示例
LogiCORE™ IP虚拟输入/输出(VIO)内核是一款可定制化的内核,能够实时监控和驱动FPGA(现场可编程门阵列)内部信号。其输入和输出端口的数量及位宽均可根据需求定制,以便与FPGA设计进行接口对接。由于VIO内核与被监控和/或驱动的设计保持同步,因此应用于您设计中的所有设计…...
Vue3+Vite+TypeScript+Element Plus开发-09.登录成功跳转主页
系列文档目录 Vue3ViteTypeScript安装 Element Plus安装与配置 主页设计与router配置 静态菜单设计 Pinia引入 Header响应式菜单缩展 Mockjs引用与Axios封装 登录设计 登录成功跳转主页 多用户动态加载菜单 Pinia持久化 动态路由-配置 文章目录 目录 系列文档目…...
网络安全应急响应-启动项和任务计划排查
应急响应-启动项排查 在应急响应排查中,启动项和任务计划是攻击者常用的持久化手段。以下是对Windows和Linux系统的详细排查指南,涵盖基础步骤及扩展注意事项: 一、启动项排查 Windows系统 系统配置(msconfig) 运行 …...
Linux : 内核中的信号捕捉
目录 一 前言 二 信号捕捉的方法 1.sigaction()编辑 2. sigaction() 使用 三 可重入函数 四 volatile 关键字 一 前言 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。在Linux: 进程信号初识-CSDN博客 这一篇中已经学习到了一种信号…...
开发效率提升200%——cursor
cursor带来的编程"革命" 高级语言编程转为"自然语言编程"借助cursor,直接超越初级后台开发、超越初级前端开发、超越初级测试、超越初级UI,产研一体linux命令只用学不用记,语言描述就是命令给一个表结构流程提示词&…...
微软庆祝它成立整整50周年
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
SpringBoot 整合 MCP
SpringBoot 整合 MCP MCP MCP 协议主要分为: Client 客户端(一般就是指 openai,deepseek 这些大模型)Server 服务端(也就是我们的业务系统)我们要做的就是把我们存量系统配置成 MCP Server 环境 JDK17…...
【详细】MySQL 8 安装解压即用 (包含MySQL 5 卸载)
卸载MySQL 1.卸载 2.安装目录删除残余文件(当初安装的位置) 3.删除programData下面的mysql数据文件 4.检查mysql服务是否存在,如果存在则删除(先暂停mysql服务) sc delete mysql 5.删除注册表中残留信息 安装MySQL 8&…...
显示器各类异常处理方法
显示器各类异常处理方法 导航 文章目录 显示器各类异常处理方法导航画面无显示/黑屏/无HDMI信号输入显示器闪烁显示器花屏显示画面模糊或扭曲显示器颜色异常显示器出现死点或亮点 画面无显示/黑屏/无HDMI信号输入 首先应该检查的是显示器电源(真的有人弄掉电源…...
关于Spring MVC中@RequestParam注解的详细说明,用于在前后端参数名称不一致时实现参数映射。包含代码示例和总结表格
以下是关于Spring MVC中RequestParam注解的详细说明,用于在前后端参数名称不一致时实现参数映射。包含代码示例和总结表格: 1. 核心作用 RequestParam用于显式绑定HTTP请求参数到方法参数,支持以下场景: 参数名不一致࿱…...
HTML的svg元素
<svg>元素 <svg>是一种用于描述二维矢量图形的 XML 格式,可以直接嵌入 HTML 文档中。 <svg>基本用法 <svg>的几种基本用法,包括圆形,正方形,三角形,直线 ,折线等 <body><svg widt…...
一、简单的 Django 服务
一、配置虚拟环境 1.1 创建一个文件夹在导航栏输入cmd打开 1.2 安装依赖两个库 pip install virtualenv virtualenvwrapper-win -i https://pypi.tuna.tsinghua.edu.cn/simple验证是否安装成功 virtualenv --version pip show virtualenvwrapper-win 1.3 创建虚拟环境 mkvi…...
二分算法的入门笔记
二分查找 使用前提:有序。可理解为枚举的一种技巧。时间复杂度: l o g ( n ) log(n) log(n) 基础模版代码 使用时根据情景进行相应的变化。注意跳出条件and分支处理方式and返回答案,三者之间的配合,不要进入死循环。可以在模拟…...
k8s黑科技:Linux+Vagrant+VirtualBox开启Kubernetes奇幻之旅
文章目录 1. 准备硬件2. 安装系统3. 安装 VNC4. 基础配置4.1 路由转发4.2 防火墙4.3 selinux4.4 安装包4.5 重启 5. 配置代理6. 安装 virtuabox7. 安装 vagrant8. 配置 kubespray8.1 安装依赖工具8.2 定制 Vagrantfile8.3 配置代理与时间同步8.4 配置私有镜像仓库 9. 安装虚拟机…...
34% 关税冲击下 LabVIEW 开发的变局
2025 年 4 月 4 日,中国国务院关税税则委员会宣布,自 4 月 10 日起对原产于美国的所有进口商品加征 34% 关税。这一举措,给 LabVIEW 开发领域带来显著影响,相关使用者和用户亟需采取应对策略。 从成本层面看,LabVI…...
42、JavaEE高级主题:WebSocket详解
WebSocket 一、WebSocket协议与实现 WebSocket是一种基于TCP协议的全双工通信协议,能够在客户端和服务器之间建立实时、双向的通信通道。通过WebSocket,客户端和服务器可以在任何时候发送数据,并立即接收到对方的响应。 1.1 WebSocket协议…...
Http代理服务器选型与搭建
代理服务器选型-Squid 缓存加速 缓存频繁访问的网页、图片等静态资源,减少对原始服务器的重复请求,提升响应速度支持HTTP、HTTPS、FTP等协议,通过本地缓存直接响应客户端请求 访问控制 基于ACL(访问控制列表)实现精细…...
蓝桥杯第十一届省赛C++B组真题解析
蓝桥杯第十一届省赛CB组真题解析 八、回文日期https://www.lanqiao.cn/problems/348/learning 方法一:暴力枚举所有的日期,记录有多少个回文日期。 #include <bits/stdc.h> using namespace std; int month[13]{0,31,28,31,30,31,30,31,31,30,31…...
Linux主要开发工具之gcc、gdb与make
此系列还有两篇,大家想完整掌握可以阅读另外两篇 Linux文本编辑与shell程序设计-CSDN博客 Linux基础知识详解与命令大全(超详细)-CSDN博客 1.gcc编译系统 1.1 文件名后缀 文件名后缀 文 件 类 型 文件名后缀 文 件 类 型 .c C源…...
排序算法(快速排序,选择排序......)【泪光2929】
hello,大家好!今天给大家分享一下各种排序: 1,选择排序 首先从原始数组中 选择最小的1个数据,将其和位于第1个位置的数据交换。接着从剩下的n-1个数据中选择次小的1个元素,将其和第2个位置的数据交换然后…...
Conda使用方法详解
Conda是一个开源的包管理和环境管理系统,主要用于Python/R等科学计算领域,可以轻松管理不同项目的依赖关系。以下是Conda的详细使用方法: 一、安装与配置 1.安装Miniconda/Anaconda Miniconda是精简版,只包含conda和Python Ana…...
数据库的MVCC机制详解
MVCC(Multi-Version Concurrency Control,多版本并发控制)是数据库系统中常用的并发控制机制,它允许数据库在同一时间点保存数据的多个版本,从而实现非阻塞的读操作,提高并发性能。 MVCC的核心思想是&…...
C++初阶-C++入门基础
目录 编辑 1.C的简介 1.1C的产生和发展 1.2C的参考文档 1.3C优势和难度 1.4C学习的建议 2.C的第一个程序 2.1打印Hello world 2.2头文件 2.3namespace命名空间 2.4::作用域限定符 2.5namespace的延伸 2.6C的输入输出 3.总结 1.C的简介 …...
关于量化交易在拉盘砸盘方面应用的部分思考
关于“砸盘”的深层解析与操盘逻辑 一、砸盘的本质与市场含义 砸盘指通过集中抛售大量筹码导致价格快速下跌的行为,其核心目标是制造恐慌、清洗浮筹或实现利益再分配。不同场景下的砸盘含义不同: 主动砸盘(操控…...
idea手动创建resources文件夹
有时maven没有构建成功可能造成,resources文件夹不创建的现象 此时我们可以手动创建 手动创建...
第十五届蓝桥杯大赛软件赛省赛Python 大学 C 组题目试做(中)【本期题目:回文数组,挖矿】
OK,继续写我们的第十五届蓝桥杯大赛软件赛省赛Python 大学 C 组题目,后面的题目比较麻烦了,所以我们再分两期讲。 这一期的题有 : 回文数组,挖矿 文章目录 回文数组基本思路第一步,获取半个数组每个数需要…...
Qt动画 QAbstractAnimation
文章目录 简介QVariantAnimation 数值动画QPropertyAnimation 属性动画 QAnimationGroup 一组动画QParallelAnimationGroup 并行动画组QSequentialAnimationGroup 串行动画组 简介 QAbstractAnimation 是所有 Qt 动画的基类。 该类定义了所有动画应该都会有的功能函数。 要想实…...
