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 系统

  1. 安装 uv 工具
bash 复制代码
curl -LsSf https://astral.sh/uv/install.sh | sh
  1. 创建项目目录并安装依赖
bash 复制代码
# 创建项目目录并进入
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 中导入所需模块,并通过命令行参数指定允许访问的目录:

python 复制代码
from mcp.server.fastmcp import FastMCP
import os
import os.path as osp
import argparse

parser = 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 - 查找文件和目录
python 复制代码
@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 - 读取文件内容
python 复制代码
@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 - 写入文件
python 复制代码
@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 - 批量读取文件
python 复制代码
@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")
                continue
            with 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. 启动服务器

在文件末尾添加启动代码:

python 复制代码
if __name__ == "__main__":
    mcp.run(transport="stdio")

最后,在项目根目录下,运行命令启动 MCP 服务器:

bash 复制代码
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 配置,将以下配置添加到配置文件中:


json 复制代码
{
    "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 仓库,并封装了更多文件操作的工具,可通过以下命令获取源代码:

bash 复制代码
git clone https://github.com/jinzcdev/mcp-demos.git

总结

本文详细介绍了如何使用 Python 开发一个简易的 Filesystem MCP Server,实现了四个核心功能工具:

  1. list_directory - 目录内容列表
  2. read_file - 单文件读取
  3. write_file - 文件写入
  4. read_multiple_files - 批量文件读取

通过 Cherry Studio 客户端的测试验证了 Filesystem MCP Server 的功能。开发过程中我总结了以下创建 MCP Server Tools 的核心经验:

  1. 详尽的工具描述:清晰说明工具功能和使用场景,提升模型调用准确率
  2. 明确的错误反馈:工具调用失败时返回具体错误信息,辅助模型调整策略
  3. 保证工具健壮性:局部错误不要中断整体操作,返回部分成功结果

本文是 《从原理到实战:掌握 MCP》 系列的第二篇文章,间隔时间较长了。如果文章对你有帮助欢迎收藏、转发,您的关注是我更新的最大动力。如有疑问欢迎在评论区留言。

往期推荐:

  1. MCP 实战系列(Day 1):什么是 MCP?
  2. VS Code 预览版 Copilot 终于支持 MCP 了:试试使用 MCP 快速查询 GitHub Issues 吧
相关推荐
行走的小派2 分钟前
解读香橙派5系列:RK3588加持,6TOPS NPU边缘计算实践
人工智能·边缘计算
AI职业加油站4 分钟前
从“取数工具人”到“数据决策者”:传统数据分析师的技能跃迁之路
大数据·人工智能·数据分析
markfeng86 分钟前
TRAE SOLO 移动端远程部署前端项目
人工智能
AIData搭子9 分钟前
让知识在 Agent 间流动 —— 表格存储知识库 Skills 实践指南
人工智能
xiaoduo AI11 分钟前
智能客服机器人能精准预判用户疑问提前主动应答吗?能大幅缩短客户咨询沟通时长吗?
运维·服务器·机器人
user803952795254311 分钟前
Codex 的测试哲学——为什么集成测试比单元测试更重要
人工智能
勤劳的进取家13 分钟前
服务器文件交互方式
运维·服务器·microsoft
hunteritself17 分钟前
GPT Image2 + Seedance 2.0:3 小时从剧本到 AI 互动影游,深度实测复盘
前端·数据库·人工智能·深度学习·transformer
jedi-knight17 分钟前
Vibe SRM:用自然语言设计固体火箭发动机,AI做到了
人工智能·经验分享·agi
java1234_小锋18 分钟前
Spring AI 2.0 开发Java Agent智能体 - 对话与提示词工程(Prompt)
java·人工智能·spring